Commit 0a31ae6d by litek
parents f0313c3d e9971023
CC=g++
CFLAGS=-c -Wall -O2 -fPIC
LDFLAGS= -fPIC
SOURCES = \
context.cpp functions.cpp document.cpp \
document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
sass_interface.cpp
CC = g++
CFLAGS = -Wall -O2 -fPIC
LDFLAGS = -fPIC
PREFIX = /usr/local
LIBDIR = $(PREFIX)/lib
SOURCES = constants.cpp context.cpp functions.cpp document.cpp \
document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
selector.cpp sass_interface.cpp
OBJECTS = $(SOURCES:.cpp=.o)
all: $(OBJECTS)
ar rvs libsass.a $(OBJECTS)
static: libsass.a
shared: libsass.so
libsass.a: $(OBJECTS)
ar rvs $@ $(OBJECTS)
shared: $(OBJECTS)
$(CC) -shared -o libsass.so *.o
libsass.so: $(OBJECTS)
$(CC) -shared $(LDFLAGS) -o $@ $(OBJECTS)
.cpp.o:
$(CC) $(CFLAGS) $< -o $@
$(CC) $(CFLAGS) -c -o $@ $<
install: libsass.a
install -Dpm0755 $< $(DESTDIR)$(LIBDIR)/$<
install-shared: libsass.so
install -Dpm0755 $< $(DESTDIR)$(LIBDIR)/$<
clean:
rm -rf *.o *.a *.so
\ No newline at end of file
rm -f $(OBJECTS) *.a *.so
.PHONY: static shared install install-shared clean
......@@ -2,9 +2,9 @@ ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libsass.la
libsass_la_SOURCES = context.cpp functions.cpp document.cpp \
document_parser.cpp eval_apply.cpp node.cpp \
constants.cpp document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
sass_interface.cpp
selector.cpp sass_interface.cpp
libsass_la_LDFLAGS = -no-undefined -version-info 0:0:0
include_HEADERS = sass_interface.h
......@@ -85,8 +85,8 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libsass_la_LIBADD =
am_libsass_la_OBJECTS = context.lo functions.lo document.lo \
document_parser.lo eval_apply.lo node.lo node_factory.lo \
node_emitters.lo prelexer.lo sass_interface.lo
constants.lo document_parser.lo eval_apply.lo node.lo node_factory.lo \
node_emitters.lo prelexer.lo selector.lo sass_interface.lo
libsass_la_OBJECTS = $(am_libsass_la_OBJECTS)
libsass_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
......@@ -245,9 +245,9 @@ top_srcdir = @top_srcdir@
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libsass.la
libsass_la_SOURCES = context.cpp functions.cpp document.cpp \
document_parser.cpp eval_apply.cpp node.cpp \
constants.cpp document_parser.cpp eval_apply.cpp node.cpp \
node_factory.cpp node_emitters.cpp prelexer.cpp \
sass_interface.cpp
selector.cpp sass_interface.cpp
libsass_la_LDFLAGS = -no-undefined -version-info 0:0:0
include_HEADERS = sass_interface.h
......@@ -347,6 +347,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/context.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/document.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/constants.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/document_parser.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eval_apply.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/functions.Plo@am__quote@
......@@ -354,6 +355,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_emitters.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node_factory.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prelexer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selector.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sass_interface.Plo@am__quote@
.cpp.o:
......
#define SASS_COLOR_NAMES_INCLUDED
#define SASS_COLOR_NAMES
namespace Sass {
......
#include "constants.hpp"
namespace Sass {
namespace Constants {
// hidden variable name for the image path (for the image-url built-in)
extern const char image_path_var[] = "$[image path]";
// sass keywords
extern const char import_kwd[] = "@import";
extern const char mixin_kwd[] = "@mixin";
extern const char function_kwd[] = "@function";
extern const char return_kwd[] = "@return";
extern const char include_kwd[] = "@include";
extern const char extend_kwd[] = "@extend";
extern const char if_kwd[] = "@if";
extern const char else_kwd[] = "@else";
extern const char if_after_else_kwd[] = "if";
extern const char for_kwd[] = "@for";
extern const char from_kwd[] = "from";
extern const char to_kwd[] = "to";
extern const char through_kwd[] = "through";
extern const char each_kwd[] = "@each";
extern const char in_kwd[] = "in";
extern const char while_kwd[] = "@while";
extern const char warn_kwd[] = "@warn";
extern const char default_kwd[] = "default";
// css standard units
extern const char em_kwd[] = "em";
extern const char ex_kwd[] = "ex";
extern const char px_kwd[] = "px";
extern const char cm_kwd[] = "cm";
extern const char mm_kwd[] = "mm";
extern const char pt_kwd[] = "pt";
extern const char pc_kwd[] = "pc";
extern const char deg_kwd[] = "deg";
extern const char rad_kwd[] = "rad";
extern const char grad_kwd[] = "grad";
extern const char ms_kwd[] = "ms";
extern const char s_kwd[] = "s";
extern const char Hz_kwd[] = "Hz";
extern const char kHz_kwd[] = "kHz";
// css functions and keywords
extern const char media_kwd[] = "@media";
extern const char only_kwd[] = "only";
extern const char rgb_kwd[] = "rgb(";
extern const char url_kwd[] = "url(";
extern const char image_url_kwd[] = "image-url(";
extern const char important_kwd[] = "important";
extern const char pseudo_not_kwd[] = ":not(";
extern const char even_kwd[] = "even";
extern const char odd_kwd[] = "odd";
// css attribute-matching operators
extern const char tilde_equal[] = "~=";
extern const char pipe_equal[] = "|=";
extern const char caret_equal[] = "^=";
extern const char dollar_equal[] = "$=";
extern const char star_equal[] = "*=";
// relational & logical operators and constants
extern const char and_kwd[] = "and";
extern const char or_kwd[] = "or";
extern const char not_kwd[] = "not";
extern const char gt[] = ">";
extern const char gte[] = ">=";
extern const char lt[] = "<";
extern const char lte[] = "<=";
extern const char eq[] = "==";
extern const char neq[] = "!=";
extern const char true_kwd[] = "true";
extern const char false_kwd[] = "false";
// miscellaneous punctuation and delimiters
extern const char percent_str[] = "%";
extern const char empty_str[] = "";
extern const char slash_slash[] = "//";
extern const char slash_star[] = "/*";
extern const char star_slash[] = "*/";
extern const char hash_lbrace[] = "#{";
extern const char rbrace[] = "}";
extern const char rparen[] = ")";
extern const char sign_chars[] = "-+";
// type names
extern const char numeric_name[] = "numeric value";
extern const char number_name[] = "number";
extern const char percentage_name[] = "percentage";
extern const char dimension_name[] = "numeric dimension";
extern const char string_name[] = "string";
extern const char bool_name[] = "bool";
extern const char color_name[] = "color";
extern const char list_name[] = "list";
}
}
\ No newline at end of file
#define SASS_CONSTANTS
namespace Sass {
namespace Constants {
// hidden variable name for the image path (for the image-url built-in)
extern const char image_path_var[];
// sass keywords
extern const char import_kwd[];
extern const char mixin_kwd[];
extern const char function_kwd[];
extern const char return_kwd[];
extern const char include_kwd[];
extern const char extend_kwd[];
extern const char if_kwd[];
extern const char else_kwd[];
extern const char if_after_else_kwd[];
extern const char for_kwd[];
extern const char from_kwd[];
extern const char to_kwd[];
extern const char through_kwd[];
extern const char each_kwd[];
extern const char in_kwd[];
extern const char while_kwd[];
extern const char warn_kwd[];
extern const char default_kwd[];
// css standard units
extern const char em_kwd[];
extern const char ex_kwd[];
extern const char px_kwd[];
extern const char cm_kwd[];
extern const char mm_kwd[];
extern const char pt_kwd[];
extern const char pc_kwd[];
extern const char deg_kwd[];
extern const char rad_kwd[];
extern const char grad_kwd[];
extern const char ms_kwd[];
extern const char s_kwd[];
extern const char Hz_kwd[];
extern const char kHz_kwd[];
// css functions and keywords
extern const char media_kwd[];
extern const char only_kwd[];
extern const char rgb_kwd[];
extern const char url_kwd[];
extern const char image_url_kwd[];
extern const char important_kwd[];
extern const char pseudo_not_kwd[];
extern const char even_kwd[];
extern const char odd_kwd[];
// css attribute-matching operators
extern const char tilde_equal[];
extern const char pipe_equal[];
extern const char caret_equal[];
extern const char dollar_equal[];
extern const char star_equal[];
// relational & logical operators and constants
extern const char and_kwd[];
extern const char or_kwd[];
extern const char not_kwd[];
extern const char gt[];
extern const char gte[];
extern const char lt[];
extern const char lte[];
extern const char eq[];
extern const char neq[];
extern const char true_kwd[];
extern const char false_kwd[];
// miscellaneous punctuation and delimiters
extern const char percent_str[];
extern const char empty_str[];
extern const char slash_slash[];
extern const char slash_star[];
extern const char star_slash[];
extern const char hash_lbrace[];
extern const char rbrace[];
extern const char rparen[];
extern const char sign_chars[];
// type names
extern const char numeric_name[];
extern const char number_name[];
extern const char percentage_name[];
extern const char dimension_name[];
extern const char string_name[];
extern const char bool_name[];
extern const char color_name[];
extern const char list_name[];
}
}
\ No newline at end of file
#include "context.hpp"
#ifdef _WIN32
#include <direct.h>
#define getcwd _getcwd
#else
#include <unistd.h>
#endif
#include <cstring>
#include <iostream>
#include <unistd.h>
#include "prelexer.hpp"
#include <sstream>
#include "context.hpp"
#include "constants.hpp"
#include "color_names.hpp"
using std::cerr; using std::endl;
#include "prelexer.hpp"
namespace Sass {
using std::pair;
using namespace Constants;
using std::pair; using std::cerr; using std::endl;
void Context::collect_include_paths(const char* paths_str)
{
const size_t wd_len = 1024;
......@@ -64,6 +73,9 @@ namespace Sass {
path_string = "'" + path_string + "/'";
image_path = new char[path_string.length() + 1];
std::strcpy(image_path, path_string.c_str());
// stash this hidden variable for the image-url built-in to use
global_env[Token::make(image_path_var)] = new_Node(Node::string_constant, "[IMAGE PATH]", 0, Token::make(image_path));
}
Context::~Context()
......@@ -73,21 +85,20 @@ namespace Sass {
}
delete[] image_path;
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_env[pair<string, size_t>(f.name, f.parameters.size())] = f;
Function f(const_cast<char*>(sig), ip, *this);
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_env[pair<string, size_t>(f.name, arity)] = f;
function_env[f.name] = f;
Function f(const_cast<char*>(sig), ip, *this);
std::stringstream stub;
stub << f.name << " " << arity;
function_env[stub.str()] = f;
}
inline void Context::register_overload_stub(string name)
......@@ -98,67 +109,80 @@ namespace Sass {
void Context::register_functions()
{
using namespace Functions;
// RGB Functions
register_function(rgb_descriptor, rgb);
register_function(rgb_sig, rgb);
register_overload_stub("rgba");
register_function(rgba_4_descriptor, rgba_4);
register_function(rgba_2_descriptor, rgba_2);
register_function(red_descriptor, red);
register_function(green_descriptor, green);
register_function(blue_descriptor, blue);
register_overload_stub("mix");
register_function(mix_2_descriptor, mix_2);
register_function(mix_3_descriptor, mix_3);
register_function(rgba_4_sig, rgba_4, 4);
register_function(rgba_2_sig, rgba_2, 2);
register_function(red_sig, red);
register_function(green_sig, green);
register_function(blue_sig, blue);
register_function(mix_sig, mix);
// HSL Functions
register_function(hsla_descriptor, hsla);
register_function(hsl_descriptor, hsl);
register_function(invert_descriptor, invert);
register_function(hsl_sig, hsl);
register_function(hsla_sig, hsla);
register_function(hue_sig, hue);
register_function(saturation_sig, saturation);
register_function(lightness_sig, lightness);
register_function(adjust_hue_sig, adjust_hue);
register_function(lighten_sig, lighten);
register_function(darken_sig, darken);
register_function(saturate_sig, saturate);
register_function(desaturate_sig, desaturate);
register_function(grayscale_sig, grayscale);
register_function(complement_sig, complement);
register_function(invert_sig, invert);
// Opacity Functions
register_function(alpha_descriptor, alpha);
register_function(opacity_descriptor, alpha);
register_function(opacify_descriptor, opacify);
register_function(fade_in_descriptor, opacify);
register_function(transparentize_descriptor, transparentize);
register_function(fade_out_descriptor, transparentize);
register_function(alpha_sig, alpha);
register_function(opacity_sig, opacity);
register_function(opacify_sig, opacify);
register_function(fade_in_sig, fade_in);
register_function(transparentize_sig, transparentize);
register_function(fade_out_sig, fade_out);
// Other Color Functions
register_function(adjust_color_sig, adjust_color);
register_function(scale_color_sig, scale_color);
register_function(change_color_sig, change_color);
// String Functions
register_function(unquote_descriptor, unquote);
register_function(quote_descriptor, quote);
register_function(unquote_sig, unquote);
register_function(quote_sig, quote);
// Number Functions
register_function(percentage_descriptor, percentage);
register_function(round_descriptor, round);
register_function(ceil_descriptor, ceil);
register_function(floor_descriptor, floor);
register_function(abs_descriptor, abs);
register_function(percentage_sig, percentage);
register_function(round_sig, round);
register_function(ceil_sig, ceil);
register_function(floor_sig, floor);
register_function(abs_sig, abs);
// List Functions
register_function(length_descriptor, length);
register_function(nth_descriptor, nth);
register_overload_stub("join");
register_function(join_2_descriptor, join_2);
register_function(join_3_descriptor, join_3);
register_overload_stub("append");
register_function(append_2_descriptor, append_2);
register_function(append_3_descriptor, append_3);
register_function(length_sig, length);
register_function(nth_sig, nth);
register_function(index_sig, index);
register_function(join_sig, join);
register_function(append_sig, append);
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);
register_function(compact_1_sig, compact_1, 1);
register_function(compact_n_sig, compact_n, 0);
register_function(compact_n_sig, compact_n, 2);
register_function(compact_n_sig, compact_n, 3);
register_function(compact_n_sig, compact_n, 4);
register_function(compact_n_sig, compact_n, 5);
register_function(compact_n_sig, compact_n, 6);
register_function(compact_n_sig, compact_n, 7);
register_function(compact_n_sig, compact_n, 8);
register_function(compact_n_sig, compact_n, 9);
register_function(compact_n_sig, compact_n, 10);
register_function(compact_n_sig, compact_n, 11);
register_function(compact_n_sig, compact_n, 12);
// Introspection Functions
register_function(type_of_descriptor, type_of);
register_function(unit_descriptor, unit);
register_function(unitless_descriptor, unitless);
register_function(comparable_descriptor, comparable);
register_function(type_of_sig, type_of);
register_function(unit_sig, unit);
register_function(unitless_sig, unitless);
register_function(comparable_sig, comparable);
// Boolean Functions
register_function(not_descriptor, not_impl);
register_function(if_descriptor, if_impl);
register_function(not_sig, not_impl);
register_function(if_sig, if_impl);
// Path Functions
register_function(image_url_sig, image_url);
}
void Context::setup_color_map()
......
#define SASS_CONTEXT_INCLUDED
#define SASS_CONTEXT
//#ifndef SASS_ENVIRONMENT
#include "environment.hpp"
//#endif
#include <utility>
#include <map>
#ifndef SASS_NODE_FACTORY
#include "node_factory.hpp"
#endif
#ifndef SASS_FUNCTIONS
#include "functions.hpp"
#endif
namespace Sass {
using std::pair;
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 {
Environment global_env;
map<string, Function> function_env;
......@@ -59,9 +37,9 @@ namespace Sass {
void collect_include_paths(const char* paths_str);
Context(const char* paths_str = 0, const char* img_path_str = 0);
~Context();
void register_function(Function_Descriptor d, Primitive ip);
void register_function(Function_Descriptor d, Primitive ip, size_t arity);
void register_function(Signature sig, Primitive ip);
void register_function(Signature sig, Primitive ip, size_t arity);
void register_overload_stub(string name);
void register_functions();
void setup_color_map();
......
#ifdef _WIN32
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#include <cstdio>
#include <cstring>
#include "document.hpp"
......
#define SASS_DOCUMENT
#include <map>
#ifndef SASS_PRELEXER_INCLUDED
#ifndef SASS_PRELEXER
#include "prelexer.hpp"
#endif
#ifndef SASS_NODE_INCLUDED
#ifndef SASS_NODE
#include "node.hpp"
#endif
#ifndef SASS_CONTEXT_INCLUDED
#ifndef SASS_CONTEXT
#include "context.hpp"
#endif
......@@ -130,10 +132,10 @@ namespace Sass {
Node parse_mixin_definition();
Node parse_function_definition();
Node parse_parameters();
Node parse_parameter();
Node parse_parameter(Node::Type);
Node parse_mixin_call();
Node parse_arguments();
Node parse_argument();
Node parse_argument(Node::Type);
Node parse_assignment();
Node parse_propset();
Node parse_ruleset(Selector_Lookahead lookahead, Node::Type inside_of = Node::none);
......@@ -162,6 +164,7 @@ namespace Sass {
Node parse_string();
Node parse_value_schema();
Node parse_identifier_schema();
Node parse_url_schema();
Node parse_if_directive(Node surrounding_ruleset, Node::Type inside_of = Node::none);
Node parse_for_directive(Node surrounding_ruleset, Node::Type inside_of = Node::none);
Node parse_each_directive(Node surrounding_ruleset, Node::Type inside_of = Node::none);
......@@ -172,7 +175,8 @@ namespace Sass {
Node parse_warning();
Selector_Lookahead lookahead_for_selector(const char* start = 0);
Selector_Lookahead lookahead_for_extension_target(const char* start = 0);
void throw_syntax_error(string message, size_t ln = 0);
void throw_read_error(string message, size_t ln = 0);
......
#define SASS_ENVIRONMENT
#include <map>
#ifndef SASS_NODE
#include "node.hpp"
#endif
namespace Sass {
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];
}
void print()
{
for (map<Token, Node>::iterator i = current_frame.begin(); i != current_frame.end(); ++i) {
cerr << i->first.to_string() << ": " << i->second.to_string() << endl;
}
if (parent) {
cerr << "---" << endl;
parent->print();
}
}
};
}
\ No newline at end of file
#define SASS_ERROR
namespace Sass {
struct Error {
......
#define SASS_EVAL_APPLY
#include <map>
#ifndef SASS_NODE_INCLUDED
#ifndef SASS_NODE
#include "node.hpp"
#endif
#ifndef SASS_CONTEXT_INCLUDED
#ifndef SASS_CONTEXT
#include "context.hpp"
#endif
namespace Sass {
using std::map;
void expand(Node expr, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx, bool function_name = false);
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 eval_arguments(Node args, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx);
Node eval_function(string name, Node stm, Environment& bindings, Node_Factory& new_Node, Context& ctx, bool toplevel = false);
Node reduce(Node list, size_t head, Node acc, 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 op, double lhs, double rhs);
Node apply_mixin(Node mixin, const Node args, Node prefix, Environment& env, map<string, Function>& f_env, Node_Factory& new_Node, Context& ctx, bool dynamic_scope = false);
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, string& path, size_t line);
Node expand_selector(Node sel, Node pre, Node_Factory& new_Node);
Node expand_backref(Node sel, Node pre);
void extend(Node expr, multimap<Node, Node>& extension_requests, Node_Factory& new_Node);
void extend_selectors(vector<pair<Node, Node> >&, multimap<Node, Node>&, Node_Factory&);
Node generate_extension(Node extendee, Node extender, Node_Factory& new_Node);
......
#include <sstream>
#include <algorithm>
#include <iostream>
#include "node.hpp"
#include "constants.hpp"
#include "error.hpp"
#include <iostream>
namespace Sass {
using namespace std;
using namespace Constants;
// ------------------------------------------------------------------------
// Node method implementations
......@@ -16,8 +18,9 @@ namespace Sass {
switch (type())
{
case block:
case expansion:
case mixin_call:
case root:
case if_directive:
case for_through_directive:
case for_to_directive:
case each_directive:
......@@ -31,8 +34,9 @@ namespace Sass {
for (size_t i = 0; i < size(); ++i) {
switch (at(i).type())
{
case expansion:
case mixin_call:
case block:
case if_directive:
case for_through_directive:
case for_to_directive:
case each_directive:
......@@ -57,6 +61,18 @@ namespace Sass {
string Node::unquote() const
{
switch (type())
{
case string_constant:
case identifier: {
return token().unquote();
} break;
default: {
// do nothing; fall though to the rest
} break;
}
string intermediate(to_string());
if (!intermediate.empty() && (intermediate[0] == '"' || intermediate[0] == '\'')) {
return intermediate.substr(1, intermediate.length() - 2);
......@@ -70,8 +86,11 @@ namespace Sass {
{
Type t = type(), u = rhs.type();
if ((t == identifier || t == string_constant || t == string_schema || t == concatenation) &&
(u == identifier || u == string_constant || u == string_schema || u == concatenation)) {
// if ((t == identifier || t == string_constant || t == string_schema || t == concatenation) &&
// (u == identifier || u == string_constant || u == string_schema || u == concatenation)) {
// return unquote() == rhs.unquote();
// }
if (is_string() && rhs.is_string()) {
return unquote() == rhs.unquote();
}
else if (t != u) {
......@@ -80,12 +99,12 @@ namespace Sass {
switch (t)
{
case comma_list:
case space_list:
case list:
case expression:
case term:
case numeric_color: {
if (size() != rhs.size()) return false;
if ((t == list) && (is_comma_separated() != rhs.is_comma_separated())) return false;
for (size_t i = 0, L = size(); i < L; ++i) {
if (at(i) == rhs[i]) continue;
else return false;
......@@ -122,8 +141,25 @@ namespace Sass {
return boolean_value() == rhs.boolean_value();
} break;
case selector: {
if (has_children() && rhs.has_children() && (size() == rhs.size())) {
for (size_t i = 0, S = size(); i < S; ++i) {
if (at(i) == rhs[i]) continue;
else return false;
}
return true;
}
else {
return false;
}
} break;
case simple_selector: {
if (token() == rhs.token()) return true;
} break;
default: {
return true;
return false;
} break;
}
return false;
......@@ -159,12 +195,17 @@ namespace Sass {
}
// comparing identifiers and strings (treat them as comparable)
else if ((lhs_type == identifier || lhs_type == string_constant || lhs_type == value) &&
(rhs_type == identifier || lhs_type == string_constant || rhs_type == value)) {
return token().unquote() < rhs.token().unquote();
else if ((is_string() && rhs.is_string()) ||
(lhs_type == value && rhs_type == value)) {
return unquote() < rhs.unquote();
}
// COMPARING SELECTORS -- IMPORTANT FOR INHERITANCE
// else if ((lhs_type == identifier || lhs_type == string_constant || lhs_type == value) &&
// (rhs_type == identifier || lhs_type == string_constant || rhs_type == value)) {
// return token().unquote() < rhs.token().unquote();
// }
// COMPARING SELECTORS -- IMPORTANT FOR ORDERING AND NORMALIZING
else if ((type() >= selector_group && type() <=selector_schema) &&
(rhs.type() >= selector_group && rhs.type() <=selector_schema)) {
......@@ -179,13 +220,15 @@ namespace Sass {
return token() < rhs.token();
} break;
// assumes selectors are normalized by the time they're compared
case selector:
case attribute_selector: {
case simple_selector_sequence:
case attribute_selector:
case functional_pseudo:
case pseudo_negation: {
return lexicographical_compare(begin(), end(), rhs.begin(), rhs.end());
} break;
default: {
return false;
} break;
......@@ -340,8 +383,6 @@ namespace Sass {
return 0;
}
extern const char percent_str[] = "%";
extern const char empty_str[] = "";
Token Node_Impl::unit()
{
switch (type)
......
#define SASS_NODE_INCLUDED
#define SASS_NODE
#include <cstring>
#include <string>
......@@ -8,6 +8,7 @@
namespace Sass {
using namespace std;
// Token type for representing lexed chunks of text
struct Token {
const char* begin;
const char* end;
......@@ -61,6 +62,7 @@ namespace Sass {
struct Node_Impl;
// Node type for representing SCSS expression nodes. Really just a handle.
class Node {
private:
friend class Node_Factory;
......@@ -69,6 +71,9 @@ namespace Sass {
public:
enum Type {
none,
any,
numeric, // number, numeric_percentage, or numeric_dimension
string_t, // string_constant, identifier, concatenation, schemata
comment,
root,
......@@ -98,9 +103,7 @@ namespace Sass {
rule,
property,
nil,
comma_list,
space_list,
list,
disjunction,
conjunction,
......@@ -128,7 +131,6 @@ namespace Sass {
value,
identifier,
uri,
image_url,
textual_percentage,
textual_dimension,
textual_number,
......@@ -148,13 +150,15 @@ namespace Sass {
identifier_schema,
css_import,
function,
function_call,
mixin,
function,
mixin_call,
parameters,
expansion,
arguments,
extend_directive,
if_directive,
for_through_directive,
for_to_directive,
......@@ -175,6 +179,7 @@ namespace Sass {
Node(Node_Impl* ip = 0);
Type type() const;
Type type(Type);
bool has_children() const;
bool has_statements() const;
......@@ -183,11 +188,14 @@ namespace Sass {
bool has_backref() const;
bool from_variable() const;
bool& should_eval() const;
bool& is_unquoted() const; // for strings
bool& is_quoted() const; // for identifiers
bool& is_quoted() const;
bool is_numeric() const;
bool is_string() const; // for all string-like types
bool is_schema() const; // for all interpolated data
bool is_guarded() const;
bool& has_been_extended() const;
bool is_false() const;
bool& is_comma_separated() const;
string& path() const;
size_t line() const;
......@@ -198,6 +206,7 @@ namespace Sass {
Node& back() const;
Node& operator[](size_t i) const;
void pop_back();
void pop_all();
Node& push_back(Node n);
Node& push_front(Node n);
Node& operator<<(Node n);
......@@ -214,7 +223,7 @@ namespace Sass {
Token token() const;
Token unit() const;
bool is_null_ptr() const { return !ip_; }
bool is_null() const { return !ip_; }
bool is(Node n) const { return ip_ == n.ip_; }
void flatten();
......@@ -236,6 +245,7 @@ namespace Sass {
};
// The actual implementation object for Nodes; Node handles point at these.
struct Node_Impl {
union value_t {
bool boolean;
......@@ -259,9 +269,9 @@ namespace Sass {
bool has_backref;
bool from_variable;
bool should_eval;
bool is_unquoted;
bool is_quoted;
bool has_been_extended;
bool is_comma_separated;
Node_Impl()
: /* value(value_t()),
......@@ -276,14 +286,53 @@ namespace Sass {
has_backref(false),
from_variable(false),
should_eval(false),
is_unquoted(false), // for strings
is_quoted(false), // for identifiers -- yeah, it's hacky for now
has_been_extended(false)
is_quoted(false),
has_been_extended(false),
is_comma_separated(false)
{ }
bool is_numeric()
{ return type >= Node::number && type <= Node::numeric_dimension; }
bool is_string()
{
switch (type)
{
case Node::string_t:
case Node::identifier:
case Node::value_schema:
case Node::identifier_schema:
case Node::string_constant:
case Node::string_schema:
case Node::concatenation: {
return true;
} break;
default: {
return false;
} break;
}
return false;
}
bool is_schema()
{
switch (type)
{
case Node::selector_schema:
case Node::value_schema:
case Node::string_schema:
case Node::identifier_schema: {
return true;
} break;
default: {
return false;
} break;
}
return false;
}
size_t size()
{ return children.size(); }
......@@ -323,7 +372,7 @@ namespace Sass {
case Node::for_to_directive:
case Node::each_directive:
case Node::while_directive:
case Node::expansion: {
case Node::mixin_call: {
has_expansions = true;
} break;
......@@ -355,7 +404,7 @@ namespace Sass {
case Node::for_to_directive:
case Node::each_directive:
case Node::while_directive:
case Node::expansion: has_expansions = true; break;
case Node::mixin_call: has_expansions = true; break;
case Node::backref: has_backref = true; break;
......@@ -367,6 +416,9 @@ namespace Sass {
void pop_back()
{ children.pop_back(); }
void pop_all()
{ for (size_t i = 0, S = size(); i < S; ++i) pop_back(); }
bool& boolean_value()
{ return value.boolean; }
......@@ -382,9 +434,10 @@ namespace Sass {
// ------------------------------------------------------------------------
inline Node::Node(Node_Impl* ip) : ip_(ip) { }
inline Node::Type Node::type() const { return ip_->type; }
inline Node::Type Node::type(Type t) { return ip_->type = t; }
inline bool Node::has_children() const { return ip_->has_children; }
inline bool Node::has_statements() const { return ip_->has_statements; }
inline bool Node::has_blocks() const { return ip_->has_blocks; }
......@@ -392,11 +445,14 @@ namespace Sass {
inline bool Node::has_backref() const { return ip_->has_backref; }
inline bool Node::from_variable() const { return ip_->from_variable; }
inline bool& Node::should_eval() const { return ip_->should_eval; }
inline bool& Node::is_unquoted() const { return ip_->is_unquoted; }
inline bool& Node::is_quoted() const { return ip_->is_quoted; }
inline bool Node::is_numeric() const { return ip_->is_numeric(); }
inline bool Node::is_string() const { return ip_->is_string(); }
inline bool Node::is_schema() const { return ip_->is_schema(); }
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::is_false() const { return (type() == boolean) && (boolean_value() == false); }
inline bool& Node::is_comma_separated() const { return ip_->is_comma_separated; }
inline string& Node::path() const { return ip_->path; }
inline size_t Node::line() const { return ip_->line; }
......@@ -407,6 +463,7 @@ namespace Sass {
inline Node& Node::back() const { return ip_->back(); }
inline Node& Node::operator[](size_t i) const { return at(i); }
inline void Node::pop_back() { ip_->pop_back(); }
inline void Node::pop_all() { ip_->pop_all(); }
inline Node& Node::push_back(Node n)
{
ip_->push_back(n);
......
......@@ -19,6 +19,10 @@ namespace Sass {
{
switch (type())
{
case none: {
return "";
} break;
case selector_group:
case media_expression_group: { // really only needed for arg to :not
string result(at(0).to_string());
......@@ -116,26 +120,19 @@ namespace Sass {
return result;
} break;
case comma_list: {
case list: {
if (size() == 0) return "";
string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) {
if (at(i).type() == nil) continue;
result += ", ";
result += at(i).to_string();
}
return result;
} break;
case space_list: {
string result(at(0).to_string());
for (size_t i = 1, S = size(); i < S; ++i) {
if (at(i).type() == nil) continue;
result += " ";
if (at(i).is_null()) continue;
if (at(i).type() == list && at(i).size() == 0) continue;
result += is_comma_separated() ? ", " : " ";
result += at(i).to_string();
}
return result;
} break;
// still necessary for unevaluated expressions
case expression:
case term: {
string result(at(0).to_string());
......@@ -274,13 +271,13 @@ namespace Sass {
return result;
} break;
case expansion: {
case mixin_call: {
// ignore it
return "";
} break;
case string_constant: {
if (is_unquoted()) return token().unquote();
if (!is_quoted()) return token().unquote();
else {
string result(token().to_string());
if (result[0] != '"' && result[0] != '\'') return "\"" + result + "\"";
......@@ -329,35 +326,22 @@ namespace Sass {
result += chunk;
}
}
if (is_unquoted()) result = result.substr(1, result.length() - 2);
if (!is_quoted()) result = result.substr(1, result.length() - 2);
return result;
} break;
case concatenation: {
string result;
for (size_t i = 0, S = size(); i < S; ++i) {
result += at(i).to_string().substr(1, at(i).token().length()-2);
result += at(i).unquote();
}
// if (inside_of == identifier_schema || inside_of == property) return result;
// else return "\"" + result + "\"";
if (!(inside_of == identifier_schema || inside_of == property) && !is_unquoted()) {
if (!(inside_of == identifier_schema || inside_of == property) && is_quoted()) {
result = "\"" + result + "\"";
}
return result;
} break;
case warning: {
string prefix("WARNING: ");
string indent(" ");
Node contents(at(0));
string result(contents.to_string());
if (contents.type() == string_constant || contents.type() == string_schema) {
result = result.substr(1, result.size()-2); // unquote if it's a single string
}
// These cerrs aren't log lines! They're supposed to be here!
cerr << prefix << result << endl;
cerr << indent << "on line " << at(0).line() << " of " << at(0).path();
cerr << endl << endl;
return "";
} break;
......
......@@ -27,6 +27,21 @@ namespace Sass {
return ip_cpy;
}
// returns a deep-copy of its argument, but uses the path and line that are passed in
Node_Impl* Node_Factory::alloc_Node_Impl(string& path, size_t line, Node_Impl* ip)
{
Node_Impl* ip_cpy = new Node_Impl(*ip);
pool_.push_back(ip_cpy);
if (ip_cpy->has_children) {
for (size_t i = 0, S = ip_cpy->size(); i < S; ++i) {
Node n(ip_cpy->at(i));
ip_cpy->at(i) = (*this)(path, line, n);
}
}
return ip_cpy;
}
// for cloning nodes
Node Node_Factory::operator()(const Node& n1)
{
......@@ -34,6 +49,15 @@ namespace Sass {
return Node(ip_cpy);
}
// for cloning nodes and resetting their path and line-number fields
Node Node_Factory::operator()(string& path, size_t line, const Node& n1)
{
Node_Impl* ip_cpy = alloc_Node_Impl(path, line, n1.ip_); // deep-copy the implementation object
ip_cpy->path = path;
ip_cpy->line = line;
return Node(ip_cpy);
}
// for making leaf nodes out of terminals/tokens
Node Node_Factory::operator()(Node::Type type, string path, size_t line, Token t)
{
......
#define SASS_NODE_FACTORY
#include <vector>
#ifndef SASS_NODE_INCLUDED
#ifndef SASS_NODE
#include "node.hpp"
#endif
......@@ -15,9 +17,11 @@ namespace Sass {
Node_Impl* alloc_Node_Impl(Node::Type type, string file, size_t line);
// returns a deep-copy of its argument
Node_Impl* alloc_Node_Impl(Node_Impl* ip);
Node_Impl* alloc_Node_Impl(string& path, size_t line, Node_Impl* ip);
public:
// for cloning nodes
Node operator()(const Node& n1);
Node operator()(string& path, size_t line, const Node& n1);
// for making leaf nodes out of terminals/tokens
Node operator()(Node::Type type, string file, size_t line, Token t);
// for making boolean values or interior nodes that have children
......
#define SASS_PRELEXER_INCLUDED
#define SASS_PRELEXER
namespace Sass {
namespace Prelexer {
......@@ -305,6 +305,10 @@ namespace Sass {
// Match interpolant schemas
const char* identifier_schema(const char* src);
const char* value_schema(const char* src);
const char* filename(const char* src);
const char* filename_schema(const char* src);
const char* url_schema(const char* src);
const char* url_value(const char* src);
// Match CSS '@' keywords.
const char* at_keyword(const char* src);
const char* import(const char* src);
......@@ -354,8 +358,7 @@ namespace Sass {
// Match CSS uri specifiers.
const char* uri_prefix(const char* src);
const char* uri(const char* src);
// Match SCSS image-url function.
const char* image_url_prefix(const char* src);
const char* url(const char* src);
// Match CSS "!important" keyword.
const char* important(const char* src);
// Match Sass "!default" keyword.
......@@ -385,11 +388,11 @@ namespace Sass {
const char* variable(const char* src);
// Match Sass boolean keywords.
const char* true_kwd(const char* src);
const char* false_kwd(const char* src);
const char* and_kwd(const char* src);
const char* or_kwd(const char* src);
const char* not_kwd(const char* src);
const char* true_val(const char* src);
const char* false_val(const char* src);
const char* and_op(const char* src);
const char* or_op(const char* src);
const char* not_op(const char* src);
const char* eq_op(const char* src);
const char* neq_op(const char* src);
const char* gt_op(const char* src);
......@@ -444,6 +447,5 @@ namespace Sass {
}
return counter;
}
}
}
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <iostream>
#include <sstream>
#include <string>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include "document.hpp"
#include "eval_apply.hpp"
......@@ -41,13 +46,14 @@ extern "C" {
{
using namespace Sass;
doc.parse_scss();
eval(doc.root,
doc.context.new_Node(Node::none, doc.path, doc.line, 0),
doc.context.global_env,
doc.context.function_env,
doc.context.new_Node,
doc.context);
extend_selectors(doc.context.pending_extensions, doc.context.extensions, doc.context.new_Node);
expand(doc.root,
Node(),
doc.context.global_env,
doc.context.function_env,
doc.context.new_Node,
doc.context);
// extend_selectors(doc.context.pending_extensions, doc.context.extensions, doc.context.new_Node);
if (doc.context.has_extensions) extend(doc.root, doc.context.extensions, doc.context.new_Node);
string output(doc.emit_css(static_cast<Document::CSS_Style>(style)));
char* c_output = (char*) malloc(output.size() + 1);
strcpy(c_output, output.c_str());
......
#include <set>
#include "selector.hpp"
namespace Sass {
using namespace std;
Node normalize_selector(Node s, Node_Factory& new_Node)
{
switch (s.type())
{
case Node::selector_group: {
Node normalized(new_Node(Node::selector_group, s.path(), s.line(), 1));
set<Node> normalizer;
for (size_t i = 0, S = s.size(); i < S; ++i)
normalizer.insert(normalize_selector(s[i], new_Node));
for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
normalized << *i;
return normalized;
} break;
case Node::selector: {
Node normalized(new_Node(Node::selector, s.path(), s.line(), s.size()));
for (size_t i = 0, S = s.size(); i < S; ++i)
normalized << normalize_selector(s[i], new_Node);
return normalized;
} break;
case Node::simple_selector_sequence: {
Node normalized(new_Node(Node::simple_selector_sequence, s.path(), s.line(), 1));
set<Node> normalizer;
size_t i = 0;
if (!selector_is_qualifier(s[0])) {
normalized << s[0];
i = 1;
}
for (size_t S = s.size(); i < S; ++i)
normalizer.insert(normalize_selector(s[i], new_Node));
for (set<Node>::iterator i = normalizer.begin(); i != normalizer.end(); ++i)
normalized << *i;
return normalized;
} break;
default: {
return s;
} break;
}
return s;
}
// Remove duplicate selectors from a selector group. Used when extending.
Node remove_duplicate_selectors(Node group, Node_Factory& new_Node)
{
if (group.type() != Node::selector_group) return group;
Node filtered(new_Node(Node::selector_group, group.path(), group.line(), 1));
for (size_t i = 0, S = group.size(); i < S; ++i) {
bool found_dup = false;
for (size_t j = 0; j < filtered.size(); ++j) {
if (group[i] == filtered[j]) {
found_dup = true;
break;
}
}
if (!found_dup) filtered << group[i];
}
return filtered;
}
bool selector_is_qualifier(Node s)
{
switch (s.type())
{
case Node::pseudo:
case Node::pseudo_negation:
case Node::functional_pseudo:
case Node::attribute_selector: {
return true;
} break;
case Node::simple_selector: {
if ((*s.token().begin == '.') || (*s.token().begin == '#')) return true;
} break;
default: {
return false;
} break;
}
return false;
}
// Node selector_is_specialization_of(Node s, Node t)
// {
// }
}
\ No newline at end of file
#ifndef SASS_NODE
#include "node.hpp"
#endif
#ifndef SASS_NODE_FACTORY
#include "node_factory.hpp"
#endif
namespace Sass {
Node normalize_selector(Node s, Node_Factory& new_Node);
Node remove_duplicate_selectors(Node group, Node_Factory& new_Node);
bool selector_is_qualifier(Node s);
}
\ No newline at end of file
#if _MSC_VER >= 1600
#include <unordered_map>
#else
#include <tr1/unordered_map>
#endif
#include <iostream>
#include <string>
#include <tr1/unordered_map>
#include <map>
#include <algorithm>
#ifndef SASS_NODE_INCLUDED
#ifndef SASS_NODE
#include "node.hpp"
#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