Commit 863cddce by Aaron Leung

Trying out new scheme built-in function definitions. Allows built-ins to have…

Trying out new scheme built-in function definitions. Allows built-ins to have default args and whatnot, and to be specified more easily than before.
parent d74cdbb2
...@@ -90,6 +90,12 @@ namespace Sass { ...@@ -90,6 +90,12 @@ namespace Sass {
function_env[f.name] = f; function_env[f.name] = f;
} }
inline void Context::register_function_2(const char* sig, Primitive_2 ip)
{
Function f(const_cast<char*>(sig), ip, *this);
function_env[f.name] = f;
}
inline void Context::register_overload_stub(string name) inline void Context::register_overload_stub(string name)
{ {
function_env[name] = Function(name, true); function_env[name] = Function(name, true);
...@@ -98,6 +104,8 @@ namespace Sass { ...@@ -98,6 +104,8 @@ namespace Sass {
void Context::register_functions() void Context::register_functions()
{ {
using namespace Functions; using namespace Functions;
register_function_2(foo_sig, foo);
// RGB Functions // RGB Functions
register_function(rgb_descriptor, rgb); register_function(rgb_descriptor, rgb);
register_overload_stub("rgba"); register_overload_stub("rgba");
......
...@@ -37,7 +37,8 @@ namespace Sass { ...@@ -37,7 +37,8 @@ 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_2(const char* sig, Primitive_2 ip);
void register_function(Function_Descriptor d, Primitive ip); void register_function(Function_Descriptor d, Primitive ip);
void register_function(Function_Descriptor d, Primitive ip, size_t arity); void register_function(Function_Descriptor d, Primitive ip, size_t arity);
void register_overload_stub(string name); void register_overload_stub(string name);
......
...@@ -706,7 +706,23 @@ namespace Sass { ...@@ -706,7 +706,23 @@ namespace Sass {
// 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<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_2) {
// evaluate arguments in the current environment
for (size_t i = 0, S = args.size(); i < S; ++i) {
if (args[i].type() != Node::assignment) {
args[i] = eval(args[i], prefix, env, f_env, new_Node, ctx);
}
else {
args[i][1] = eval(args[i][1], prefix, env, f_env, new_Node, ctx);
}
}
// 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_2(f.parameter_names, bindings, new_Node);
}
else if (f.primitive) {
map<Token, Node> bindings; map<Token, Node> bindings;
// bind arguments // bind arguments
for (size_t i = 0, j = 0, S = args.size(); i < S; ++i) { for (size_t i = 0, j = 0, S = args.size(); i < S; ++i) {
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "node_factory.hpp" #include "node_factory.hpp"
#include "functions.hpp" #include "functions.hpp"
#include "context.hpp" #include "context.hpp"
#include "document.hpp"
#include "eval_apply.hpp"
#include "error.hpp" #include "error.hpp"
#include <iostream> #include <iostream>
...@@ -14,9 +16,27 @@ using std::cerr; using std::endl; ...@@ -14,9 +16,27 @@ using std::cerr; using std::endl;
namespace Sass { namespace Sass {
Function::Function(const char* signature, Primitive ip, Node_Factory& new_Node) // this constructor needs context.hpp, so it can't be defined in functions.hpp
Function::Function(char* signature, Primitive_2 ip, Context& ctx)
: primitive_2(ip),
overloaded(false)
{ {
//Document sig_doc(Document::make_from_source_chars( 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];
// assuming default args for primitives can be evaluated only once at init
param[1] = eval(param[1], Node(), ctx.global_env, ctx.function_env, ctx.new_Node, ctx);
}
}
} }
...@@ -30,9 +50,15 @@ namespace Sass { ...@@ -30,9 +50,15 @@ namespace Sass {
throw Error(Error::evaluation, path, line, message); throw Error(Error::evaluation, path, line, message);
} }
extern const char foo_sig[] = "foo($x, $y, $z: hey hey)"; extern const char foo_sig[] = "foo($x, $y, $z: \"hey\")";
Node foo(const Node parameters, Environment& bindings, Node_Factory& new_Node) { Node foo(const Node parameter_names, Environment& bindings, Node_Factory& new_Node) {
return 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 ///////////////////////////////////////////////////////
......
...@@ -8,21 +8,25 @@ ...@@ -8,21 +8,25 @@
#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, map<Token, Node>&, Node_Factory& new_Node);
typedef Node (*Primitive_2)(const Node, Environment&, Node_Factory&);
typedef const char* str; typedef const char* str;
typedef str Function_Descriptor[]; typedef str Function_Descriptor[];
struct Environment;
struct Function { struct Function {
string name; string name;
// vector<Token> parameters; // vector<Token> parameters;
Node parameters; Node parameters;
Node parameter_names;
Node definition; Node definition;
Primitive primitive; Primitive primitive;
Primitive_2 primitive_2;
bool overloaded; bool overloaded;
Function() Function()
...@@ -34,6 +38,7 @@ namespace Sass { ...@@ -34,6 +38,7 @@ namespace Sass {
parameters(def[1]), parameters(def[1]),
definition(def), definition(def),
primitive(0), primitive(0),
primitive_2(0),
overloaded(false) overloaded(false)
{ } { }
...@@ -43,16 +48,18 @@ namespace Sass { ...@@ -43,16 +48,18 @@ namespace Sass {
parameters(Node()), parameters(Node()),
definition(Node()), definition(Node()),
primitive(0), primitive(0),
primitive_2(0),
overloaded(overloaded) overloaded(overloaded)
{ } { }
Function(const char* signature, Primitive ip, Node_Factory& new_Node); Function(char* signature, Primitive_2 ip, Context& ctx);
Function(Function_Descriptor d, Primitive ip, Node_Factory& new_Node) Function(Function_Descriptor d, Primitive ip, Node_Factory& new_Node)
: name(d[0]), : name(d[0]),
parameters(new_Node(Node::parameters, "[PRIMITIVE FUNCTIONS]", 0, 0)), parameters(new_Node(Node::parameters, "[PRIMITIVE FUNCTIONS]", 0, 0)),
definition(Node()), definition(Node()),
primitive(ip), primitive(ip),
primitive_2(0),
overloaded(false) overloaded(false)
{ {
size_t len = 0; size_t len = 0;
...@@ -74,6 +81,9 @@ namespace Sass { ...@@ -74,6 +81,9 @@ 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 Function_Descriptor rgb_descriptor;
......
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