Commit e2021333 by Aaron Leung

Getting the pegs to fit into the holes.

parent ea68a55e
......@@ -3,6 +3,7 @@
#include <utility>
#include <map>
#include "node_factory.hpp"
#include "functions.hpp"
namespace Sass {
......@@ -45,7 +46,7 @@ namespace Sass {
vector<char*> source_refs; // all the source c-strings
vector<vector<Node>*> registry; // all the child vectors
vector<string> include_paths;
Node_Factory new_node;
Node_Factory new_Node;
size_t ref_count;
string sass_path;
string css_path;
......
......@@ -4,6 +4,7 @@
#include "eval_apply.hpp"
#include "error.hpp"
#include <iostream>
#include <sstream>
namespace Sass {
......@@ -25,7 +26,7 @@ namespace Sass {
Document::~Document()
{ --context.ref_count; }
static Document Document::make_from_file(Context& ctx, string path)
Document Document::make_from_file(Context& ctx, string path)
{
std::FILE *f;
f = std::fopen(path.c_str(), "rb");
......@@ -55,7 +56,7 @@ namespace Sass {
return doc;
}
static Document Document::make_from_source_chars(Context& ctx, char* src, string path)
Document Document::make_from_source_chars(Context& ctx, char* src, string path)
{
Document doc(ctx);
doc.path = path;
......@@ -70,7 +71,7 @@ namespace Sass {
return doc;
}
static Document Document::make_from_token(Context& ctx, Token t, string path, size_t line_number)
Document Document::make_from_token(Context& ctx, Token t, string path, size_t line_number)
{
Document doc(ctx);
doc.path = path;
......
......@@ -4,6 +4,7 @@
#include "node.hpp"
#endif
#include "prelexer.hpp"
#include "context.hpp"
namespace Sass {
......@@ -32,6 +33,7 @@ namespace Sass {
Document(Context& ctx);
~Document();
public:
Document(const Document& doc);
static Document make_from_file(Context& ctx, string path);
static Document make_from_source_chars(Context& ctx, char* src, string path = "");
......@@ -144,26 +146,14 @@ namespace Sass {
Node parse_term();
Node parse_factor();
Node parse_value();
Node parse_identifier();
Node parse_variable();
Node parse_function_call();
Node parse_string();
Node parse_value_schema();
const char* lookahead_for_selector(const char* start = 0);
const char* look_for_rule(const char* start = 0);
const char* look_for_values(const char* start = 0);
const char* look_for_selector_group(const char* start = 0);
const char* look_for_selector(const char* start = 0);
const char* look_for_simple_selector_sequence(const char* start = 0);
const char* look_for_simple_selector(const char* start = 0);
const char* look_for_pseudo(const char* start = 0);
const char* look_for_attrib(const char* start = 0);
void syntax_error(string message, size_t ln = 0);
void read_error(string message, size_t ln = 0);
void throw_syntax_error(string message, size_t ln = 0);
void throw_read_error(string message, size_t ln = 0);
string emit_css(CSS_Style style);
......
......@@ -39,7 +39,7 @@ namespace Sass {
}
else {
lex< spaces_and_comments >();
syntax_error("invalid top-level expression");
throw_syntax_error("invalid top-level expression");
}
lex< optional_spaces >();
}
......@@ -61,9 +61,9 @@ namespace Sass {
const char* beg = position;
const char* end = find_first< exactly<')'> >(position);
if (!end) throw_syntax_error("unterminated url in @import directive");
Node path(context.new_Node(Node::identifier, path, line_number, Token::make(beg, end)));
Node importee(context.new_Node(Node::css_import, path, line_number, 1);
importee << path;
Node path_node(context.new_Node(Node::identifier, path, line_number, Token::make(beg, end)));
Node importee(context.new_Node(Node::css_import, path, line_number, 1));
importee << path_node;
position = end;
lex< exactly<')'> >();
return importee;
......@@ -98,14 +98,14 @@ namespace Sass {
Node params(parse_mixin_parameters());
if (!peek< exactly<'{'> >()) throw_syntax_error("body for mixin " + name.token().to_string() + " must begin with a '{'");
Node body(parse_block(true));
Node the_mixin(context.new_Node(Node::mixin, path, line_number, 3);
Node the_mixin(context.new_Node(Node::mixin, path, line_number, 3));
the_mixin << name << params << body;
return mixin;
return the_mixin;
}
Node Document::parse_mixin_parameters()
{
Node params(context.new_Node(Node::parameters, path, line_number, 0);
Node params(context.new_Node(Node::parameters, path, line_number, 0));
Token name(lexed);
if (lex< exactly<'('> >()) {
if (peek< variable >()) {
......@@ -151,7 +151,7 @@ namespace Sass {
Node Document::parse_arguments()
{
Token name(lexed);
Node args(context.new_Node(Node::arguments, path, line_number, 0);
Node args(context.new_Node(Node::arguments, path, line_number, 0));
if (lex< exactly<'('> >()) {
if (!peek< exactly<')'> >(position)) {
Node arg(parse_argument());
......@@ -212,7 +212,7 @@ namespace Sass {
}
}
if (block.empty()) throw_syntax_error("namespaced property cannot be empty");
Node propset(context.new_Node(Node::propset, path, line_number, 2);
Node propset(context.new_Node(Node::propset, path, line_number, 2));
propset << property_segment;
propset << block;
return propset;
......@@ -359,7 +359,7 @@ namespace Sass {
pseudo << context.new_Node(Node::string_constant, path, line_number, lexed);
}
else {
syntax_error("invalid argument to " + name.to_string() + "...)");
throw_syntax_error("invalid argument to " + name.to_string() + "...)");
}
if (!lex< exactly<')'> >()) throw_syntax_error("unterminated argument to " + name.to_string() + "...)");
return pseudo;
......@@ -700,62 +700,49 @@ namespace Sass {
}
if (lex< value_schema >())
{
// cerr << "parsing value schema: " << lexed.to_string() << endl;
return Document::make_from_token(context, lexed, path, line_number).parse_value_schema();
}
{ return Document::make_from_token(context, lexed, path, line_number).parse_value_schema(); }
if (lex< sequence< true_kwd, negate< identifier > > >())
{
Node T(Node::boolean);
T.line_number = line_number;
T.content.boolean_value = true;
return T;
}
{ return context.new_Node(Node::boolean, path, line_number, true); }
if (lex< sequence< false_kwd, negate< identifier > > >())
{
Node F(Node::boolean);
F.line_number = line_number;
F.content.boolean_value = false;
return F;
}
{ return context.new_Node(Node::boolean, path, line_number, false); }
if (peek< functional >())
{ return parse_function_call(); }
if (lex< important >())
{ return Node(Node::important, line_number, lexed); }
{ return context.new_Node(Node::important, path, line_number, lexed); }
if (lex< identifier >())
{ return Node(Node::identifier, line_number, lexed); }
{ return context.new_Node(Node::identifier, path, line_number, lexed); }
if (lex< percentage >())
{ return Node(Node::textual_percentage, line_number, lexed); }
{ return context.new_Node(Node::textual_percentage, path, line_number, lexed); }
if (lex< dimension >())
{ return Node(Node::textual_dimension, line_number, lexed); }
{ return context.new_Node(Node::textual_dimension, path, line_number, lexed); }
if (lex< number >())
{ return Node(Node::textual_number, line_number, lexed); }
{ return context.new_Node(Node::textual_number, path, line_number, lexed); }
if (lex< hex >())
{ return Node(Node::textual_hex, line_number, lexed); }
{ return context.new_Node(Node::textual_hex, path, line_number, lexed); }
if (peek< string_constant >())
// { return Node(Node::string_constant, line_number, lexed); }
{ return parse_string(); }
if (lex< variable >())
{
Node var(Node::variable, line_number, lexed);
Node var(context.new_Node(Node::variable, path, line_number, lexed));
var.should_eval() = true;
return var;
}
syntax_error("error reading values after " + lexed.to_string());
// unreached statement
return Node(Node::none);
throw_syntax_error("error reading values after " + lexed.to_string());
// unreachable statement
return Node();
}
extern const char hash_lbrace[] = "#{";
......@@ -769,34 +756,35 @@ namespace Sass {
// see if there any interpolants
const char* p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(str.begin, str.end);
if (!p) {
return Node(Node::string_constant, line_number, str);
return context.new_Node(Node::string_constant, path, line_number, str);
}
Node schema(Node::string_schema, path, line_number, 1);
Node schema(context.new_Node(Node::string_schema, path, line_number, 1));
while (i < str.end) {
p = find_first_in_interval< sequence< negate< exactly<'\\'> >, exactly<hash_lbrace> > >(i, str.end);
if (p) {
if (i < p) {
schema << Node(Node::identifier, line_number, Token::make(i, p-2)); // accumulate the preceding segment if it's nonempty
schema << context.new_Node(Node::identifier, path, line_number, Token::make(i, p-2)); // accumulate the preceding segment if it's nonempty
// cerr << '[' << Token::make(i,p-2).to_string() << ']' << endl;
}
const char* j = find_first_in_interval< exactly<rbrace> >(p, str.end); // find the closing brace
if (j) {
// parse the interpolant and accumulate it
// cerr << '[' << Token::make(p, j-1).to_string() << ']' << endl;
Document interp_doc(path, line_number, Token::make(p,j-1), context);
Node interp_node(interp_doc.parse_list());
// Document interp_doc(path, line_number, Token::make(p,j-1), context);
Node interp_node(Document::make_from_token(context, Token::make(p, j-1), path, line_number).parse_list());
// Node interp_node(interp_doc.parse_list());
interp_node.should_eval() = true;
schema << interp_node;
i = j;
}
else {
// throw an error if the interpolant is unterminated
syntax_error("unterminated interpolant inside string constant " + str.to_string());
throw_syntax_error("unterminated interpolant inside string constant " + str.to_string());
}
}
else { // no interpolants left; add the last segment if nonempty
if (i < str.end) schema << Node(Node::identifier, line_number, Token::make(i, str.end));
if (i < str.end) schema << context.new_Node(Node::identifier, path, line_number, Token::make(i, str.end));
break;
}
}
......@@ -805,38 +793,39 @@ namespace Sass {
Node Document::parse_value_schema()
{
Node schema(Node::value_schema, path, line_number, 1);
Node schema(context.new_Node(Node::value_schema, path, line_number, 1));
while (position < end) {
if (lex< interpolant >()) {
Token insides(Token::make(lexed.begin + 2, lexed.end - 1));
Document interp_doc(path, line_number, insides, context);
Node interp_node(interp_doc.parse_list());
// Document interp_doc(path, line_number, insides, context);
// Node interp_node(interp_doc.parse_list());
Node interp_node(Document::make_from_token(context, insides, path, line_number).parse_list());
schema << interp_node;
}
else if (lex< identifier >()) {
schema << Node(Node::identifier, line_number, lexed);
schema << context.new_Node(Node::identifier, path, line_number, lexed);
}
else if (lex< percentage >()) {
schema << Node(Node::textual_percentage, line_number, lexed);
schema << context.new_Node(Node::textual_percentage, path, line_number, lexed);
}
else if (lex< dimension >()) {
schema << Node(Node::textual_dimension, line_number, lexed);
schema << context.new_Node(Node::textual_dimension, path, line_number, lexed);
}
else if (lex< number >()) {
schema << Node(Node::textual_number, line_number, lexed);
schema << context.new_Node(Node::textual_number, path, line_number, lexed);
}
else if (lex< hex >()) {
schema << Node(Node::textual_hex, line_number, lexed);
schema << context.new_Node(Node::textual_hex, path, line_number, lexed);
}
else if (lex< string_constant >()) {
schema << Node(Node::string_constant, line_number, lexed);
schema << context.new_Node(Node::string_constant, path, line_number, lexed);
}
else if (lex< variable >()) {
schema << Node(Node::variable, line_number, lexed);
schema << context.new_Node(Node::variable, path, line_number, lexed);
}
else {
syntax_error("error parsing interpolated value");
throw_syntax_error("error parsing interpolated value");
}
}
schema.should_eval() = true;
......@@ -846,24 +835,14 @@ namespace Sass {
Node Document::parse_function_call()
{
lex< identifier >();
Node name(Node::identifier, line_number, lexed);
Node name(context.new_Node(Node::identifier, path, line_number, lexed));
Node args(parse_arguments());
Node call(Node::function_call, path, line_number, 2);
Node call(context.new_Node(Node::function_call, path, line_number, 2));
call << name << args;
call.should_eval() = true;
return call;
}
Node Document::parse_identifier() {
lex< identifier >();
return Node(Node::identifier, line_number, lexed);
}
Node Document::parse_variable() {
lex< variable >();
return Node(Node::variable, line_number, lexed);
}
const char* Document::lookahead_for_selector(const char* start)
{
const char* p = start ? start : position;
......@@ -903,150 +882,3 @@ namespace Sass {
}
}
\ No newline at end of file
// const char* Document::look_for_rule(const char* start)
// {
// const char* p = start ? start : position;
// (p = peek< identifier >(p)) &&
// (p = peek< exactly<':'> >(p)) &&
// (p = look_for_values(p)) &&
// (p = peek< alternatives< exactly<';'>, exactly<'}'> > >(p));
// return p;
// }
//
// const char* Document::look_for_values(const char* start)
// {
// const char* p = start ? start : position;
// const char* q;
// while ((q = peek< identifier >(p)) || (q = peek< dimension >(p)) ||
// (q = peek< percentage >(p)) || (q = peek< number >(p)) ||
// (q = peek< hex >(p)) || (q = peek< string_constant >(p)) ||
// (q = peek< variable >(p)))
// { p = q; }
// return p == start ? 0 : p;
// }
// // NEW LOOKAHEAD FUNCTIONS. THIS ESSENTIALLY IMPLEMENTS A BACKTRACKING
// // PARSER, BECAUSE SELECTORS AND VALUES ARE NOT EXPRESSIBLE IN A
// // REGULAR LANGUAGE.
// const char* Document::look_for_selector_group(const char* start)
// {
// const char* p = start ? start : position;
// const char* q = look_for_selector(p);
//
// if (!q) { return 0; }
// else { p = q; }
//
// while ((q = peek< exactly<','> >(p)) && (q = look_for_selector(q)))
// { p = q; }
//
// // return peek< exactly<'{'> >(p) ? p : 0;
// return peek< alternatives< exactly<'{'>, exactly<')'> > >(p) ? p : 0;
// }
//
// const char* Document::look_for_selector(const char* start)
// {
// const char* p = start ? start : position;
// const char* q;
//
// if ((q = peek< exactly<'+'> >(p)) ||
// (q = peek< exactly<'~'> >(p)) ||
// (q = peek< exactly<'>'> >(p)))
// { p = q; }
//
// p = look_for_simple_selector_sequence(p);
//
// if (!p) return 0;
//
// while (((q = peek< exactly<'+'> >(p)) ||
// (q = peek< exactly<'~'> >(p)) ||
// (q = peek< exactly<'>'> >(p)) ||
// (q = peek< ancestor_of > (p))) &&
// (q = look_for_simple_selector_sequence(q)))
// { p = q; }
//
// return p;
// }
//
// const char* Document::look_for_simple_selector_sequence(const char* start)
// {
// const char* p = start ? start : position;
// const char* q;
//
// if ((q = peek< type_selector >(p)) ||
// (q = peek< universal >(p)) ||
// (q = peek< exactly <'&'> >(p)) ||
// (q = look_for_simple_selector(p)))
// { p = q; }
// else
// { return 0; }
//
// while (!peek< spaces >(p) &&
// !(peek < exactly<'+'> >(p) ||
// peek < exactly<'~'> >(p) ||
// peek < exactly<'>'> >(p) ||
// peek < exactly<','> >(p) ||
// peek < exactly<')'> >(p) ||
// peek < exactly<'{'> >(p)) &&
// (q = look_for_simple_selector(p)))
// { p = q; }
//
// return p;
// }
//
// const char* Document::look_for_simple_selector(const char* start)
// {
// const char* p = start ? start : position;
// const char* q;
// (q = peek< id_name >(p)) || (q = peek< class_name >(p)) ||
// (q = look_for_pseudo(p)) || (q = look_for_attrib(p));
// // cerr << "looking for simple selector; found:" << endl;
// // cerr << (q ? string(Token::make(q,q+8)) : "nothing") << endl;
// return q;
// }
//
// const char* Document::look_for_pseudo(const char* start)
// {
// const char* p = start ? start : position;
// const char* q;
//
// if (q = peek< pseudo_not >(p)) {
// // (q = look_for_simple_selector(q)) && (q = peek< exactly<')'> >(q));
// (q = look_for_selector_group(q)) && (q = peek< exactly<')'> >(q));
// }
// else if (q = peek< sequence< pseudo_prefix, functional > >(p)) {
// p = q;
// (q = peek< alternatives< even, odd > >(p)) ||
// (q = peek< binomial >(p)) ||
// (q = peek< sequence< optional<sign>,
// optional<digits>,
// exactly<'n'> > >(p)) ||
// (q = peek< sequence< optional<sign>,
// digits > >(p));
// p = q;
// q = peek< exactly<')'> >(p);
// }
// else {
// q = peek< sequence< pseudo_prefix, identifier > >(p);
// }
// return q ? q : 0;
// }
//
// const char* Document::look_for_attrib(const char* start)
// {
// const char* p = start ? start : position;
//
// (p = peek< exactly<'['> >(p)) &&
// (p = peek< type_selector >(p)) &&
// (p = peek< alternatives<exact_match,
// class_match,
// dash_match,
// prefix_match,
// suffix_match,
// substring_match> >(p)) &&
// (p = peek< string_constant >(p)) &&
// (p = peek< exactly<']'> >(p));
//
// return p;
// }
// }
......@@ -176,7 +176,7 @@ namespace Sass {
Node& operator<<(Node n);
Node& operator+=(Node n);
bool boolean_value() const;
bool& boolean_value() const;
double numeric_value() const;
Token token() const;
Token unit() const;
......@@ -268,7 +268,7 @@ namespace Sass {
void pop_back()
{ children.pop_back(); }
bool boolean_value()
bool& boolean_value()
{ return value.boolean; }
double numeric_value();
......@@ -320,7 +320,7 @@ namespace Sass {
for (size_t i = 0, L = n.size(); i < L; ++i) push_back(n[i]);
return *this;
}
inline bool Node::boolean_value() const { return ip_->boolean_value(); }
inline bool& Node::boolean_value() const { return ip_->boolean_value(); }
inline double Node::numeric_value() const { return ip_->numeric_value(); }
inline Token Node::token() const { return ip_->value.token; }
inline Token Node::unit() const { return ip_->unit(); }
......
......@@ -35,21 +35,31 @@ namespace Sass {
}
// for making leaf nodes out of terminals/tokens
Node Node_Factory::operator()(Node::Type type, string file, size_t line, const Token& t)
Node Node_Factory::operator()(Node::Type type, string file, size_t line, Token& t)
{
Node_Impl* ip = alloc_Node_Impl(type, file, line);
ip->value.token = t;
return Node(ip);
}
// for making interior nodes that have children
// for making boolean values or interior nodes that have children
Node Node_Factory::operator()(Node::Type type, string file, size_t line, size_t size)
{
Node_Impl* ip = alloc_Node_Impl(type, file, line);
ip->children.reserve(size);
if (type == Node::boolean) ip->value.boolean = size;
else ip->children.reserve(size);
return Node(ip);
}
// Node Node_Factory::operator()(Node::Type type, string file, size_t line, bool b)
// {
// Node_Impl* ip = alloc_Node_Impl(type, file, line);
// ip->content.boolean_value = b;
// return Node(ip);
// }
// for making nodes representing numbers
Node Node_Factory::operator()(string file, size_t line, double v)
{
......
......@@ -19,9 +19,11 @@ namespace Sass {
// for cloning nodes
Node operator()(const Node& n1);
// for making leaf nodes out of terminals/tokens
Node operator()(Node::Type type, string file, size_t line, const Token& t);
// for making interior nodes that have children
Node operator()(Node::Type type, string file, size_t line, Token& t);
// for making boolean values or interior nodes that have children
Node operator()(Node::Type type, string file, size_t line, size_t size);
// // for making nodes representing boolean values
// Node operator()(Node::Type type, string file, size_t line, bool b);
// for making nodes representing numbers
Node operator()(string file, size_t line, double v);
// for making nodes representing numeric dimensions (e.g. 5px, 3em)
......
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