Commit f0f9eab1 by Aaron Leung

Merge branch 'master' into func_resolver

Conflicts:
	functions.cpp
parents eb153df1 d5875e5e
...@@ -153,7 +153,7 @@ namespace Sass { ...@@ -153,7 +153,7 @@ namespace Sass {
"yellowgreen", "yellowgreen",
// sentinel value // sentinel value
0 0
} };
const double color_values[] = const double color_values[] =
{ {
...@@ -306,6 +306,6 @@ namespace Sass { ...@@ -306,6 +306,6 @@ namespace Sass {
0x9a, 0xcd, 0x32, 0x9a, 0xcd, 0x32,
// sentinel value // sentinel value
0xfff 0xfff
} };
} }
\ No newline at end of file
#include "context.hpp" #include "context.hpp"
#include <cstring>
#include <iostream> #include <iostream>
#include <unistd.h> #include <unistd.h>
#include "prelexer.hpp" #include "prelexer.hpp"
#include "color_names.hpp"
using std::cerr; using std::endl; using std::cerr; using std::endl;
namespace Sass { namespace Sass {
...@@ -40,19 +42,28 @@ namespace Sass { ...@@ -40,19 +42,28 @@ namespace Sass {
// } // }
} }
Context::Context(const char* paths_str) Context::Context(const char* paths_str, const char* img_path_str)
: global_env(Environment()), : global_env(Environment()),
function_env(map<string, Function>()), function_env(map<string, Function>()),
extensions(multimap<Node, Node>()), extensions(multimap<Node, Node>()),
pending_extensions(vector<pair<Node, Node> >()), pending_extensions(vector<pair<Node, Node> >()),
source_refs(vector<char*>()), source_refs(vector<char*>()),
include_paths(vector<string>()), include_paths(vector<string>()),
color_names_to_values(map<string, Node>()),
color_values_to_names(map<Node, string>()),
new_Node(Node_Factory()), new_Node(Node_Factory()),
image_path(0),
ref_count(0), ref_count(0),
has_extensions(false) has_extensions(false)
{ {
register_functions(); register_functions();
collect_include_paths(paths_str); collect_include_paths(paths_str);
setup_color_map();
string path_string(img_path_str ? img_path_str : "");
path_string = "'" + path_string + "/'";
image_path = new char[path_string.length() + 1];
std::strcpy(image_path, path_string.c_str());
} }
Context::~Context() Context::~Context()
...@@ -60,7 +71,7 @@ namespace Sass { ...@@ -60,7 +71,7 @@ namespace Sass {
for (size_t i = 0; i < source_refs.size(); ++i) { for (size_t i = 0; i < source_refs.size(); ++i) {
delete[] source_refs[i]; delete[] source_refs[i];
} }
delete[] image_path;
new_Node.free(); new_Node.free();
// cerr << "Deallocated " << i << " source string(s)." << endl; // cerr << "Deallocated " << i << " source string(s)." << endl;
} }
...@@ -148,6 +159,23 @@ namespace Sass { ...@@ -148,6 +159,23 @@ namespace Sass {
register_function(comparable_descriptor, comparable); register_function(comparable_descriptor, comparable);
// Boolean Functions // Boolean Functions
register_function(not_descriptor, not_impl); register_function(not_descriptor, not_impl);
register_function(if_descriptor, if_impl);
}
void Context::setup_color_map()
{
size_t i = 0;
while (color_names[i]) {
string name(color_names[i]);
Node value(new_Node("[COLOR TABLE]", 0,
color_values[i*3],
color_values[i*3+1],
color_values[i*3+2],
1));
color_names_to_values[name] = value;
color_values_to_names[value] = name;
++i;
}
} }
} }
...@@ -47,20 +47,24 @@ namespace Sass { ...@@ -47,20 +47,24 @@ namespace Sass {
vector<pair<Node, Node> > pending_extensions; vector<pair<Node, Node> > pending_extensions;
vector<char*> source_refs; // all the source c-strings vector<char*> source_refs; // all the source c-strings
vector<string> include_paths; vector<string> include_paths;
map<string, Node> color_names_to_values;
map<Node, string> color_values_to_names;
Node_Factory new_Node; Node_Factory new_Node;
char* image_path;
size_t ref_count; size_t ref_count;
string sass_path; // string sass_path;
string css_path; // string css_path;
bool has_extensions; bool has_extensions;
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, const char* img_path_str = 0);
~Context(); ~Context();
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);
void register_functions(); void register_functions();
void setup_color_map();
}; };
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "error.hpp" #include "error.hpp"
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <sys/stat.h>
namespace Sass { namespace Sass {
...@@ -30,28 +31,28 @@ namespace Sass { ...@@ -30,28 +31,28 @@ namespace Sass {
{ {
std::FILE *f; std::FILE *f;
const char* path_str = path.c_str(); const char* path_str = path.c_str();
f = std::fopen(path_str, "rb"); struct stat st;
if (!f) { string tmp;
string path_with_extension(path + ".scss"); if (stat(path_str, &st) == -1 || S_ISDIR(st.st_mode)) {
f = std::fopen(path_with_extension.c_str(), "rb"); tmp = path + ".scss";
if (!f) { path_str = tmp.c_str();
const char* file_name_str = Prelexer::folders(path_str); if (stat(path_str, &st) == -1 || S_ISDIR(st.st_mode)) {
string path_with_underscore(Token::make(path_str, file_name_str).to_string() + const char *full_path_str = path.c_str();
"_" + const char *file_name_str = Prelexer::folders(full_path_str);
Token::make(file_name_str).to_string()); tmp = Token::make(full_path_str, file_name_str).to_string() +
f = std::fopen(path_with_underscore.c_str(), "rb"); "_" +
if (!f) { string(file_name_str);
string path_with_underscore_and_extension(path_with_underscore + ".scss"); path_str = tmp.c_str();
f = std::fopen(path_with_underscore_and_extension.c_str(), "rb"); if (stat(path_str, &st) == -1 || S_ISDIR(st.st_mode)) {
if (!f) throw path; tmp = tmp + ".scss";
path_str = tmp.c_str();
if (stat(path_str, &st) == -1 || S_ISDIR(st.st_mode))
throw path;
}
} }
}
} }
if (std::fseek(f, 0, SEEK_END)) throw path; f = std::fopen(path_str, "rb");
int status = std::ftell(f); size_t len = st.st_size;
if (status < 0) throw path;
size_t len = status;
std::rewind(f);
char* source = new char[len + 1]; char* source = new char[len + 1];
size_t bytes_read = std::fread(source, sizeof(char), len, f); size_t bytes_read = std::fread(source, sizeof(char), len, f);
if (bytes_read != len) { if (bytes_read != len) {
...@@ -61,10 +62,12 @@ namespace Sass { ...@@ -61,10 +62,12 @@ namespace Sass {
source[len] = '\0'; source[len] = '\0';
char* end = source + len; char* end = source + len;
if (std::fclose(f)) throw path; if (std::fclose(f)) throw path;
const char *file_name_str = Prelexer::folders(path_str);
string include_path(path_str, file_name_str - path_str);
Document doc(ctx); Document doc(ctx);
doc.path = path; doc.path = path;
doc.line = 1; doc.line = 1;
doc.root = ctx.new_Node(Node::root, path, 1, 0); doc.root = ctx.new_Node(Node::root, path, 1, 0);
doc.lexed = Token::make(); doc.lexed = Token::make();
doc.own_source = true; doc.own_source = true;
...@@ -72,6 +75,9 @@ namespace Sass { ...@@ -72,6 +75,9 @@ namespace Sass {
doc.end = end; doc.end = end;
doc.position = source; doc.position = source;
doc.context.source_refs.push_back(source); doc.context.source_refs.push_back(source);
if (!include_path.empty()) {
doc.context.include_paths.push_back(include_path);
}
return doc; return doc;
} }
...@@ -136,7 +142,8 @@ namespace Sass { ...@@ -136,7 +142,8 @@ namespace Sass {
// trim trailing whitespace // trim trailing whitespace
if (!retval.empty()) { if (!retval.empty()) {
size_t newlines = 0; size_t newlines = 0;
for (size_t i = retval.length() - 1; i >= 0; --i) { size_t i = retval.length();
while (i--) {
if (retval[i] == '\n') { if (retval[i] == '\n') {
++newlines; ++newlines;
continue; continue;
......
...@@ -101,17 +101,16 @@ namespace Sass { ...@@ -101,17 +101,16 @@ namespace Sass {
if (!lex< string_constant >()) throw_syntax_error("@import directive requires a url or quoted path"); if (!lex< string_constant >()) throw_syntax_error("@import directive requires a url or quoted path");
// TO DO: BETTER PATH HANDLING // TO DO: BETTER PATH HANDLING
string import_path(lexed.unquote()); string import_path(lexed.unquote());
const char* curr_path_start = path.c_str(); for (vector<string>::iterator path = context.include_paths.begin(); path < context.include_paths.end(); ++path) {
const char* curr_path_end = folders(curr_path_start); try {
string current_path(curr_path_start, curr_path_end - curr_path_start); Document importee(Document::make_from_file(context, *path + import_path));
try { importee.parse_scss();
Document importee(Document::make_from_file(context, current_path + import_path)); return importee.root;
importee.parse_scss(); }
return importee.root; catch (string& path) {
} }
catch (string& path) {
throw_read_error("error reading file \"" + path + "\"");
} }
throw_read_error("error reading file \"" + import_path + "\"");
// unreached statement // unreached statement
return Node(); return Node();
} }
...@@ -814,14 +813,26 @@ namespace Sass { ...@@ -814,14 +813,26 @@ namespace Sass {
const char* value = position; const char* value = position;
const char* rparen = find_first< exactly<')'> >(position); const char* rparen = find_first< exactly<')'> >(position);
if (!rparen) throw_syntax_error("URI is missing ')'"); if (!rparen) throw_syntax_error("URI is missing ')'");
Token contents(Token::make(value, rparen)); Token content_tok(Token::make(value, rparen));
Node content_node(context.new_Node(Node::string_constant, path, line, content_tok));
// lex< string_constant >(); // lex< string_constant >();
Node result(context.new_Node(Node::uri, path, line, contents)); Node result(context.new_Node(Node::uri, path, line, 1));
result << content_node;
position = rparen; position = rparen;
lex< exactly<')'> >(); lex< exactly<')'> >();
return result; return result;
} }
if (lex< image_url_prefix >())
{
Node url(parse_value());
if (!lex< exactly<')'> >()) throw_syntax_error("call to image-url is missing ')'");
Node the_call(context.new_Node(Node::image_url, path, line, 1));
the_call << url;
the_call.should_eval() = true;
return the_call;
}
if (peek< functional >()) if (peek< functional >())
{ return parse_function_call(); } { return parse_function_call(); }
...@@ -1197,4 +1208,4 @@ namespace Sass { ...@@ -1197,4 +1208,4 @@ namespace Sass {
return result; return result;
} }
} }
\ No newline at end of file
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include "eval_apply.hpp" #include "eval_apply.hpp"
#include "document.hpp" #include "document.hpp"
#include "error.hpp" #include "error.hpp"
#include <cctype>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <cstdlib> #include <cstdlib>
...@@ -19,7 +20,7 @@ namespace Sass { ...@@ -19,7 +20,7 @@ namespace Sass {
// Evaluate the parse tree in-place (mostly). Most nodes will be left alone. // Evaluate the parse tree in-place (mostly). Most nodes will be left alone.
Node eval(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx) Node eval(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx, bool function_name)
{ {
switch (expr.type()) switch (expr.type())
{ {
...@@ -287,12 +288,22 @@ namespace Sass { ...@@ -287,12 +288,22 @@ namespace Sass {
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::image_url: {
Node base(eval(expr[0], prefix, env, f_env, new_Node, ctx));
Node prefix(new_Node(Node::identifier, base.path(), base.line(), Token::make(ctx.image_path)));
Node fullpath(new_Node(Node::concatenation, base.path(), base.line(), 2));
Node url(new_Node(Node::uri, base.path(), base.line(), 1));
fullpath << prefix << base;
url << fullpath;
return url;
} break;
case Node::function_call: { case Node::function_call: {
// TO DO: default-constructed Function should be a generic callback (maybe) // TO DO: default-constructed Function should be a generic callback (maybe)
// eval the function name in case it's interpolated // eval the function name in case it's interpolated
expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx); expr[0] = eval(expr[0], prefix, env, f_env, new_Node, ctx, true);
string name(expr[0].to_string()); string name(expr[0].to_string());
if (!f_env.count(name)) { if (!f_env.count(name)) {
// no definition available; just pass it through (with evaluated args) // no definition available; just pass it through (with evaluated args)
...@@ -337,6 +348,17 @@ namespace Sass { ...@@ -337,6 +348,17 @@ namespace Sass {
return expr; return expr;
} }
} break; } break;
case Node::identifier: {
string id_str(expr.to_string());
to_lowercase(id_str);
if (!function_name && ctx.color_names_to_values.count(id_str)) {
return ctx.color_names_to_values[id_str];
}
else {
return expr;
}
} break;
case Node::string_schema: case Node::string_schema:
case Node::value_schema: case Node::value_schema:
...@@ -1258,4 +1280,7 @@ namespace Sass { ...@@ -1258,4 +1280,7 @@ namespace Sass {
Node selector_butlast(Node sel, Node_Factory& new_Node) Node selector_butlast(Node sel, Node_Factory& new_Node)
{ return selector_but(sel, new_Node, 0, 1); } { return selector_but(sel, new_Node, 0, 1); }
void to_lowercase(string& s)
{ for (size_t i = 0, L = s.length(); i < L; ++i) s[i] = tolower(s[i]); }
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
namespace Sass { namespace Sass {
using std::map; using std::map;
Node eval(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx); Node eval(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx, bool function_name = false);
Node function_eval(string name, Node stm, Environment& bindings, Node_Factory& new_Node, Context& ctx, bool toplevel = false); Node function_eval(string name, Node stm, Environment& bindings, Node_Factory& new_Node, Context& ctx, bool toplevel = false);
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);
...@@ -29,4 +29,5 @@ namespace Sass { ...@@ -29,4 +29,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);
void to_lowercase(string& s);
} }
\ No newline at end of file
...@@ -199,6 +199,9 @@ namespace Sass { ...@@ -199,6 +199,9 @@ namespace Sass {
extern Function_Descriptor not_descriptor; extern Function_Descriptor not_descriptor;
Node not_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node); Node not_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
extern Function_Descriptor if_descriptor;
Node if_impl(const Node parameters, map<Token, Node>& bindings, Node_Factory& new_Node);
} }
} }
...@@ -128,6 +128,7 @@ namespace Sass { ...@@ -128,6 +128,7 @@ namespace Sass {
value, value,
identifier, identifier,
uri, uri,
image_url,
textual_percentage, textual_percentage,
textual_dimension, textual_dimension,
textual_number, textual_number,
...@@ -182,8 +183,8 @@ namespace Sass { ...@@ -182,8 +183,8 @@ namespace Sass {
bool has_backref() const; bool has_backref() const;
bool from_variable() const; bool from_variable() const;
bool& should_eval() const; bool& should_eval() const;
bool& is_unquoted() const; bool& is_unquoted() const; // for strings
bool& is_quoted() const; bool& is_quoted() const; // for identifiers
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;
......
...@@ -268,7 +268,8 @@ namespace Sass { ...@@ -268,7 +268,8 @@ namespace Sass {
case uri: { case uri: {
string result("url("); string result("url(");
result += token().to_string(); // result += token().to_string();
result += at(0).to_string();
result += ")"; result += ")";
return result; return result;
} break; } break;
......
...@@ -278,6 +278,11 @@ namespace Sass { ...@@ -278,6 +278,11 @@ namespace Sass {
optional<spaces>, optional<spaces>,
exactly<')'> >(src); exactly<')'> >(src);
} }
// Match SCSS image-url function
extern const char image_url_kwd[] = "image-url(";
const char* image_url_prefix(const char* src) {
return exactly<image_url_kwd>(src);
}
// Match CSS "!important" keyword. // Match CSS "!important" keyword.
extern const char important_kwd[] = "important"; extern const char important_kwd[] = "important";
const char* important(const char* src) { const char* important(const char* src) {
......
...@@ -354,6 +354,8 @@ namespace Sass { ...@@ -354,6 +354,8 @@ namespace Sass {
// Match CSS uri specifiers. // Match CSS uri specifiers.
const char* uri_prefix(const char* src); const char* uri_prefix(const char* src);
const char* uri(const char* src); const char* uri(const char* src);
// Match SCSS image-url function.
const char* image_url_prefix(const char* src);
// Match CSS "!important" keyword. // Match CSS "!important" keyword.
const char* important(const char* src); const char* important(const char* src);
// Match Sass "!default" keyword. // Match Sass "!default" keyword.
......
...@@ -13,7 +13,7 @@ extern "C" { ...@@ -13,7 +13,7 @@ extern "C" {
using namespace std; using namespace std;
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)
{ {
...@@ -24,7 +24,7 @@ extern "C" { ...@@ -24,7 +24,7 @@ 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)
{ {
...@@ -58,7 +58,8 @@ extern "C" { ...@@ -58,7 +58,8 @@ extern "C" {
{ {
using namespace Sass; using namespace Sass;
try { try {
Context cpp_ctx(c_ctx->options.include_paths); Context cpp_ctx(c_ctx->options.include_paths, c_ctx->options.image_path);
// cpp_ctx.image_path = c_ctx->options.image_path;
// Document doc(0, c_ctx->input_string, cpp_ctx); // Document doc(0, c_ctx->input_string, cpp_ctx);
Document doc(Document::make_from_source_chars(cpp_ctx, c_ctx->source_string)); Document doc(Document::make_from_source_chars(cpp_ctx, c_ctx->source_string));
c_ctx->output_string = process_document(doc, c_ctx->options.output_style); c_ctx->output_string = process_document(doc, c_ctx->options.output_style);
...@@ -93,8 +94,11 @@ extern "C" { ...@@ -93,8 +94,11 @@ extern "C" {
{ {
using namespace Sass; using namespace Sass;
try { try {
Context cpp_ctx(c_ctx->options.include_paths); Context cpp_ctx(c_ctx->options.include_paths, c_ctx->options.image_path);
// Document doc(c_ctx->input_path, 0, cpp_ctx); // Document doc(c_ctx->input_path, 0, cpp_ctx);
// string path_string(c_ctx->options.image_path);
// path_string = "'" + path_string + "/";
// cpp_ctx.image_path = c_ctx->options.image_path;
Document doc(Document::make_from_file(cpp_ctx, string(c_ctx->input_path))); Document doc(Document::make_from_file(cpp_ctx, string(c_ctx->input_path)));
// cerr << "MADE A DOC AND CONTEXT OBJ" << endl; // cerr << "MADE A DOC AND CONTEXT OBJ" << endl;
// cerr << "REGISTRY: " << doc.context.registry.size() << endl; // cerr << "REGISTRY: " << doc.context.registry.size() << endl;
......
...@@ -10,6 +10,7 @@ extern "C" { ...@@ -10,6 +10,7 @@ extern "C" {
struct sass_options { struct sass_options {
int output_style; int output_style;
char* include_paths; char* include_paths;
char* image_path;
}; };
struct sass_context { struct sass_context {
......
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