Commit 9180b5c4 by Dean Mao

add callback support and add newlines at end of files

parent c4ce49a4
...@@ -6,13 +6,12 @@ Node bindings to libsass ...@@ -6,13 +6,12 @@ Node bindings to libsass
## Install ## Install
cd libsass && make && cd .. npm install
node-waf configure && node-waf build
## Usage ## Usage
var sass = require('./sass'); var sass = require('./sass');
sass.render('body{background:blue; a{color:black;}}', function(css){ sass.render('body{background:blue; a{color:black;}}', function(err, css){
console.log(css) console.log(css)
}); });
...@@ -40,4 +39,4 @@ Heavily inspired by <https://github.com/LearnBoost/stylus> ...@@ -40,4 +39,4 @@ Heavily inspired by <https://github.com/LearnBoost/stylus>
* publish npm * publish npm
* use node-gyp for builds * use node-gyp for builds
* file context * file context
* folder context * folder context
\ No newline at end of file
#include <v8.h> #include <v8.h>
#include <node.h> #include <node.h>
#include <string>
#include <cstdlib>
#include "libsass/sass_interface.h" #include "libsass/sass_interface.h"
using namespace v8; using namespace v8;
void WorkOnContext(uv_work_t* req) {
sass_context* ctx = static_cast<sass_context*>(req->data);
sass_compile(ctx);
}
void MakeCallback(uv_work_t* req) {
HandleScope scope;
TryCatch try_catch;
sass_context* ctx = static_cast<sass_context*>(req->data);
if (ctx->error_status == 0) {
// if no error, do callback(null, result)
const unsigned argc = 2;
Local<Value> argv[argc] = {
Local<Value>::New(Null()),
Local<Value>::New(String::New(ctx->output_string))
};
ctx->callback->Call(Context::GetCurrent()->Global(), argc, argv);
} else {
// if error, do callback(error)
const unsigned argc = 1;
Local<Value> argv[argc] = {
Local<Value>::New(String::New(ctx->error_message))
};
ctx->callback->Call(Context::GetCurrent()->Global(), argc, argv);
}
if (try_catch.HasCaught()) {
node::FatalException(try_catch);
}
}
Handle<Value> Render(const Arguments& args) { Handle<Value> Render(const Arguments& args) {
HandleScope scope; HandleScope scope;
struct sass_context* ctx = sass_new_context(); sass_context* ctx = sass_new_context();
String::AsciiValue astr(args[0]); String::AsciiValue astr(args[0]);
char * cs = *astr; Local<Function> callback = Local<Function>::Cast(args[1]);
ctx->source_string = cs; ctx->source_string = new char[strlen(*astr)+1];
strcpy(ctx->source_string, *astr);
ctx->options.include_paths = 0; ctx->options.include_paths = 0;
ctx->options.output_style = SASS_STYLE_NESTED; ctx->options.output_style = SASS_STYLE_NESTED;
ctx->callback = Persistent<Function>::New(callback);
ctx->request.data = ctx;
sass_compile(ctx); int status = uv_queue_work(uv_default_loop(), &ctx->request, WorkOnContext, MakeCallback);
assert(status == 0);
return scope.Close(String::New(ctx->output_string)); return Undefined();
} }
void RegisterModule(v8::Handle<v8::Object> target) { void RegisterModule(v8::Handle<v8::Object> target) {
......
...@@ -20,13 +20,13 @@ var imports = {}; ...@@ -20,13 +20,13 @@ var imports = {};
* when undefined defaults to `src`. * when undefined defaults to `src`.
* *
* Examples: * Examples:
* *
* Pass the middleware to Connect, grabbing .scss files from this directory * Pass the middleware to Connect, grabbing .scss files from this directory
* and saving .css files to _./public_. * and saving .css files to _./public_.
* *
* Following that we have a `staticProvider` layer setup to serve the .css * Following that we have a `staticProvider` layer setup to serve the .css
* files generated by Sass. * files generated by Sass.
* *
* var server = connect.createServer( * var server = connect.createServer(
* sass.middleware({ * sass.middleware({
* src: __dirname * src: __dirname
...@@ -34,7 +34,7 @@ var imports = {}; ...@@ -34,7 +34,7 @@ var imports = {};
* }) * })
* , connect.static(__dirname + '/public') * , connect.static(__dirname + '/public')
* ); * );
* *
* @param {Object} options * @param {Object} options
* @return {Function} * @return {Function}
* @api public * @api public
...@@ -99,8 +99,8 @@ module.exports = function(options){ ...@@ -99,8 +99,8 @@ module.exports = function(options){
var style = options.compile(); var style = options.compile();
var paths = []; var paths = [];
delete imports[sassPath]; delete imports[sassPath];
style.render(str, function(css){ style.render(str, function(err, css){
// if (err) return next(err); if (err) return next(err);
if (debug) log('render', sassPath); if (debug) log('render', sassPath);
imports[sassPath] = paths; imports[sassPath] = paths;
mkdirp(dirname(cssPath), 0700, function(err){ mkdirp(dirname(cssPath), 0700, function(err){
...@@ -187,4 +187,4 @@ function checkImports(path, fn) { ...@@ -187,4 +187,4 @@ function checkImports(path, fn) {
function log(key, val) { function log(key, val) {
console.error(' \033[90m%s :\033[0m \033[36m%s\033[0m', key, val); console.error(' \033[90m%s :\033[0m \033[36m%s\033[0m', key, val);
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ using std::cerr; using std::endl; ...@@ -6,7 +6,7 @@ using std::cerr; using std::endl;
namespace Sass { namespace Sass {
using std::pair; using std::pair;
void Context::collect_include_paths(const char* paths_str) void Context::collect_include_paths(const char* paths_str)
{ {
const size_t wd_len = 1024; const size_t wd_len = 1024;
...@@ -39,7 +39,7 @@ namespace Sass { ...@@ -39,7 +39,7 @@ namespace Sass {
// cerr << include_paths[i] << endl; // cerr << include_paths[i] << endl;
// } // }
} }
Context::Context(const char* paths_str) Context::Context(const char* paths_str)
: global_env(Environment()), : global_env(Environment()),
function_env(map<pair<string, size_t>, Function>()), function_env(map<pair<string, size_t>, Function>()),
...@@ -54,7 +54,7 @@ namespace Sass { ...@@ -54,7 +54,7 @@ namespace Sass {
register_functions(); register_functions();
collect_include_paths(paths_str); collect_include_paths(paths_str);
} }
Context::~Context() Context::~Context()
{ {
for (size_t i = 0; i < source_refs.size(); ++i) { for (size_t i = 0; i < source_refs.size(); ++i) {
...@@ -64,19 +64,19 @@ namespace Sass { ...@@ -64,19 +64,19 @@ namespace Sass {
new_Node.free(); new_Node.free();
// cerr << "Deallocated " << i << " source string(s)." << endl; // cerr << "Deallocated " << i << " source string(s)." << endl;
} }
inline void Context::register_function(Function_Descriptor d, Implementation ip) inline void Context::register_function(Function_Descriptor d, Implementation ip)
{ {
Function f(d, ip); Function f(d, ip);
function_env[pair<string, size_t>(f.name, f.parameters.size())] = f; function_env[pair<string, size_t>(f.name, f.parameters.size())] = f;
} }
inline void Context::register_function(Function_Descriptor d, Implementation ip, size_t arity) inline void Context::register_function(Function_Descriptor d, Implementation ip, size_t arity)
{ {
Function f(d, ip); Function f(d, ip);
function_env[pair<string, size_t>(f.name, arity)] = f; function_env[pair<string, size_t>(f.name, arity)] = f;
} }
void Context::register_functions() void Context::register_functions()
{ {
using namespace Functions; using namespace Functions;
...@@ -122,5 +122,6 @@ namespace Sass { ...@@ -122,5 +122,6 @@ namespace Sass {
// Boolean Functions // Boolean Functions
register_function(not_descriptor, not_impl); register_function(not_descriptor, not_impl);
} }
} }
...@@ -9,29 +9,29 @@ ...@@ -9,29 +9,29 @@
namespace Sass { namespace Sass {
using std::pair; using std::pair;
using std::map; using std::map;
struct Environment { struct Environment {
map<Token, Node> current_frame; map<Token, Node> current_frame;
Environment* parent; Environment* parent;
Environment* global; Environment* global;
Environment() Environment()
: current_frame(map<Token, Node>()), parent(0), global(0) : current_frame(map<Token, Node>()), parent(0), global(0)
{ } { }
void link(Environment& env) void link(Environment& env)
{ {
parent = &env; parent = &env;
global = parent->global ? parent->global : parent; global = parent->global ? parent->global : parent;
} }
bool query(const Token& key) const bool query(const Token& key) const
{ {
if (current_frame.count(key)) return true; if (current_frame.count(key)) return true;
else if (parent) return parent->query(key); else if (parent) return parent->query(key);
else return false; else return false;
} }
Node& operator[](const Token& key) Node& operator[](const Token& key)
{ {
if (current_frame.count(key)) return current_frame[key]; if (current_frame.count(key)) return current_frame[key];
...@@ -56,10 +56,11 @@ namespace Sass { ...@@ -56,10 +56,11 @@ namespace Sass {
void collect_include_paths(const char* paths_str); void collect_include_paths(const char* paths_str);
Context(const char* paths_str = 0); Context(const char* paths_str = 0);
~Context(); ~Context();
void register_function(Function_Descriptor d, Implementation ip); void register_function(Function_Descriptor d, Implementation ip);
void register_function(Function_Descriptor d, Implementation ip, size_t arity); void register_function(Function_Descriptor d, Implementation ip, size_t arity);
void register_functions(); void register_functions();
}; };
} }
...@@ -90,17 +90,17 @@ namespace Sass { ...@@ -90,17 +90,17 @@ namespace Sass {
return doc; return doc;
} }
void Document::throw_syntax_error(string message, size_t ln) void Document::throw_syntax_error(string message, size_t ln)
{ throw Error(Error::syntax, path, ln ? ln : line, message); } { throw Error(Error::syntax, path, ln ? ln : line, message); }
void Document::throw_read_error(string message, size_t ln) void Document::throw_read_error(string message, size_t ln)
{ throw Error(Error::read, path, ln ? ln : line, message); } { throw Error(Error::read, path, ln ? ln : line, message); }
using std::string; using std::string;
using std::stringstream; using std::stringstream;
using std::endl; using std::endl;
string Document::emit_css(CSS_Style style) { string Document::emit_css(CSS_Style style) {
stringstream output; stringstream output;
switch (style) { switch (style) {
...@@ -121,3 +121,4 @@ namespace Sass { ...@@ -121,3 +121,4 @@ namespace Sass {
return retval; return retval;
} }
} }
...@@ -25,7 +25,7 @@ namespace Sass { ...@@ -25,7 +25,7 @@ namespace Sass {
struct Document { struct Document {
enum CSS_Style { nested, expanded, compact, compressed, echo }; enum CSS_Style { nested, expanded, compact, compressed, echo };
string path; string path;
char* source; char* source;
const char* position; const char* position;
...@@ -34,7 +34,7 @@ namespace Sass { ...@@ -34,7 +34,7 @@ namespace Sass {
bool own_source; bool own_source;
Context& context; Context& context;
Node root; Node root;
Token lexed; Token lexed;
...@@ -84,7 +84,7 @@ namespace Sass { ...@@ -84,7 +84,7 @@ namespace Sass {
return 0; return 0;
} }
} }
template <prelexer mx> template <prelexer mx>
const char* lex() const char* lex()
{ {
...@@ -123,7 +123,7 @@ namespace Sass { ...@@ -123,7 +123,7 @@ namespace Sass {
return 0; return 0;
} }
} }
void parse_scss(); void parse_scss();
Node parse_import(); Node parse_import();
Node parse_include(); Node parse_include();
...@@ -163,13 +163,14 @@ namespace Sass { ...@@ -163,13 +163,14 @@ namespace Sass {
Node parse_if_directive(Node surrounding_ruleset); Node parse_if_directive(Node surrounding_ruleset);
Node parse_for_directive(Node surrounding_ruleset); Node parse_for_directive(Node surrounding_ruleset);
Selector_Lookahead lookahead_for_selector(const char* start = 0); Selector_Lookahead lookahead_for_selector(const char* start = 0);
void throw_syntax_error(string message, size_t ln = 0); void throw_syntax_error(string message, size_t ln = 0);
void throw_read_error(string message, size_t ln = 0); void throw_read_error(string message, size_t ln = 0);
string emit_css(CSS_Style style); string emit_css(CSS_Style style);
}; };
} }
\ No newline at end of file
...@@ -149,7 +149,7 @@ namespace Sass { ...@@ -149,7 +149,7 @@ namespace Sass {
the_call << name << args; the_call << name << args;
return the_call; return the_call;
} }
Node Document::parse_arguments() Node Document::parse_arguments()
{ {
Token name(lexed); Token name(lexed);
...@@ -169,7 +169,7 @@ namespace Sass { ...@@ -169,7 +169,7 @@ namespace Sass {
} }
return args; return args;
} }
Node Document::parse_argument() Node Document::parse_argument()
{ {
if (peek< sequence < variable, spaces_and_comments, exactly<':'> > >()) { if (peek< sequence < variable, spaces_and_comments, exactly<':'> > >()) {
...@@ -196,7 +196,7 @@ namespace Sass { ...@@ -196,7 +196,7 @@ namespace Sass {
assn << var << val; assn << var << val;
return assn; return assn;
} }
Node Document::parse_propset() Node Document::parse_propset()
{ {
lex< identifier >(); lex< identifier >();
...@@ -237,7 +237,7 @@ namespace Sass { ...@@ -237,7 +237,7 @@ namespace Sass {
extern const char hash_lbrace[] = "#{"; extern const char hash_lbrace[] = "#{";
extern const char rbrace[] = "}"; extern const char rbrace[] = "}";
Node Document::parse_selector_schema(const char* end_of_selector) Node Document::parse_selector_schema(const char* end_of_selector)
{ {
const char* i = position; const char* i = position;
const char* p; const char* p;
Node schema(context.new_Node(Node::selector_schema, path, line, 1)); Node schema(context.new_Node(Node::selector_schema, path, line, 1));
...@@ -267,7 +267,7 @@ namespace Sass { ...@@ -267,7 +267,7 @@ namespace Sass {
{ {
Node sel1(parse_selector()); Node sel1(parse_selector());
if (!peek< exactly<','> >()) return sel1; if (!peek< exactly<','> >()) return sel1;
Node group(context.new_Node(Node::selector_group, path, line, 2)); Node group(context.new_Node(Node::selector_group, path, line, 2));
group << sel1; group << sel1;
while (lex< exactly<','> >()) group << parse_selector(); while (lex< exactly<','> >()) group << parse_selector();
...@@ -280,7 +280,7 @@ namespace Sass { ...@@ -280,7 +280,7 @@ namespace Sass {
if (peek< exactly<','> >() || if (peek< exactly<','> >() ||
peek< exactly<')'> >() || peek< exactly<')'> >() ||
peek< exactly<'{'> >()) return seq1; peek< exactly<'{'> >()) return seq1;
Node selector(context.new_Node(Node::selector, path, line, 2)); Node selector(context.new_Node(Node::selector, path, line, 2));
selector << seq1; selector << seq1;
...@@ -297,7 +297,7 @@ namespace Sass { ...@@ -297,7 +297,7 @@ namespace Sass {
lex< exactly<'~'> >() || lex< exactly<'~'> >() ||
lex< exactly<'>'> >()) lex< exactly<'>'> >())
{ return context.new_Node(Node::selector_combinator, path, line, lexed); } { return context.new_Node(Node::selector_combinator, path, line, lexed); }
// check for backref or type selector, which are only allowed at the front // check for backref or type selector, which are only allowed at the front
Node simp1; Node simp1;
if (lex< exactly<'&'> >()) { if (lex< exactly<'&'> >()) {
...@@ -309,7 +309,7 @@ namespace Sass { ...@@ -309,7 +309,7 @@ namespace Sass {
else { else {
simp1 = parse_simple_selector(); simp1 = parse_simple_selector();
} }
// now we have one simple/atomic selector -- see if that's all // now we have one simple/atomic selector -- see if that's all
if (peek< spaces >() || peek< exactly<'>'> >() || if (peek< spaces >() || peek< exactly<'>'> >() ||
peek< exactly<'+'> >() || peek< exactly<'~'> >() || peek< exactly<'+'> >() || peek< exactly<'~'> >() ||
...@@ -320,7 +320,7 @@ namespace Sass { ...@@ -320,7 +320,7 @@ namespace Sass {
// otherwise, we have a sequence of simple selectors // otherwise, we have a sequence of simple selectors
Node seq(context.new_Node(Node::simple_selector_sequence, path, line, 2)); Node seq(context.new_Node(Node::simple_selector_sequence, path, line, 2));
seq << simp1; seq << simp1;
while (!peek< spaces >(position) && while (!peek< spaces >(position) &&
!(peek < exactly<'+'> >(position) || !(peek < exactly<'+'> >(position) ||
peek < exactly<'~'> >(position) || peek < exactly<'~'> >(position) ||
...@@ -333,14 +333,14 @@ namespace Sass { ...@@ -333,14 +333,14 @@ namespace Sass {
} }
return seq; return seq;
} }
Node Document::parse_selector_combinator() Node Document::parse_selector_combinator()
{ {
lex< exactly<'+'> >() || lex< exactly<'~'> >() || lex< exactly<'+'> >() || lex< exactly<'~'> >() ||
lex< exactly<'>'> >() || lex< ancestor_of >(); lex< exactly<'>'> >() || lex< ancestor_of >();
return context.new_Node(Node::selector_combinator, path, line, lexed); return context.new_Node(Node::selector_combinator, path, line, lexed);
} }
Node Document::parse_simple_selector() Node Document::parse_simple_selector()
{ {
if (lex< id_name >() || lex< class_name >()) { if (lex< id_name >() || lex< class_name >()) {
...@@ -358,7 +358,7 @@ namespace Sass { ...@@ -358,7 +358,7 @@ namespace Sass {
// unreachable statement // unreachable statement
return Node(); return Node();
} }
Node Document::parse_pseudo() { Node Document::parse_pseudo() {
if (lex< pseudo_not >()) { if (lex< pseudo_not >()) {
Node ps_not(context.new_Node(Node::pseudo_negation, path, line, 2)); Node ps_not(context.new_Node(Node::pseudo_negation, path, line, 2));
...@@ -410,7 +410,7 @@ namespace Sass { ...@@ -410,7 +410,7 @@ namespace Sass {
// unreachable statement // unreachable statement
return Node(); return Node();
} }
Node Document::parse_attribute_selector() Node Document::parse_attribute_selector()
{ {
Node attr_sel(context.new_Node(Node::attribute_selector, path, line, 3)); Node attr_sel(context.new_Node(Node::attribute_selector, path, line, 3));
...@@ -532,12 +532,12 @@ namespace Sass { ...@@ -532,12 +532,12 @@ namespace Sass {
rule << parse_list(); rule << parse_list();
return rule; return rule;
} }
Node Document::parse_list() Node Document::parse_list()
{ {
return parse_comma_list(); return parse_comma_list();
} }
Node Document::parse_comma_list() Node Document::parse_comma_list()
{ {
if (peek< exactly<';'> >(position) || if (peek< exactly<';'> >(position) ||
...@@ -548,21 +548,21 @@ namespace Sass { ...@@ -548,21 +548,21 @@ namespace Sass {
Node list1(parse_space_list()); Node list1(parse_space_list());
// if it's a singleton, return it directly; don't wrap it // if it's a singleton, return it directly; don't wrap it
if (!peek< exactly<','> >(position)) return list1; if (!peek< exactly<','> >(position)) return list1;
Node comma_list(context.new_Node(Node::comma_list, path, line, 2)); Node comma_list(context.new_Node(Node::comma_list, path, line, 2));
comma_list << list1; comma_list << list1;
comma_list.should_eval() |= list1.should_eval(); comma_list.should_eval() |= list1.should_eval();
while (lex< exactly<','> >()) while (lex< exactly<','> >())
{ {
Node list(parse_space_list()); Node list(parse_space_list());
comma_list << list; comma_list << list;
comma_list.should_eval() |= list.should_eval(); comma_list.should_eval() |= list.should_eval();
} }
return comma_list; return comma_list;
} }
Node Document::parse_space_list() Node Document::parse_space_list()
{ {
Node disj1(parse_disjunction()); Node disj1(parse_disjunction());
...@@ -573,11 +573,11 @@ namespace Sass { ...@@ -573,11 +573,11 @@ namespace Sass {
peek< exactly<')'> >(position) || peek< exactly<')'> >(position) ||
peek< exactly<','> >(position)) peek< exactly<','> >(position))
{ return disj1; } { return disj1; }
Node space_list(context.new_Node(Node::space_list, path, line, 2)); Node space_list(context.new_Node(Node::space_list, path, line, 2));
space_list << disj1; space_list << disj1;
space_list.should_eval() |= disj1.should_eval(); space_list.should_eval() |= disj1.should_eval();
while (!(peek< exactly<';'> >(position) || while (!(peek< exactly<';'> >(position) ||
peek< exactly<'}'> >(position) || peek< exactly<'}'> >(position) ||
peek< exactly<'{'> >(position) || peek< exactly<'{'> >(position) ||
...@@ -588,37 +588,37 @@ namespace Sass { ...@@ -588,37 +588,37 @@ namespace Sass {
space_list << disj; space_list << disj;
space_list.should_eval() |= disj.should_eval(); space_list.should_eval() |= disj.should_eval();
} }
return space_list; return space_list;
} }
Node Document::parse_disjunction() Node Document::parse_disjunction()
{ {
Node conj1(parse_conjunction()); Node conj1(parse_conjunction());
// if it's a singleton, return it directly; don't wrap it // if it's a singleton, return it directly; don't wrap it
if (!peek< sequence< or_kwd, negate< identifier > > >()) return conj1; if (!peek< sequence< or_kwd, negate< identifier > > >()) return conj1;
Node disjunction(context.new_Node(Node::disjunction, path, line, 2)); Node disjunction(context.new_Node(Node::disjunction, path, line, 2));
disjunction << conj1; disjunction << conj1;
while (lex< sequence< or_kwd, negate< identifier > > >()) disjunction << parse_conjunction(); while (lex< sequence< or_kwd, negate< identifier > > >()) disjunction << parse_conjunction();
disjunction.should_eval() = true; disjunction.should_eval() = true;
return disjunction; return disjunction;
} }
Node Document::parse_conjunction() Node Document::parse_conjunction()
{ {
Node rel1(parse_relation()); Node rel1(parse_relation());
// if it's a singleton, return it directly; don't wrap it // if it's a singleton, return it directly; don't wrap it
if (!peek< sequence< and_kwd, negate< identifier > > >()) return rel1; if (!peek< sequence< and_kwd, negate< identifier > > >()) return rel1;
Node conjunction(context.new_Node(Node::conjunction, path, line, 2)); Node conjunction(context.new_Node(Node::conjunction, path, line, 2));
conjunction << rel1; conjunction << rel1;
while (lex< sequence< and_kwd, negate< identifier > > >()) conjunction << parse_relation(); while (lex< sequence< and_kwd, negate< identifier > > >()) conjunction << parse_relation();
conjunction.should_eval() = true; conjunction.should_eval() = true;
return conjunction; return conjunction;
} }
Node Document::parse_relation() Node Document::parse_relation()
{ {
Node expr1(parse_expression()); Node expr1(parse_expression());
...@@ -630,26 +630,26 @@ namespace Sass { ...@@ -630,26 +630,26 @@ namespace Sass {
peek< lt_op >(position) || peek< lt_op >(position) ||
peek< lte_op >(position))) peek< lte_op >(position)))
{ return expr1; } { return expr1; }
Node relation(context.new_Node(Node::relation, path, line, 3)); Node relation(context.new_Node(Node::relation, path, line, 3));
expr1.should_eval() = true; expr1.should_eval() = true;
relation << expr1; relation << expr1;
if (lex< eq_op >()) relation << context.new_Node(Node::eq, path, line, lexed); if (lex< eq_op >()) relation << context.new_Node(Node::eq, path, line, lexed);
else if (lex< neq_op >()) relation << context.new_Node(Node::neq, path, line, lexed); else if (lex< neq_op >()) relation << context.new_Node(Node::neq, path, line, lexed);
else if (lex< gte_op >()) relation << context.new_Node(Node::gte, path, line, lexed); else if (lex< gte_op >()) relation << context.new_Node(Node::gte, path, line, lexed);
else if (lex< lte_op >()) relation << context.new_Node(Node::lte, path, line, lexed); else if (lex< lte_op >()) relation << context.new_Node(Node::lte, path, line, lexed);
else if (lex< gt_op >()) relation << context.new_Node(Node::gt, path, line, lexed); else if (lex< gt_op >()) relation << context.new_Node(Node::gt, path, line, lexed);
else if (lex< lt_op >()) relation << context.new_Node(Node::lt, path, line, lexed); else if (lex< lt_op >()) relation << context.new_Node(Node::lt, path, line, lexed);
Node expr2(parse_expression()); Node expr2(parse_expression());
expr2.should_eval() = true; expr2.should_eval() = true;
relation << expr2; relation << expr2;
relation.should_eval() = true; relation.should_eval() = true;
return relation; return relation;
} }
Node Document::parse_expression() Node Document::parse_expression()
{ {
Node term1(parse_term()); Node term1(parse_term());
...@@ -657,11 +657,11 @@ namespace Sass { ...@@ -657,11 +657,11 @@ namespace Sass {
if (!(peek< exactly<'+'> >(position) || if (!(peek< exactly<'+'> >(position) ||
peek< sequence< negate< number >, exactly<'-'> > >(position))) peek< sequence< negate< number >, exactly<'-'> > >(position)))
{ return term1; } { return term1; }
Node expression(context.new_Node(Node::expression, path, line, 3)); Node expression(context.new_Node(Node::expression, path, line, 3));
term1.should_eval() = true; term1.should_eval() = true;
expression << term1; expression << term1;
while (lex< exactly<'+'> >() || lex< sequence< negate< number >, exactly<'-'> > >()) { while (lex< exactly<'+'> >() || lex< sequence< negate< number >, exactly<'-'> > >()) {
if (lexed.begin[0] == '+') { if (lexed.begin[0] == '+') {
expression << context.new_Node(Node::add, path, line, lexed); expression << context.new_Node(Node::add, path, line, lexed);
...@@ -677,7 +677,7 @@ namespace Sass { ...@@ -677,7 +677,7 @@ namespace Sass {
return expression; return expression;
} }
Node Document::parse_term() Node Document::parse_term()
{ {
Node fact1(parse_factor()); Node fact1(parse_factor());
...@@ -705,7 +705,7 @@ namespace Sass { ...@@ -705,7 +705,7 @@ namespace Sass {
return term; return term;
} }
Node Document::parse_factor() Node Document::parse_factor()
{ {
if (lex< exactly<'('> >()) { if (lex< exactly<'('> >()) {
...@@ -733,7 +733,7 @@ namespace Sass { ...@@ -733,7 +733,7 @@ namespace Sass {
return parse_value(); return parse_value();
} }
} }
Node Document::parse_value() Node Document::parse_value()
{ {
if (lex< uri_prefix >()) if (lex< uri_prefix >())
...@@ -748,19 +748,19 @@ namespace Sass { ...@@ -748,19 +748,19 @@ namespace Sass {
lex< exactly<')'> >(); lex< exactly<')'> >();
return result; return result;
} }
if (lex< value_schema >()) if (lex< value_schema >())
{ return Document::make_from_token(context, lexed, path, line).parse_value_schema(); } { return Document::make_from_token(context, lexed, path, line).parse_value_schema(); }
if (lex< sequence< true_kwd, negate< identifier > > >()) if (lex< sequence< true_kwd, negate< identifier > > >())
{ return context.new_Node(Node::boolean, path, line, true); } { return context.new_Node(Node::boolean, path, line, true); }
if (lex< sequence< false_kwd, negate< identifier > > >()) if (lex< sequence< false_kwd, negate< identifier > > >())
{ return context.new_Node(Node::boolean, path, line, false); } { return context.new_Node(Node::boolean, path, line, false); }
if (peek< functional >()) if (peek< functional >())
{ return parse_function_call(); } { return parse_function_call(); }
if (lex< important >()) if (lex< important >())
{ return context.new_Node(Node::important, path, line, lexed); } { return context.new_Node(Node::important, path, line, lexed); }
...@@ -780,7 +780,7 @@ namespace Sass { ...@@ -780,7 +780,7 @@ namespace Sass {
{ return context.new_Node(Node::textual_hex, path, line, lexed); } { return context.new_Node(Node::textual_hex, path, line, lexed); }
if (peek< string_constant >()) if (peek< string_constant >())
{ return parse_string(); } { return parse_string(); }
if (lex< variable >()) if (lex< variable >())
{ {
...@@ -788,15 +788,15 @@ namespace Sass { ...@@ -788,15 +788,15 @@ namespace Sass {
var.should_eval() = true; var.should_eval() = true;
return var; return var;
} }
throw_syntax_error("error reading values after " + lexed.to_string()); throw_syntax_error("error reading values after " + lexed.to_string());
// unreachable statement // unreachable statement
return Node(); return Node();
} }
Node Document::parse_string() Node Document::parse_string()
{ {
lex< string_constant >(); lex< string_constant >();
Token str(lexed); Token str(lexed);
const char* i = str.begin; const char* i = str.begin;
...@@ -805,7 +805,7 @@ namespace Sass { ...@@ -805,7 +805,7 @@ namespace Sass {
if (!p) { if (!p) {
return context.new_Node(Node::string_constant, path, line, str); return context.new_Node(Node::string_constant, path, line, str);
} }
Node schema(context.new_Node(Node::string_schema, path, line, 1)); Node schema(context.new_Node(Node::string_schema, path, line, 1));
while (i < str.end) { while (i < str.end) {
p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end); p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
...@@ -833,11 +833,11 @@ namespace Sass { ...@@ -833,11 +833,11 @@ namespace Sass {
} }
return schema; return schema;
} }
Node Document::parse_value_schema() Node Document::parse_value_schema()
{ {
Node schema(context.new_Node(Node::value_schema, path, line, 1)); Node schema(context.new_Node(Node::value_schema, path, line, 1));
while (position < end) { while (position < end) {
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));
...@@ -872,7 +872,7 @@ namespace Sass { ...@@ -872,7 +872,7 @@ namespace Sass {
schema.should_eval() = true; schema.should_eval() = true;
return schema; return schema;
} }
Node Document::parse_function_call() Node Document::parse_function_call()
{ {
lex< identifier >(); lex< identifier >();
...@@ -924,7 +924,7 @@ namespace Sass { ...@@ -924,7 +924,7 @@ namespace Sass {
loop << var << lower_bound << upper_bound << body; loop << var << lower_bound << upper_bound << body;
return loop; return loop;
} }
Selector_Lookahead Document::lookahead_for_selector(const char* start) Selector_Lookahead Document::lookahead_for_selector(const char* start)
{ {
const char* p = start ? start : position; const char* p = start ? start : position;
...@@ -974,5 +974,6 @@ namespace Sass { ...@@ -974,5 +974,6 @@ namespace Sass {
return result; return result;
} }
} }
\ No newline at end of file
namespace Sass { namespace Sass {
struct Error { struct Error {
enum Type { read, write, syntax, evaluation }; enum Type { read, write, syntax, evaluation };
Type type; Type type;
string path; string path;
size_t line; size_t line;
string message; string message;
Error(Type type, string path, size_t line, string message) Error(Type type, string path, size_t line, string message)
: type(type), path(path), line(line), message(message) : type(type), path(path), line(line), message(message)
{ } { }
}; };
} }
\ No newline at end of file
...@@ -27,7 +27,7 @@ namespace Sass { ...@@ -27,7 +27,7 @@ namespace Sass {
env[expr[0].token()] = expr; env[expr[0].token()] = expr;
return expr; return expr;
} break; } break;
case Node::expansion: { case Node::expansion: {
Token name(expr[0].token()); Token name(expr[0].token());
Node args(expr[1]); Node args(expr[1]);
...@@ -39,7 +39,7 @@ namespace Sass { ...@@ -39,7 +39,7 @@ namespace Sass {
expr += expansion; expr += expansion;
return expr; return expr;
} break; } break;
case Node::propset: { case Node::propset: {
eval(expr[1], prefix, env, f_env, new_Node, ctx); eval(expr[1], prefix, env, f_env, new_Node, ctx);
return expr; return expr;
...@@ -91,14 +91,14 @@ namespace Sass { ...@@ -91,14 +91,14 @@ namespace Sass {
Node sel(needs_reparsing.parse_selector_group()); Node sel(needs_reparsing.parse_selector_group());
return sel; return sel;
} break; } break;
case Node::root: { case Node::root: {
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); expr[i] = eval(expr[i], prefix, env, f_env, new_Node, ctx);
} }
return expr; return expr;
} break; } break;
case Node::block: { case Node::block: {
Environment new_frame; Environment new_frame;
new_frame.link(env); new_frame.link(env);
...@@ -107,7 +107,7 @@ namespace Sass { ...@@ -107,7 +107,7 @@ namespace Sass {
} }
return expr; return expr;
} break; } break;
case Node::assignment: { case Node::assignment: {
Node val(expr[1]); Node val(expr[1]);
if (val.type() == Node::comma_list || val.type() == Node::space_list) { if (val.type() == Node::comma_list || val.type() == Node::space_list) {
...@@ -149,7 +149,7 @@ namespace Sass { ...@@ -149,7 +149,7 @@ namespace Sass {
if (expr.should_eval()) expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx); if (expr.should_eval()) expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx);
return expr; return expr;
} break; } break;
case Node::disjunction: { case Node::disjunction: {
Node result; Node result;
for (size_t i = 0, S = expr.size(); i < S; ++i) { for (size_t i = 0, S = expr.size(); i < S; ++i) {
...@@ -159,7 +159,7 @@ namespace Sass { ...@@ -159,7 +159,7 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case Node::conjunction: { case Node::conjunction: {
Node result; Node result;
for (size_t i = 0, S = expr.size(); i < S; ++i) { for (size_t i = 0, S = expr.size(); i < S; ++i) {
...@@ -168,16 +168,16 @@ namespace Sass { ...@@ -168,16 +168,16 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case Node::relation: { case Node::relation: {
Node lhs(eval(expr[0], prefix, env, f_env, new_Node, ctx)); Node lhs(eval(expr[0], prefix, env, f_env, new_Node, ctx));
Node op(expr[1]); Node op(expr[1]);
Node rhs(eval(expr[2], prefix, env, f_env, new_Node, ctx)); Node rhs(eval(expr[2], prefix, env, f_env, new_Node, ctx));
// TO DO: don't allocate both T and F // TO DO: don't allocate both T and F
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 (op.type())
{ {
case Node::eq: return (lhs == rhs) ? T : F; case Node::eq: return (lhs == rhs) ? T : F;
...@@ -231,12 +231,12 @@ namespace Sass { ...@@ -231,12 +231,12 @@ namespace Sass {
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: {
return new_Node(expr.path(), expr.line(), std::atof(expr.token().begin)); return 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)); Node triple(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) {
...@@ -252,19 +252,19 @@ namespace Sass { ...@@ -252,19 +252,19 @@ namespace Sass {
triple << new_Node(expr.path(), expr.line(), 1.0); triple << new_Node(expr.path(), expr.line(), 1.0);
return triple; 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());
return env[expr.token()]; return env[expr.token()];
} 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)
pair<string, size_t> sig(expr[0].token().to_string(), expr[1].size()); pair<string, size_t> sig(expr[0].token().to_string(), expr[1].size());
if (!f_env.count(sig)) return expr; if (!f_env.count(sig)) return expr;
return apply_function(f_env[sig], expr[1], prefix, env, f_env, new_Node, ctx); return apply_function(f_env[sig], expr[1], prefix, env, f_env, new_Node, ctx);
} 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()) {
...@@ -275,7 +275,7 @@ namespace Sass { ...@@ -275,7 +275,7 @@ namespace Sass {
return expr; return expr;
} }
} 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()) {
...@@ -286,7 +286,7 @@ namespace Sass { ...@@ -286,7 +286,7 @@ namespace Sass {
return expr; return expr;
} }
} break; } break;
case Node::string_schema: case Node::string_schema:
case Node::value_schema: { case Node::value_schema: {
for (size_t i = 0, S = expr.size(); i < S; ++i) { for (size_t i = 0, S = expr.size(); i < S; ++i) {
...@@ -294,7 +294,7 @@ namespace Sass { ...@@ -294,7 +294,7 @@ namespace Sass {
} }
return expr; return expr;
} break; } break;
case Node::css_import: { case Node::css_import: {
expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx); expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx);
return expr; return expr;
...@@ -359,7 +359,7 @@ namespace Sass { ...@@ -359,7 +359,7 @@ namespace Sass {
Node lhs(acc.back()); Node lhs(acc.back());
double lnum = lhs.numeric_value(); double lnum = lhs.numeric_value();
double rnum = rhs.numeric_value(); double rnum = rhs.numeric_value();
if (lhs.type() == Node::number && rhs.type() == Node::number) { if (lhs.type() == Node::number && rhs.type() == Node::number) {
Node result(new_Node(acc.path(), acc.line(), operate(op, lnum, rnum))); Node result(new_Node(acc.path(), acc.line(), operate(op, lnum, rnum)));
acc.pop_back(); acc.pop_back();
...@@ -451,7 +451,7 @@ namespace Sass { ...@@ -451,7 +451,7 @@ 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 args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& ctx) Node apply_mixin(Node mixin, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& ctx)
{ {
Node params(mixin[1]); Node params(mixin[1]);
...@@ -510,7 +510,7 @@ namespace Sass { ...@@ -510,7 +510,7 @@ namespace Sass {
// 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 args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& ctx) Node apply_function(const Function& f, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& ctx)
{ {
map<Token, Node> bindings; map<Token, Node> bindings;
...@@ -855,3 +855,4 @@ namespace Sass { ...@@ -855,3 +855,4 @@ namespace Sass {
{ return selector_but(sel, new_Node, 0, 1); } { return selector_but(sel, new_Node, 0, 1); }
} }
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
namespace Sass { namespace Sass {
using std::map; using std::map;
Node eval(Node expr, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs); Node eval(Node expr, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs);
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::Type op, double lhs, double rhs); double operate(Node::Type op, double lhs, double rhs);
Node apply_mixin(Node mixin, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs); Node apply_mixin(Node mixin, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs);
Node apply_function(const Function& f, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs); Node apply_function(const Function& f, const Node args, Node prefix, Environment& env, map<pair<string, size_t>, Function>& f_env, Node_Factory& new_Node, Context& src_refs);
Node expand_selector(Node sel, Node pre, Node_Factory& new_Node); Node expand_selector(Node sel, Node pre, Node_Factory& new_Node);
...@@ -28,4 +28,5 @@ namespace Sass { ...@@ -28,4 +28,5 @@ namespace Sass {
Node selector_butfirst(Node sel, Node_Factory& new_Node); Node selector_butfirst(Node sel, Node_Factory& new_Node);
Node selector_butlast(Node sel, Node_Factory& new_Node); Node selector_butlast(Node sel, Node_Factory& new_Node);
} }
\ No newline at end of file
...@@ -21,7 +21,7 @@ namespace Sass { ...@@ -21,7 +21,7 @@ namespace Sass {
// RGB Functions /////////////////////////////////////////////////////// // RGB Functions ///////////////////////////////////////////////////////
Function_Descriptor rgb_descriptor = Function_Descriptor rgb_descriptor =
{ "rgb", "$red", "$green", "$blue", 0 }; { "rgb", "$red", "$green", "$blue", 0 };
Node rgb(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node rgb(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node r(bindings[parameters[0]]); Node r(bindings[parameters[0]]);
...@@ -33,7 +33,7 @@ namespace Sass { ...@@ -33,7 +33,7 @@ namespace Sass {
return new_Node(r.path(), r.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), 1.0); return new_Node(r.path(), r.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), 1.0);
} }
Function_Descriptor rgba_4_descriptor = Function_Descriptor rgba_4_descriptor =
{ "rgba", "$red", "$green", "$blue", "$alpha", 0 }; { "rgba", "$red", "$green", "$blue", "$alpha", 0 };
Node rgba_4(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node rgba_4(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node r(bindings[parameters[0]]); Node r(bindings[parameters[0]]);
...@@ -45,8 +45,8 @@ namespace Sass { ...@@ -45,8 +45,8 @@ namespace Sass {
} }
return new_Node(r.path(), r.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value()); return new_Node(r.path(), r.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value());
} }
Function_Descriptor rgba_2_descriptor = Function_Descriptor rgba_2_descriptor =
{ "rgba", "$color", "$alpha", 0 }; { "rgba", "$color", "$alpha", 0 };
Node rgba_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node rgba_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node color(bindings[parameters[0]]); Node color(bindings[parameters[0]]);
...@@ -57,7 +57,7 @@ namespace Sass { ...@@ -57,7 +57,7 @@ namespace Sass {
if (color.type() != Node::numeric_color || a.type() != Node::number) throw_eval_error("arguments to rgba must be a color and a number", color.path(), color.line()); if (color.type() != Node::numeric_color || a.type() != Node::number) throw_eval_error("arguments to rgba must be a color and a number", color.path(), color.line());
return new_Node(color.path(), color.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value()); return new_Node(color.path(), color.line(), r.numeric_value(), g.numeric_value(), b.numeric_value(), a.numeric_value());
} }
Function_Descriptor red_descriptor = Function_Descriptor red_descriptor =
{ "red", "$color", 0 }; { "red", "$color", 0 };
Node red(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node red(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -65,7 +65,7 @@ namespace Sass { ...@@ -65,7 +65,7 @@ namespace Sass {
if (color.type() != Node::numeric_color) throw_eval_error("argument to red must be a color", color.path(), color.line()); if (color.type() != Node::numeric_color) throw_eval_error("argument to red must be a color", color.path(), color.line());
return color[0]; return color[0];
} }
Function_Descriptor green_descriptor = Function_Descriptor green_descriptor =
{ "green", "$color", 0 }; { "green", "$color", 0 };
Node green(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node green(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -73,7 +73,7 @@ namespace Sass { ...@@ -73,7 +73,7 @@ namespace Sass {
if (color.type() != Node::numeric_color) throw_eval_error("argument to green must be a color", color.path(), color.line()); if (color.type() != Node::numeric_color) throw_eval_error("argument to green must be a color", color.path(), color.line());
return color[1]; return color[1];
} }
Function_Descriptor blue_descriptor = Function_Descriptor blue_descriptor =
{ "blue", "$color", 0 }; { "blue", "$color", 0 };
Node blue(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node blue(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -81,7 +81,7 @@ namespace Sass { ...@@ -81,7 +81,7 @@ namespace Sass {
if (color.type() != Node::numeric_color) throw_eval_error("argument to blue must be a color", color.path(), color.line()); if (color.type() != Node::numeric_color) throw_eval_error("argument to blue must be a color", color.path(), color.line());
return color[2]; return color[2];
} }
Node mix_impl(Node color1, Node color2, double weight, Node_Factory& new_Node) { Node mix_impl(Node color1, Node color2, double weight, Node_Factory& new_Node) {
if (!(color1.type() == Node::numeric_color && color2.type() == Node::numeric_color)) { if (!(color1.type() == Node::numeric_color && color2.type() == Node::numeric_color)) {
throw_eval_error("first two arguments to mix must be colors", color1.path(), color1.line()); throw_eval_error("first two arguments to mix must be colors", color1.path(), color1.line());
...@@ -89,10 +89,10 @@ namespace Sass { ...@@ -89,10 +89,10 @@ namespace Sass {
double p = weight/100; double p = weight/100;
double w = 2*p - 1; double w = 2*p - 1;
double a = color1[3].numeric_value() - color2[3].numeric_value(); double a = color1[3].numeric_value() - color2[3].numeric_value();
double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0; double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0;
double w2 = 1 - w1; double w2 = 1 - w1;
Node mixed(new_Node(Node::numeric_color, color1.path(), color1.line(), 4)); Node mixed(new_Node(Node::numeric_color, color1.path(), color1.line(), 4));
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
mixed << new_Node(mixed.path(), mixed.line(), mixed << new_Node(mixed.path(), mixed.line(),
...@@ -102,13 +102,13 @@ namespace Sass { ...@@ -102,13 +102,13 @@ namespace Sass {
mixed << new_Node(mixed.path(), mixed.line(), alpha); mixed << new_Node(mixed.path(), mixed.line(), alpha);
return mixed; return mixed;
} }
Function_Descriptor mix_2_descriptor = Function_Descriptor mix_2_descriptor =
{ "mix", "$color1", "$color2", 0 }; { "mix", "$color1", "$color2", 0 };
Node mix_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node mix_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return mix_impl(bindings[parameters[0]], bindings[parameters[1]], 50, new_Node); return mix_impl(bindings[parameters[0]], bindings[parameters[1]], 50, new_Node);
} }
Function_Descriptor mix_3_descriptor = Function_Descriptor mix_3_descriptor =
{ "mix", "$color1", "$color2", "$weight", 0 }; { "mix", "$color1", "$color2", "$weight", 0 };
Node mix_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node mix_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -121,9 +121,9 @@ namespace Sass { ...@@ -121,9 +121,9 @@ namespace Sass {
percentage.numeric_value(), percentage.numeric_value(),
new_Node); new_Node);
} }
// HSL Functions /////////////////////////////////////////////////////// // HSL Functions ///////////////////////////////////////////////////////
double h_to_rgb(double m1, double m2, double h) { double h_to_rgb(double m1, double m2, double h) {
if (h < 0) ++h; if (h < 0) ++h;
if (h > 1) --h; if (h > 1) --h;
...@@ -145,7 +145,7 @@ namespace Sass { ...@@ -145,7 +145,7 @@ namespace Sass {
double r = h_to_rgb(m1, m2, h+1.0/3.0) * 255.0; double r = h_to_rgb(m1, m2, h+1.0/3.0) * 255.0;
double g = h_to_rgb(m1, m2, h) * 255.0; double g = h_to_rgb(m1, m2, h) * 255.0;
double b = h_to_rgb(m1, m2, h-1.0/3.0) * 255.0; double b = h_to_rgb(m1, m2, h-1.0/3.0) * 255.0;
return new_Node("", 0, r, g, b, a); return new_Node("", 0, r, g, b, a);
} }
...@@ -157,7 +157,7 @@ namespace Sass { ...@@ -157,7 +157,7 @@ namespace Sass {
bindings[parameters[2]].is_numeric() && bindings[parameters[2]].is_numeric() &&
bindings[parameters[3]].is_numeric())) { bindings[parameters[3]].is_numeric())) {
throw_eval_error("arguments to hsla must be numeric", bindings[parameters[0]].path(), bindings[parameters[0]].line()); throw_eval_error("arguments to hsla must be numeric", bindings[parameters[0]].path(), bindings[parameters[0]].line());
} }
double h = bindings[parameters[0]].numeric_value(); double h = bindings[parameters[0]].numeric_value();
double s = bindings[parameters[1]].numeric_value(); double s = bindings[parameters[1]].numeric_value();
double l = bindings[parameters[2]].numeric_value(); double l = bindings[parameters[2]].numeric_value();
...@@ -166,7 +166,7 @@ namespace Sass { ...@@ -166,7 +166,7 @@ namespace Sass {
// color.line() = bindings[parameters[0]].line(); // color.line() = bindings[parameters[0]].line();
return color; return color;
} }
Function_Descriptor hsl_descriptor = Function_Descriptor hsl_descriptor =
{ "hsl", "$hue", "$saturation", "$lightness", 0 }; { "hsl", "$hue", "$saturation", "$lightness", 0 };
Node hsl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node hsl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -174,7 +174,7 @@ namespace Sass { ...@@ -174,7 +174,7 @@ namespace Sass {
bindings[parameters[1]].is_numeric() && bindings[parameters[1]].is_numeric() &&
bindings[parameters[2]].is_numeric())) { bindings[parameters[2]].is_numeric())) {
throw_eval_error("arguments to hsl must be numeric", bindings[parameters[0]].path(), bindings[parameters[0]].line()); throw_eval_error("arguments to hsl must be numeric", bindings[parameters[0]].path(), bindings[parameters[0]].line());
} }
double h = bindings[parameters[0]].numeric_value(); double h = bindings[parameters[0]].numeric_value();
double s = bindings[parameters[1]].numeric_value(); double s = bindings[parameters[1]].numeric_value();
double l = bindings[parameters[2]].numeric_value(); double l = bindings[parameters[2]].numeric_value();
...@@ -182,7 +182,7 @@ namespace Sass { ...@@ -182,7 +182,7 @@ namespace Sass {
// color.line() = bindings[parameters[0]].line(); // color.line() = bindings[parameters[0]].line();
return color; return color;
} }
Function_Descriptor invert_descriptor = Function_Descriptor invert_descriptor =
{ "invert", "$color", 0 }; { "invert", "$color", 0 };
Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -194,9 +194,9 @@ namespace Sass { ...@@ -194,9 +194,9 @@ namespace Sass {
255 - orig[2].numeric_value(), 255 - orig[2].numeric_value(),
orig[3].numeric_value()); orig[3].numeric_value());
} }
// Opacity Functions /////////////////////////////////////////////////// // Opacity Functions ///////////////////////////////////////////////////
Function_Descriptor alpha_descriptor = Function_Descriptor alpha_descriptor =
{ "alpha", "$color", 0 }; { "alpha", "$color", 0 };
Function_Descriptor opacity_descriptor = Function_Descriptor opacity_descriptor =
...@@ -206,7 +206,7 @@ namespace Sass { ...@@ -206,7 +206,7 @@ namespace Sass {
if (color.type() != Node::numeric_color) throw_eval_error("argument to alpha must be a color", color.path(), color.line()); if (color.type() != Node::numeric_color) throw_eval_error("argument to alpha must be a color", color.path(), color.line());
return color[3]; return color[3];
} }
Function_Descriptor opacify_descriptor = Function_Descriptor opacify_descriptor =
{ "opacify", "$color", "$amount", 0 }; { "opacify", "$color", "$amount", 0 };
Function_Descriptor fade_in_descriptor = Function_Descriptor fade_in_descriptor =
...@@ -226,7 +226,7 @@ namespace Sass { ...@@ -226,7 +226,7 @@ namespace Sass {
return new_Node(color.path(), color.line(), return new_Node(color.path(), color.line(),
color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha); color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha);
} }
Function_Descriptor transparentize_descriptor = Function_Descriptor transparentize_descriptor =
{ "transparentize", "$color", "$amount", 0 }; { "transparentize", "$color", "$amount", 0 };
Function_Descriptor fade_out_descriptor = Function_Descriptor fade_out_descriptor =
...@@ -246,9 +246,9 @@ namespace Sass { ...@@ -246,9 +246,9 @@ namespace Sass {
return new_Node(color.path(), color.line(), return new_Node(color.path(), color.line(),
color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha); color[0].numeric_value(), color[1].numeric_value(), color[2].numeric_value(), alpha);
} }
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
Function_Descriptor unquote_descriptor = Function_Descriptor unquote_descriptor =
{ "unquote", "$string", 0 }; { "unquote", "$string", 0 };
Node unquote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node unquote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -259,7 +259,7 @@ namespace Sass { ...@@ -259,7 +259,7 @@ namespace Sass {
cpy.is_unquoted() = true; cpy.is_unquoted() = true;
return cpy; return cpy;
} }
Function_Descriptor quote_descriptor = Function_Descriptor quote_descriptor =
{ "quote", "$string", 0 }; { "quote", "$string", 0 };
Node quote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node quote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -271,9 +271,9 @@ namespace Sass { ...@@ -271,9 +271,9 @@ namespace Sass {
cpy.is_unquoted() = false; cpy.is_unquoted() = false;
return cpy; return cpy;
} }
// Number Functions //////////////////////////////////////////////////// // Number Functions ////////////////////////////////////////////////////
Function_Descriptor percentage_descriptor = Function_Descriptor percentage_descriptor =
{ "percentage", "$value", 0 }; { "percentage", "$value", 0 };
Node percentage(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node percentage(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -403,7 +403,7 @@ namespace Sass { ...@@ -403,7 +403,7 @@ namespace Sass {
// unreachable statement // unreachable statement
return Node(); return Node();
} }
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
Function_Descriptor length_descriptor = Function_Descriptor length_descriptor =
...@@ -429,7 +429,7 @@ namespace Sass { ...@@ -429,7 +429,7 @@ namespace Sass {
// unreachable statement // unreachable statement
return Node(); return Node();
} }
Function_Descriptor nth_descriptor = Function_Descriptor nth_descriptor =
{ "nth", "$list", "$n", 0 }; { "nth", "$list", "$n", 0 };
Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -451,7 +451,7 @@ namespace Sass { ...@@ -451,7 +451,7 @@ namespace Sass {
} }
return l[n_prim - 1]; return l[n_prim - 1];
} }
extern const char separator_kwd[] = "$separator"; extern const char separator_kwd[] = "$separator";
Node join_impl(const vector<Token>& parameters, map<Token, Node>& bindings, bool has_sep, Node_Factory& new_Node) { Node join_impl(const vector<Token>& parameters, map<Token, Node>& bindings, bool has_sep, Node_Factory& new_Node) {
// if the args aren't lists, turn them into singleton lists // if the args aren't lists, turn them into singleton lists
...@@ -490,27 +490,27 @@ namespace Sass { ...@@ -490,27 +490,27 @@ namespace Sass {
if (l2.type() != Node::nil) lr += l2; if (l2.type() != Node::nil) lr += l2;
return lr; return lr;
} }
Function_Descriptor join_2_descriptor = Function_Descriptor join_2_descriptor =
{ "join", "$list1", "$list2", 0 }; { "join", "$list1", "$list2", 0 };
Node join_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node join_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return join_impl(parameters, bindings, false, new_Node); return join_impl(parameters, bindings, false, new_Node);
} }
Function_Descriptor join_3_descriptor = Function_Descriptor join_3_descriptor =
{ "join", "$list1", "$list2", "$separator", 0 }; { "join", "$list1", "$list2", "$separator", 0 };
Node join_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node join_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return join_impl(parameters, bindings, true, new_Node); return join_impl(parameters, bindings, true, new_Node);
} }
// Introspection Functions ///////////////////////////////////////////// // Introspection Functions /////////////////////////////////////////////
extern const char number_name[] = "number"; extern const char number_name[] = "number";
extern const char string_name[] = "string"; extern const char string_name[] = "string";
extern const char bool_name[] = "bool"; extern const char bool_name[] = "bool";
extern const char color_name[] = "color"; extern const char color_name[] = "color";
extern const char list_name[] = "list"; extern const char list_name[] = "list";
Function_Descriptor type_of_descriptor = Function_Descriptor type_of_descriptor =
{ "type-of", "$value", 0 }; { "type-of", "$value", 0 };
Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -546,10 +546,10 @@ namespace Sass { ...@@ -546,10 +546,10 @@ namespace Sass {
type.is_unquoted() = true; type.is_unquoted() = true;
return type; return type;
} }
extern const char empty_str[] = ""; extern const char empty_str[] = "";
extern const char percent_str[] = "%"; extern const char percent_str[] = "%";
Function_Descriptor unit_descriptor = Function_Descriptor unit_descriptor =
{ "unit", "$number", 0 }; { "unit", "$number", 0 };
Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -598,7 +598,7 @@ namespace Sass { ...@@ -598,7 +598,7 @@ namespace Sass {
// unreachable statement // unreachable statement
return Node(); return Node();
} }
Function_Descriptor comparable_descriptor = Function_Descriptor comparable_descriptor =
{ "comparable", "$number_1", "$number_2", 0 }; { "comparable", "$number_1", "$number_2", 0 };
Node comparable(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node comparable(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
...@@ -632,7 +632,7 @@ namespace Sass { ...@@ -632,7 +632,7 @@ namespace Sass {
// default to false if we missed anything // default to false if we missed anything
return new_Node(Node::boolean, n1.path(), n1.line(), false); return new_Node(Node::boolean, n1.path(), n1.line(), false);
} }
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
Function_Descriptor not_descriptor = Function_Descriptor not_descriptor =
{ "not", "value", 0 }; { "not", "value", 0 };
...@@ -648,3 +648,4 @@ namespace Sass { ...@@ -648,3 +648,4 @@ namespace Sass {
} }
} }
...@@ -7,20 +7,20 @@ ...@@ -7,20 +7,20 @@
namespace Sass { namespace Sass {
using std::map; using std::map;
typedef Node (*Implementation)(const vector<Token>&, map<Token, Node>&, Node_Factory& new_Node); typedef Node (*Implementation)(const vector<Token>&, map<Token, Node>&, Node_Factory& new_Node);
typedef const char* str; typedef const char* str;
typedef str Function_Descriptor[]; typedef str Function_Descriptor[];
struct Function { struct Function {
string name; string name;
vector<Token> parameters; vector<Token> parameters;
Implementation implementation; Implementation implementation;
Function() Function()
{ /* TO DO: set up the generic callback here */ } { /* TO DO: set up the generic callback here */ }
Function(Function_Descriptor d, Implementation ip) Function(Function_Descriptor d, Implementation ip)
: name(d[0]), : name(d[0]),
parameters(vector<Token>()), parameters(vector<Token>()),
...@@ -28,7 +28,7 @@ namespace Sass { ...@@ -28,7 +28,7 @@ namespace Sass {
{ {
size_t len = 0; size_t len = 0;
while (d[len+1]) ++len; while (d[len+1]) ++len;
parameters.reserve(len); parameters.reserve(len);
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
const char* p = d[i+1]; const char* p = d[i+1];
...@@ -36,12 +36,12 @@ namespace Sass { ...@@ -36,12 +36,12 @@ namespace Sass {
parameters.push_back(name); parameters.push_back(name);
} }
} }
Node operator()(map<Token, Node>& bindings, Node_Factory& new_Node) const Node operator()(map<Token, Node>& bindings, Node_Factory& new_Node) const
{ return implementation(parameters, bindings, new_Node); } { return implementation(parameters, bindings, new_Node); }
}; };
namespace Functions { namespace Functions {
// RGB Functions /////////////////////////////////////////////////////// // RGB Functions ///////////////////////////////////////////////////////
...@@ -51,58 +51,58 @@ namespace Sass { ...@@ -51,58 +51,58 @@ namespace Sass {
extern Function_Descriptor rgba_4_descriptor; extern Function_Descriptor rgba_4_descriptor;
Node rgba_4(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node rgba_4(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor rgba_2_descriptor; extern Function_Descriptor rgba_2_descriptor;
Node rgba_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node rgba_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor red_descriptor; extern Function_Descriptor red_descriptor;
Node red(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node red(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor green_descriptor; extern Function_Descriptor green_descriptor;
Node green(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node green(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor blue_descriptor; extern Function_Descriptor blue_descriptor;
Node blue(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node blue(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor mix_2_descriptor; extern Function_Descriptor mix_2_descriptor;
Node mix_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node mix_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor mix_3_descriptor; extern Function_Descriptor mix_3_descriptor;
Node mix_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node mix_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// HSL Functions /////////////////////////////////////////////////////// // HSL Functions ///////////////////////////////////////////////////////
extern Function_Descriptor hsla_descriptor; extern Function_Descriptor hsla_descriptor;
Node hsla(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node hsla(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor hsl_descriptor; extern Function_Descriptor hsl_descriptor;
Node hsl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node hsl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor invert_descriptor; extern Function_Descriptor invert_descriptor;
Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node invert(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// Opacity Functions /////////////////////////////////////////////////// // Opacity Functions ///////////////////////////////////////////////////
extern Function_Descriptor alpha_descriptor; extern Function_Descriptor alpha_descriptor;
extern Function_Descriptor opacity_descriptor; extern Function_Descriptor opacity_descriptor;
Node alpha(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node alpha(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor opacify_descriptor; extern Function_Descriptor opacify_descriptor;
extern Function_Descriptor fade_in_descriptor; extern Function_Descriptor fade_in_descriptor;
Node opacify(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node opacify(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor transparentize_descriptor; extern Function_Descriptor transparentize_descriptor;
extern Function_Descriptor fade_out_descriptor; extern Function_Descriptor fade_out_descriptor;
Node transparentize(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node transparentize(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
extern Function_Descriptor unquote_descriptor; extern Function_Descriptor unquote_descriptor;
Node unquote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unquote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor quote_descriptor; extern Function_Descriptor quote_descriptor;
Node quote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node quote(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// Number Functions //////////////////////////////////////////////////// // Number Functions ////////////////////////////////////////////////////
extern Function_Descriptor percentage_descriptor; extern Function_Descriptor percentage_descriptor;
...@@ -117,42 +117,43 @@ namespace Sass { ...@@ -117,42 +117,43 @@ namespace Sass {
extern Function_Descriptor floor_descriptor; extern Function_Descriptor floor_descriptor;
Node floor(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node floor(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor abs_descriptor; extern Function_Descriptor abs_descriptor;
Node abs(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node abs(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
extern Function_Descriptor length_descriptor; extern Function_Descriptor length_descriptor;
Node length(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node length(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor nth_descriptor; extern Function_Descriptor nth_descriptor;
Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node nth(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor join_2_descriptor; extern Function_Descriptor join_2_descriptor;
Node join_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node join_2(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor join_3_descriptor; extern Function_Descriptor join_3_descriptor;
Node join_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node join_3(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// Introspection Functions ///////////////////////////////////////////// // Introspection Functions /////////////////////////////////////////////
extern Function_Descriptor type_of_descriptor; extern Function_Descriptor type_of_descriptor;
Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node type_of(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor unit_descriptor; extern Function_Descriptor unit_descriptor;
Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unit(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor unitless_descriptor; extern Function_Descriptor unitless_descriptor;
Node unitless(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unitless(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor comparable_descriptor; extern Function_Descriptor comparable_descriptor;
Node comparable(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node comparable(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
extern Function_Descriptor not_descriptor; extern Function_Descriptor not_descriptor;
Node not_impl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node not_impl(const vector<Token>& parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
} }
} }
...@@ -51,7 +51,7 @@ namespace Sass { ...@@ -51,7 +51,7 @@ namespace Sass {
} }
return true; return true;
} break; } break;
case variable: case variable:
case identifier: case identifier:
case uri: case uri:
...@@ -62,12 +62,12 @@ namespace Sass { ...@@ -62,12 +62,12 @@ namespace Sass {
case string_constant: { case string_constant: {
return token().unquote() == rhs.token().unquote(); return token().unquote() == rhs.token().unquote();
} break; } break;
case number: case number:
case numeric_percentage: { case numeric_percentage: {
return numeric_value() == rhs.numeric_value(); return numeric_value() == rhs.numeric_value();
} break; } break;
case numeric_dimension: { case numeric_dimension: {
if (unit() == rhs.unit()) { if (unit() == rhs.unit()) {
return numeric_value() == rhs.numeric_value(); return numeric_value() == rhs.numeric_value();
...@@ -76,26 +76,26 @@ namespace Sass { ...@@ -76,26 +76,26 @@ namespace Sass {
return false; return false;
} }
} break; } break;
case boolean: { case boolean: {
return boolean_value() == rhs.boolean_value(); return boolean_value() == rhs.boolean_value();
} break; } break;
default: { default: {
return true; return true;
} break; } break;
} }
return false; return false;
} }
bool Node::operator!=(Node rhs) const bool Node::operator!=(Node rhs) const
{ return !(*this == rhs); } { return !(*this == rhs); }
bool Node::operator<(Node rhs) const bool Node::operator<(Node rhs) const
{ {
Type lhs_type = type(); Type lhs_type = type();
Type rhs_type = rhs.type(); Type rhs_type = rhs.type();
// comparing atomic numbers // comparing atomic numbers
if ((lhs_type == number && rhs_type == number) || if ((lhs_type == number && rhs_type == number) ||
(lhs_type == numeric_percentage && rhs_type == numeric_percentage)) { (lhs_type == numeric_percentage && rhs_type == numeric_percentage)) {
...@@ -158,13 +158,13 @@ namespace Sass { ...@@ -158,13 +158,13 @@ namespace Sass {
throw Error(Error::evaluation, path(), line(), "incomparable types"); throw Error(Error::evaluation, path(), line(), "incomparable types");
} }
} }
bool Node::operator<=(Node rhs) const bool Node::operator<=(Node rhs) const
{ return *this < rhs || *this == rhs; } { return *this < rhs || *this == rhs; }
bool Node::operator>(Node rhs) const bool Node::operator>(Node rhs) const
{ return !(*this <= rhs); } { return !(*this <= rhs); }
bool Node::operator>=(Node rhs) const bool Node::operator>=(Node rhs) const
{ return !(*this < rhs); } { return !(*this < rhs); }
...@@ -172,7 +172,7 @@ namespace Sass { ...@@ -172,7 +172,7 @@ namespace Sass {
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Token method implementations // Token method implementations
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
string Token::unquote() const string Token::unquote() const
{ {
string result; string result;
...@@ -210,7 +210,7 @@ namespace Sass { ...@@ -210,7 +210,7 @@ namespace Sass {
return result; return result;
} }
} }
void Token::unquote_to_stream(std::stringstream& buf) const void Token::unquote_to_stream(std::stringstream& buf) const
{ {
const char* p = begin; const char* p = begin;
...@@ -247,7 +247,7 @@ namespace Sass { ...@@ -247,7 +247,7 @@ namespace Sass {
return; return;
} }
} }
bool Token::operator<(const Token& rhs) const bool Token::operator<(const Token& rhs) const
{ {
const char* first1 = begin; const char* first1 = begin;
...@@ -262,15 +262,15 @@ namespace Sass { ...@@ -262,15 +262,15 @@ namespace Sass {
} }
return (first2 != last2); return (first2 != last2);
} }
bool Token::operator==(const Token& rhs) const bool Token::operator==(const Token& rhs) const
{ {
if (length() != rhs.length()) return false; if (length() != rhs.length()) return false;
if ((begin[0] == '"' || begin[0] == '\'') && if ((begin[0] == '"' || begin[0] == '\'') &&
(rhs.begin[0] == '"' || rhs.begin[0] == '\'')) (rhs.begin[0] == '"' || rhs.begin[0] == '\''))
{ return unquote() == rhs.unquote(); } { return unquote() == rhs.unquote(); }
const char* p = begin; const char* p = begin;
const char* q = rhs.begin; const char* q = rhs.begin;
for (; p < end; ++p, ++q) if (*p != *q) return false; for (; p < end; ++p, ++q) if (*p != *q) return false;
...@@ -298,7 +298,7 @@ namespace Sass { ...@@ -298,7 +298,7 @@ namespace Sass {
// if you reach this point, you've got a logic error somewhere // if you reach this point, you've got a logic error somewhere
return 0; return 0;
} }
extern const char percent_str[] = "%"; extern const char percent_str[] = "%";
extern const char empty_str[] = ""; extern const char empty_str[] = "";
Token Node_Impl::unit() Token Node_Impl::unit()
...@@ -308,14 +308,15 @@ namespace Sass { ...@@ -308,14 +308,15 @@ namespace Sass {
case Node::numeric_percentage: { case Node::numeric_percentage: {
return Token::make(percent_str); return Token::make(percent_str);
} break; } break;
case Node::numeric_dimension: { case Node::numeric_dimension: {
return value.dimension.unit; return value.dimension.unit;
} break; } break;
default: break; default: break;
} }
return Token::make(empty_str); return Token::make(empty_str);
} }
} }
\ No newline at end of file
...@@ -46,7 +46,7 @@ namespace Sass { ...@@ -46,7 +46,7 @@ namespace Sass {
string unquote() const; string unquote() const;
void unquote_to_stream(std::stringstream& buf) const; void unquote_to_stream(std::stringstream& buf) const;
operator bool() operator bool()
{ return begin && end && begin >= end; } { return begin && end && begin >= end; }
...@@ -58,7 +58,7 @@ namespace Sass { ...@@ -58,7 +58,7 @@ namespace Sass {
double numeric; double numeric;
Token unit; Token unit;
}; };
struct Node_Impl; struct Node_Impl;
class Node { class Node {
...@@ -199,7 +199,7 @@ namespace Sass { ...@@ -199,7 +199,7 @@ namespace Sass {
bool is_null_ptr() const; bool is_null_ptr() const;
void flatten(); void flatten();
bool operator==(Node rhs) const; bool operator==(Node rhs) const;
bool operator!=(Node rhs) const; bool operator!=(Node rhs) const;
bool operator<(Node rhs) const; bool operator<(Node rhs) const;
...@@ -214,7 +214,7 @@ namespace Sass { ...@@ -214,7 +214,7 @@ namespace Sass {
void emit_expanded_css(stringstream& buf, const string& prefix); void emit_expanded_css(stringstream& buf, const string& prefix);
}; };
struct Node_Impl { struct Node_Impl {
union value_t { union value_t {
bool boolean; bool boolean;
...@@ -255,13 +255,13 @@ namespace Sass { ...@@ -255,13 +255,13 @@ namespace Sass {
should_eval(false), should_eval(false),
is_unquoted(false) is_unquoted(false)
{ } { }
bool is_numeric() bool is_numeric()
{ return type >= Node::number && type <= Node::numeric_dimension; } { return type >= Node::number && type <= Node::numeric_dimension; }
size_t size() size_t size()
{ return children.size(); } { return children.size(); }
bool empty() bool empty()
{ return children.empty(); } { return children.empty(); }
...@@ -321,7 +321,7 @@ namespace Sass { ...@@ -321,7 +321,7 @@ namespace Sass {
bool& boolean_value() bool& boolean_value()
{ return value.boolean; } { return value.boolean; }
double numeric_value(); double numeric_value();
Token unit(); Token unit();
}; };
...@@ -332,11 +332,11 @@ namespace Sass { ...@@ -332,11 +332,11 @@ namespace Sass {
// -- in the header file so they can easily be declared inline // -- in the header file so they can easily be declared inline
// -- outside of their class definition to get the right declaration order // -- outside of their class definition to get the right declaration order
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
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 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; }
...@@ -346,12 +346,12 @@ namespace Sass { ...@@ -346,12 +346,12 @@ namespace Sass {
inline bool& Node::should_eval() const { return ip_->should_eval; } inline bool& Node::should_eval() const { return ip_->should_eval; }
inline bool& Node::is_unquoted() const { return ip_->is_unquoted; } inline bool& Node::is_unquoted() const { return ip_->is_unquoted; }
inline bool Node::is_numeric() const { return ip_->is_numeric(); } inline bool Node::is_numeric() const { return ip_->is_numeric(); }
inline string& Node::path() const { return ip_->path; } inline string& Node::path() const { return ip_->path; }
inline size_t Node::line() const { return ip_->line; } inline size_t Node::line() const { return ip_->line; }
inline size_t Node::size() const { return ip_->size(); } inline size_t Node::size() const { return ip_->size(); }
inline bool Node::empty() const { return ip_->empty(); } inline bool Node::empty() const { return ip_->empty(); }
inline Node& Node::at(size_t i) const { return ip_->at(i); } inline Node& Node::at(size_t i) const { return ip_->at(i); }
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); }
...@@ -390,3 +390,4 @@ namespace Sass { ...@@ -390,3 +390,4 @@ namespace Sass {
inline bool Node::is_null_ptr() const { return !ip_; } inline bool Node::is_null_ptr() const { return !ip_; }
} }
...@@ -27,10 +27,10 @@ namespace Sass { ...@@ -27,10 +27,10 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case selector: { case selector: {
string result; string result;
result += at(0).to_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) {
result += " "; result += " ";
...@@ -38,11 +38,11 @@ namespace Sass { ...@@ -38,11 +38,11 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case selector_combinator: { case selector_combinator: {
return token().to_string(); return token().to_string();
} break; } break;
case simple_selector_sequence: { case simple_selector_sequence: {
string result; string result;
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
...@@ -50,12 +50,12 @@ namespace Sass { ...@@ -50,12 +50,12 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case pseudo: case pseudo:
case simple_selector: { case simple_selector: {
return token().to_string(); return token().to_string();
} break; } break;
case pseudo_negation: { case pseudo_negation: {
string result; string result;
result += at(0).to_string(); result += at(0).to_string();
...@@ -63,7 +63,7 @@ namespace Sass { ...@@ -63,7 +63,7 @@ namespace Sass {
result += ')'; result += ')';
return result; return result;
} break; } break;
case functional_pseudo: { case functional_pseudo: {
string result; string result;
result += at(0).to_string(); result += at(0).to_string();
...@@ -73,7 +73,7 @@ namespace Sass { ...@@ -73,7 +73,7 @@ namespace Sass {
result += ')'; result += ')';
return result; return result;
} break; } break;
case attribute_selector: { case attribute_selector: {
string result; string result;
result += "["; result += "[";
...@@ -93,7 +93,7 @@ namespace Sass { ...@@ -93,7 +93,7 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case space_list: { case space_list: {
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) {
...@@ -103,7 +103,7 @@ namespace Sass { ...@@ -103,7 +103,7 @@ namespace Sass {
} }
return result; return result;
} break; } break;
case expression: case expression:
case term: { case term: {
string result(at(0).to_string()); string result(at(0).to_string());
...@@ -116,16 +116,16 @@ namespace Sass { ...@@ -116,16 +116,16 @@ namespace Sass {
} }
return result; return result;
} break; } break;
//edge case //edge case
case sub: { case sub: {
return "-"; return "-";
} break; } break;
case div: { case div: {
return "/"; return "/";
} break; } break;
case css_import: { case css_import: {
stringstream ss; stringstream ss;
ss << "@import url("; ss << "@import url(";
...@@ -134,7 +134,7 @@ namespace Sass { ...@@ -134,7 +134,7 @@ namespace Sass {
ss << ")"; ss << ")";
return ss.str(); return ss.str();
} }
case function_call: { case function_call: {
stringstream ss; stringstream ss;
ss << at(0).to_string(); ss << at(0).to_string();
...@@ -143,7 +143,7 @@ namespace Sass { ...@@ -143,7 +143,7 @@ namespace Sass {
ss << ")"; ss << ")";
return ss.str(); return ss.str();
} }
case arguments: { case arguments: {
stringstream ss; stringstream ss;
size_t S = size(); size_t S = size();
...@@ -156,40 +156,40 @@ namespace Sass { ...@@ -156,40 +156,40 @@ namespace Sass {
} }
return ss.str(); return ss.str();
} }
case unary_plus: { case unary_plus: {
stringstream ss; stringstream ss;
ss << "+"; ss << "+";
ss << at(0).to_string(); ss << at(0).to_string();
return ss.str(); return ss.str();
} }
case unary_minus: { case unary_minus: {
stringstream ss; stringstream ss;
ss << "-"; ss << "-";
ss << at(0).to_string(); ss << at(0).to_string();
return ss.str(); return ss.str();
} }
case numeric_percentage: { case numeric_percentage: {
stringstream ss; stringstream ss;
ss << numeric_value(); ss << numeric_value();
ss << '%'; ss << '%';
return ss.str(); return ss.str();
} }
case numeric_dimension: { case numeric_dimension: {
stringstream ss; stringstream ss;
ss << numeric_value() << unit().to_string(); ss << numeric_value() << unit().to_string();
return ss.str(); return ss.str();
} break; } break;
case number: { case number: {
stringstream ss; stringstream ss;
ss << numeric_value(); ss << numeric_value();
return ss.str(); return ss.str();
} break; } break;
case numeric_color: { case numeric_color: {
if (at(3).numeric_value() >= 1.0) if (at(3).numeric_value() >= 1.0)
{ {
...@@ -201,7 +201,7 @@ namespace Sass { ...@@ -201,7 +201,7 @@ namespace Sass {
else if (a >= 0xff && b >= 0xff && c == 0) else if (a >= 0xff && b >= 0xff && c == 0)
{ return "yellow"; } { return "yellow"; }
else if (a == 0 && b >= 0xff && c >= 0xff) else if (a == 0 && b >= 0xff && c >= 0xff)
{ return "aqua"; } { return "aqua"; }
else if (a >= 0xff && b == 0 && c >= 0xff) else if (a >= 0xff && b == 0 && c >= 0xff)
{ return "fuchsia"; } { return "fuchsia"; }
else if (a >= 0xff && b == 0 && c == 0) else if (a >= 0xff && b == 0 && c == 0)
...@@ -236,7 +236,7 @@ namespace Sass { ...@@ -236,7 +236,7 @@ namespace Sass {
return ss.str(); return ss.str();
} }
} break; } break;
case uri: { case uri: {
string result("url("); string result("url(");
result += token().to_string(); result += token().to_string();
...@@ -248,7 +248,7 @@ namespace Sass { ...@@ -248,7 +248,7 @@ namespace Sass {
// ignore it // ignore it
return ""; return "";
} break; } break;
case string_constant: { case string_constant: {
if (is_unquoted()) return token().unquote(); if (is_unquoted()) return token().unquote();
else { else {
...@@ -257,22 +257,22 @@ namespace Sass { ...@@ -257,22 +257,22 @@ namespace Sass {
else return result; else return result;
} }
} break; } break;
case boolean: { case boolean: {
if (boolean_value()) return "true"; if (boolean_value()) return "true";
else return "false"; else return "false";
} break; } break;
case important: { case important: {
return "!important"; return "!important";
} break; } break;
case value_schema: { case value_schema: {
string result; string result;
for (size_t i = 0, S = size(); i < S; ++i) result += at(i).to_string(); for (size_t i = 0, S = size(); i < S; ++i) result += at(i).to_string();
return result; return result;
} break; } break;
case string_schema: { case string_schema: {
string result; string result;
for (size_t i = 0, S = size(); i < S; ++i) { for (size_t i = 0, S = size(); i < S; ++i) {
...@@ -286,7 +286,7 @@ namespace Sass { ...@@ -286,7 +286,7 @@ namespace Sass {
} }
return result; return result;
} break; } break;
default: { default: {
// return content.token.to_string(); // return content.token.to_string();
if (!has_children()) return token().to_string(); if (!has_children()) return token().to_string();
...@@ -338,14 +338,14 @@ namespace Sass { ...@@ -338,14 +338,14 @@ namespace Sass {
case propset: { case propset: {
emit_propset(buf, depth, ""); emit_propset(buf, depth, "");
} break; } break;
case rule: { case rule: {
buf << endl << string(2*depth, ' '); buf << endl << string(2*depth, ' ');
at(0).emit_nested_css(buf, depth); // property at(0).emit_nested_css(buf, depth); // property
at(1).emit_nested_css(buf, depth); // values at(1).emit_nested_css(buf, depth); // values
buf << ";"; buf << ";";
} break; } break;
case css_import: { case css_import: {
buf << string(2*depth, ' '); buf << string(2*depth, ' ');
buf << to_string(); buf << to_string();
...@@ -373,7 +373,7 @@ namespace Sass { ...@@ -373,7 +373,7 @@ namespace Sass {
} break; } break;
} }
} }
void Node::emit_propset(stringstream& buf, size_t depth, const string& prefix) void Node::emit_propset(stringstream& buf, size_t depth, const string& prefix)
{ {
string new_prefix(prefix); string new_prefix(prefix);
...@@ -405,4 +405,5 @@ namespace Sass { ...@@ -405,4 +405,5 @@ namespace Sass {
void Node::echo(stringstream& buf, size_t depth) { } void Node::echo(stringstream& buf, size_t depth) { }
void Node::emit_expanded_css(stringstream& buf, const string& prefix) { } void Node::emit_expanded_css(stringstream& buf, const string& prefix) { }
} }
\ No newline at end of file
#include "node_factory.hpp" #include "node_factory.hpp"
namespace Sass { namespace Sass {
Node_Impl* Node_Factory::alloc_Node_Impl(Node::Type type, string path, size_t line) Node_Impl* Node_Factory::alloc_Node_Impl(Node::Type type, string path, size_t line)
{ {
Node_Impl* ip = new Node_Impl(); Node_Impl* ip = new Node_Impl();
...@@ -69,7 +69,7 @@ namespace Sass { ...@@ -69,7 +69,7 @@ namespace Sass {
ip->value.dimension.unit = t; ip->value.dimension.unit = t;
return Node(ip); return Node(ip);
} }
// for making nodes representing rgba color quads // for making nodes representing rgba color quads
Node Node_Factory::operator()(string path, size_t line, double r, double g, double b, double a) Node Node_Factory::operator()(string path, size_t line, double r, double g, double b, double a)
{ {
...@@ -84,4 +84,5 @@ namespace Sass { ...@@ -84,4 +84,5 @@ namespace Sass {
void Node_Factory::free() void Node_Factory::free()
{ for (size_t i = 0, S = pool_.size(); i < S; ++i) delete pool_[i]; } { for (size_t i = 0, S = pool_.size(); i < S; ++i) delete pool_[i]; }
} }
\ No newline at end of file
...@@ -9,7 +9,7 @@ namespace Sass { ...@@ -9,7 +9,7 @@ namespace Sass {
struct Token; struct Token;
struct Node_Impl; struct Node_Impl;
class Node_Factory { class Node_Factory {
vector<Node_Impl*> pool_; vector<Node_Impl*> pool_;
Node_Impl* alloc_Node_Impl(Node::Type type, string file, size_t line); Node_Impl* alloc_Node_Impl(Node::Type type, string file, size_t line);
...@@ -33,5 +33,6 @@ namespace Sass { ...@@ -33,5 +33,6 @@ namespace Sass {
void free(); void free();
}; };
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Sass { namespace Sass {
namespace Prelexer { namespace Prelexer {
// Matches zero characters (always succeeds without consuming input). // Matches zero characters (always succeeds without consuming input).
const char* epsilon(char *src) { const char* epsilon(char *src) {
return src; return src;
...@@ -12,10 +12,10 @@ namespace Sass { ...@@ -12,10 +12,10 @@ namespace Sass {
const char* empty(char *src) { const char* empty(char *src) {
return *src ? 0 : src; return *src ? 0 : src;
} }
// Match any single character. // Match any single character.
const char* any_char(const char* src) { return *src ? src++ : src; } const char* any_char(const char* src) { return *src ? src++ : src; }
// Match a single character satisfying the ctype predicates. // Match a single character satisfying the ctype predicates.
const char* space(const char* src) { return std::isspace(*src) ? src+1 : 0; } const char* space(const char* src) { return std::isspace(*src) ? src+1 : 0; }
const char* alpha(const char* src) { return std::isalpha(*src) ? src+1 : 0; } const char* alpha(const char* src) { return std::isalpha(*src) ? src+1 : 0; }
...@@ -30,7 +30,7 @@ namespace Sass { ...@@ -30,7 +30,7 @@ namespace Sass {
const char* xdigits(const char* src) { return one_plus<xdigit>(src); } const char* xdigits(const char* src) { return one_plus<xdigit>(src); }
const char* alnums(const char* src) { return one_plus<alnum>(src); } const char* alnums(const char* src) { return one_plus<alnum>(src); }
const char* puncts(const char* src) { return one_plus<punct>(src); } const char* puncts(const char* src) { return one_plus<punct>(src); }
// Match a line comment. // Match a line comment.
extern const char slash_slash[] = "//"; extern const char slash_slash[] = "//";
const char* line_comment(const char* src) { return to_endl<slash_slash>(src); } const char* line_comment(const char* src) { return to_endl<slash_slash>(src); }
...@@ -60,7 +60,7 @@ namespace Sass { ...@@ -60,7 +60,7 @@ namespace Sass {
const char* interpolant(const char* src) { const char* interpolant(const char* src) {
return delimited_by<hash_lbrace, rbrace, false>(src); return delimited_by<hash_lbrace, rbrace, false>(src);
} }
// Whitespace handling. // Whitespace handling.
const char* optional_spaces(const char* src) { return optional<spaces>(src); } const char* optional_spaces(const char* src) { return optional<spaces>(src); }
const char* optional_comment(const char* src) { return optional<comment>(src); } const char* optional_comment(const char* src) { return optional<comment>(src); }
...@@ -70,7 +70,7 @@ namespace Sass { ...@@ -70,7 +70,7 @@ namespace Sass {
const char* no_spaces(const char* src) { const char* no_spaces(const char* src) {
return negate< spaces >(src); return negate< spaces >(src);
} }
// Match CSS identifiers. // Match CSS identifiers.
const char* identifier(const char* src) { const char* identifier(const char* src) {
return sequence< optional< exactly<'-'> >, return sequence< optional< exactly<'-'> >,
...@@ -79,8 +79,8 @@ namespace Sass { ...@@ -79,8 +79,8 @@ namespace Sass {
exactly<'-'>, exactly<'-'>,
exactly<'_'> > > >(src); exactly<'_'> > > >(src);
} }
// Match interpolant schemas // Match interpolant schemas
const char* identifier_schema(const char* src) { const char* identifier_schema(const char* src) {
// follows this pattern: (x*ix*)+ // follows this pattern: (x*ix*)+
...@@ -94,7 +94,7 @@ namespace Sass { ...@@ -94,7 +94,7 @@ namespace Sass {
interpolant, interpolant,
zero_plus< alternatives< identifier, percentage, dimension, hex, number, string_constant > > > >(src); zero_plus< alternatives< identifier, percentage, dimension, hex, number, string_constant > > > >(src);
} }
// Match CSS '@' keywords. // Match CSS '@' keywords.
const char* at_keyword(const char* src) { const char* at_keyword(const char* src) {
return sequence<exactly<'@'>, identifier>(src); return sequence<exactly<'@'>, identifier>(src);
...@@ -156,7 +156,7 @@ namespace Sass { ...@@ -156,7 +156,7 @@ namespace Sass {
const char* while_directive(const char* src) { const char* while_directive(const char* src) {
return exactly<while_kwd>(src); return exactly<while_kwd>(src);
} }
const char* name(const char* src) { const char* name(const char* src) {
return one_plus< alternatives< alnum, return one_plus< alternatives< alnum,
exactly<'-'>, exactly<'-'>,
...@@ -305,12 +305,12 @@ namespace Sass { ...@@ -305,12 +305,12 @@ namespace Sass {
const char* ancestor_of(const char* src) { const char* ancestor_of(const char* src) {
return sequence< spaces, negate< exactly<'{'> > >(src); return sequence< spaces, negate< exactly<'{'> > >(src);
} }
// Match SCSS variable names. // Match SCSS variable names.
const char* variable(const char* src) { const char* variable(const char* src) {
return sequence<exactly<'$'>, name>(src); return sequence<exactly<'$'>, name>(src);
} }
// Match Sass boolean keywords. // Match Sass boolean keywords.
extern const char and_chars[] = "and"; extern const char and_chars[] = "and";
extern const char or_chars[] = "or"; extern const char or_chars[] = "or";
...@@ -357,7 +357,7 @@ namespace Sass { ...@@ -357,7 +357,7 @@ namespace Sass {
const char* lte_op(const char* src) { const char* lte_op(const char* src) {
return exactly<lte_chars>(src); return exactly<lte_chars>(src);
} }
// Path matching functions. // Path matching functions.
const char* folder(const char* src) { const char* folder(const char* src) {
return sequence< zero_plus< any_char_except<'/'> >, return sequence< zero_plus< any_char_except<'/'> >,
...@@ -367,4 +367,5 @@ namespace Sass { ...@@ -367,4 +367,5 @@ namespace Sass {
return zero_plus< folder >(src); return zero_plus< folder >(src);
} }
} }
} }
\ No newline at end of file
...@@ -11,7 +11,7 @@ namespace Sass { ...@@ -11,7 +11,7 @@ namespace Sass {
const char* exactly(const char* src) { const char* exactly(const char* src) {
return *src == pre ? src + 1 : 0; return *src == pre ? src + 1 : 0;
} }
// Match a string constant. // Match a string constant.
template <const char* prefix> template <const char* prefix>
const char* exactly(const char* src) { const char* exactly(const char* src) {
...@@ -49,7 +49,7 @@ namespace Sass { ...@@ -49,7 +49,7 @@ namespace Sass {
while (class_char<char_class>(p)) ++p; while (class_char<char_class>(p)) ++p;
return p == src ? 0 : p; return p == src ? 0 : p;
} }
// Match a sequence of characters up to the next newline. // Match a sequence of characters up to the next newline.
template <const char* prefix> template <const char* prefix>
const char* to_endl(const char* src) { const char* to_endl(const char* src) {
...@@ -57,7 +57,7 @@ namespace Sass { ...@@ -57,7 +57,7 @@ namespace Sass {
while (*src && *src != '\n') ++src; while (*src && *src != '\n') ++src;
return src; return src;
} }
// Match a sequence of characters delimited by the supplied chars. // Match a sequence of characters delimited by the supplied chars.
template <char beg, char end, bool esc> template <char beg, char end, bool esc>
const char* delimited_by(const char* src) { const char* delimited_by(const char* src) {
...@@ -71,7 +71,7 @@ namespace Sass { ...@@ -71,7 +71,7 @@ namespace Sass {
src = stop ? stop : src + 1; src = stop ? stop : src + 1;
} }
} }
// Match a sequence of characters delimited by the supplied strings. // Match a sequence of characters delimited by the supplied strings.
template <const char* beg, const char* end, bool esc> template <const char* beg, const char* end, bool esc>
const char* delimited_by(const char* src) { const char* delimited_by(const char* src) {
...@@ -85,7 +85,7 @@ namespace Sass { ...@@ -85,7 +85,7 @@ namespace Sass {
src = stop ? stop : src + 1; src = stop ? stop : src + 1;
} }
} }
// Match any single character. // Match any single character.
const char* any_char(const char* src); const char* any_char(const char* src);
// Match any single character except the supplied one. // Match any single character except the supplied one.
...@@ -93,19 +93,19 @@ namespace Sass { ...@@ -93,19 +93,19 @@ namespace Sass {
const char* any_char_except(const char* src) { const char* any_char_except(const char* src) {
return (*src && *src != c) ? src+1 : 0; return (*src && *src != c) ? src+1 : 0;
} }
// Matches zero characters (always succeeds without consuming input). // Matches zero characters (always succeeds without consuming input).
const char* epsilon(const char*); const char* epsilon(const char*);
// Matches the empty string. // Matches the empty string.
const char* empty(const char*); const char* empty(const char*);
// Succeeds of the supplied matcher fails, and vice versa. // Succeeds of the supplied matcher fails, and vice versa.
template <prelexer mx> template <prelexer mx>
const char* negate(const char* src) { const char* negate(const char* src) {
return mx(src) ? 0 : src; return mx(src) ? 0 : src;
} }
// Tries the matchers in sequence and returns the first match (or none) // Tries the matchers in sequence and returns the first match (or none)
template <prelexer mx1, prelexer mx2> template <prelexer mx1, prelexer mx2>
const char* alternatives(const char* src) { const char* alternatives(const char* src) {
...@@ -113,7 +113,7 @@ namespace Sass { ...@@ -113,7 +113,7 @@ namespace Sass {
(rslt = mx1(src)) || (rslt = mx2(src)); (rslt = mx1(src)) || (rslt = mx2(src));
return rslt; return rslt;
} }
// Same as above, but with 3 arguments. // Same as above, but with 3 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3> template <prelexer mx1, prelexer mx2, prelexer mx3>
const char* alternatives(const char* src) { const char* alternatives(const char* src) {
...@@ -121,7 +121,7 @@ namespace Sass { ...@@ -121,7 +121,7 @@ namespace Sass {
(rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)); (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src));
return rslt; return rslt;
} }
// Same as above, but with 4 arguments. // Same as above, but with 4 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3, prelexer mx4> template <prelexer mx1, prelexer mx2, prelexer mx3, prelexer mx4>
const char* alternatives(const char* src) { const char* alternatives(const char* src) {
...@@ -130,7 +130,7 @@ namespace Sass { ...@@ -130,7 +130,7 @@ namespace Sass {
(rslt = mx3(src)) || (rslt = mx4(src)); (rslt = mx3(src)) || (rslt = mx4(src));
return rslt; return rslt;
} }
// Same as above, but with 5 arguments. // Same as above, but with 5 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3, template <prelexer mx1, prelexer mx2, prelexer mx3,
prelexer mx4, prelexer mx5> prelexer mx4, prelexer mx5>
...@@ -140,7 +140,7 @@ namespace Sass { ...@@ -140,7 +140,7 @@ namespace Sass {
(rslt = mx4(src)) || (rslt = mx5(src)); (rslt = mx4(src)) || (rslt = mx5(src));
return rslt; return rslt;
} }
// Same as above, but with 6 arguments. // Same as above, but with 6 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3, template <prelexer mx1, prelexer mx2, prelexer mx3,
prelexer mx4, prelexer mx5, prelexer mx6> prelexer mx4, prelexer mx5, prelexer mx6>
...@@ -150,7 +150,7 @@ namespace Sass { ...@@ -150,7 +150,7 @@ namespace Sass {
(rslt = mx4(src)) || (rslt = mx5(src)) || (rslt = mx6(src)); (rslt = mx4(src)) || (rslt = mx5(src)) || (rslt = mx6(src));
return rslt; return rslt;
} }
// Same as above, but with 7 arguments. // Same as above, but with 7 arguments.
template <prelexer mx1, prelexer mx2, template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4, prelexer mx3, prelexer mx4,
...@@ -164,7 +164,7 @@ namespace Sass { ...@@ -164,7 +164,7 @@ namespace Sass {
(rslt = mx7(rslt)); (rslt = mx7(rslt));
return rslt; return rslt;
} }
// Same as above, but with 8 arguments. // Same as above, but with 8 arguments.
template <prelexer mx1, prelexer mx2, template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4, prelexer mx3, prelexer mx4,
...@@ -178,7 +178,7 @@ namespace Sass { ...@@ -178,7 +178,7 @@ namespace Sass {
(rslt = mx7(rslt)) || (rslt = mx8(rslt)); (rslt = mx7(rslt)) || (rslt = mx8(rslt));
return rslt; return rslt;
} }
// Tries the matchers in sequence and succeeds if they all succeed. // Tries the matchers in sequence and succeeds if they all succeed.
template <prelexer mx1, prelexer mx2> template <prelexer mx1, prelexer mx2>
const char* sequence(const char* src) { const char* sequence(const char* src) {
...@@ -186,7 +186,7 @@ namespace Sass { ...@@ -186,7 +186,7 @@ namespace Sass {
(rslt = mx1(rslt)) && (rslt = mx2(rslt)); (rslt = mx1(rslt)) && (rslt = mx2(rslt));
return rslt; return rslt;
} }
// Same as above, but with 3 arguments. // Same as above, but with 3 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3> template <prelexer mx1, prelexer mx2, prelexer mx3>
const char* sequence(const char* src) { const char* sequence(const char* src) {
...@@ -194,7 +194,7 @@ namespace Sass { ...@@ -194,7 +194,7 @@ namespace Sass {
(rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)); (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt));
return rslt; return rslt;
} }
// Same as above, but with 4 arguments. // Same as above, but with 4 arguments.
template <prelexer mx1, prelexer mx2, prelexer mx3, prelexer mx4> template <prelexer mx1, prelexer mx2, prelexer mx3, prelexer mx4>
const char* sequence(const char* src) { const char* sequence(const char* src) {
...@@ -203,7 +203,7 @@ namespace Sass { ...@@ -203,7 +203,7 @@ namespace Sass {
(rslt = mx3(rslt)) && (rslt = mx4(rslt)); (rslt = mx3(rslt)) && (rslt = mx4(rslt));
return rslt; return rslt;
} }
// Same as above, but with 5 arguments. // Same as above, but with 5 arguments.
template <prelexer mx1, prelexer mx2, template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4, prelexer mx3, prelexer mx4,
...@@ -215,7 +215,7 @@ namespace Sass { ...@@ -215,7 +215,7 @@ namespace Sass {
(rslt = mx5(rslt)); (rslt = mx5(rslt));
return rslt; return rslt;
} }
// Same as above, but with 6 arguments. // Same as above, but with 6 arguments.
template <prelexer mx1, prelexer mx2, template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4, prelexer mx3, prelexer mx4,
...@@ -227,7 +227,7 @@ namespace Sass { ...@@ -227,7 +227,7 @@ namespace Sass {
(rslt = mx5(rslt)) && (rslt = mx6(rslt)); (rslt = mx5(rslt)) && (rslt = mx6(rslt));
return rslt; return rslt;
} }
// Same as above, but with 7 arguments. // Same as above, but with 7 arguments.
template <prelexer mx1, prelexer mx2, template <prelexer mx1, prelexer mx2,
prelexer mx3, prelexer mx4, prelexer mx3, prelexer mx4,
...@@ -241,14 +241,14 @@ namespace Sass { ...@@ -241,14 +241,14 @@ namespace Sass {
(rslt = mx7(rslt)); (rslt = mx7(rslt));
return rslt; return rslt;
} }
// Match a pattern or not. Always succeeds. // Match a pattern or not. Always succeeds.
template <prelexer mx> template <prelexer mx>
const char* optional(const char* src) { const char* optional(const char* src) {
const char* p = mx(src); const char* p = mx(src);
return p ? p : src; return p ? p : src;
} }
// Match zero or more of the supplied pattern // Match zero or more of the supplied pattern
template <prelexer mx> template <prelexer mx>
const char* zero_plus(const char* src) { const char* zero_plus(const char* src) {
...@@ -256,7 +256,7 @@ namespace Sass { ...@@ -256,7 +256,7 @@ namespace Sass {
while (p) src = p, p = mx(src); while (p) src = p, p = mx(src);
return src; return src;
} }
// Match one or more of the supplied pattern // Match one or more of the supplied pattern
template <prelexer mx> template <prelexer mx>
const char* one_plus(const char* src) { const char* one_plus(const char* src) {
...@@ -265,7 +265,7 @@ namespace Sass { ...@@ -265,7 +265,7 @@ namespace Sass {
while (p) src = p, p = mx(src); while (p) src = p, p = mx(src);
return src; return src;
} }
// Match a single character satisfying the ctype predicates. // Match a single character satisfying the ctype predicates.
const char* space(const char* src); const char* space(const char* src);
const char* alpha(const char* src); const char* alpha(const char* src);
...@@ -280,7 +280,7 @@ namespace Sass { ...@@ -280,7 +280,7 @@ namespace Sass {
const char* xdigits(const char* src); const char* xdigits(const char* src);
const char* alnums(const char* src); const char* alnums(const char* src);
const char* puncts(const char* src); const char* puncts(const char* src);
// Match a line comment. // Match a line comment.
const char* line_comment(const char* src); const char* line_comment(const char* src);
// Match a block comment. // Match a block comment.
...@@ -368,10 +368,10 @@ namespace Sass { ...@@ -368,10 +368,10 @@ namespace Sass {
const char* precedes(const char* src); const char* precedes(const char* src);
const char* parent_of(const char* src); const char* parent_of(const char* src);
const char* ancestor_of(const char* src); const char* ancestor_of(const char* src);
// Match SCSS variable names. // Match SCSS variable names.
const char* variable(const char* src); const char* variable(const char* src);
// Match Sass boolean keywords. // Match Sass boolean keywords.
const char* true_kwd(const char* src); const char* true_kwd(const char* src);
const char* false_kwd(const char* src); const char* false_kwd(const char* src);
...@@ -384,11 +384,11 @@ namespace Sass { ...@@ -384,11 +384,11 @@ namespace Sass {
const char* gte_op(const char* src); const char* gte_op(const char* src);
const char* lt_op(const char* src); const char* lt_op(const char* src);
const char* lte_op(const char* src); const char* lte_op(const char* src);
// Path matching functions. // Path matching functions.
const char* folder(const char* src); const char* folder(const char* src);
const char* folders(const char* src); const char* folders(const char* src);
// Utility functions for finding and counting characters in a string. // Utility functions for finding and counting characters in a string.
template<char c> template<char c>
const char* find_first(const char* src) { const char* find_first(const char* src) {
...@@ -433,6 +433,7 @@ namespace Sass { ...@@ -433,6 +433,7 @@ namespace Sass {
} }
return counter; return counter;
} }
} }
} }
...@@ -14,9 +14,9 @@ extern "C" { ...@@ -14,9 +14,9 @@ extern "C" {
sass_context* sass_new_context() sass_context* sass_new_context()
{ return (sass_context*) calloc(1, sizeof(sass_context)); } { return (sass_context*) calloc(1, sizeof(sass_context)); }
void sass_free_context(sass_context* ctx) void sass_free_context(sass_context* ctx)
{ {
if (ctx->output_string) if (ctx->output_string)
free(ctx->output_string); free(ctx->output_string);
free(ctx); free(ctx);
...@@ -24,14 +24,14 @@ extern "C" { ...@@ -24,14 +24,14 @@ extern "C" {
sass_file_context* sass_new_file_context() sass_file_context* sass_new_file_context()
{ return (sass_file_context*) calloc(1, sizeof(sass_file_context)); } { return (sass_file_context*) calloc(1, sizeof(sass_file_context)); }
void sass_free_file_context(sass_file_context* ctx) void sass_free_file_context(sass_file_context* ctx)
{ {
if (ctx->output_string) if (ctx->output_string)
free(ctx->output_string); free(ctx->output_string);
free(ctx); free(ctx);
} }
sass_folder_context* sass_new_folder_context() sass_folder_context* sass_new_folder_context()
{ return (sass_folder_context*) calloc(1, sizeof(sass_folder_context)); } { return (sass_folder_context*) calloc(1, sizeof(sass_folder_context)); }
...@@ -86,7 +86,7 @@ extern "C" { ...@@ -86,7 +86,7 @@ extern "C" {
// TO DO: CATCH EVERYTHING ELSE // TO DO: CATCH EVERYTHING ELSE
return 0; return 0;
} }
int sass_compile_file(sass_file_context* c_ctx) int sass_compile_file(sass_file_context* c_ctx)
{ {
using namespace Sass; using namespace Sass;
...@@ -123,10 +123,11 @@ extern "C" { ...@@ -123,10 +123,11 @@ extern "C" {
// TO DO: CATCH EVERYTHING ELSE // TO DO: CATCH EVERYTHING ELSE
return 0; return 0;
} }
int sass_compile_folder(sass_folder_context* c_ctx) int sass_compile_folder(sass_folder_context* c_ctx)
{ {
return 1; return 1;
} }
} }
#include <node.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
...@@ -18,6 +20,8 @@ struct sass_context { ...@@ -18,6 +20,8 @@ struct sass_context {
struct sass_options options; struct sass_options options;
int error_status; int error_status;
char* error_message; char* error_message;
uv_work_t request;
v8::Persistent<v8::Function> callback;
}; };
struct sass_file_context { struct sass_file_context {
...@@ -50,4 +54,5 @@ int sass_compile_folder (struct sass_folder_context* ctx); ...@@ -50,4 +54,5 @@ int sass_compile_folder (struct sass_folder_context* ctx);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
\ No newline at end of file
...@@ -14,36 +14,36 @@ int main() ...@@ -14,36 +14,36 @@ int main()
{ {
using namespace Sass; using namespace Sass;
using namespace std; using namespace std;
cout << sizeof(Node_Impl*) << endl; cout << sizeof(Node_Impl*) << endl;
cout << sizeof(Node) << endl; cout << sizeof(Node) << endl;
cout << sizeof(Node_Impl) << endl << endl; cout << sizeof(Node_Impl) << endl << endl;
Node_Factory new_Node = Node_Factory(); Node_Factory new_Node = Node_Factory();
Node interior(new_Node(Node::block, "", 0, 3)); Node interior(new_Node(Node::block, "", 0, 3));
cout << interior.size() << endl; cout << interior.size() << endl;
cout << interior.has_children() << endl; cout << interior.has_children() << endl;
cout << interior.should_eval() << endl << endl; cout << interior.should_eval() << endl << endl;
Node num(new_Node("", 0, 255, 123, 32)); Node num(new_Node("", 0, 255, 123, 32));
Node num2(new_Node("", 0, 255, 123, 32)); Node num2(new_Node("", 0, 255, 123, 32));
Node num3(new_Node("", 0, 255, 122, 20, .75)); Node num3(new_Node("", 0, 255, 122, 20, .75));
cout << num.size() << endl; cout << num.size() << endl;
cout << num.has_children() << endl; cout << num.has_children() << endl;
cout << num.has_statements() << endl << endl; cout << num.has_statements() << endl << endl;
cout << num[1].is_numeric() << endl; cout << num[1].is_numeric() << endl;
cout << num[1].numeric_value() << endl << endl; cout << num[1].numeric_value() << endl << endl;
cout << (num == num2) << endl; cout << (num == num2) << endl;
cout << (num == num3) << endl << endl; cout << (num == num3) << endl << endl;
cout << (num3[2] < num2[2]) << endl; cout << (num3[2] < num2[2]) << endl;
cout << (num2[3] < num3[3]) << endl << endl; cout << (num2[3] < num3[3]) << endl << endl;
cout << (num2[2] >= num3[2]) << endl; cout << (num2[2] >= num3[2]) << endl;
cout << (num2[3] != num3[3]) << endl << endl; cout << (num2[3] != num3[3]) << endl << endl;
...@@ -92,4 +92,5 @@ int main() ...@@ -92,4 +92,5 @@ int main()
new_Node.free(); new_Node.free();
return 0; return 0;
} }
\ No newline at end of file
var binding = require('./build/Release/binding') var binding = require('./build/Release/binding')
var render = function(str, cb){ exports.render = binding.render
cb(binding.render(str)) exports.middleware = require('./lib/middleware');
}
exports.render = render
exports.middleware = require('./lib/middleware');
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment