Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
node-sass
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
楚学文
node-sass
Commits
5bd4581b
Commit
5bd4581b
authored
Oct 04, 2012
by
Aaron Leung
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'expand-eval-apply'
Conflicts: eval_apply.cpp
parents
580c318b
e44e4923
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
396 additions
and
388 deletions
+396
-388
document_parser.cpp
document_parser.cpp
+9
-17
eval_apply.cpp
eval_apply.cpp
+359
-353
eval_apply.hpp
eval_apply.hpp
+4
-2
node.cpp
node.cpp
+4
-2
node.hpp
node.hpp
+12
-7
node_emitters.cpp
node_emitters.cpp
+2
-1
sass_interface.cpp
sass_interface.cpp
+6
-6
No files found.
document_parser.cpp
View file @
5bd4581b
...
@@ -202,7 +202,7 @@ namespace Sass {
...
@@ -202,7 +202,7 @@ namespace Sass {
if
(
!
lex
<
identifier
>
())
throw_syntax_error
(
"invalid name in @include directive"
);
if
(
!
lex
<
identifier
>
())
throw_syntax_error
(
"invalid name in @include directive"
);
Node
name
(
context
.
new_Node
(
Node
::
identifier
,
path
,
line
,
lexed
));
Node
name
(
context
.
new_Node
(
Node
::
identifier
,
path
,
line
,
lexed
));
Node
args
(
parse_arguments
());
Node
args
(
parse_arguments
());
Node
the_call
(
context
.
new_Node
(
Node
::
expansion
,
path
,
line
,
2
));
Node
the_call
(
context
.
new_Node
(
Node
::
mixin_call
,
path
,
line
,
2
));
the_call
<<
name
<<
args
;
the_call
<<
name
<<
args
;
return
the_call
;
return
the_call
;
}
}
...
@@ -215,12 +215,10 @@ namespace Sass {
...
@@ -215,12 +215,10 @@ namespace Sass {
if
(
lex
<
exactly
<
'('
>
>
())
{
if
(
lex
<
exactly
<
'('
>
>
())
{
if
(
!
peek
<
exactly
<
')'
>
>
(
position
))
{
if
(
!
peek
<
exactly
<
')'
>
>
(
position
))
{
Node
arg
(
parse_argument
(
Node
::
none
));
Node
arg
(
parse_argument
(
Node
::
none
));
arg
.
should_eval
()
=
true
;
args
<<
arg
;
args
<<
arg
;
if
(
arg
.
type
()
==
Node
::
assignment
)
arg_type
=
Node
::
assignment
;
if
(
arg
.
type
()
==
Node
::
assignment
)
arg_type
=
Node
::
assignment
;
while
(
lex
<
exactly
<
','
>
>
())
{
while
(
lex
<
exactly
<
','
>
>
())
{
Node
arg
(
parse_argument
(
arg_type
));
Node
arg
(
parse_argument
(
arg_type
));
arg
.
should_eval
()
=
true
;
args
<<
arg
;
args
<<
arg
;
if
(
arg
.
type
()
==
Node
::
assignment
)
arg_type
=
Node
::
assignment
;
if
(
arg
.
type
()
==
Node
::
assignment
)
arg_type
=
Node
::
assignment
;
}
}
...
@@ -239,6 +237,7 @@ namespace Sass {
...
@@ -239,6 +237,7 @@ namespace Sass {
Node
var
(
context
.
new_Node
(
Node
::
variable
,
path
,
line
,
lexed
));
Node
var
(
context
.
new_Node
(
Node
::
variable
,
path
,
line
,
lexed
));
lex
<
exactly
<
':'
>
>
();
lex
<
exactly
<
':'
>
>
();
Node
val
(
parse_space_list
());
Node
val
(
parse_space_list
());
val
.
should_eval
()
=
true
;
Node
assn
(
context
.
new_Node
(
Node
::
assignment
,
path
,
line
,
2
));
Node
assn
(
context
.
new_Node
(
Node
::
assignment
,
path
,
line
,
2
));
assn
<<
var
<<
val
;
assn
<<
var
<<
val
;
return
assn
;
return
assn
;
...
@@ -254,23 +253,14 @@ namespace Sass {
...
@@ -254,23 +253,14 @@ namespace Sass {
Node
var
(
context
.
new_Node
(
Node
::
variable
,
path
,
line
,
lexed
));
Node
var
(
context
.
new_Node
(
Node
::
variable
,
path
,
line
,
lexed
));
lex
<
exactly
<
':'
>
>
();
lex
<
exactly
<
':'
>
>
();
Node
val
(
parse_space_list
());
Node
val
(
parse_space_list
());
val
.
should_eval
()
=
true
;
Node
assn
(
context
.
new_Node
(
Node
::
assignment
,
path
,
line
,
2
));
Node
assn
(
context
.
new_Node
(
Node
::
assignment
,
path
,
line
,
2
));
assn
<<
var
<<
val
;
assn
<<
var
<<
val
;
return
assn
;
return
assn
;
}
}
return
parse_space_list
();
Node
val
(
parse_space_list
());
// if (peek< sequence < variable, spaces_and_comments, exactly<':'> > >()) {
val
.
should_eval
()
=
true
;
// lex< variable >();
return
val
;
// Node var(context.new_Node(Node::variable, path, line, lexed));
// lex< exactly<':'> >();
// Node val(parse_space_list());
// Node assn(context.new_Node(Node::assignment, path, line, 2));
// assn << var << val;
// return assn;
// }
// else {
// return parse_space_list();
// }
}
}
Node
Document
::
parse_assignment
()
Node
Document
::
parse_assignment
()
...
@@ -598,7 +588,7 @@ namespace Sass {
...
@@ -598,7 +588,7 @@ namespace Sass {
semicolon
=
true
;
semicolon
=
true
;
}
}
else
if
(
lex
<
extend
>
())
{
else
if
(
lex
<
extend
>
())
{
if
(
surrounding_ruleset
.
is_null
_ptr
())
throw_syntax_error
(
"@extend directive may only be used within rules"
);
if
(
surrounding_ruleset
.
is_null
())
throw_syntax_error
(
"@extend directive may only be used within rules"
);
Node
extendee
(
parse_simple_selector_sequence
());
Node
extendee
(
parse_simple_selector_sequence
());
context
.
extensions
.
insert
(
pair
<
Node
,
Node
>
(
extendee
,
surrounding_ruleset
));
context
.
extensions
.
insert
(
pair
<
Node
,
Node
>
(
extendee
,
surrounding_ruleset
));
context
.
has_extensions
=
true
;
context
.
has_extensions
=
true
;
...
@@ -1016,6 +1006,7 @@ namespace Sass {
...
@@ -1016,6 +1006,7 @@ namespace Sass {
if
(
lex
<
interpolant
>
())
{
if
(
lex
<
interpolant
>
())
{
Token
insides
(
Token
::
make
(
lexed
.
begin
+
2
,
lexed
.
end
-
1
));
Token
insides
(
Token
::
make
(
lexed
.
begin
+
2
,
lexed
.
end
-
1
));
Node
interp_node
(
Document
::
make_from_token
(
context
,
insides
,
path
,
line
).
parse_list
());
Node
interp_node
(
Document
::
make_from_token
(
context
,
insides
,
path
,
line
).
parse_list
());
interp_node
.
should_eval
()
=
true
;
schema
<<
interp_node
;
schema
<<
interp_node
;
}
}
else
if
(
lex
<
identifier
>
())
{
else
if
(
lex
<
identifier
>
())
{
...
@@ -1080,6 +1071,7 @@ namespace Sass {
...
@@ -1080,6 +1071,7 @@ namespace Sass {
else
if
(
lex
<
interpolant
>
())
{
else
if
(
lex
<
interpolant
>
())
{
Token
insides
(
Token
::
make
(
lexed
.
begin
+
2
,
lexed
.
end
-
1
));
Token
insides
(
Token
::
make
(
lexed
.
begin
+
2
,
lexed
.
end
-
1
));
Node
interp_node
(
Document
::
make_from_token
(
context
,
insides
,
path
,
line
).
parse_list
());
Node
interp_node
(
Document
::
make_from_token
(
context
,
insides
,
path
,
line
).
parse_list
());
interp_node
.
should_eval
()
=
true
;
schema
<<
interp_node
;
schema
<<
interp_node
;
}
}
else
if
(
lex
<
sequence
<
identifier
,
exactly
<
':'
>
>
>
())
{
else
if
(
lex
<
sequence
<
identifier
,
exactly
<
':'
>
>
>
())
{
...
...
eval_apply.cpp
View file @
5bd4581b
...
@@ -20,43 +20,60 @@ namespace Sass {
...
@@ -20,43 +20,60 @@ namespace Sass {
throw
Error
(
Error
::
evaluation
,
path
,
line
,
message
);
throw
Error
(
Error
::
evaluation
,
path
,
line
,
message
);
}
}
// Evaluate the parse tree in-place (mostly). Most nodes will be left alone.
// Expansion function for nodes in an expansion context.
void
expand
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
)
Node
eval
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
)
{
{
switch
(
expr
.
type
())
switch
(
expr
.
type
())
{
{
case
Node
:
:
mixin
:
{
case
Node
:
:
root
:
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expand
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
break
;
case
Node
:
:
mixin
:
{
// mixin definition
env
[
expr
[
0
].
token
()]
=
expr
;
env
[
expr
[
0
].
token
()]
=
expr
;
return
expr
;
}
break
;
}
break
;
case
Node
:
:
function
:
{
case
Node
:
:
function
:
{
// function definition
f_env
[
expr
[
0
].
to_string
()]
=
Function
(
expr
);
f_env
[
expr
[
0
].
to_string
()]
=
Function
(
expr
);
return
expr
;
}
break
;
}
break
;
case
Node
:
:
expansion
:
{
case
Node
:
:
mixin_call
:
{
// mixin invocation
Token
name
(
expr
[
0
].
token
());
Token
name
(
expr
[
0
].
token
());
Node
args
(
expr
[
1
]);
Node
args
(
expr
[
1
]);
if
(
!
env
.
query
(
name
))
throw_eval_error
(
"mixin "
+
name
.
to_string
()
+
" is undefined"
,
expr
.
path
(),
expr
.
line
());
if
(
!
env
.
query
(
name
))
throw_eval_error
(
"mixin "
+
name
.
to_string
()
+
" is undefined"
,
expr
.
path
(),
expr
.
line
());
Node
mixin
(
env
[
name
]);
Node
mixin
(
env
[
name
]);
Node
expansion
(
apply_mixin
(
mixin
,
args
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
expansion
(
apply_mixin
(
mixin
,
args
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
expr
.
pop_back
();
expr
.
pop_all
();
// pop the mixin metadata
expr
.
pop_back
();
expr
+=
expansion
;
// push the expansion
expr
+=
expansion
;
return
expr
;
}
break
;
}
break
;
case
Node
:
:
propset
:
{
case
Node
:
:
propset
:
{
eval
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
// TO DO: perform the property expansion here, rather than in the emitter (also requires the parser to allow interpolants in the property names)
return
expr
;
expand
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
)
;
}
break
;
}
break
;
case
Node
:
:
ruleset
:
{
case
Node
:
:
ruleset
:
{
// if the selector contains interpolants, eval it and re-parse
// if the selector contains interpolants, eval it and re-parse
if
(
expr
[
0
].
type
()
==
Node
::
selector_schema
)
{
if
(
expr
[
0
].
type
()
==
Node
::
selector_schema
)
{
expr
[
0
]
=
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
Node
schema
(
expr
[
0
]);
string
expansion
;
for
(
size_t
i
=
0
,
S
=
schema
.
size
();
i
<
S
;
++
i
)
{
schema
[
i
]
=
eval
(
schema
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
schema
[
i
].
type
()
==
Node
::
string_constant
)
{
expansion
+=
schema
[
i
].
token
().
unquote
();
}
else
{
expansion
+=
schema
[
i
].
to_string
();
}
}
expansion
+=
" {"
;
// the parser looks for an lbrace to end a selector
char
*
expn_src
=
new
char
[
expansion
.
size
()
+
1
];
strcpy
(
expn_src
,
expansion
.
c_str
());
Document
needs_reparsing
(
Document
::
make_from_source_chars
(
ctx
,
expn_src
,
schema
.
path
(),
true
));
needs_reparsing
.
line
=
schema
.
line
();
// set the line number to the original node's line
expr
[
0
]
=
needs_reparsing
.
parse_selector_group
();
}
}
// expand the selector with the prefix and save it in expr[2]
// expand the selector with the prefix and save it in expr[2]
...
@@ -87,56 +104,28 @@ namespace Sass {
...
@@ -87,56 +104,28 @@ namespace Sass {
}
}
}
}
// eval the body with the current selector as the prefix
// expand the body with the newly expanded selector as the prefix
eval
(
expr
[
1
],
expr
.
back
(),
env
,
f_env
,
new_Node
,
ctx
);
expand
(
expr
[
1
],
expr
.
back
(),
env
,
f_env
,
new_Node
,
ctx
);
return
expr
;
}
break
;
}
break
;
case
Node
:
:
media_query
:
{
case
Node
:
:
media_query
:
{
Node
block
(
expr
[
1
]);
Node
block
(
expr
[
1
]);
Node
new_ruleset
(
new_Node
(
Node
::
ruleset
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
new_ruleset
(
new_Node
(
Node
::
ruleset
,
expr
.
path
(),
expr
.
line
(),
3
));
new_ruleset
<<
prefix
<<
block
<<
prefix
;
expr
[
1
]
=
new_ruleset
<<
prefix
<<
block
<<
prefix
;
expr
[
1
]
=
eval
(
new_ruleset
,
new_Node
(
Node
::
none
,
expr
.
path
(),
expr
.
line
(),
0
),
env
,
f_env
,
new_Node
,
ctx
);
expand
(
expr
[
1
],
new_Node
(
Node
::
none
,
expr
.
path
(),
expr
.
line
(),
0
),
env
,
f_env
,
new_Node
,
ctx
);
return
expr
;
}
break
;
}
break
;
case
Node
:
:
selector_schema
:
{
string
expansion
;
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expr
[
i
]
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
expr
[
i
].
type
()
==
Node
::
string_constant
)
{
expansion
+=
expr
[
i
].
token
().
unquote
();
}
else
{
expansion
+=
expr
[
i
].
to_string
();
}
}
expansion
+=
" {"
;
// the parser looks for an lbrace to end a selector
char
*
expn_src
=
new
char
[
expansion
.
size
()
+
1
];
strcpy
(
expn_src
,
expansion
.
c_str
());
Document
needs_reparsing
(
Document
::
make_from_source_chars
(
ctx
,
expn_src
,
expr
.
path
(),
true
));
needs_reparsing
.
line
=
expr
.
line
();
// set the line number to the original node's line
Node
sel
(
needs_reparsing
.
parse_selector_group
());
return
sel
;
}
break
;
case
Node
:
:
root
:
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expr
[
i
]
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
return
expr
;
}
break
;
case
Node
:
:
block
:
{
case
Node
:
:
block
:
{
Environment
new_frame
;
Environment
new_frame
;
new_frame
.
link
(
env
);
new_frame
.
link
(
env
);
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
exp
r
[
i
]
=
eval
(
expr
[
i
],
prefix
,
new_frame
,
f_env
,
new_Node
,
ctx
);
exp
and
(
expr
[
i
],
prefix
,
new_frame
,
f_env
,
new_Node
,
ctx
);
}
}
return
expr
;
}
break
;
}
break
;
case
Node
:
:
assignment
:
{
case
Node
:
:
assignment
:
{
Node
var
(
expr
[
0
]);
if
(
expr
.
is_guarded
()
&&
env
.
query
(
var
.
token
()))
return
;
Node
val
(
expr
[
1
]);
Node
val
(
expr
[
1
]);
if
(
val
.
type
()
==
Node
::
list
)
{
if
(
val
.
type
()
==
Node
::
list
)
{
for
(
size_t
i
=
0
,
S
=
val
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
val
.
size
();
i
<
S
;
++
i
)
{
...
@@ -146,9 +135,8 @@ namespace Sass {
...
@@ -146,9 +135,8 @@ namespace Sass {
else
{
else
{
val
=
eval
(
val
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
val
=
eval
(
val
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
Node
var
(
expr
[
0
]);
if
(
expr
.
is_guarded
()
&&
env
.
query
(
var
.
token
()))
return
expr
;
// If a binding exists (possibly upframe), then update it.
// If a binding exists (possible upframe), then update it.
// Otherwise, make a new on in the current frame.
// Otherwise, make a new on in the current frame.
if
(
env
.
query
(
var
.
token
()))
{
if
(
env
.
query
(
var
.
token
()))
{
env
[
var
.
token
()]
=
val
;
env
[
var
.
token
()]
=
val
;
...
@@ -156,156 +144,280 @@ namespace Sass {
...
@@ -156,156 +144,280 @@ namespace Sass {
else
{
else
{
env
.
current_frame
[
var
.
token
()]
=
val
;
env
.
current_frame
[
var
.
token
()]
=
val
;
}
}
return
expr
;
}
break
;
}
break
;
case
Node
:
:
rule
:
{
case
Node
:
:
rule
:
{
Node
lhs
(
expr
[
0
]);
Node
lhs
(
expr
[
0
]);
if
(
lhs
.
should_eval
())
eval
(
lhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
lhs
.
is_schema
())
{
expr
[
0
]
=
eval
(
lhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
Node
rhs
(
expr
[
1
]);
Node
rhs
(
expr
[
1
]);
if
(
rhs
.
type
()
==
Node
::
list
)
{
if
(
rhs
.
type
()
==
Node
::
list
)
{
for
(
size_t
i
=
0
,
S
=
rhs
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
rhs
.
size
();
i
<
S
;
++
i
)
{
if
(
rhs
[
i
].
should_eval
())
rhs
[
i
]
=
eval
(
rhs
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
rhs
[
i
].
should_eval
())
{
rhs
[
i
]
=
eval
(
rhs
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
}
}
}
else
if
(
rhs
.
type
()
==
Node
::
value_schema
||
rhs
.
type
()
==
Node
::
string_schema
)
{
else
if
(
rhs
.
is_schema
()
||
rhs
.
should_eval
()
)
{
eval
(
rhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
e
xpr
[
1
]
=
e
val
(
rhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
else
{
}
break
;
if
(
rhs
.
should_eval
())
expr
[
1
]
=
eval
(
rhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
case
Node
:
:
if_directive
:
{
Node
expansion
=
Node
();
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
i
+=
2
)
{
if
(
expr
[
i
].
type
()
!=
Node
::
block
)
{
Node
predicate_val
(
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
(
!
predicate_val
.
is_false
())
{
expand
(
expansion
=
expr
[
i
+
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
break
;
}
}
else
{
expand
(
expansion
=
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
break
;
}
}
}
return
expr
;
expr
.
pop_all
();
if
(
!
expansion
.
is_null
())
expr
+=
expansion
;
}
break
;
}
break
;
case
Node
:
:
for_through_directive
:
case
Node
:
:
for_to_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
for_kwd
))
// stub name for debugging
<<
(
fake_param
<<
expr
[
0
])
// iteration variable
<<
expr
[
3
];
// body
Node
lower_bound
(
eval
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
upper_bound
(
eval
(
expr
[
2
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
(
!
(
lower_bound
.
is_numeric
()
&&
upper_bound
.
is_numeric
()))
{
throw_eval_error
(
"bounds of @for directive must be numeric"
,
expr
.
path
(),
expr
.
line
());
}
expr
.
pop_all
();
for
(
double
i
=
lower_bound
.
numeric_value
(),
U
=
upper_bound
.
numeric_value
()
+
((
expr
.
type
()
==
Node
::
for_to_directive
)
?
0
:
1
);
i
<
U
;
++
i
)
{
Node
i_node
(
new_Node
(
expr
.
path
(),
expr
.
line
(),
i
));
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_arg
<<
i_node
;
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
}
}
break
;
case
Node
:
:
each_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
each_kwd
))
// stub name for debugging
<<
(
fake_param
<<
expr
[
0
])
// iteration variable
<<
expr
[
2
];
// body
Node
list
(
eval
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
// If the list isn't really a list, make a singleton out of it.
if
(
list
.
type
()
!=
Node
::
list
)
{
list
=
(
new_Node
(
Node
::
list
,
list
.
path
(),
list
.
line
(),
1
)
<<
list
);
}
expr
.
pop_all
();
for
(
size_t
i
=
0
,
S
=
list
.
size
();
i
<
S
;
++
i
)
{
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
1
));
list
[
i
].
should_eval
()
=
true
;
fake_arg
<<
eval
(
list
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
}
}
break
;
case
Node
:
:
while_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
0
));
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
0
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
while_kwd
))
// stub name for debugging
<<
fake_param
// no iteration variable
<<
expr
[
1
];
// body
Node
pred
(
expr
[
0
]);
expr
.
pop_back
();
expr
.
pop_back
();
Node
ev_pred
(
eval
(
pred
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
while
(
!
ev_pred
.
is_false
())
{
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
ev_pred
=
eval
(
pred
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
break
;
case
Node
:
:
block_directive
:
{
// TO DO: eval the directive name for interpolants
expand
(
expr
[
1
],
new_Node
(
Node
::
none
,
expr
.
path
(),
expr
.
line
(),
0
),
env
,
f_env
,
new_Node
,
ctx
);
}
break
;
case
Node
:
:
warning
:
{
Node
contents
(
eval
(
expr
[
0
],
Node
(),
env
,
f_env
,
new_Node
,
ctx
));
string
prefix
(
"WARNING: "
);
string
indent
(
" "
);
string
result
(
contents
.
to_string
());
if
(
contents
.
type
()
==
Node
::
string_constant
||
contents
.
type
()
==
Node
::
string_schema
)
{
result
=
result
.
substr
(
1
,
result
.
size
()
-
2
);
// unquote if it's a single string
}
// These cerrs aren't log lines! They're supposed to be here!
cerr
<<
prefix
<<
result
<<
endl
;
cerr
<<
indent
<<
"on line "
<<
expr
.
line
()
<<
" of "
<<
expr
.
path
();
cerr
<<
endl
<<
endl
;
}
break
;
default:
{
// do nothing
}
break
;
}
}
void
expand_list
(
Node
list
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
)
{
for
(
size_t
i
=
0
,
S
=
list
.
size
();
i
<
S
;
++
i
)
{
list
[
i
].
should_eval
()
=
true
;
list
[
i
]
=
eval
(
list
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
// Evaluation function for nodes in a value context.
Node
eval
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
)
{
Node
result
=
Node
();
switch
(
expr
.
type
())
{
case
Node
:
:
list
:
{
case
Node
:
:
list
:
{
if
(
expr
.
should_eval
()
&&
expr
.
size
()
>
0
)
expr
[
0
]
=
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
expr
.
should_eval
()
&&
expr
.
size
()
>
0
)
{
return
expr
;
result
=
new_Node
(
Node
::
list
,
expr
.
path
(),
expr
.
line
(),
expr
.
size
());
result
.
is_comma_separated
()
=
expr
.
is_comma_separated
();
result
<<
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
for
(
size_t
i
=
1
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
result
<<
expr
[
i
];
}
}
break
;
}
break
;
case
Node
:
:
disjunction
:
{
case
Node
:
:
disjunction
:
{
Node
result
;
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
result
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
result
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
result
.
type
()
==
Node
::
boolean
&&
result
.
boolean_value
()
==
false
)
continue
;
if
(
result
.
is_false
()
)
continue
;
else
return
result
;
else
break
;
}
}
return
result
;
}
break
;
}
break
;
case
Node
:
:
conjunction
:
{
case
Node
:
:
conjunction
:
{
Node
result
;
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
result
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
result
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
result
.
type
()
==
Node
::
boolean
&&
result
.
boolean_value
()
==
false
)
return
result
;
if
(
result
.
is_false
())
break
;
}
}
return
result
;
}
break
;
}
break
;
case
Node
:
:
relation
:
{
case
Node
:
:
relation
:
{
Node
lhs
(
new_Node
(
Node
::
arguments
,
expr
[
0
].
path
(),
expr
[
0
].
line
(),
1
));
Node
lhs
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
rhs
(
new_Node
(
Node
::
arguments
,
expr
[
2
].
path
(),
expr
[
2
].
line
(),
1
));
Node
op
(
expr
[
1
]);
Node
rel
(
expr
[
1
]);
Node
rhs
(
eval
(
expr
[
2
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
// TO DO: don't allocate both T and F
lhs
<<
expr
[
0
];
rhs
<<
expr
[
2
];
lhs
=
eval_arguments
(
lhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
rhs
=
eval_arguments
(
rhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
lhs
=
lhs
[
0
];
rhs
=
rhs
[
0
];
if
(
lhs
.
type
()
==
Node
::
list
)
expand_list
(
lhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
rhs
.
type
()
==
Node
::
list
)
expand_list
(
rhs
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
Node
T
(
new_Node
(
Node
::
boolean
,
lhs
.
path
(),
lhs
.
line
(),
true
));
Node
T
(
new_Node
(
Node
::
boolean
,
lhs
.
path
(),
lhs
.
line
(),
true
));
Node
F
(
new_Node
(
Node
::
boolean
,
lhs
.
path
(),
lhs
.
line
(),
false
));
Node
F
(
new_Node
(
Node
::
boolean
,
lhs
.
path
(),
lhs
.
line
(),
false
));
switch
(
op
.
type
())
switch
(
rel
.
type
())
{
{
case
Node
:
:
eq
:
re
turn
(
lhs
==
rhs
)
?
T
:
F
;
case
Node
:
:
eq
:
re
sult
=
((
lhs
==
rhs
)
?
T
:
F
);
break
;
case
Node
:
:
neq
:
re
turn
(
lhs
!=
rhs
)
?
T
:
F
;
case
Node
:
:
neq
:
re
sult
=
((
lhs
!=
rhs
)
?
T
:
F
);
break
;
case
Node
:
:
gt
:
re
turn
(
lhs
>
rhs
)
?
T
:
F
;
case
Node
:
:
gt
:
re
sult
=
((
lhs
>
rhs
)
?
T
:
F
);
break
;
case
Node
:
:
gte
:
re
turn
(
lhs
>=
rhs
)
?
T
:
F
;
case
Node
:
:
gte
:
re
sult
=
((
lhs
>=
rhs
)
?
T
:
F
);
break
;
case
Node
:
:
lt
:
re
turn
(
lhs
<
rhs
)
?
T
:
F
;
case
Node
:
:
lt
:
re
sult
=
((
lhs
<
rhs
)
?
T
:
F
);
break
;
case
Node
:
:
lte
:
re
turn
(
lhs
<=
rhs
)
?
T
:
F
;
case
Node
:
:
lte
:
re
sult
=
((
lhs
<=
rhs
)
?
T
:
F
);
break
;
default:
default:
throw_eval_error
(
"unknown comparison operator "
+
expr
.
token
().
to_string
(),
expr
.
path
(),
expr
.
line
());
throw_eval_error
(
"unknown comparison operator "
+
expr
.
token
().
to_string
(),
expr
.
path
(),
expr
.
line
());
return
Node
();
}
}
}
break
;
}
break
;
case
Node
:
:
expression
:
{
case
Node
:
:
expression
:
{
Node
list
(
new_Node
(
Node
::
expression
,
expr
.
path
(),
expr
.
line
(),
expr
.
size
()));
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expr
[
i
]
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
list
<<
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
re
turn
reduce
(
expr
,
1
,
expr
[
0
],
new_Node
);
re
sult
=
reduce
(
list
,
1
,
list
[
0
],
new_Node
);
}
break
;
}
break
;
case
Node
:
:
term
:
{
case
Node
:
:
term
:
{
if
(
expr
.
should_eval
())
{
if
(
expr
.
should_eval
())
{
Node
list
(
new_Node
(
Node
::
term
,
expr
.
path
(),
expr
.
line
(),
expr
.
size
()));
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expr
[
i
]
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
list
<<
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
return
reduce
(
expr
,
1
,
expr
[
0
],
new_Node
);
result
=
reduce
(
list
,
1
,
list
[
0
],
new_Node
);
}
else
{
return
expr
;
}
}
}
break
;
}
break
;
case
Node
:
:
textual_percentage
:
{
case
Node
:
:
textual_percentage
:
{
re
turn
new_Node
(
expr
.
path
(),
expr
.
line
(),
std
::
atof
(
expr
.
token
().
begin
),
Node
::
numeric_percentage
);
re
sult
=
new_Node
(
expr
.
path
(),
expr
.
line
(),
std
::
atof
(
expr
.
token
().
begin
),
Node
::
numeric_percentage
);
}
break
;
}
break
;
case
Node
:
:
textual_dimension
:
{
case
Node
:
:
textual_dimension
:
{
re
turn
new_Node
(
expr
.
path
(),
expr
.
line
(),
re
sult
=
new_Node
(
expr
.
path
(),
expr
.
line
(),
std
::
atof
(
expr
.
token
().
begin
),
std
::
atof
(
expr
.
token
().
begin
),
Token
::
make
(
Prelexer
::
number
(
expr
.
token
().
begin
),
Token
::
make
(
Prelexer
::
number
(
expr
.
token
().
begin
),
expr
.
token
().
end
));
expr
.
token
().
end
));
}
break
;
}
break
;
case
Node
:
:
textual_number
:
{
case
Node
:
:
textual_number
:
{
re
turn
new_Node
(
expr
.
path
(),
expr
.
line
(),
std
::
atof
(
expr
.
token
().
begin
));
re
sult
=
new_Node
(
expr
.
path
(),
expr
.
line
(),
std
::
atof
(
expr
.
token
().
begin
));
}
break
;
}
break
;
case
Node
:
:
textual_hex
:
{
case
Node
:
:
textual_hex
:
{
Node
triple
(
new_Node
(
Node
::
numeric_color
,
expr
.
path
(),
expr
.
line
(),
4
)
);
result
=
new_Node
(
Node
::
numeric_color
,
expr
.
path
(),
expr
.
line
(),
4
);
Token
hext
(
Token
::
make
(
expr
.
token
().
begin
+
1
,
expr
.
token
().
end
));
Token
hext
(
Token
::
make
(
expr
.
token
().
begin
+
1
,
expr
.
token
().
end
));
if
(
hext
.
length
()
==
6
)
{
if
(
hext
.
length
()
==
6
)
{
for
(
int
i
=
0
;
i
<
6
;
i
+=
2
)
{
for
(
int
i
=
0
;
i
<
6
;
i
+=
2
)
{
triple
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
static_cast
<
double
>
(
std
::
strtol
(
string
(
hext
.
begin
+
i
,
2
).
c_str
(),
NULL
,
16
)));
result
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
static_cast
<
double
>
(
std
::
strtol
(
string
(
hext
.
begin
+
i
,
2
).
c_str
(),
NULL
,
16
)));
}
}
}
}
else
{
else
{
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
for
(
int
i
=
0
;
i
<
3
;
++
i
)
{
triple
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
static_cast
<
double
>
(
std
::
strtol
(
string
(
2
,
hext
.
begin
[
i
]).
c_str
(),
NULL
,
16
)));
result
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
static_cast
<
double
>
(
std
::
strtol
(
string
(
2
,
hext
.
begin
[
i
]).
c_str
(),
NULL
,
16
)));
}
}
}
}
triple
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
1.0
);
result
<<
new_Node
(
expr
.
path
(),
expr
.
line
(),
1.0
);
return
triple
;
}
break
;
}
break
;
case
Node
:
:
variable
:
{
case
Node
:
:
variable
:
{
if
(
!
env
.
query
(
expr
.
token
()))
throw_eval_error
(
"reference to unbound variable "
+
expr
.
token
().
to_string
(),
expr
.
path
(),
expr
.
line
());
if
(
!
env
.
query
(
expr
.
token
()))
throw_eval_error
(
"reference to unbound variable "
+
expr
.
token
().
to_string
(),
expr
.
path
(),
expr
.
line
());
result
=
env
[
expr
.
token
()];
// cerr << "ACCESSING VARIABLE " << expr.token().to_string() << endl;
// cerr << endl << "*** ENV DUMP ***" << endl;
// env.print();
// cerr << "*** END ENV ***" << endl << endl;
return
env
[
expr
.
token
()];
}
break
;
}
break
;
case
Node
:
:
uri
:
{
case
Node
:
:
uri
:
{
expr
[
0
]
=
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
result
=
new_Node
(
Node
::
uri
,
expr
.
path
(),
expr
.
line
(),
1
);
re
turn
expr
;
re
sult
<<
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
)
;
}
break
;
}
break
;
case
Node
:
:
function_call
:
{
case
Node
:
:
function_call
:
{
// TO DO: default-constructed Function should be a generic callback (maybe)
// TO DO: default-constructed Function should be a generic callback (maybe)
// eval the function name in case it's interpolated
// eval the function name in case it's interpolated
expr
[
0
]
=
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
Node
name_node
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
)
);
string
name
(
expr
[
0
]
.
to_string
());
string
name
(
name_node
.
to_string
());
if
(
!
f_env
.
count
(
name
))
{
if
(
!
f_env
.
count
(
name
))
{
// no definition available; just pass it through (with evaluated args)
// no definition available; just pass it through (with evaluated args)
Node
args
(
expr
[
1
]);
Node
args
(
expr
[
1
]);
Node
evaluated_args
(
new_Node
(
Node
::
arguments
,
args
.
path
(),
args
.
line
(),
args
.
size
()));
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
args
[
i
]
=
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
evaluated_args
<<
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
evaluated_args
.
back
().
type
()
==
Node
::
list
)
{
Node
arg_list
(
evaluated_args
.
back
());
for
(
size_t
j
=
0
,
S
=
arg_list
.
size
();
j
<
S
;
++
j
)
{
if
(
arg_list
[
j
].
should_eval
())
arg_list
[
j
]
=
eval
(
arg_list
[
j
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
}
}
return
expr
;
result
=
new_Node
(
Node
::
function_call
,
expr
.
path
(),
expr
.
line
(),
2
);
result
<<
name_node
<<
evaluated_args
;
}
}
else
{
else
{
// check to see if the function is primitive/built-in
// check to see if the function is primitive/built-in
...
@@ -317,29 +429,29 @@ namespace Sass {
...
@@ -317,29 +429,29 @@ namespace Sass {
if
(
!
f_env
.
count
(
resolved_name
))
throw_eval_error
(
"wrong number of arguments to "
+
name
,
expr
.
path
(),
expr
.
line
());
if
(
!
f_env
.
count
(
resolved_name
))
throw_eval_error
(
"wrong number of arguments to "
+
name
,
expr
.
path
(),
expr
.
line
());
f
=
f_env
[
resolved_name
];
f
=
f_env
[
resolved_name
];
}
}
re
turn
apply_function
(
f
,
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
expr
.
path
(),
expr
.
line
());
re
sult
=
apply_function
(
f
,
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
expr
.
path
(),
expr
.
line
());
}
}
}
break
;
}
break
;
case
Node
:
:
unary_plus
:
{
case
Node
:
:
unary_plus
:
{
Node
arg
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
arg
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
(
arg
.
is_numeric
())
{
if
(
arg
.
is_numeric
())
{
re
turn
arg
;
re
sult
=
arg
;
}
}
else
{
else
{
expr
[
0
]
=
arg
;
result
=
new_Node
(
Node
::
unary_plus
,
expr
.
path
(),
expr
.
line
(),
1
)
;
re
turn
expr
;
re
sult
<<
arg
;
}
}
}
break
;
}
break
;
case
Node
:
:
unary_minus
:
{
case
Node
:
:
unary_minus
:
{
Node
arg
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
arg
(
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
(
arg
.
is_numeric
())
{
if
(
arg
.
is_numeric
())
{
re
turn
new_Node
(
expr
.
path
(),
expr
.
line
(),
-
arg
.
numeric_value
());
re
sult
=
new_Node
(
expr
.
path
(),
expr
.
line
(),
-
arg
.
numeric_value
());
}
}
else
{
else
{
expr
[
0
]
=
arg
;
result
=
new_Node
(
Node
::
unary_minus
,
expr
.
path
(),
expr
.
line
(),
1
)
;
re
turn
expr
;
re
sult
<<
arg
;
}
}
}
break
;
}
break
;
...
@@ -352,138 +464,35 @@ namespace Sass {
...
@@ -352,138 +464,35 @@ namespace Sass {
Node
g
(
color_orig
[
1
]);
Node
g
(
color_orig
[
1
]);
Node
b
(
color_orig
[
2
]);
Node
b
(
color_orig
[
2
]);
Node
a
(
color_orig
[
3
]);
Node
a
(
color_orig
[
3
]);
return
new_Node
(
expr
.
path
(),
expr
.
line
(),
result
=
new_Node
(
expr
.
path
(),
expr
.
line
(),
r
.
numeric_value
(),
r
.
numeric_value
(),
g
.
numeric_value
(),
g
.
numeric_value
(),
b
.
numeric_value
(),
b
.
numeric_value
(),
a
.
numeric_value
());
a
.
numeric_value
());
}
else
{
return
expr
;
}
}
}
break
;
}
break
;
case
Node
:
:
string_schema
:
case
Node
:
:
string_schema
:
case
Node
:
:
value_schema
:
case
Node
:
:
value_schema
:
case
Node
:
:
identifier_schema
:
{
case
Node
:
:
identifier_schema
:
{
result
=
new_Node
(
expr
.
type
(),
expr
.
path
(),
expr
.
line
(),
expr
.
size
());
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
++
i
)
{
expr
[
i
]
=
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
result
<<
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
re
turn
expr
;
re
sult
.
is_quoted
()
=
expr
.
is_quoted
()
;
}
break
;
}
break
;
case
Node
:
:
css_import
:
{
case
Node
:
:
css_import
:
{
expr
[
0
]
=
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
result
=
new_Node
(
Node
::
css_import
,
expr
.
path
(),
expr
.
line
(),
1
);
return
expr
;
result
<<
eval
(
expr
[
0
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
break
;
case
Node
:
:
if_directive
:
{
for
(
size_t
i
=
0
,
S
=
expr
.
size
();
i
<
S
;
i
+=
2
)
{
if
(
expr
[
i
].
type
()
!=
Node
::
block
)
{
// cerr << "EVALUATING PREDICATE " << (i/2+1) << endl;
Node
predicate_val
(
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
((
predicate_val
.
type
()
!=
Node
::
boolean
)
||
predicate_val
.
boolean_value
())
{
// cerr << "EVALUATING CONSEQUENT " << (i/2+1) << endl;
return
eval
(
expr
[
i
+
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
else
{
// cerr << "EVALUATING ALTERNATIVE" << endl;
return
eval
(
expr
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
}
break
;
case
Node
:
:
for_through_directive
:
case
Node
:
:
for_to_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
for_kwd
))
<<
(
fake_param
<<
expr
[
0
])
<<
expr
[
3
];
Node
lower_bound
(
eval
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
Node
upper_bound
(
eval
(
expr
[
2
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
if
(
!
(
lower_bound
.
is_numeric
()
&&
upper_bound
.
is_numeric
()))
{
throw_eval_error
(
"bounds of @for directive must be numeric"
,
expr
.
path
(),
expr
.
line
());
}
expr
.
pop_back
();
expr
.
pop_back
();
expr
.
pop_back
();
expr
.
pop_back
();
for
(
double
i
=
lower_bound
.
numeric_value
(),
U
=
upper_bound
.
numeric_value
()
+
((
expr
.
type
()
==
Node
::
for_to_directive
)
?
0
:
1
);
i
<
U
;
++
i
)
{
Node
i_node
(
new_Node
(
expr
.
path
(),
expr
.
line
(),
i
));
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_arg
<<
i_node
;
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
}
}
break
;
case
Node
:
:
each_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
each_kwd
))
<<
(
fake_param
<<
expr
[
0
])
<<
expr
[
2
];
Node
list
(
eval
(
expr
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
// If the list isn't really a list, make a singleton out of it.
if
(
list
.
type
()
!=
Node
::
list
)
{
list
=
(
new_Node
(
Node
::
list
,
list
.
path
(),
list
.
line
(),
1
)
<<
list
);
}
expr
.
pop_back
();
expr
.
pop_back
();
expr
.
pop_back
();
for
(
size_t
i
=
0
,
S
=
list
.
size
();
i
<
S
;
++
i
)
{
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
1
));
fake_arg
<<
eval
(
list
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
}
}
break
;
case
Node
:
:
while_directive
:
{
Node
fake_mixin
(
new_Node
(
Node
::
mixin
,
expr
.
path
(),
expr
.
line
(),
3
));
Node
fake_param
(
new_Node
(
Node
::
parameters
,
expr
.
path
(),
expr
.
line
(),
0
));
Node
fake_arg
(
new_Node
(
Node
::
arguments
,
expr
.
path
(),
expr
.
line
(),
0
));
fake_mixin
<<
new_Node
(
Node
::
identifier
,
""
,
0
,
Token
::
make
(
while_kwd
))
<<
fake_param
<<
expr
[
1
];
Node
pred
(
expr
[
0
]);
expr
.
pop_back
();
expr
.
pop_back
();
Node
ev_pred
(
eval
(
pred
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
while
((
ev_pred
.
type
()
!=
Node
::
boolean
)
||
ev_pred
.
boolean_value
())
{
expr
+=
apply_mixin
(
fake_mixin
,
fake_arg
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
,
true
);
ev_pred
=
eval
(
pred
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
break
;
case
Node
:
:
block_directive
:
{
// TO DO: eval the directive name for interpolants
eval
(
expr
[
1
],
new_Node
(
Node
::
none
,
expr
.
path
(),
expr
.
line
(),
0
),
env
,
f_env
,
new_Node
,
ctx
);
return
expr
;
}
break
;
case
Node
:
:
warning
:
{
expr
=
new_Node
(
expr
);
expr
[
0
]
=
eval
(
expr
[
0
],
Node
(),
env
,
f_env
,
new_Node
,
ctx
);
string
prefix
(
"WARNING: "
);
string
indent
(
" "
);
Node
contents
(
expr
[
0
]);
string
result
(
contents
.
to_string
());
if
(
contents
.
type
()
==
Node
::
string_constant
||
contents
.
type
()
==
Node
::
string_schema
)
{
result
=
result
.
substr
(
1
,
result
.
size
()
-
2
);
// unquote if it's a single string
}
// These cerrs aren't log lines! They're supposed to be here!
cerr
<<
prefix
<<
result
<<
endl
;
cerr
<<
indent
<<
"on line "
<<
expr
.
line
()
<<
" of "
<<
expr
.
path
();
cerr
<<
endl
<<
endl
;
return
expr
;
}
break
;
}
break
;
default:
{
default:
{
re
turn
expr
;
re
sult
=
expr
;
}
break
;
}
break
;
}
}
if
(
result
.
is_null
())
result
=
expr
;
return
expr
;
return
result
;
}
}
// Reduce arithmetic operations. Arithmetic expressions are stored as vectors
// Reduce arithmetic operations. Arithmetic expressions are stored as vectors
...
@@ -497,13 +506,6 @@ namespace Sass {
...
@@ -497,13 +506,6 @@ namespace Sass {
Node
::
Type
optype
=
op
.
type
();
Node
::
Type
optype
=
op
.
type
();
Node
::
Type
ltype
=
acc
.
type
();
Node
::
Type
ltype
=
acc
.
type
();
Node
::
Type
rtype
=
rhs
.
type
();
Node
::
Type
rtype
=
rhs
.
type
();
// if (ltype == Node::number && rhs.is_string()) {
// acc = (new_Node(Node::concatenation, list.path(), list.line(), 2) << acc);
// if (optype != Node::add) acc << op;
// if (rtype == Node::concatenation) acc += rhs;
// else acc << rhs;
// acc.is_quoted() = rhs.is_quoted();
// }
if
(
ltype
==
Node
::
number
&&
rtype
==
Node
::
number
)
{
if
(
ltype
==
Node
::
number
&&
rtype
==
Node
::
number
)
{
acc
=
new_Node
(
list
.
path
(),
list
.
line
(),
operate
(
op
,
acc
.
numeric_value
(),
rhs
.
numeric_value
()));
acc
=
new_Node
(
list
.
path
(),
list
.
line
(),
operate
(
op
,
acc
.
numeric_value
(),
rhs
.
numeric_value
()));
}
}
...
@@ -616,6 +618,65 @@ namespace Sass {
...
@@ -616,6 +618,65 @@ namespace Sass {
}
}
}
}
Node
eval_arguments
(
Node
args
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
)
{
Node
evaluated_args
(
new_Node
(
Node
::
arguments
,
args
.
path
(),
args
.
line
(),
args
.
size
()));
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
if
(
args
[
i
].
type
()
!=
Node
::
assignment
)
{
evaluated_args
<<
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
evaluated_args
.
back
().
type
()
==
Node
::
list
)
{
Node
arg_list
(
evaluated_args
.
back
());
Node
new_arg_list
(
new_Node
(
Node
::
list
,
arg_list
.
path
(),
arg_list
.
line
(),
arg_list
.
size
()));
for
(
size_t
j
=
0
,
S
=
arg_list
.
size
();
j
<
S
;
++
j
)
{
if
(
arg_list
[
j
].
should_eval
())
new_arg_list
<<
eval
(
arg_list
[
j
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
else
new_arg_list
<<
arg_list
[
j
];
}
}
}
else
{
Node
kwdarg
(
new_Node
(
Node
::
assignment
,
args
[
i
].
path
(),
args
[
i
].
line
(),
2
));
kwdarg
<<
args
[
i
][
0
];
kwdarg
<<
eval
(
args
[
i
][
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
kwdarg
.
back
().
type
()
==
Node
::
list
)
{
Node
arg_list
(
kwdarg
.
back
());
Node
new_arg_list
(
new_Node
(
Node
::
list
,
arg_list
.
path
(),
arg_list
.
line
(),
arg_list
.
size
()));
for
(
size_t
j
=
0
,
S
=
arg_list
.
size
();
j
<
S
;
++
j
)
{
if
(
arg_list
[
j
].
should_eval
())
new_arg_list
<<
eval
(
arg_list
[
j
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
else
new_arg_list
<<
arg_list
[
j
];
}
kwdarg
[
1
]
=
new_arg_list
;
}
evaluated_args
<<
kwdarg
;
}
}
// eval twice because args may be delayed
for
(
size_t
i
=
0
,
S
=
evaluated_args
.
size
();
i
<
S
;
++
i
)
{
if
(
evaluated_args
[
i
].
type
()
!=
Node
::
assignment
)
{
evaluated_args
[
i
].
should_eval
()
=
true
;
evaluated_args
[
i
]
=
eval
(
evaluated_args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
evaluated_args
[
i
].
type
()
==
Node
::
list
)
{
Node
arg_list
(
evaluated_args
[
i
]);
for
(
size_t
j
=
0
,
S
=
arg_list
.
size
();
j
<
S
;
++
j
)
{
if
(
arg_list
[
j
].
should_eval
())
arg_list
[
j
]
=
eval
(
arg_list
[
j
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
}
else
{
Node
kwdarg
(
evaluated_args
[
i
]);
kwdarg
[
1
].
should_eval
()
=
true
;
kwdarg
[
1
]
=
eval
(
kwdarg
[
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
if
(
kwdarg
[
1
].
type
()
==
Node
::
list
)
{
Node
arg_list
(
kwdarg
[
1
]);
for
(
size_t
j
=
0
,
S
=
arg_list
.
size
();
j
<
S
;
++
j
)
{
if
(
arg_list
[
j
].
should_eval
())
arg_list
[
j
]
=
eval
(
arg_list
[
j
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
evaluated_args
[
i
]
=
kwdarg
;
}
}
return
evaluated_args
;
}
// Helper function for binding arguments in function and mixin calls.
// Helper function for binding arguments in function and mixin calls.
// Needs the environment containing the bindings to be passed in by the
// Needs the environment containing the bindings to be passed in by the
// caller. Also expects the caller to have pre-evaluated the arguments.
// caller. Also expects the caller to have pre-evaluated the arguments.
...
@@ -649,7 +710,7 @@ namespace Sass {
...
@@ -649,7 +710,7 @@ namespace Sass {
if
(
!
env
.
query
(
arg_name
))
{
if
(
!
env
.
query
(
arg_name
))
{
throw_eval_error
(
callee_name
+
" has no parameter named "
+
arg_name
.
to_string
(),
arg
.
path
(),
arg
.
line
());
throw_eval_error
(
callee_name
+
" has no parameter named "
+
arg_name
.
to_string
(),
arg
.
path
(),
arg
.
line
());
}
}
if
(
!
env
[
arg_name
].
is_n
one
())
{
if
(
!
env
[
arg_name
].
is_n
ull
())
{
throw_eval_error
(
callee_name
+
" was passed argument "
+
arg_name
.
to_string
()
+
" both by position and by name"
,
arg
.
path
(),
arg
.
line
());
throw_eval_error
(
callee_name
+
" was passed argument "
+
arg_name
.
to_string
()
+
" both by position and by name"
,
arg
.
path
(),
arg
.
line
());
}
}
env
[
arg_name
]
=
arg_value
;
env
[
arg_name
]
=
arg_value
;
...
@@ -660,7 +721,7 @@ namespace Sass {
...
@@ -660,7 +721,7 @@ namespace Sass {
for
(
size_t
i
=
0
,
S
=
params
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
params
.
size
();
i
<
S
;
++
i
)
{
Node
param
(
params
[
i
]);
Node
param
(
params
[
i
]);
Token
param_name
((
param
.
type
()
==
Node
::
assignment
?
param
[
0
]
:
param
).
token
());
Token
param_name
((
param
.
type
()
==
Node
::
assignment
?
param
[
0
]
:
param
).
token
());
if
(
env
[
param_name
].
is_n
one
())
{
if
(
env
[
param_name
].
is_n
ull
())
{
if
(
param
.
type
()
!=
Node
::
assignment
)
{
if
(
param
.
type
()
!=
Node
::
assignment
)
{
throw_eval_error
(
callee_name
+
" is missing argument "
+
param_name
.
to_string
(),
args
.
path
(),
args
.
line
());
throw_eval_error
(
callee_name
+
" is missing argument "
+
param_name
.
to_string
(),
args
.
path
(),
args
.
line
());
}
}
...
@@ -673,32 +734,11 @@ namespace Sass {
...
@@ -673,32 +734,11 @@ namespace Sass {
// Apply a mixin -- bind the arguments in a new environment, link the new
// Apply a mixin -- bind the arguments in a new environment, link the new
// environment to the current one, then copy the body and eval in the new
// environment to the current one, then copy the body and eval in the new
// environment.
// environment.
Node
apply_mixin
(
Node
mixin
,
const
Node
a
a
rgs
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
dynamic_scope
)
Node
apply_mixin
(
Node
mixin
,
const
Node
args
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
dynamic_scope
)
{
{
Node
params
(
mixin
[
1
]);
Node
params
(
mixin
[
1
]);
Node
body
(
new_Node
(
mixin
[
2
]));
// clone the body
Node
body
(
new_Node
(
mixin
[
2
]));
// clone the body
Node
args
=
new_Node
(
aargs
);
Node
evaluated_args
(
eval_arguments
(
args
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
// evaluate arguments in the current environment
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
if
(
args
[
i
].
type
()
!=
Node
::
assignment
)
{
args
[
i
]
=
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
else
{
args
[
i
][
1
]
=
eval
(
args
[
i
][
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
// need to eval twice because some expressions get delayed
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
if
(
args
[
i
].
type
()
!=
Node
::
assignment
)
{
args
[
i
].
should_eval
()
=
true
;
args
[
i
]
=
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
else
{
args
[
i
][
1
].
should_eval
()
=
true
;
args
[
i
][
1
]
=
eval
(
args
[
i
][
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
// Create a new environment for the mixin and link it to the appropriate parent
// Create a new environment for the mixin and link it to the appropriate parent
Environment
bindings
;
Environment
bindings
;
if
(
dynamic_scope
)
{
if
(
dynamic_scope
)
{
...
@@ -712,54 +752,30 @@ namespace Sass {
...
@@ -712,54 +752,30 @@ namespace Sass {
// bind arguments in the extended environment
// bind arguments in the extended environment
stringstream
mixin_name
;
stringstream
mixin_name
;
mixin_name
<<
"mixin"
;
mixin_name
<<
"mixin"
;
if
(
!
mixin
[
0
].
is_n
one
())
mixin_name
<<
" "
<<
mixin
[
0
].
to_string
();
if
(
!
mixin
[
0
].
is_n
ull
())
mixin_name
<<
" "
<<
mixin
[
0
].
to_string
();
bind_arguments
(
mixin_name
.
str
(),
params
,
args
,
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
bind_arguments
(
mixin_name
.
str
(),
params
,
evaluated_
args
,
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
// evaluate the mixin's body
// evaluate the mixin's body
for
(
size_t
i
=
0
,
S
=
body
.
size
();
i
<
S
;
++
i
)
{
expand
(
body
,
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
body
[
i
]
=
eval
(
body
[
i
],
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
}
// cerr << "expanded " << mixin_name.str() << endl;
return
body
;
return
body
;
}
}
// Apply a function -- bind the arguments and pass them to the underlying
// Apply a function -- bind the arguments and pass them to the underlying
// primitive function implementation, then return its value.
// primitive function implementation, then return its value.
Node
apply_function
(
const
Function
&
f
,
const
Node
a
a
rgs
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
string
&
path
,
size_t
line
)
Node
apply_function
(
const
Function
&
f
,
const
Node
args
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
string
&
path
,
size_t
line
)
{
{
Node
args
=
new_Node
(
aargs
);
Node
evaluated_args
(
eval_arguments
(
args
,
prefix
,
env
,
f_env
,
new_Node
,
ctx
));
// evaluate arguments in the current environment
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
if
(
args
[
i
].
type
()
!=
Node
::
assignment
)
{
args
[
i
]
=
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
else
{
args
[
i
][
1
]
=
eval
(
args
[
i
][
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
// need to eval twice because some expressions get delayed
for
(
size_t
i
=
0
,
S
=
args
.
size
();
i
<
S
;
++
i
)
{
if
(
args
[
i
].
type
()
!=
Node
::
assignment
)
{
args
[
i
].
should_eval
()
=
true
;
args
[
i
]
=
eval
(
args
[
i
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
else
{
args
[
i
][
1
].
should_eval
()
=
true
;
args
[
i
][
1
]
=
eval
(
args
[
i
][
1
],
prefix
,
env
,
f_env
,
new_Node
,
ctx
);
}
}
// bind arguments
// bind arguments
Environment
bindings
;
Environment
bindings
;
Node
params
(
f
.
primitive
?
f
.
parameters
:
f
.
definition
[
1
]);
Node
params
(
f
.
primitive
?
f
.
parameters
:
f
.
definition
[
1
]);
bindings
.
link
(
env
.
global
?
*
env
.
global
:
env
);
bindings
.
link
(
env
.
global
?
*
env
.
global
:
env
);
bind_arguments
(
"function "
+
f
.
name
,
params
,
args
,
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
bind_arguments
(
"function "
+
f
.
name
,
params
,
evaluated_
args
,
prefix
,
bindings
,
f_env
,
new_Node
,
ctx
);
if
(
f
.
primitive
)
{
if
(
f
.
primitive
)
{
return
f
.
primitive
(
f
.
parameter_names
,
bindings
,
new_Node
,
path
,
line
);
return
f
.
primitive
(
f
.
parameter_names
,
bindings
,
new_Node
,
path
,
line
);
}
}
else
{
else
{
// TO DO: consider cloning the function body?
// TO DO: consider cloning the function body?
return
function_eval
(
f
.
name
,
f
.
definition
[
2
],
bindings
,
new_Node
,
ctx
,
true
);
return
eval_function
(
f
.
name
,
f
.
definition
[
2
],
bindings
,
new_Node
,
ctx
,
true
);
}
}
}
}
...
@@ -767,54 +783,52 @@ namespace Sass {
...
@@ -767,54 +783,52 @@ namespace Sass {
// algorithm is different in this case because the body needs to be
// algorithm is different in this case because the body needs to be
// executed and a single value needs to be returned directly, rather than
// executed and a single value needs to be returned directly, rather than
// styles being expanded and spliced in place.
// styles being expanded and spliced in place.
Node
eval_function
(
string
name
,
Node
body
,
Environment
&
bindings
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
at_toplevel
)
Node
function_eval
(
string
name
,
Node
body
,
Environment
&
bindings
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
at_toplevel
)
{
{
for
(
size_t
i
=
0
,
S
=
body
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
body
.
size
();
i
<
S
;
++
i
)
{
Node
stm
(
body
[
i
]);
Node
stm
(
body
[
i
]);
switch
(
stm
.
type
())
switch
(
stm
.
type
())
{
{
case
Node
:
:
assignment
:
{
case
Node
:
:
assignment
:
{
Node
val
(
new_Node
(
stm
[
1
]));
// clone the value because it might get mutated in place
Node
val
(
stm
[
1
]);
Node
newval
;
if
(
val
.
type
()
==
Node
::
list
)
{
if
(
val
.
type
()
==
Node
::
list
)
{
newval
=
new_Node
(
Node
::
list
,
val
.
path
(),
val
.
line
(),
val
.
size
());
newval
.
is_comma_separated
()
=
val
.
is_comma_separated
();
for
(
size_t
i
=
0
,
S
=
val
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
val
.
size
();
i
<
S
;
++
i
)
{
if
(
val
[
i
].
should_eval
())
val
[
i
]
=
eval
(
val
[
i
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
if
(
val
[
i
].
should_eval
())
newval
<<
eval
(
val
[
i
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
else
newval
<<
val
[
i
];
}
}
}
}
else
{
else
{
val
=
eval
(
val
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
new
val
=
eval
(
val
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
}
}
Node
var
(
stm
[
0
]);
Node
var
(
stm
[
0
]);
// cerr << "ASSIGNMENT IN FUNCTION: " << var.to_string() << ": " << val.to_string() << endl;
if
(
stm
.
is_guarded
()
&&
bindings
.
query
(
var
.
token
()))
continue
;
if
(
stm
.
is_guarded
()
&&
bindings
.
query
(
var
.
token
()))
continue
;
// If a binding exists (possibly upframe), then update it.
// If a binding exists (possibly upframe), then update it.
// Otherwise, make a new one in the current frame.
// Otherwise, make a new one in the current frame.
if
(
bindings
.
query
(
var
.
token
()))
{
if
(
bindings
.
query
(
var
.
token
()))
{
// cerr << "MODIFYING EXISTING BINDING FOR " << var.token().to_string() << endl;
bindings
[
var
.
token
()]
=
newval
;
// cerr << "CURRENT VALUE: " << bindings[var.token()].to_string() << endl;
// cerr << "NEW VALUE: " << val.to_string() << endl;
bindings
[
var
.
token
()]
=
val
;
}
}
else
{
else
{
bindings
.
current_frame
[
var
.
token
()]
=
val
;
bindings
.
current_frame
[
var
.
token
()]
=
new
val
;
}
}
}
break
;
}
break
;
case
Node
:
:
if_directive
:
{
case
Node
:
:
if_directive
:
{
for
(
size_t
j
=
0
,
S
=
stm
.
size
();
j
<
S
;
j
+=
2
)
{
for
(
size_t
j
=
0
,
S
=
stm
.
size
();
j
<
S
;
j
+=
2
)
{
if
(
stm
[
j
].
type
()
!=
Node
::
block
)
{
if
(
stm
[
j
].
type
()
!=
Node
::
block
)
{
Node
pred
(
new_Node
(
stm
[
j
]));
Node
predicate_val
(
eval
(
stm
[
j
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
predicate_val
(
eval
(
pred
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
if
(
!
predicate_val
.
is_false
())
{
if
((
predicate_val
.
type
()
!=
Node
::
boolean
)
||
predicate_val
.
boolean_value
())
{
Node
v
(
eval_function
(
name
,
stm
[
j
+
1
],
bindings
,
new_Node
,
ctx
));
Node
v
(
function_eval
(
name
,
stm
[
j
+
1
],
bindings
,
new_Node
,
ctx
));
if
(
v
.
is_null
())
break
;
if
(
v
.
is_null_ptr
())
break
;
else
return
v
;
else
return
v
;
}
}
}
}
else
{
else
{
Node
v
(
function_eval
(
name
,
stm
[
j
],
bindings
,
new_Node
,
ctx
));
Node
v
(
eval_function
(
name
,
stm
[
j
],
bindings
,
new_Node
,
ctx
));
if
(
v
.
is_null
_ptr
())
break
;
if
(
v
.
is_null
())
break
;
else
return
v
;
else
return
v
;
}
}
}
}
}
break
;
}
break
;
...
@@ -823,8 +837,8 @@ namespace Sass {
...
@@ -823,8 +837,8 @@ namespace Sass {
case
Node
:
:
for_to_directive
:
{
case
Node
:
:
for_to_directive
:
{
Node
::
Type
for_type
=
stm
.
type
();
Node
::
Type
for_type
=
stm
.
type
();
Node
iter_var
(
stm
[
0
]);
Node
iter_var
(
stm
[
0
]);
Node
lower_bound
(
eval
(
new_Node
(
stm
[
1
])
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
lower_bound
(
eval
(
stm
[
1
]
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
upper_bound
(
eval
(
new_Node
(
stm
[
2
])
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
upper_bound
(
eval
(
stm
[
2
]
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
for_body
(
stm
[
3
]);
Node
for_body
(
stm
[
3
]);
Environment
for_env
;
// re-use this env for each iteration
Environment
for_env
;
// re-use this env for each iteration
for_env
.
link
(
bindings
);
for_env
.
link
(
bindings
);
...
@@ -832,15 +846,15 @@ namespace Sass {
...
@@ -832,15 +846,15 @@ namespace Sass {
j
<
T
;
j
<
T
;
j
+=
1
)
{
j
+=
1
)
{
for_env
.
current_frame
[
iter_var
.
token
()]
=
new_Node
(
lower_bound
.
path
(),
lower_bound
.
line
(),
j
);
for_env
.
current_frame
[
iter_var
.
token
()]
=
new_Node
(
lower_bound
.
path
(),
lower_bound
.
line
(),
j
);
Node
v
(
function_eval
(
name
,
for_body
,
for_env
,
new_Node
,
ctx
));
Node
v
(
eval_function
(
name
,
for_body
,
for_env
,
new_Node
,
ctx
));
if
(
v
.
is_null
_ptr
())
continue
;
if
(
v
.
is_null
())
continue
;
else
return
v
;
else
return
v
;
}
}
}
break
;
}
break
;
case
Node
:
:
each_directive
:
{
case
Node
:
:
each_directive
:
{
Node
iter_var
(
stm
[
0
]);
Node
iter_var
(
stm
[
0
]);
Node
list
(
eval
(
new_Node
(
stm
[
1
])
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
list
(
eval
(
stm
[
1
]
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
if
(
list
.
type
()
!=
Node
::
list
)
{
if
(
list
.
type
()
!=
Node
::
list
)
{
list
=
(
new_Node
(
Node
::
list
,
list
.
path
(),
list
.
line
(),
1
)
<<
list
);
list
=
(
new_Node
(
Node
::
list
,
list
.
path
(),
list
.
line
(),
1
)
<<
list
);
}
}
...
@@ -848,27 +862,24 @@ namespace Sass {
...
@@ -848,27 +862,24 @@ namespace Sass {
Environment
each_env
;
// re-use this env for each iteration
Environment
each_env
;
// re-use this env for each iteration
each_env
.
link
(
bindings
);
each_env
.
link
(
bindings
);
for
(
size_t
j
=
0
,
T
=
list
.
size
();
j
<
T
;
++
j
)
{
for
(
size_t
j
=
0
,
T
=
list
.
size
();
j
<
T
;
++
j
)
{
list
[
j
].
should_eval
()
=
true
;
each_env
.
current_frame
[
iter_var
.
token
()]
=
eval
(
list
[
j
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
each_env
.
current_frame
[
iter_var
.
token
()]
=
eval
(
list
[
j
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
// cerr << "EACH with " << iter_var.token().to_string() << ": " << each_env[iter_var.token()].to_string() << endl;
Node
v
(
eval_function
(
name
,
each_body
,
each_env
,
new_Node
,
ctx
));
Node
v
(
function_eval
(
name
,
each_body
,
each_env
,
new_Node
,
ctx
));
if
(
v
.
is_null
())
continue
;
// cerr << endl << "*** ENV DUMP ***" << endl;
else
return
v
;
// each_env.print();
// cerr << "*** END ENV ***" << endl << endl;
if
(
v
.
is_null_ptr
())
continue
;
else
return
v
;
}
}
}
break
;
}
break
;
case
Node
:
:
while_directive
:
{
case
Node
:
:
while_directive
:
{
Node
pred_expr
(
new_Node
(
stm
[
0
])
);
Node
pred_expr
(
stm
[
0
]
);
Node
while_body
(
stm
[
1
]);
Node
while_body
(
stm
[
1
]);
Environment
while_env
;
// re-use this env for each iteration
Environment
while_env
;
// re-use this env for each iteration
while_env
.
link
(
bindings
);
while_env
.
link
(
bindings
);
Node
pred_val
(
eval
(
pred_expr
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
pred_val
(
eval
(
pred_expr
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
while
(
(
pred_val
.
type
()
!=
Node
::
boolean
)
||
pred_val
.
boolean_valu
e
())
{
while
(
!
pred_val
.
is_fals
e
())
{
Node
v
(
function_eval
(
name
,
while_body
,
while_env
,
new_Node
,
ctx
));
Node
v
(
eval_function
(
name
,
while_body
,
while_env
,
new_Node
,
ctx
));
if
(
v
.
is_null
_ptr
())
{
if
(
v
.
is_null
())
{
pred_val
=
eval
(
new_Node
(
stm
[
0
])
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
pred_val
=
eval
(
pred_expr
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
continue
;
continue
;
}
}
else
return
v
;
else
return
v
;
...
@@ -876,12 +887,9 @@ namespace Sass {
...
@@ -876,12 +887,9 @@ namespace Sass {
}
break
;
}
break
;
case
Node
:
:
warning
:
{
case
Node
:
:
warning
:
{
stm
=
new_Node
(
stm
);
stm
[
0
]
=
eval
(
stm
[
0
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
string
prefix
(
"WARNING: "
);
string
prefix
(
"WARNING: "
);
string
indent
(
" "
);
string
indent
(
" "
);
Node
contents
(
stm
[
0
]
);
Node
contents
(
eval
(
stm
[
0
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
)
);
string
result
(
contents
.
to_string
());
string
result
(
contents
.
to_string
());
if
(
contents
.
type
()
==
Node
::
string_constant
||
contents
.
type
()
==
Node
::
string_schema
)
{
if
(
contents
.
type
()
==
Node
::
string_constant
||
contents
.
type
()
==
Node
::
string_schema
)
{
result
=
result
.
substr
(
1
,
result
.
size
()
-
2
);
// unquote if it's a single string
result
=
result
.
substr
(
1
,
result
.
size
()
-
2
);
// unquote if it's a single string
...
@@ -893,11 +901,14 @@ namespace Sass {
...
@@ -893,11 +901,14 @@ namespace Sass {
}
break
;
}
break
;
case
Node
:
:
return_directive
:
{
case
Node
:
:
return_directive
:
{
Node
retval
(
eval
(
new_Node
(
stm
[
0
])
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
Node
retval
(
eval
(
stm
[
0
]
,
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
));
if
(
retval
.
type
()
==
Node
::
list
)
{
if
(
retval
.
type
()
==
Node
::
list
)
{
Node
new_list
(
new_Node
(
Node
::
list
,
retval
.
path
(),
retval
.
line
(),
retval
.
size
()));
new_list
.
is_comma_separated
()
=
retval
.
is_comma_separated
();
for
(
size_t
i
=
0
,
S
=
retval
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
retval
.
size
();
i
<
S
;
++
i
)
{
retval
[
i
]
=
eval
(
retval
[
i
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
new_list
<<
eval
(
retval
[
i
],
Node
(),
bindings
,
ctx
.
function_env
,
new_Node
,
ctx
);
}
}
retval
=
new_list
;
}
}
return
retval
;
return
retval
;
}
break
;
}
break
;
...
@@ -916,7 +927,6 @@ namespace Sass {
...
@@ -916,7 +927,6 @@ namespace Sass {
// of a backref. When the selector doesn't have backrefs, just prepend the
// of a backref. When the selector doesn't have backrefs, just prepend the
// prefix. This function needs multiple subsidiary cases in order to properly
// prefix. This function needs multiple subsidiary cases in order to properly
// combine the various kinds of selectors.
// combine the various kinds of selectors.
Node
expand_selector
(
Node
sel
,
Node
pre
,
Node_Factory
&
new_Node
)
Node
expand_selector
(
Node
sel
,
Node
pre
,
Node_Factory
&
new_Node
)
{
{
if
(
pre
.
type
()
==
Node
::
none
)
return
sel
;
if
(
pre
.
type
()
==
Node
::
none
)
return
sel
;
...
@@ -1001,7 +1011,6 @@ namespace Sass {
...
@@ -1001,7 +1011,6 @@ namespace Sass {
}
}
// Helper for expanding selectors with backrefs.
// Helper for expanding selectors with backrefs.
Node
expand_backref
(
Node
sel
,
Node
pre
)
Node
expand_backref
(
Node
sel
,
Node
pre
)
{
{
switch
(
sel
.
type
())
switch
(
sel
.
type
())
...
@@ -1027,7 +1036,6 @@ namespace Sass {
...
@@ -1027,7 +1036,6 @@ namespace Sass {
}
}
// Resolve selector extensions.
// Resolve selector extensions.
void
extend_selectors
(
vector
<
pair
<
Node
,
Node
>
>&
pending
,
multimap
<
Node
,
Node
>&
extension_table
,
Node_Factory
&
new_Node
)
void
extend_selectors
(
vector
<
pair
<
Node
,
Node
>
>&
pending
,
multimap
<
Node
,
Node
>&
extension_table
,
Node_Factory
&
new_Node
)
{
{
for
(
size_t
i
=
0
,
S
=
pending
.
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
0
,
S
=
pending
.
size
();
i
<
S
;
++
i
)
{
...
@@ -1202,7 +1210,6 @@ namespace Sass {
...
@@ -1202,7 +1210,6 @@ namespace Sass {
// Helper for generating selector extensions; called for each extendee and
// Helper for generating selector extensions; called for each extendee and
// extender in a pair of selector groups.
// extender in a pair of selector groups.
Node
generate_extension
(
Node
extendee
,
Node
extender
,
Node_Factory
&
new_Node
)
Node
generate_extension
(
Node
extendee
,
Node
extender
,
Node_Factory
&
new_Node
)
{
{
Node
new_group
(
new_Node
(
Node
::
selector_group
,
extendee
.
path
(),
extendee
.
line
(),
1
));
Node
new_group
(
new_Node
(
Node
::
selector_group
,
extendee
.
path
(),
extendee
.
line
(),
1
));
...
@@ -1258,7 +1265,6 @@ namespace Sass {
...
@@ -1258,7 +1265,6 @@ namespace Sass {
}
}
// Helpers for extracting subsets of selectors
// Helpers for extracting subsets of selectors
Node
selector_prefix
(
Node
sel
,
Node_Factory
&
new_Node
)
Node
selector_prefix
(
Node
sel
,
Node_Factory
&
new_Node
)
{
{
switch
(
sel
.
type
())
switch
(
sel
.
type
())
...
...
eval_apply.hpp
View file @
5bd4581b
...
@@ -12,9 +12,11 @@
...
@@ -12,9 +12,11 @@
namespace
Sass
{
namespace
Sass
{
using
std
::
map
;
using
std
::
map
;
void
expand
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
=
false
);
Node
eval
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
=
false
);
Node
eval
(
Node
expr
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
function_name
=
false
);
Node
function_eval
(
string
name
,
Node
stm
,
Environment
&
bindings
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
toplevel
=
false
);
Node
eval_arguments
(
Node
args
,
Node
prefix
,
Environment
&
env
,
map
<
string
,
Function
>&
f_env
,
Node_Factory
&
new_Node
,
Context
&
ctx
);
Node
eval_function
(
string
name
,
Node
stm
,
Environment
&
bindings
,
Node_Factory
&
new_Node
,
Context
&
ctx
,
bool
toplevel
=
false
);
Node
reduce
(
Node
list
,
size_t
head
,
Node
acc
,
Node_Factory
&
new_Node
);
Node
reduce
(
Node
list
,
size_t
head
,
Node
acc
,
Node_Factory
&
new_Node
);
Node
accumulate
(
Node
::
Type
op
,
Node
acc
,
Node
rhs
,
Node_Factory
&
new_Node
);
Node
accumulate
(
Node
::
Type
op
,
Node
acc
,
Node
rhs
,
Node_Factory
&
new_Node
);
double
operate
(
Node
op
,
double
lhs
,
double
rhs
);
double
operate
(
Node
op
,
double
lhs
,
double
rhs
);
...
...
node.cpp
View file @
5bd4581b
...
@@ -18,8 +18,9 @@ namespace Sass {
...
@@ -18,8 +18,9 @@ namespace Sass {
switch
(
type
())
switch
(
type
())
{
{
case
block
:
case
block
:
case
expansion
:
case
mixin_call
:
case
root
:
case
root
:
case
if_directive
:
case
for_through_directive
:
case
for_through_directive
:
case
for_to_directive
:
case
for_to_directive
:
case
each_directive
:
case
each_directive
:
...
@@ -33,8 +34,9 @@ namespace Sass {
...
@@ -33,8 +34,9 @@ namespace Sass {
for
(
size_t
i
=
0
;
i
<
size
();
++
i
)
{
for
(
size_t
i
=
0
;
i
<
size
();
++
i
)
{
switch
(
at
(
i
).
type
())
switch
(
at
(
i
).
type
())
{
{
case
expansion
:
case
mixin_call
:
case
block
:
case
block
:
case
if_directive
:
case
for_through_directive
:
case
for_through_directive
:
case
for_to_directive
:
case
for_to_directive
:
case
each_directive
:
case
each_directive
:
...
...
node.hpp
View file @
5bd4581b
...
@@ -150,11 +150,11 @@ namespace Sass {
...
@@ -150,11 +150,11 @@ namespace Sass {
identifier_schema
,
identifier_schema
,
css_import
,
css_import
,
function
,
function_call
,
function_call
,
mixin
,
mixin
,
function
,
mixin_call
,
parameters
,
parameters
,
expansion
,
arguments
,
arguments
,
if_directive
,
if_directive
,
...
@@ -177,8 +177,8 @@ namespace Sass {
...
@@ -177,8 +177,8 @@ namespace Sass {
Node
(
Node_Impl
*
ip
=
0
);
Node
(
Node_Impl
*
ip
=
0
);
Type
type
()
const
;
Type
type
()
const
;
Type
type
(
Type
);
bool
is_none
()
const
;
bool
has_children
()
const
;
bool
has_children
()
const
;
bool
has_statements
()
const
;
bool
has_statements
()
const
;
bool
has_blocks
()
const
;
bool
has_blocks
()
const
;
...
@@ -204,6 +204,7 @@ namespace Sass {
...
@@ -204,6 +204,7 @@ namespace Sass {
Node
&
back
()
const
;
Node
&
back
()
const
;
Node
&
operator
[](
size_t
i
)
const
;
Node
&
operator
[](
size_t
i
)
const
;
void
pop_back
();
void
pop_back
();
void
pop_all
();
Node
&
push_back
(
Node
n
);
Node
&
push_back
(
Node
n
);
Node
&
push_front
(
Node
n
);
Node
&
push_front
(
Node
n
);
Node
&
operator
<<
(
Node
n
);
Node
&
operator
<<
(
Node
n
);
...
@@ -220,7 +221,7 @@ namespace Sass {
...
@@ -220,7 +221,7 @@ namespace Sass {
Token
token
()
const
;
Token
token
()
const
;
Token
unit
()
const
;
Token
unit
()
const
;
bool
is_null
_ptr
()
const
{
return
!
ip_
;
}
bool
is_null
()
const
{
return
!
ip_
;
}
bool
is
(
Node
n
)
const
{
return
ip_
==
n
.
ip_
;
}
bool
is
(
Node
n
)
const
{
return
ip_
==
n
.
ip_
;
}
void
flatten
();
void
flatten
();
...
@@ -369,7 +370,7 @@ namespace Sass {
...
@@ -369,7 +370,7 @@ namespace Sass {
case
Node
:
:
for_to_directive
:
case
Node
:
:
for_to_directive
:
case
Node
:
:
each_directive
:
case
Node
:
:
each_directive
:
case
Node
:
:
while_directive
:
case
Node
:
:
while_directive
:
case
Node
:
:
expansion
:
{
case
Node
:
:
mixin_call
:
{
has_expansions
=
true
;
has_expansions
=
true
;
}
break
;
}
break
;
...
@@ -401,7 +402,7 @@ namespace Sass {
...
@@ -401,7 +402,7 @@ namespace Sass {
case
Node
:
:
for_to_directive
:
case
Node
:
:
for_to_directive
:
case
Node
:
:
each_directive
:
case
Node
:
:
each_directive
:
case
Node
:
:
while_directive
:
case
Node
:
:
while_directive
:
case
Node
:
:
expansion
:
has_expansions
=
true
;
break
;
case
Node
:
:
mixin_call
:
has_expansions
=
true
;
break
;
case
Node
:
:
backref
:
has_backref
=
true
;
break
;
case
Node
:
:
backref
:
has_backref
=
true
;
break
;
...
@@ -413,6 +414,9 @@ namespace Sass {
...
@@ -413,6 +414,9 @@ namespace Sass {
void
pop_back
()
void
pop_back
()
{
children
.
pop_back
();
}
{
children
.
pop_back
();
}
void
pop_all
()
{
for
(
size_t
i
=
0
,
S
=
size
();
i
<
S
;
++
i
)
pop_back
();
}
bool
&
boolean_value
()
bool
&
boolean_value
()
{
return
value
.
boolean
;
}
{
return
value
.
boolean
;
}
...
@@ -430,8 +434,8 @@ namespace Sass {
...
@@ -430,8 +434,8 @@ namespace Sass {
inline
Node
::
Node
(
Node_Impl
*
ip
)
:
ip_
(
ip
)
{
}
inline
Node
::
Node
(
Node_Impl
*
ip
)
:
ip_
(
ip
)
{
}
inline
Node
::
Type
Node
::
type
()
const
{
return
ip_
->
type
;
}
inline
Node
::
Type
Node
::
type
()
const
{
return
ip_
->
type
;
}
inline
Node
::
Type
Node
::
type
(
Type
t
)
{
return
ip_
->
type
=
t
;
}
inline
bool
Node
::
is_none
()
const
{
return
!
ip_
;
}
inline
bool
Node
::
has_children
()
const
{
return
ip_
->
has_children
;
}
inline
bool
Node
::
has_children
()
const
{
return
ip_
->
has_children
;
}
inline
bool
Node
::
has_statements
()
const
{
return
ip_
->
has_statements
;
}
inline
bool
Node
::
has_statements
()
const
{
return
ip_
->
has_statements
;
}
inline
bool
Node
::
has_blocks
()
const
{
return
ip_
->
has_blocks
;
}
inline
bool
Node
::
has_blocks
()
const
{
return
ip_
->
has_blocks
;
}
...
@@ -457,6 +461,7 @@ namespace Sass {
...
@@ -457,6 +461,7 @@ namespace Sass {
inline
Node
&
Node
::
back
()
const
{
return
ip_
->
back
();
}
inline
Node
&
Node
::
back
()
const
{
return
ip_
->
back
();
}
inline
Node
&
Node
::
operator
[](
size_t
i
)
const
{
return
at
(
i
);
}
inline
Node
&
Node
::
operator
[](
size_t
i
)
const
{
return
at
(
i
);
}
inline
void
Node
::
pop_back
()
{
ip_
->
pop_back
();
}
inline
void
Node
::
pop_back
()
{
ip_
->
pop_back
();
}
inline
void
Node
::
pop_all
()
{
ip_
->
pop_all
();
}
inline
Node
&
Node
::
push_back
(
Node
n
)
inline
Node
&
Node
::
push_back
(
Node
n
)
{
{
ip_
->
push_back
(
n
);
ip_
->
push_back
(
n
);
...
...
node_emitters.cpp
View file @
5bd4581b
...
@@ -124,6 +124,7 @@ namespace Sass {
...
@@ -124,6 +124,7 @@ namespace Sass {
if
(
size
()
==
0
)
return
""
;
if
(
size
()
==
0
)
return
""
;
string
result
(
at
(
0
).
to_string
());
string
result
(
at
(
0
).
to_string
());
for
(
size_t
i
=
1
,
S
=
size
();
i
<
S
;
++
i
)
{
for
(
size_t
i
=
1
,
S
=
size
();
i
<
S
;
++
i
)
{
if
(
at
(
i
).
is_null
())
continue
;
if
(
at
(
i
).
type
()
==
list
&&
at
(
i
).
size
()
==
0
)
continue
;
if
(
at
(
i
).
type
()
==
list
&&
at
(
i
).
size
()
==
0
)
continue
;
result
+=
is_comma_separated
()
?
", "
:
" "
;
result
+=
is_comma_separated
()
?
", "
:
" "
;
result
+=
at
(
i
).
to_string
();
result
+=
at
(
i
).
to_string
();
...
@@ -270,7 +271,7 @@ namespace Sass {
...
@@ -270,7 +271,7 @@ namespace Sass {
return
result
;
return
result
;
}
break
;
}
break
;
case
expansion
:
{
case
mixin_call
:
{
// ignore it
// ignore it
return
""
;
return
""
;
}
break
;
}
break
;
...
...
sass_interface.cpp
View file @
5bd4581b
...
@@ -41,12 +41,12 @@ extern "C" {
...
@@ -41,12 +41,12 @@ extern "C" {
{
{
using
namespace
Sass
;
using
namespace
Sass
;
doc
.
parse_scss
();
doc
.
parse_scss
();
e
val
(
doc
.
root
,
e
xpand
(
doc
.
root
,
doc
.
context
.
new_Node
(
Node
::
none
,
doc
.
path
,
doc
.
line
,
0
),
doc
.
context
.
new_Node
(
Node
::
none
,
doc
.
path
,
doc
.
line
,
0
),
doc
.
context
.
global_env
,
doc
.
context
.
global_env
,
doc
.
context
.
function_env
,
doc
.
context
.
function_env
,
doc
.
context
.
new_Node
,
doc
.
context
.
new_Node
,
doc
.
context
);
doc
.
context
);
extend_selectors
(
doc
.
context
.
pending_extensions
,
doc
.
context
.
extensions
,
doc
.
context
.
new_Node
);
extend_selectors
(
doc
.
context
.
pending_extensions
,
doc
.
context
.
extensions
,
doc
.
context
.
new_Node
);
string
output
(
doc
.
emit_css
(
static_cast
<
Document
::
CSS_Style
>
(
style
)));
string
output
(
doc
.
emit_css
(
static_cast
<
Document
::
CSS_Style
>
(
style
)));
char
*
c_output
=
(
char
*
)
malloc
(
output
.
size
()
+
1
);
char
*
c_output
=
(
char
*
)
malloc
(
output
.
size
()
+
1
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment