Commit d008daf9 by Aaron Leung

Built-in function framework is in place. Had to jump through some hoops to…

Built-in function framework is in place. Had to jump through some hoops to resolve the usual #include dependency headaches.
parent 213cf18c
build: sassc.cpp document.cpp node.cpp values.cpp prelexer.cpp build: sassc.cpp document.cpp node.cpp values.cpp prelexer.cpp
g++ -o bin/sassc sassc.cpp document.cpp document_parser.cpp eval_apply.cpp node.cpp values.cpp prelexer.cpp g++ -o bin/sassc sassc.cpp context.cpp functions.cpp document.cpp document_parser.cpp eval_apply.cpp node.cpp values.cpp prelexer.cpp
test: build test: build
ruby spec.rb spec/basic/ ruby spec.rb spec/basic/
......
#include "context.hpp"
#include <iostream>
using std::cerr; using std::endl;
namespace Sass {
Context::Context()
: global_env(Environment()),
function_env(map<string, Function>()),
source_refs(vector<char*>()),
ref_count(0)
{
register_functions();
}
Context::~Context()
{
for (int i = 0; i < source_refs.size(); ++i) {
delete[] source_refs[i];
}
}
inline void Context::register_function(Function_Descriptor d, Implementation ip)
{
function_env[d[0]] = Function(d, ip);
cerr << "Registered function: " << d[0] << endl;
cerr << "Verifying " << function_env[string(d[0])].name << endl;
}
void Context::register_functions()
{
using namespace Functions;
register_function(rgb_descriptor, rgb);
register_function(rgba_descriptor, rgba);
}
}
\ No newline at end of file
#define SASS_CONTEXT_INCLUDED #define SASS_CONTEXT_INCLUDED
#include <map>
#include "functions.hpp" #include "functions.hpp"
namespace Sass { namespace Sass {
...@@ -41,17 +42,11 @@ namespace Sass { ...@@ -41,17 +42,11 @@ namespace Sass {
vector<char*> source_refs; vector<char*> source_refs;
size_t ref_count; size_t ref_count;
Context() Context();
: source_refs(vector<char*>()), ~Context();
ref_count(0)
{ }
~Context() void register_function(Function_Descriptor d, Implementation ip);
{ void register_functions();
for (int i = 0; i < source_refs.size(); ++i) {
delete[] source_refs[i];
}
}
}; };
} }
...@@ -524,20 +524,20 @@ namespace Sass { ...@@ -524,20 +524,20 @@ namespace Sass {
return result; return result;
} }
if (lex< rgb_prefix >()) // if (lex< rgb_prefix >())
{ // {
Node result(Node::numeric_color, line_number, 3); // Node result(Node::numeric_color, line_number, 3);
lex< number >(); // lex< number >();
result << Node(line_number, std::atof(lexed.begin)); // result << Node(line_number, std::atof(lexed.begin));
lex< exactly<','> >(); // lex< exactly<','> >();
lex< number >(); // lex< number >();
result << Node(line_number, std::atof(lexed.begin)); // result << Node(line_number, std::atof(lexed.begin));
lex< exactly<','> >(); // lex< exactly<','> >();
lex< number >(); // lex< number >();
result << Node(line_number, std::atof(lexed.begin)); // result << Node(line_number, std::atof(lexed.begin));
lex< exactly<')'> >(); // lex< exactly<')'> >();
return result; // return result;
} // }
if (peek< functional >()) if (peek< functional >())
{ return parse_function_call(); } { return parse_function_call(); }
...@@ -575,6 +575,7 @@ namespace Sass { ...@@ -575,6 +575,7 @@ namespace Sass {
Node args(parse_arguments()); Node args(parse_arguments());
Node call(Node::function_call, line_number, 2); Node call(Node::function_call, line_number, 2);
call << name << args; call << name << args;
call.eval_me = true;
return call; return call;
} }
......
...@@ -148,6 +148,7 @@ namespace Sass { ...@@ -148,6 +148,7 @@ namespace Sass {
case Node::function_call: { case Node::function_call: {
// TO DO: default-constructed Function should be a generic callback // TO DO: default-constructed Function should be a generic callback
cerr << "about to apply " << expr[0].content.token.to_string() << endl;
return apply_function(f_env[expr[0].content.token.to_string()], expr[1], env, f_env); return apply_function(f_env[expr[0].content.token.to_string()], expr[1], env, f_env);
} break; } break;
...@@ -289,8 +290,7 @@ namespace Sass { ...@@ -289,8 +290,7 @@ namespace Sass {
Node apply_function(const Function& f, const Node& args, Environment& env, map<string, Function>& f_env) Node apply_function(const Function& f, const Node& args, Environment& env, map<string, Function>& f_env)
{ {
Node params(f.parameters); map<Token, Node> bindings;
Environment bindings;
// bind arguments // bind arguments
for (int i = 0, j = 0; i < args.size(); ++i) { for (int i = 0, j = 0; i < args.size(); ++i) {
if (args[i].type == Node::assignment) { if (args[i].type == Node::assignment) {
...@@ -299,10 +299,8 @@ namespace Sass { ...@@ -299,10 +299,8 @@ namespace Sass {
bindings[name] = eval(arg[1], env, f_env); bindings[name] = eval(arg[1], env, f_env);
} }
else { else {
// TO DO: ensure (j < params.size()) // TO DO: ensure (j < f.parameters.size())
Node param(params[j]); bindings[f.parameters[j]] = eval(args[i], env, f_env);
Token name(param.type == Node::variable ? param.content.token : param[0].content.token);
bindings[name] = eval(args[i], env, f_env);
++j; ++j;
} }
} }
......
#include "functions.hpp" #include "functions.hpp"
#include "node.hpp" #include <iostream>
using std::cerr; using std::endl;
namespace Sass { namespace Sass {
namespace Functions { namespace Functions {
extern const char* rgb_metadata[] = { // TO DO: functions need to check the types of their arguments
"rgb",
"$red", Function_Descriptor rgb_descriptor =
"$green", { "rgb", "$red", "$green", "$blue", 0 };
"$blue", Node rgb(const vector<Token>& parameters, map<Token, Node>& bindings) {
0 cerr << "rgb arg count: " << bindings.size() << endl;
};
Node rgb(const vector<Token>& param_names, const Environment& bindings) {
Node color(Node::numeric_color, 0, 3); Node color(Node::numeric_color, 0, 3);
color << bindings[param_names[0]] color << bindings[parameters[0]]
<< bindings[param_names[1]] << bindings[parameters[1]]
<< bindings[param_names[2]]; << bindings[parameters[2]];
return color; return color;
} }
extern const char* rgba_metadata[] = { Function_Descriptor rgba_descriptor =
"rgba", { "rgba", "$red", "$green", "$blue", "$alpha", 0 };
"$red", Node rgba(const vector<Token>& parameters, map<Token, Node>& bindings) {
"$green", Node color(Node::numeric_color, 0, 4);
"$blue", color << bindings[parameters[0]]
"$alpha", << bindings[parameters[1]]
0 << bindings[parameters[2]]
}; << bindings[parameters[3]];
Node rgba(const vector<Token>& param_names, const Environment& bindings) {
Node color(Node::numeric_color, 0, 3);
color << bindings[param_names[0]]
<< bindings[param_names[1]]
<< bindings[param_names[2]]
<< bindings[param_names[3]];
return color; return color;
} }
}
} }
\ No newline at end of file
#include <cstring>
#include <map>
#ifndef SASS_NODE_INCLUDED
#include "node.hpp"
#endif
namespace Sass { namespace Sass {
using std::map;
struct Environment; typedef Node (*Implementation)(const vector<Token>&, map<Token, Node>&);
typedef const char* str;
typedef str Function_Descriptor[];
struct Function { struct Function {
typedef Node (*Primitive)(const Node&, const Environment&);
string name; string name;
Node parameters; vector<Token> parameters;
vector<Token> param_names; Implementation implementation;
Primitive primitive;
Function() Function()
{ } { /* TO DO: set up the generic callback here */ }
Function(Function_Descriptor d, Implementation ip)
: name(d[0]),
parameters(vector<Token>()),
implementation(ip)
{
size_t len = 0;
while (d[len+1]) ++len;
parameters.reserve(len);
for (int i = 0; i < len; ++i) {
const char* p = d[i+1];
Token name(Token::make(p, p + std::strlen(p)));
parameters.push_back(name);
}
}
Node operator()(map<Token, Node>& bindings) const
{ return implementation(parameters, bindings); }
Function(string name, Node parameters, Primitive primitive) };
: name(name), parameters(parameters), primitive(primitive)
{ }
Node operator()(const Environment& bindings) const namespace Functions {
{ return primitive(parameters, bindings); } extern Function_Descriptor rgb_descriptor;
Node rgb(const vector<Token>& parameters, map<Token, Node>& bindings);
}; extern Function_Descriptor rgba_descriptor;
Node rgba(const vector<Token>& parameters, map<Token, Node>& bindings);
}
} }
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