Commit c28965db by Aaron Leung

Merge branch 'func_resolver'

parents d6ae70ed 74e8c9f1
#include "context.hpp" #include "context.hpp"
#include <cstring> #include <cstring>
#include <iostream> #include <iostream>
#include <sstream>
#include <unistd.h> #include <unistd.h>
#include "prelexer.hpp" #include "prelexer.hpp"
#include "color_names.hpp" #include "color_names.hpp"
...@@ -73,21 +74,20 @@ namespace Sass { ...@@ -73,21 +74,20 @@ namespace Sass {
} }
delete[] image_path; delete[] image_path;
new_Node.free(); new_Node.free();
// cerr << "Deallocated " << i << " source string(s)." << endl;
} }
inline void Context::register_function(Function_Descriptor d, Primitive ip) inline void Context::register_function(Signature sig, Primitive ip)
{ {
Function f(d, ip, new_Node); Function f(const_cast<char*>(sig), ip, *this);
// function_env[pair<string, size_t>(f.name, f.parameters.size())] = f;
function_env[f.name] = f; function_env[f.name] = f;
} }
inline void Context::register_function(Function_Descriptor d, Primitive ip, size_t arity) inline void Context::register_function(Signature sig, Primitive ip, size_t arity)
{ {
Function f(d, ip, new_Node); Function f(const_cast<char*>(sig), ip, *this);
// function_env[pair<string, size_t>(f.name, arity)] = f; std::stringstream stub;
function_env[f.name] = f; stub << f.name << " " << arity;
function_env[stub.str()] = f;
} }
inline void Context::register_overload_stub(string name) inline void Context::register_overload_stub(string name)
...@@ -98,68 +98,53 @@ namespace Sass { ...@@ -98,68 +98,53 @@ namespace Sass {
void Context::register_functions() void Context::register_functions()
{ {
using namespace Functions; using namespace Functions;
// RGB Functions // RGB Functions
register_function(rgb_descriptor, rgb); register_function(rgb_sig, rgb);
register_overload_stub("rgba"); register_overload_stub("rgba");
register_function(rgba_4_descriptor, rgba_4); register_function(rgba_4_sig, rgba_4, 4);
register_function(rgba_2_descriptor, rgba_2); register_function(rgba_2_sig, rgba_2, 2);
register_function(red_descriptor, red); register_function(red_sig, red);
register_function(green_descriptor, green); register_function(green_sig, green);
register_function(blue_descriptor, blue); register_function(blue_sig, blue);
register_overload_stub("mix"); register_function(mix_sig, mix);
register_function(mix_2_descriptor, mix_2);
register_function(mix_3_descriptor, mix_3);
// HSL Functions // HSL Functions
register_function(hsla_descriptor, hsla); register_function(hsla_sig, hsla);
register_function(hsl_descriptor, hsl); register_function(hsl_sig, hsl);
register_function(adjust_hue_descriptor, adjust_hue); register_function(adjust_hue_sig, adjust_hue);
register_function(invert_descriptor, invert); register_function(adjust_color_sig, adjust_color);
register_function(change_color_sig, change_color);
register_function(invert_sig, invert);
// Opacity Functions // Opacity Functions
register_function(alpha_descriptor, alpha); register_function(alpha_sig, alpha);
register_function(opacity_descriptor, alpha); register_function(opacity_sig, alpha);
register_function(opacify_descriptor, opacify); register_function(opacify_sig, opacify);
register_function(fade_in_descriptor, opacify); register_function(fade_in_sig, opacify);
register_function(transparentize_descriptor, transparentize); register_function(transparentize_sig, transparentize);
register_function(fade_out_descriptor, transparentize); register_function(fade_out_sig, transparentize);
// String Functions // String Functions
register_function(unquote_descriptor, unquote); register_function(unquote_sig, unquote);
register_function(quote_descriptor, quote); register_function(quote_sig, quote);
// Number Functions // Number Functions
register_function(percentage_descriptor, percentage); register_function(percentage_sig, percentage);
register_function(round_descriptor, round); register_function(round_sig, round);
register_function(ceil_descriptor, ceil); register_function(ceil_sig, ceil);
register_function(floor_descriptor, floor); register_function(floor_sig, floor);
register_function(abs_descriptor, abs); register_function(abs_sig, abs);
// List Functions // List Functions
register_function(length_descriptor, length); register_function(length_sig, length);
register_function(nth_descriptor, nth); register_function(nth_sig, nth);
register_overload_stub("join"); register_function(join_sig, join);
register_function(join_2_descriptor, join_2); register_function(append_sig, append);
register_function(join_3_descriptor, join_3); register_function(compact_sig, compact);
register_overload_stub("append");
register_function(append_2_descriptor, append_2);
register_function(append_3_descriptor, append_3);
register_overload_stub("compact");
register_function(compact_1_descriptor, compact);
register_function(compact_2_descriptor, compact);
register_function(compact_3_descriptor, compact);
register_function(compact_4_descriptor, compact);
register_function(compact_5_descriptor, compact);
register_function(compact_6_descriptor, compact);
register_function(compact_7_descriptor, compact);
register_function(compact_8_descriptor, compact);
register_function(compact_9_descriptor, compact);
register_function(compact_10_descriptor, compact);
register_function(compact_11_descriptor, compact);
register_function(compact_12_descriptor, compact);
// Introspection Functions // Introspection Functions
register_function(type_of_descriptor, type_of); register_function(type_of_sig, type_of);
register_function(unit_descriptor, unit); register_function(unit_sig, unit);
register_function(unitless_descriptor, unitless); register_function(unitless_sig, unitless);
register_function(comparable_descriptor, comparable); register_function(comparable_sig, comparable);
// Boolean Functions // Boolean Functions
register_function(not_descriptor, not_impl); register_function(not_sig, not_impl);
register_function(if_descriptor, if_impl); register_function(if_sig, if_impl);
} }
void Context::setup_color_map() void Context::setup_color_map()
......
#define SASS_CONTEXT #define SASS_CONTEXT
#ifndef SASS_ENVIRONMENT //#ifndef SASS_ENVIRONMENT
#include "environment.hpp" #include "environment.hpp"
#endif //#endif
#include <utility> #include <utility>
#ifndef SASS_NODE_FACTORY
#include "node_factory.hpp" #include "node_factory.hpp"
#endif
#ifndef SASS_FUNCTIONS
#include "functions.hpp" #include "functions.hpp"
#endif
namespace Sass { namespace Sass {
using std::pair; using std::pair;
using std::map; using std::map;
// struct Environment {
// map<Token, Node> current_frame;
// Environment* parent;
// Environment* global;
// Environment()
// : current_frame(map<Token, Node>()), parent(0), global(0)
// { }
// void link(Environment& env)
// {
// parent = &env;
// global = parent->global ? parent->global : parent;
// }
// bool query(const Token& key) const
// {
// if (current_frame.count(key)) return true;
// else if (parent) return parent->query(key);
// else return false;
// }
// Node& operator[](const Token& key)
// {
// if (current_frame.count(key)) return current_frame[key];
// else if (parent) return (*parent)[key];
// else return current_frame[key];
// }
// };
struct Context { struct Context {
Environment global_env; Environment global_env;
map<string, Function> function_env; map<string, Function> function_env;
...@@ -61,9 +37,9 @@ namespace Sass { ...@@ -61,9 +37,9 @@ namespace Sass {
void collect_include_paths(const char* paths_str); void collect_include_paths(const char* paths_str);
Context(const char* paths_str = 0, const char* img_path_str = 0); Context(const char* paths_str = 0, const char* img_path_str = 0);
~Context(); ~Context();
void register_function(Function_Descriptor d, Primitive ip); void register_function(Signature sig, Primitive ip);
void register_function(Function_Descriptor d, Primitive ip, size_t arity); void register_function(Signature sig, Primitive ip, size_t arity);
void register_overload_stub(string name); void register_overload_stub(string name);
void register_functions(); void register_functions();
void setup_color_map(); void setup_color_map();
......
#define SASS_DOCUMENT
#include <map> #include <map>
#ifndef SASS_PRELEXER #ifndef SASS_PRELEXER
......
#define SASS_ERROR
namespace Sass { namespace Sass {
struct Error { struct Error {
......
...@@ -707,21 +707,20 @@ namespace Sass { ...@@ -707,21 +707,20 @@ namespace Sass {
Node apply_function(const Function& f, const Node args, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx) Node apply_function(const Function& f, const Node args, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx)
{ {
if (f.primitive) { if (f.primitive) {
map<Token, Node> bindings; // evaluate arguments in the current environment
// bind arguments for (size_t i = 0, S = args.size(); i < S; ++i) {
for (size_t i = 0, j = 0, S = args.size(); i < S; ++i) { if (args[i].type() != Node::assignment) {
if (args[i].type() == Node::assignment) { args[i] = eval(args[i], prefix, env, f_env, new_Node, ctx);
Node arg(args[i]);
Token name(arg[0].token());
bindings[name] = eval(arg[1], prefix, env, f_env, new_Node, ctx);
} }
else { else {
// TO DO: ensure (j < f.parameters.size()) args[i][1] = eval(args[i][1], prefix, env, f_env, new_Node, ctx);
bindings[f.parameters[j].token()] = eval(args[i], prefix, env, f_env, new_Node, ctx);
++j;
} }
} }
return f(bindings, new_Node); // bind arguments
Environment bindings;
bindings.link(env.global ? *env.global : env);
bind_arguments("function " + f.name, f.parameters, args, prefix, bindings, f_env, new_Node, ctx);
return f.primitive(f.parameter_names, bindings, new_Node);
} }
else { else {
Node params(f.definition[1]); Node params(f.definition[1]);
......
#define SASS_EVAL_APPLY
#include <map> #include <map>
#ifndef SASS_NODE #ifndef SASS_NODE
......
#ifndef SASS_PRELEXER #ifndef SASS_PRELEXER
#include "prelexer.hpp" #include "prelexer.hpp"
#endif #endif
#include "node_factory.hpp" #include "node_factory.hpp"
#include "functions.hpp" #include "functions.hpp"
#include "context.hpp"
#include "document.hpp"
#include "eval_apply.hpp"
#include "error.hpp" #include "error.hpp"
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
#include <algorithm>
using std::cerr; using std::endl; using std::cerr; using std::endl;
namespace Sass { namespace Sass {
// this constructor needs context.hpp, so it can't be defined in functions.hpp
Function::Function(char* signature, Primitive ip, Context& ctx)
: definition(Node()),
primitive(ip),
overloaded(false)
{
Document sig_doc(Document::make_from_source_chars(ctx, signature));
sig_doc.lex<Prelexer::identifier>();
name = sig_doc.lexed.to_string();
parameters = sig_doc.parse_parameters();
parameter_names = ctx.new_Node(Node::parameters, "[PRIMITIVE FUNCTIONS]", 0, parameters.size());
for (size_t i = 0, S = parameters.size(); i < S; ++i) {
Node param(parameters[i]);
if (param.type() == Node::variable) {
parameter_names << param;
}
else {
parameter_names << param[0];
// assume it's safe to evaluate default args just once at initialization
param[1] = eval(param[1], Node(), ctx.global_env, ctx.function_env, ctx.new_Node, ctx);
}
}
}
namespace Functions { namespace Functions {
static void throw_eval_error(string message, string path, size_t line) static void throw_eval_error(string message, string path, size_t line)
...@@ -19,153 +52,144 @@ namespace Sass { ...@@ -19,153 +52,144 @@ namespace Sass {
throw Error(Error::evaluation, path, line, message); throw Error(Error::evaluation, path, line, message);
} }
extern Signature foo_sig = "foo($x, $y, $z: \"hey\")";
Node foo(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node arg1(bindings[parameter_names[0].token()]);
Node arg2(bindings[parameter_names[1].token()]);
Node arg3(bindings[parameter_names[2].token()]);
Node cat(new_Node(Node::concatenation, arg1.path(), arg1.line(), 3));
cat << arg3 << arg2 << arg1;
return cat;
}
// RGB Functions /////////////////////////////////////////////////////// // RGB Functions ///////////////////////////////////////////////////////
Function_Descriptor rgb_descriptor = extern Signature rgb_sig = "rgb($red, $green, $blue)";
{ "rgb", "$red", "$green", "$blue", 0 }; Node rgb(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node rgb(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node r(bindings[parameter_names[0].token()]);
Node r(bindings[parameters[0].token()]); Node g(bindings[parameter_names[1].token()]);
Node g(bindings[parameters[1].token()]); Node b(bindings[parameter_names[2].token()]);
Node b(bindings[parameters[2].token()]);
if (!(r.type() == Node::number && g.type() == Node::number && b.type() == Node::number)) { if (!(r.type() == Node::number && g.type() == Node::number && b.type() == Node::number)) {
throw_eval_error("arguments for rgb must be numbers", r.path(), r.line()); throw_eval_error("arguments for rgb must be numbers", r.path(), r.line());
} }
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 = // TODO: SOMETHING SPECIAL FOR OVERLOADED FUNCTIONS
{ "rgba 4", "$red", "$green", "$blue", "$alpha", 0 }; extern Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
Node rgba_4(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node rgba_4(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node r(bindings[parameters[0].token()]); Node r(bindings[parameter_names[0].token()]);
Node g(bindings[parameters[1].token()]); Node g(bindings[parameter_names[1].token()]);
Node b(bindings[parameters[2].token()]); Node b(bindings[parameter_names[2].token()]);
Node a(bindings[parameters[3].token()]); Node a(bindings[parameter_names[3].token()]);
if (!(r.type() == Node::number && g.type() == Node::number && b.type() == Node::number && a.type() == Node::number)) { if (!(r.type() == Node::number && g.type() == Node::number && b.type() == Node::number && a.type() == Node::number)) {
throw_eval_error("arguments for rgba must be numbers", r.path(), r.line()); throw_eval_error("arguments for rgba must be numbers", r.path(), r.line());
} }
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 = extern Signature rgba_2_sig = "rgba($color, $alpha)";
{ "rgba 2", "$color", "$alpha", 0 }; Node rgba_2(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node rgba_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node color(bindings[parameter_names[0].token()]);
Node color(bindings[parameters[0].token()]);
Node r(color[0]); Node r(color[0]);
Node g(color[1]); Node g(color[1]);
Node b(color[2]); Node b(color[2]);
Node a(bindings[parameters[1].token()]); Node a(bindings[parameter_names[1].token()]);
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 = extern Signature red_sig = "red($color)";
{ "red", "$color", 0 }; Node red(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node red(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node color(bindings[parameter_names[0].token()]);
Node color(bindings[parameters[0].token()]);
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 = extern Signature green_sig = "green($color)";
{ "green", "$color", 0 }; Node green(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node green(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node color(bindings[parameter_names[0].token()]);
Node color(bindings[parameters[0].token()]);
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 = extern Signature blue_sig = "blue($color)";
{ "blue", "$color", 0 }; Node blue(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node blue(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node color(bindings[parameter_names[0].token()]);
Node color(bindings[parameters[0].token()]);
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) { extern Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
if (!(color1.type() == Node::numeric_color && color2.type() == Node::numeric_color)) { Node mix(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
throw_eval_error("first two arguments to mix must be colors", color1.path(), color1.line()); Node color1(bindings[parameter_names[0].token()]);
} Node color2(bindings[parameter_names[1].token()]);
double p = weight/100; Node weight(bindings[parameter_names[2].token()]);
if (color1.type() != Node::numeric_color) throw_eval_error("first argument to mix must be a color", color1.path(), color1.line());
if (color2.type() != Node::numeric_color) throw_eval_error("second argument to mix must be a color", color2.path(), color2.line());
if (!weight.is_numeric()) throw_eval_error("third argument to mix must be numeric", weight.path(), weight.line());
double p = weight.numeric_value()/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(), w1*color1[i].numeric_value() + w2*color2[i].numeric_value());
w1*color1[i].numeric_value() + w2*color2[i].numeric_value());
} }
double alpha = color1[3].numeric_value()*p + color2[3].numeric_value()*(1-p); double alpha = color1[3].numeric_value()*p + color2[3].numeric_value()*(1-p);
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 =
{ "mix 2", "$color1", "$color2", 0 };
Node mix_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return mix_impl(bindings[parameters[0].token()], bindings[parameters[1].token()], 50, new_Node);
}
Function_Descriptor mix_3_descriptor =
{ "mix 3", "$color1", "$color2", "$weight", 0 };
Node mix_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
Node percentage(bindings[parameters[2].token()]);
if (!(percentage.type() == Node::number || percentage.type() == Node::numeric_percentage || percentage.type() == Node::numeric_dimension)) {
throw_eval_error("third argument to mix must be numeric", percentage.path(), percentage.line());
}
return mix_impl(bindings[parameters[0].token()],
bindings[parameters[1].token()],
percentage.numeric_value(),
new_Node);
}
// HSL Functions /////////////////////////////////////////////////////// // HSL Functions ///////////////////////////////////////////////////////
// Utility rgb to hsl function so we can do hsl operations // Utility rgb to hsl function so we can do hsl operations
Node rgb_to_hsl(double r, double g, double b, Node_Factory& new_Node) { Node rgb_to_hsl(double r, double g, double b, Node_Factory& new_Node) {
r = r/255.0; cerr << "rgb to hsl: " << r << " " << g << " " << b << endl;
g = g/255.0; r /= 255.0; g /= 255.0; b /= 255.0;
b = b/255.0;
double v, m, vm, r2, g2, b2;
double h = 0, s = 0, l = 0;
v = r > g ? r : g; double max = std::max(r, std::max(g, b));
v = v > b ? v : b; double min = std::min(r, std::min(g, b));
m = r < g ? r : g; double del = max - min;
m = m < b ? m : b;
l = (m + v)/2.0;
if (l <= 0.0) return new_Node("", 0, h, s, l); double h = 0, s = 0, l = (max + min)/2;
vm = v - m; if (max == min) {
s = vm; h = s = 0; // achromatic
}
else {
/*
double delta = max - min;
s = (l > 0.5) ? (2 - max - min) : (delta / (max + min));
if (max == r) h = (g - b) / delta + (g < b ? 6 : 0);
else if (max == g) h = (b - r) / delta + 2;
else if (max == b) h = (r - g) / delta + 4;
h /= 6;
*/
if (s > 0.0) s /= (l <= 0.5) ? (v + m) : (2.0 - v - m); if (l < 0.5) s = del / (max + min);
else return new_Node("", 0, h, s, l); else s = del / (2.0 - max - min);
r2 = (v - r)/vm; double dr = (((max - r)/6.0) + (del/2.0))/del;
g2 = (v - g)/vm; double dg = (((max - g)/6.0) + (del/2.0))/del;
b2 = (v - b)/vm; double db = (((max - b)/6.0) + (del/2.0))/del;
if (r == v) h = (g == m ? 5.0 + b2 : 1.0 - g2); if (r == max) h = db - dg;
else if (g == v) h = (b == m ? 1.0 + r2 : 3.0 - b2); else if (g == max) h = (1.0/3.0) + dr - db;
else h = (r == m ? 3.0 + g2 : 5.0 - r2); else if (b == max) h = (2.0/3.0) + dg - dr;
h /= 6.0; if (h < 0) h += 1;
else if (h > 1) h -= 1;
}
return new_Node("", 0, static_cast<int>(h*360)%360, s*100, l*100); return new_Node("", 0, static_cast<int>(h*360)%360, s*100, l*100);
} }
// Function_Descriptor adjust_color_descriptor =
// { "adjust_color 1", "$color", 0 }
// Function_Descriptor adjust_color_2_descriptor =
// { "adjust_color 2", "$color", "2")
// Node adjust_color_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
// blah;
// }
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;
...@@ -177,8 +201,8 @@ namespace Sass { ...@@ -177,8 +201,8 @@ namespace Sass {
Node hsla_impl(double h, double s, double l, double a, Node_Factory& new_Node) { Node hsla_impl(double h, double s, double l, double a, Node_Factory& new_Node) {
h = static_cast<double>(((static_cast<int>(h) % 360) + 360) % 360) / 360.0; h = static_cast<double>(((static_cast<int>(h) % 360) + 360) % 360) / 360.0;
s = s / 100.0; s = (s < 0) ? 0 : (s / 100.0);
l = l / 100.0; l = (l < 0) ? 0 : (l / 100.0);
double m2; double m2;
if (l <= 0.5) m2 = l*(s+1.0); if (l <= 0.5) m2 = l*(s+1.0);
...@@ -187,49 +211,44 @@ namespace Sass { ...@@ -187,49 +211,44 @@ 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);
} }
Function_Descriptor hsla_descriptor = extern Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)";
{ "hsla", "$hue", "$saturation", "$lightness", "$alpha", 0 }; Node hsla(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node hsla(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { if (!(bindings[parameter_names[0].token()].is_numeric() &&
if (!(bindings[parameters[0].token()].is_numeric() && bindings[parameter_names[1].token()].is_numeric() &&
bindings[parameters[1].token()].is_numeric() && bindings[parameter_names[2].token()].is_numeric() &&
bindings[parameters[2].token()].is_numeric() && bindings[parameter_names[3].token()].is_numeric())) {
bindings[parameters[3].token()].is_numeric())) { throw_eval_error("arguments to hsla must be numeric", bindings[parameter_names[0].token()].path(), bindings[parameter_names[0].token()].line());
throw_eval_error("arguments to hsla must be numeric", bindings[parameters[0].token()].path(), bindings[parameters[0].token()].line());
} }
double h = bindings[parameters[0].token()].numeric_value(); double h = bindings[parameter_names[0].token()].numeric_value();
double s = bindings[parameters[1].token()].numeric_value(); double s = bindings[parameter_names[1].token()].numeric_value();
double l = bindings[parameters[2].token()].numeric_value(); double l = bindings[parameter_names[2].token()].numeric_value();
double a = bindings[parameters[3].token()].numeric_value(); double a = bindings[parameter_names[3].token()].numeric_value();
Node color(hsla_impl(h, s, l, a, new_Node)); Node color(hsla_impl(h, s, l, a, new_Node));
// color.line() = bindings[parameters[0].token()].line();
return color; return color;
} }
Function_Descriptor hsl_descriptor = extern Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
{ "hsl", "$hue", "$saturation", "$lightness", 0 }; Node hsl(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node hsl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { if (!(bindings[parameter_names[0].token()].is_numeric() &&
if (!(bindings[parameters[0].token()].is_numeric() && bindings[parameter_names[1].token()].is_numeric() &&
bindings[parameters[1].token()].is_numeric() && bindings[parameter_names[2].token()].is_numeric())) {
bindings[parameters[2].token()].is_numeric())) { throw_eval_error("arguments to hsl must be numeric", bindings[parameter_names[0].token()].path(), bindings[parameter_names[0].token()].line());
throw_eval_error("arguments to hsl must be numeric", bindings[parameters[0].token()].path(), bindings[parameters[0].token()].line());
} }
double h = bindings[parameters[0].token()].numeric_value(); double h = bindings[parameter_names[0].token()].numeric_value();
double s = bindings[parameters[1].token()].numeric_value(); double s = bindings[parameter_names[1].token()].numeric_value();
double l = bindings[parameters[2].token()].numeric_value(); double l = bindings[parameter_names[2].token()].numeric_value();
Node color(hsla_impl(h, s, l, 1, new_Node)); Node color(hsla_impl(h, s, l, 1, new_Node));
// color.line() = bindings[parameters[0].token()].line();
return color; return color;
} }
Function_Descriptor adjust_hue_descriptor = extern Signature adjust_hue_sig = "adjust-hue($color, $degrees)";
{ "adjust-hue", "$color", "$degrees", 0 }; Node adjust_hue(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node adjust_hue(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node rgb_col(bindings[parameter_names[0].token()]);
Node rgb_col(bindings[parameters[0].token()]); Node degrees(bindings[parameter_names[1].token()]);
Node degrees(bindings[parameters[1].token()]);
if (rgb_col.type() != Node::numeric_color) throw_eval_error("first argument to adjust-hue must be a color", rgb_col.path(), rgb_col.line()); if (rgb_col.type() != Node::numeric_color) throw_eval_error("first argument to adjust-hue must be a color", rgb_col.path(), rgb_col.line());
if (!degrees.is_numeric()) throw_eval_error("second argument to adjust-hue must be numeric", degrees.path(), degrees.line()); if (!degrees.is_numeric()) throw_eval_error("second argument to adjust-hue must be numeric", degrees.path(), degrees.line());
Node hsl_col(rgb_to_hsl(rgb_col[0].numeric_value(), Node hsl_col(rgb_to_hsl(rgb_col[0].numeric_value(),
...@@ -243,10 +262,109 @@ namespace Sass { ...@@ -243,10 +262,109 @@ namespace Sass {
new_Node); new_Node);
} }
Function_Descriptor invert_descriptor = extern Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
{ "invert", "$color", 0 }; Node adjust_color(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node invert(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node color(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]); Node r(bindings[parameter_names[1].token()]);
Node g(bindings[parameter_names[2].token()]);
Node b(bindings[parameter_names[3].token()]);
Node h(bindings[parameter_names[4].token()]);
Node s(bindings[parameter_names[5].token()]);
Node l(bindings[parameter_names[6].token()]);
Node a(bindings[parameter_names[7].token()]);
bool no_rgb = r.is_false() && g.is_false() && b.is_false();
bool no_hsl = h.is_false() && s.is_false() && l.is_false();
if (!no_rgb && !no_hsl) {
throw_eval_error("cannot specify RGB and HSL values for a color at the same time for 'adjust-color'", r.path(), r.line());
}
else if (!no_rgb) {
double new_r = color[0].numeric_value() + (r.is_false() ? 0 : r.numeric_value());
double new_g = color[1].numeric_value() + (g.is_false() ? 0 : g.numeric_value());
double new_b = color[2].numeric_value() + (b.is_false() ? 0 : b.numeric_value());
double new_a = color[3].numeric_value() + (a.is_false() ? 0 : a.numeric_value());
return new_Node("", 0, new_r, new_g, new_b, new_a);
}
else if (!no_hsl) {
Node hsl_node(rgb_to_hsl(color[0].numeric_value(),
color[1].numeric_value(),
color[2].numeric_value(),
new_Node));
double new_h = (h.is_false() ? 0 : h.numeric_value()) + hsl_node[0].numeric_value();
double new_s = (s.is_false() ? 0 : s.numeric_value()) + hsl_node[1].numeric_value();
double new_l = (l.is_false() ? 0 : l.numeric_value()) + hsl_node[2].numeric_value();
double new_a = (a.is_false() ? 0 : a.numeric_value()) + color[3].numeric_value();
return hsla_impl(new_h, new_s, new_l, new_a, new_Node);
}
else if (!a.is_false()) {
return new_Node("", 0,
color[0].numeric_value(),
color[1].numeric_value(),
color[2].numeric_value(),
color[3].numeric_value() + a.numeric_value());
}
else {
throw_eval_error("not enough arguments for 'adjust-color'", color.path(), color.line());
}
// unreachable statement
return Node();
}
extern Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
Node change_color(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node color(bindings[parameter_names[0].token()]);
Node r(bindings[parameter_names[1].token()]);
Node g(bindings[parameter_names[2].token()]);
Node b(bindings[parameter_names[3].token()]);
Node h(bindings[parameter_names[4].token()]);
Node s(bindings[parameter_names[5].token()]);
Node l(bindings[parameter_names[6].token()]);
Node a(bindings[parameter_names[7].token()]);
bool no_rgb = r.is_false() && g.is_false() && b.is_false();
bool no_hsl = h.is_false() && s.is_false() && l.is_false();
if (!no_rgb && !no_hsl) {
throw_eval_error("cannot specify RGB and HSL values for a color at the same time for 'change-color'", r.path(), r.line());
}
else if (!no_rgb) {
double new_r = (r.is_false() ? color[0] : r).numeric_value();
double new_g = (g.is_false() ? color[1] : g).numeric_value();
double new_b = (b.is_false() ? color[2] : b).numeric_value();
double new_a = (a.is_false() ? color[3] : a).numeric_value();
return new_Node("", 0, new_r, new_g, new_b, new_a);
}
else if (!no_hsl) {
cerr << color.to_string() << endl;
Node hsl_node(rgb_to_hsl(color[0].numeric_value(),
color[1].numeric_value(),
color[2].numeric_value(),
new_Node));
cerr << hsl_node.to_string() << endl;
double new_h = (h.is_false() ? hsl_node[0].numeric_value() : h.numeric_value());
double new_s = (s.is_false() ? hsl_node[1].numeric_value() : s.numeric_value());
double new_l = (l.is_false() ? hsl_node[2].numeric_value() : l.numeric_value());
double new_a = (a.is_false() ? color[3].numeric_value() : a.numeric_value());
return hsla_impl(new_h, new_s, new_l, new_a, new_Node);
}
else if (!a.is_false()) {
return new_Node("", 0,
color[0].numeric_value(),
color[1].numeric_value(),
color[2].numeric_value(),
a.numeric_value());
}
else {
throw_eval_error("not enough arguments for 'change-color'", color.path(), color.line());
}
// unreachable statement
return Node();
}
extern Signature invert_sig = "invert($color)";
Node invert(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node orig(bindings[parameter_names[0].token()]);
if (orig.type() != Node::numeric_color) throw_eval_error("argument to invert must be a color", orig.path(), orig.line()); if (orig.type() != Node::numeric_color) throw_eval_error("argument to invert must be a color", orig.path(), orig.line());
return new_Node(orig.path(), orig.line(), return new_Node(orig.path(), orig.line(),
255 - orig[0].numeric_value(), 255 - orig[0].numeric_value(),
...@@ -257,23 +375,19 @@ namespace Sass { ...@@ -257,23 +375,19 @@ namespace Sass {
// Opacity Functions /////////////////////////////////////////////////// // Opacity Functions ///////////////////////////////////////////////////
Function_Descriptor alpha_descriptor = extern Signature alpha_sig = "alpha($color)";
{ "alpha", "$color", 0 }; extern Signature opacity_sig = "opacity($color)";
Function_Descriptor opacity_descriptor = Node alpha(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
{ "opacity", "$color", 0 }; Node color(bindings[parameter_names[0].token()]);
Node alpha(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { if (color.type() != Node::numeric_color) throw_eval_error("argument to alpha/opacity must be a color", color.path(), color.line());
Node color(bindings[parameters[0].token()]);
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 = extern Signature opacify_sig = "opacify($color, $amount)";
{ "opacify", "$color", "$amount", 0 }; extern Signature fade_in_sig = "fade-in($color, $amount)";
Function_Descriptor fade_in_descriptor = Node opacify(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
{ "fade_in", "$color", "$amount", 0 }; Node color(bindings[parameter_names[0].token()]);
Node opacify(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node delta(bindings[parameter_names[1].token()]);
Node color(bindings[parameters[0].token()]);
Node delta(bindings[parameters[1].token()]);
if (color.type() != Node::numeric_color || !delta.is_numeric()) { if (color.type() != Node::numeric_color || !delta.is_numeric()) {
throw_eval_error("arguments to opacify/fade_in must be a color and a numeric value", color.path(), color.line()); throw_eval_error("arguments to opacify/fade_in must be a color and a numeric value", color.path(), color.line());
} }
...@@ -287,13 +401,11 @@ namespace Sass { ...@@ -287,13 +401,11 @@ namespace Sass {
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 = extern Signature transparentize_sig = "transparentize($color, $amount)";
{ "transparentize", "$color", "$amount", 0 }; extern Signature fade_out_sig = "fade-out($color, $amount)";
Function_Descriptor fade_out_descriptor = Node transparentize(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
{ "fade_out", "$color", "$amount", 0 }; Node color(bindings[parameter_names[0].token()]);
Node transparentize(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node delta(bindings[parameter_names[1].token()]);
Node color(bindings[parameters[0].token()]);
Node delta(bindings[parameters[1].token()]);
if (color.type() != Node::numeric_color || !delta.is_numeric()) { if (color.type() != Node::numeric_color || !delta.is_numeric()) {
throw_eval_error("arguments to transparentize/fade_out must be a color and a numeric value", color.path(), color.line()); throw_eval_error("arguments to transparentize/fade_out must be a color and a numeric value", color.path(), color.line());
} }
...@@ -309,10 +421,9 @@ namespace Sass { ...@@ -309,10 +421,9 @@ namespace Sass {
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
Function_Descriptor unquote_descriptor = extern Signature unquote_sig = "unquote($string)";
{ "unquote", "$string", 0 }; Node unquote(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node unquote(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node cpy(new_Node(bindings[parameter_names[0].token()]));
Node cpy(new_Node(bindings[parameters[0].token()]));
// if (cpy.type() != Node::string_constant /* && cpy.type() != Node::concatenation */) { // if (cpy.type() != Node::string_constant /* && cpy.type() != Node::concatenation */) {
// throw_eval_error("argument to unquote must be a string", cpy.path(), cpy.line()); // throw_eval_error("argument to unquote must be a string", cpy.path(), cpy.line());
// } // }
...@@ -321,10 +432,9 @@ namespace Sass { ...@@ -321,10 +432,9 @@ namespace Sass {
return cpy; return cpy;
} }
Function_Descriptor quote_descriptor = extern Signature quote_sig = "quote($string)";
{ "quote", "$string", 0 }; Node quote(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node quote(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
switch (orig.type()) switch (orig.type())
{ {
default: { default: {
...@@ -347,20 +457,18 @@ namespace Sass { ...@@ -347,20 +457,18 @@ namespace Sass {
// Number Functions //////////////////////////////////////////////////// // Number Functions ////////////////////////////////////////////////////
Function_Descriptor percentage_descriptor = extern Signature percentage_sig = "percentage($value)";
{ "percentage", "$value", 0 }; Node percentage(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node percentage(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
if (orig.type() != Node::number) { if (orig.type() != Node::number) {
throw_eval_error("argument to percentage must be a unitless number", orig.path(), orig.line()); throw_eval_error("argument to percentage must be a unitless number", orig.path(), orig.line());
} }
return new_Node(orig.path(), orig.line(), orig.numeric_value() * 100, Node::numeric_percentage); return new_Node(orig.path(), orig.line(), orig.numeric_value() * 100, Node::numeric_percentage);
} }
Function_Descriptor round_descriptor = extern Signature round_sig = "round($value)";
{ "round", "$value", 0 }; Node round(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node round(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
...@@ -387,10 +495,9 @@ namespace Sass { ...@@ -387,10 +495,9 @@ namespace Sass {
return Node(); return Node();
} }
Function_Descriptor ceil_descriptor = extern Signature ceil_sig = "ceil($value)";
{ "ceil", "$value", 0 }; Node ceil(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node ceil(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
...@@ -417,10 +524,9 @@ namespace Sass { ...@@ -417,10 +524,9 @@ namespace Sass {
return Node(); return Node();
} }
Function_Descriptor floor_descriptor = extern Signature floor_sig = "floor($value)";
{ "floor", "$value", 0 }; Node floor(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node floor(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
...@@ -447,10 +553,9 @@ namespace Sass { ...@@ -447,10 +553,9 @@ namespace Sass {
return Node(); return Node();
} }
Function_Descriptor abs_descriptor = extern Signature abs_sig = "abs($value)";
{ "abs", "$value", 0 }; Node abs(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node abs(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node orig(bindings[parameter_names[0].token()]);
Node orig(bindings[parameters[0].token()]);
switch (orig.type()) switch (orig.type())
{ {
case Node::numeric_dimension: { case Node::numeric_dimension: {
...@@ -479,10 +584,9 @@ namespace Sass { ...@@ -479,10 +584,9 @@ namespace Sass {
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
Function_Descriptor length_descriptor = extern Signature length_sig = "length($list)";
{ "length", "$list", 0 }; Node length(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node length(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node arg(bindings[parameter_names[0].token()]);
Node arg(bindings[parameters[0].token()]);
switch (arg.type()) switch (arg.type())
{ {
case Node::space_list: case Node::space_list:
...@@ -503,11 +607,10 @@ namespace Sass { ...@@ -503,11 +607,10 @@ namespace Sass {
return Node(); return Node();
} }
Function_Descriptor nth_descriptor = extern Signature nth_sig = "nth($list, $n)";
{ "nth", "$list", "$n", 0 }; Node nth(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node nth(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node l(bindings[parameter_names[0].token()]);
Node l(bindings[parameters[0].token()]); Node n(bindings[parameter_names[1].token()]);
Node n(bindings[parameters[1].token()]);
if (n.type() != Node::number) { if (n.type() != Node::number) {
throw_eval_error("second argument to nth must be a number", n.path(), n.line()); throw_eval_error("second argument to nth must be a number", n.path(), n.line());
} }
...@@ -524,15 +627,15 @@ namespace Sass { ...@@ -524,15 +627,15 @@ namespace Sass {
} }
return l[n_prim - 1]; return l[n_prim - 1];
} }
extern const char separator_kwd[] = "$separator"; extern Signature join_sig = "join($list1, $list2, $separator: auto)";
Node join_impl(const Node parameters, map<Token, Node>& bindings, bool has_sep, Node_Factory& new_Node) { Node join(const Node parameter_names, Environment& bindings, 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
Node l1(bindings[parameters[0].token()]); Node l1(bindings[parameter_names[0].token()]);
if (l1.type() != Node::space_list && l1.type() != Node::comma_list && l1.type() != Node::nil) { if (l1.type() != Node::space_list && l1.type() != Node::comma_list && l1.type() != Node::nil) {
l1 = new_Node(Node::space_list, l1.path(), l1.line(), 1) << l1; l1 = new_Node(Node::space_list, l1.path(), l1.line(), 1) << l1;
} }
Node l2(bindings[parameters[1].token()]); Node l2(bindings[parameter_names[1].token()]);
if (l2.type() != Node::space_list && l2.type() != Node::comma_list && l2.type() != Node::nil) { if (l2.type() != Node::space_list && l2.type() != Node::comma_list && l2.type() != Node::nil) {
l2 = new_Node(Node::space_list, l2.path(), l2.line(), 1) << l2; l2 = new_Node(Node::space_list, l2.path(), l2.line(), 1) << l2;
} }
...@@ -546,38 +649,25 @@ namespace Sass { ...@@ -546,38 +649,25 @@ namespace Sass {
if (l2.type() != Node::nil) size += l2.size(); if (l2.type() != Node::nil) size += l2.size();
// figure out the result type in advance // figure out the result type in advance
Node::Type rtype = Node::space_list; Node::Type rtype = Node::space_list;
if (has_sep) {
string sep(bindings[parameters[2].token()].token().unquote()); string sep(bindings[parameter_names[2].token()].token().unquote());
if (sep == "comma") rtype = Node::comma_list; if (sep == "comma") rtype = Node::comma_list;
else if (sep == "space") rtype = Node::space_list; else if (sep == "space") rtype = Node::space_list;
else if (sep == "auto") rtype = l1.type(); else if (sep == "auto") rtype = l1.type();
else { else {
throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", l2.path(), l2.line()); throw_eval_error("third argument to join must be 'space', 'comma', or 'auto'", l2.path(), l2.line());
}
} }
else if (l1.type() != Node::nil) rtype = l1.type(); if (rtype == Node::nil) rtype = l2.type();
else if (l2.type() != Node::nil) rtype = l2.type();
// accumulate the result // accumulate the result
Node lr(new_Node(rtype, l1.path(), l1.line(), size)); Node lr(new_Node(rtype, l1.path(), l1.line(), size));
if (l1.type() != Node::nil) lr += l1; if (l1.type() != Node::nil) lr += l1;
if (l2.type() != Node::nil) lr += l2; if (l2.type() != Node::nil) lr += l2;
return lr; return lr;
} }
Function_Descriptor join_2_descriptor =
{ "join 2", "$list1", "$list2", 0 };
Node join_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return join_impl(parameters, bindings, false, new_Node);
}
Function_Descriptor join_3_descriptor =
{ "join 3", "$list1", "$list2", "$separator", 0 };
Node join_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return join_impl(parameters, bindings, true, new_Node);
}
Node append_impl(const Node parameters, map<Token, Node>& bindings, bool has_sep, Node_Factory& new_Node) { extern Signature append_sig = "append($list1, $list2, $separator: auto)";
Node list(bindings[parameters[0].token()]); Node append(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node list(bindings[parameter_names[0].token()]);
switch (list.type()) switch (list.type())
{ {
case Node::space_list: case Node::space_list:
...@@ -590,37 +680,26 @@ namespace Sass { ...@@ -590,37 +680,26 @@ namespace Sass {
list = (new_Node(Node::space_list, list.path(), list.line(), 1) << list); list = (new_Node(Node::space_list, list.path(), list.line(), 1) << list);
} break; } break;
} }
Node::Type sep_type = list.type();
if (has_sep) { Node::Type sep_type;
string sep_string = bindings[parameters[2].token()].token().unquote(); string sep_string = bindings[parameter_names[2].token()].token().unquote();
if (sep_string == "comma") sep_type = Node::comma_list; if (sep_string == "comma") sep_type = Node::comma_list;
else if (sep_string == "space") sep_type = Node::space_list; else if (sep_string == "space") sep_type = Node::space_list;
else if (sep_string == "auto") sep_type = list.type(); else if (sep_string == "auto") sep_type = list.type();
else throw_eval_error("third argument to append must be 'space', 'comma', or 'auto'", list.path(), list.line()); else throw_eval_error("third argument to append must be 'space', 'comma', or 'auto'", list.path(), list.line());
}
Node new_list(new_Node(sep_type, list.path(), list.line(), list.size() + 1)); Node new_list(new_Node(sep_type, list.path(), list.line(), list.size() + 1));
new_list += list; new_list += list;
new_list << bindings[parameters[1].token()]; new_list << bindings[parameter_names[1].token()];
return new_list; return new_list;
} }
Function_Descriptor append_2_descriptor = extern Signature compact_sig = "compact($arg1: false, $arg2: false, $arg3: false, $arg4: false, $arg5: false, $arg6: false, $arg7: false, $arg8: false, $arg9: false, $arg10: false, $arg11: false, $arg12: false)";
{ "append 2", "$list", "$val", 0 }; Node compact(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node append_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { size_t num_args = bindings.current_frame.size();
return append_impl(parameters, bindings, false, new_Node);
}
Function_Descriptor append_3_descriptor =
{ "append 3", "$list", "$val", "$separator", 0 };
Node append_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
return append_impl(parameters, bindings, true, new_Node);
}
Node compact(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) {
size_t num_args = bindings.size();
Node::Type sep_type = Node::comma_list; Node::Type sep_type = Node::comma_list;
Node list; Node list;
Node arg1(bindings[parameters[0].token()]); Node arg1(bindings[parameter_names[0].token()]);
if (num_args == 1 && (arg1.type() == Node::space_list || if (num_args == 1 && (arg1.type() == Node::space_list ||
arg1.type() == Node::comma_list || arg1.type() == Node::comma_list ||
arg1.type() == Node::nil)) { arg1.type() == Node::nil)) {
...@@ -630,7 +709,7 @@ namespace Sass { ...@@ -630,7 +709,7 @@ namespace Sass {
else { else {
list = new_Node(sep_type, arg1.path(), arg1.line(), num_args); list = new_Node(sep_type, arg1.path(), arg1.line(), num_args);
for (size_t i = 0; i < num_args; ++i) { for (size_t i = 0; i < num_args; ++i) {
list << bindings[parameters[i].token()]; list << bindings[parameter_names[i].token()];
} }
} }
Node new_list(new_Node(list.type(), list.path(), list.line(), 0)); Node new_list(new_Node(list.type(), list.path(), list.line(), 0));
...@@ -642,40 +721,6 @@ namespace Sass { ...@@ -642,40 +721,6 @@ namespace Sass {
return new_list.size() ? new_list : new_Node(Node::nil, list.path(), list.line(), 0); return new_list.size() ? new_list : new_Node(Node::nil, list.path(), list.line(), 0);
} }
Function_Descriptor compact_1_descriptor =
{ "compact 1", "$arg1", 0 };
Function_Descriptor compact_2_descriptor =
{ "compact 2", "$arg1", "$arg2", 0 };
Function_Descriptor compact_3_descriptor =
{ "compact 3", "$arg1", "$arg2", "$arg3", 0 };
Function_Descriptor compact_4_descriptor =
{ "compact 4", "$arg1", "$arg2", "$arg3", "$arg4", 0 };
Function_Descriptor compact_5_descriptor =
{ "compact 5", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5", 0 };
Function_Descriptor compact_6_descriptor =
{ "compact 6", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5",
"$arg6", 0 };
Function_Descriptor compact_7_descriptor =
{ "compact 7", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5",
"$arg6", "$arg7", 0 };
Function_Descriptor compact_8_descriptor =
{ "compact 8", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5",
"$arg6", "$arg7", "$arg8", 0 };
Function_Descriptor compact_9_descriptor =
{ "compact 9", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5",
"$arg6", "$arg7", "$arg8", "$arg9", 0 };
Function_Descriptor compact_10_descriptor =
{ "compact 10", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5",
"$arg6", "$arg7", "$arg8", "$arg9", "$arg10", 0 };
Function_Descriptor compact_11_descriptor =
{ "compact 11", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5", "$arg6",
"$arg7", "$arg8", "$arg9", "$arg10", "$arg11", 0 };
Function_Descriptor compact_12_descriptor =
{ "compact 12", "$arg1", "$arg2", "$arg3", "$arg4", "$arg5", "arg6",
"$arg7", "$arg8", "$arg9", "$arg10", "$arg11", "$arg12", 0 };
// Introspection Functions ///////////////////////////////////////////// // Introspection Functions /////////////////////////////////////////////
extern const char number_name[] = "number"; extern const char number_name[] = "number";
...@@ -684,10 +729,9 @@ namespace Sass { ...@@ -684,10 +729,9 @@ namespace Sass {
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 = extern Signature type_of_sig = "type-of($value)";
{ "type-of", "$value", 0 }; Node type_of(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node type_of(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node val(bindings[parameter_names[0].token()]);
Node val(bindings[parameters[0].token()]);
Token type_name; Token type_name;
switch (val.type()) switch (val.type())
{ {
...@@ -723,10 +767,9 @@ namespace Sass { ...@@ -723,10 +767,9 @@ namespace Sass {
extern const char empty_str[] = ""; extern const char empty_str[] = "";
extern const char percent_str[] = "%"; extern const char percent_str[] = "%";
Function_Descriptor unit_descriptor = extern Signature unit_sig = "unit($number)";
{ "unit", "$number", 0 }; Node unit(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node unit(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node val(bindings[parameter_names[0].token()]);
Node val(bindings[parameters[0].token()]);
switch (val.type()) switch (val.type())
{ {
case Node::number: { case Node::number: {
...@@ -749,10 +792,9 @@ namespace Sass { ...@@ -749,10 +792,9 @@ namespace Sass {
extern const char true_str[] = "true"; extern const char true_str[] = "true";
extern const char false_str[] = "false"; extern const char false_str[] = "false";
Function_Descriptor unitless_descriptor = extern Signature unitless_sig = "unitless($number)";
{ "unitless", "$number", 0 }; Node unitless(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node unitless(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node val(bindings[parameter_names[0].token()]);
Node val(bindings[parameters[0].token()]);
switch (val.type()) switch (val.type())
{ {
case Node::number: { case Node::number: {
...@@ -772,11 +814,10 @@ namespace Sass { ...@@ -772,11 +814,10 @@ namespace Sass {
return Node(); return Node();
} }
Function_Descriptor comparable_descriptor = extern Signature comparable_sig = "comparable($number-1, $number-2)";
{ "comparable", "$number_1", "$number_2", 0 }; Node comparable(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node comparable(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node n1(bindings[parameter_names[0].token()]);
Node n1(bindings[parameters[0].token()]); Node n2(bindings[parameter_names[1].token()]);
Node n2(bindings[parameters[1].token()]);
Node::Type t1 = n1.type(); Node::Type t1 = n1.type();
Node::Type t2 = n2.type(); Node::Type t2 = n2.type();
if ((t1 == Node::number && n2.is_numeric()) || if ((t1 == Node::number && n2.is_numeric()) ||
...@@ -807,10 +848,9 @@ namespace Sass { ...@@ -807,10 +848,9 @@ namespace Sass {
} }
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
Function_Descriptor not_descriptor = extern Signature not_sig = "not($value)";
{ "not", "$value", 0 }; Node not_impl(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node not_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node val(bindings[parameter_names[0].token()]);
Node val(bindings[parameters[0].token()]);
if (val.type() == Node::boolean && val.boolean_value() == false) { if (val.type() == Node::boolean && val.boolean_value() == false) {
return new_Node(Node::boolean, val.path(), val.line(), true); return new_Node(Node::boolean, val.path(), val.line(), true);
} }
...@@ -819,12 +859,11 @@ namespace Sass { ...@@ -819,12 +859,11 @@ namespace Sass {
} }
} }
Function_Descriptor if_descriptor = extern Signature if_sig = "if($condition, $if-true, $if-false)";
{ "if", "$predicate", "$consequent", "$alternative", 0 }; Node if_impl(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
Node if_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node) { Node predicate(bindings[parameter_names[0].token()]);
Node predicate(bindings[parameters[0].token()]); Node consequent(bindings[parameter_names[1].token()]);
Node consequent(bindings[parameters[1].token()]); Node alternative(bindings[parameter_names[2].token()]);
Node alternative(bindings[parameters[2].token()]);
if (predicate.type() == Node::boolean && predicate.boolean_value() == false) return alternative; if (predicate.type() == Node::boolean && predicate.boolean_value() == false) return alternative;
return consequent; return consequent;
......
#define SASS_FUNCTIONS
#include <cstring> #include <cstring>
#include <map> #include <map>
...@@ -6,19 +8,19 @@ ...@@ -6,19 +8,19 @@
#endif #endif
namespace Sass { namespace Sass {
struct Environment;
struct Context;
using std::map; using std::map;
typedef Node (*Primitive)(const Node, map<Token, Node>&, Node_Factory& new_Node); typedef Node (*Primitive)(const Node, Environment&, Node_Factory&);
typedef const char* str; typedef const char Signature[];
typedef str Function_Descriptor[];
struct Environment;
struct Function { struct Function {
string name; string name;
// vector<Token> parameters;
Node parameters; Node parameters;
Node parameter_names;
Node definition; Node definition;
Primitive primitive; Primitive primitive;
bool overloaded; bool overloaded;
...@@ -26,6 +28,7 @@ namespace Sass { ...@@ -26,6 +28,7 @@ namespace Sass {
Function() Function()
{ /* TO DO: set up the generic callback here */ } { /* TO DO: set up the generic callback here */ }
// for user-defined functions
Function(Node def) Function(Node def)
: name(def[0].to_string()), : name(def[0].to_string()),
parameters(def[1]), parameters(def[1]),
...@@ -42,24 +45,10 @@ namespace Sass { ...@@ -42,24 +45,10 @@ namespace Sass {
primitive(0), primitive(0),
overloaded(overloaded) overloaded(overloaded)
{ } { }
Function(Function_Descriptor d, Primitive ip, Node_Factory& new_Node)
: name(d[0]),
parameters(new_Node(Node::parameters, "[PRIMITIVE FUNCTIONS]", 0, 0)),
definition(Node()),
primitive(ip),
overloaded(false)
{
size_t len = 0;
while (d[len+1]) ++len;
for (size_t i = 0; i < len; ++i) {
const char* p = d[i+1];
parameters.push_back(new_Node(Node::variable, "[PRIMITIVE FUNCTIONS]", 0, Token::make(p, p + std::strlen(p))));
}
}
Node operator()(map<Token, Node>& bindings, Node_Factory& new_Node) const Function(char* signature, Primitive ip, Context& ctx);
Node operator()(Environment& bindings, Node_Factory& new_Node) const
{ {
if (primitive) return primitive(parameters, bindings, new_Node); if (primitive) return primitive(parameters, bindings, new_Node);
else return Node(); else return Node();
...@@ -69,140 +58,129 @@ namespace Sass { ...@@ -69,140 +58,129 @@ namespace Sass {
namespace Functions { namespace Functions {
extern const char foo_sig[];
Node foo(const Node parameters, Environment& bindings, Node_Factory& new_Node);
// RGB Functions /////////////////////////////////////////////////////// // RGB Functions ///////////////////////////////////////////////////////
extern Function_Descriptor rgb_descriptor; extern Signature rgb_sig;
Node rgb(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node rgb(const Node, Environment&, Node_Factory&);
extern Function_Descriptor rgba_4_descriptor; extern Signature rgba_4_sig;
Node rgba_4(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node rgba_4(const Node, Environment&, Node_Factory&);
extern Function_Descriptor rgba_2_descriptor;
Node rgba_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor red_descriptor; extern Signature rgba_2_sig;
Node red(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node rgba_2(const Node, Environment&, Node_Factory&);
extern Function_Descriptor green_descriptor; extern Signature red_sig;
Node green(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node red(const Node, Environment&, Node_Factory&);
extern Function_Descriptor blue_descriptor; extern Signature green_sig;
Node blue(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node green(const Node, Environment&, Node_Factory&);
extern Function_Descriptor mix_2_descriptor; extern Signature blue_sig;
Node mix_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node blue(const Node, Environment&, Node_Factory&);
extern Function_Descriptor mix_3_descriptor; extern Signature mix_sig;
Node mix_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node mix(const Node, Environment&, Node_Factory&);
// HSL Functions /////////////////////////////////////////////////////// // HSL Functions ///////////////////////////////////////////////////////
extern Function_Descriptor hsla_descriptor; extern Signature hsla_sig;
Node hsla(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node hsla(const Node, Environment&, Node_Factory&);
extern Function_Descriptor hsl_descriptor; extern Signature hsl_sig;
Node hsl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node hsl(const Node, Environment&, Node_Factory&);
extern Function_Descriptor adjust_hue_descriptor; extern Signature adjust_hue_sig;
Node adjust_hue(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node adjust_hue(const Node, Environment&, Node_Factory&);
extern Function_Descriptor invert_descriptor; extern Signature adjust_color_sig;
Node invert(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node adjust_color(const Node, Environment&, Node_Factory&);
extern Signature change_color_sig;
Node change_color(const Node, Environment&, Node_Factory&);
extern Signature invert_sig;
Node invert(const Node, Environment&, Node_Factory&);
// Opacity Functions /////////////////////////////////////////////////// // Opacity Functions ///////////////////////////////////////////////////
extern Function_Descriptor alpha_descriptor; extern Signature alpha_sig;
extern Function_Descriptor opacity_descriptor; extern Signature opacity_sig;
Node alpha(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node alpha(const Node, Environment&, Node_Factory&);
extern Function_Descriptor opacify_descriptor; extern Signature opacify_sig;
extern Function_Descriptor fade_in_descriptor; extern Signature fade_in_sig;
Node opacify(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node opacify(const Node, Environment&, Node_Factory&);
extern Function_Descriptor transparentize_descriptor; extern Signature transparentize_sig;
extern Function_Descriptor fade_out_descriptor; extern Signature fade_out_sig;
Node transparentize(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node transparentize(const Node, Environment&, Node_Factory&);
// String Functions //////////////////////////////////////////////////// // String Functions ////////////////////////////////////////////////////
extern Function_Descriptor unquote_descriptor; extern Signature unquote_sig;
Node unquote(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unquote(const Node, Environment&, Node_Factory&);
extern Function_Descriptor quote_descriptor; extern Signature quote_sig;
Node quote(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node quote(const Node, Environment&, Node_Factory&);
// Number Functions //////////////////////////////////////////////////// // Number Functions ////////////////////////////////////////////////////
extern Function_Descriptor percentage_descriptor; extern Signature percentage_sig;
Node percentage(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node percentage(const Node, Environment&, Node_Factory&);
extern Function_Descriptor round_descriptor; extern Signature round_sig;
Node round(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node round(const Node, Environment&, Node_Factory&);
extern Function_Descriptor ceil_descriptor; extern Signature ceil_sig;
Node ceil(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node ceil(const Node, Environment&, Node_Factory&);
extern Function_Descriptor floor_descriptor; extern Signature floor_sig;
Node floor(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node floor(const Node, Environment&, Node_Factory&);
extern Function_Descriptor abs_descriptor; extern Signature abs_sig;
Node abs(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node abs(const Node, Environment&, Node_Factory&);
// List Functions ////////////////////////////////////////////////////// // List Functions //////////////////////////////////////////////////////
extern Function_Descriptor length_descriptor; extern Signature length_sig;
Node length(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node length(const Node, Environment&, Node_Factory&);
extern Function_Descriptor nth_descriptor; extern Signature nth_sig;
Node nth(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node nth(const Node, Environment&, Node_Factory&);
extern Function_Descriptor join_2_descriptor;
Node join_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor join_3_descriptor;
Node join_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor append_2_descriptor; extern Signature join_sig;
Node append_2(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node join(const Node, Environment&, Node_Factory&);
extern Function_Descriptor append_3_descriptor; extern Signature append_sig;
Node append_3(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node append(const Node, Environment&, Node_Factory&);
extern Function_Descriptor compact_1_descriptor; extern Signature compact_sig;
extern Function_Descriptor compact_2_descriptor; Node compact(const Node, Environment&, Node_Factory&);
extern Function_Descriptor compact_3_descriptor;
extern Function_Descriptor compact_4_descriptor;
extern Function_Descriptor compact_5_descriptor;
extern Function_Descriptor compact_6_descriptor;
extern Function_Descriptor compact_7_descriptor;
extern Function_Descriptor compact_8_descriptor;
extern Function_Descriptor compact_9_descriptor;
extern Function_Descriptor compact_10_descriptor;
extern Function_Descriptor compact_11_descriptor;
extern Function_Descriptor compact_12_descriptor;
Node compact(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
// Introspection Functions ///////////////////////////////////////////// // Introspection Functions /////////////////////////////////////////////
extern Function_Descriptor type_of_descriptor; extern Signature type_of_sig;
Node type_of(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node type_of(const Node, Environment&, Node_Factory&);
extern Function_Descriptor unit_descriptor; extern Signature unit_sig;
Node unit(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unit(const Node, Environment&, Node_Factory&);
extern Function_Descriptor unitless_descriptor; extern Signature unitless_sig;
Node unitless(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node unitless(const Node, Environment&, Node_Factory&);
extern Function_Descriptor comparable_descriptor; extern Signature comparable_sig;
Node comparable(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node comparable(const Node, Environment&, Node_Factory&);
// Boolean Functions /////////////////////////////////////////////////// // Boolean Functions ///////////////////////////////////////////////////
extern Function_Descriptor not_descriptor; extern Signature not_sig;
Node not_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node not_impl(const Node, Environment&, Node_Factory&);
extern Function_Descriptor if_descriptor; extern Signature if_sig;
Node if_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node if_impl(const Node, Environment&, Node_Factory&);
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
namespace Sass { namespace Sass {
using namespace std; using namespace std;
// Token type for representing lexed chunks of text
struct Token { struct Token {
const char* begin; const char* begin;
const char* end; const char* end;
...@@ -61,6 +62,7 @@ namespace Sass { ...@@ -61,6 +62,7 @@ namespace Sass {
struct Node_Impl; struct Node_Impl;
// Node type for representing SCSS expression nodes. Really just a handle.
class Node { class Node {
private: private:
friend class Node_Factory; friend class Node_Factory;
...@@ -189,6 +191,7 @@ namespace Sass { ...@@ -189,6 +191,7 @@ namespace Sass {
bool is_numeric() const; bool is_numeric() const;
bool is_guarded() const; bool is_guarded() const;
bool& has_been_extended() const; bool& has_been_extended() const;
bool is_false() const;
string& path() const; string& path() const;
size_t line() const; size_t line() const;
...@@ -237,6 +240,7 @@ namespace Sass { ...@@ -237,6 +240,7 @@ namespace Sass {
}; };
// The actual implementation object for Nodes; Node handles point at these.
struct Node_Impl { struct Node_Impl {
union value_t { union value_t {
bool boolean; bool boolean;
...@@ -399,6 +403,7 @@ namespace Sass { ...@@ -399,6 +403,7 @@ namespace Sass {
inline bool Node::is_numeric() const { return ip_->is_numeric(); } inline bool Node::is_numeric() const { return ip_->is_numeric(); }
inline bool Node::is_guarded() const { return (type() == assignment) && (size() == 3); } inline bool Node::is_guarded() const { return (type() == assignment) && (size() == 3); }
inline bool& Node::has_been_extended() const { return ip_->has_been_extended; } inline bool& Node::has_been_extended() const { return ip_->has_been_extended; }
inline bool Node::is_false() const { return (type() == boolean) && (boolean_value() == false); }
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; }
......
#define SASS_NODE_FACTORY
#include <vector> #include <vector>
#ifndef SASS_NODE #ifndef SASS_NODE
......
#define SASS_INTERFACE
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
......
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