diff --git a/Makefile.conf b/Makefile.conf index 4bc0360e09..492987036f 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -35,6 +35,7 @@ SOURCES = \ units.cpp \ values.cpp \ plugins.cpp \ + source.cpp \ position.cpp \ lexer.cpp \ parser.cpp \ diff --git a/src/ast.cpp b/src/ast.cpp index 74b8d72043..2c0dd64c94 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -55,7 +55,7 @@ namespace Sass { void AST_Node::update_pstate(const SourceSpan& pstate) { - pstate_.offset += pstate - pstate_ + pstate.offset; + pstate_.offset += pstate.position - pstate_.position + pstate.offset; } sass::string AST_Node::to_string(Sass_Inspect_Options opt) const diff --git a/src/ast.hpp b/src/ast.hpp index f2cc15710a..c3b1e3ba9c 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -81,20 +81,18 @@ namespace Sass { virtual sass::string to_string() const; virtual void cloneChildren() {}; // generic find function (not fully implemented yet) - // ToDo: add specific implementions to all children + // ToDo: add specific implementations to all children virtual bool find ( bool (*f)(AST_Node_Obj) ) { return f(this); }; void update_pstate(const SourceSpan& pstate); - Offset off() { return pstate(); } - Position pos() { return pstate(); } - // Some obects are not meant to be compared - // ToDo: maybe fallback to pointer comparison? + // Some objects are not meant to be compared + // ToDo: maybe fall-back to pointer comparison? virtual bool operator== (const AST_Node& rhs) const { throw std::runtime_error("operator== not implemented"); } // We can give some reasonable implementations by using - // inverst operators on the specialized implementations + // invert operators on the specialized implementations virtual bool operator!= (const AST_Node& rhs) const { // Unequal if not equal return !(*this == rhs); diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index c4f4229201..0d5b7975f7 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -12,6 +12,11 @@ ///////////////////////////////////////////// namespace Sass { + class SourceData; + class SourceFile; + class SynthFile; + class ItplFile; + class AST_Node; class ParentStatement; @@ -127,6 +132,11 @@ namespace Sass { typedef SharedImpl type##Obj; \ typedef SharedImpl type##_Obj; \ + IMPL_MEM_OBJ(SourceData); + IMPL_MEM_OBJ(SourceFile); + IMPL_MEM_OBJ(SynthFile); + IMPL_MEM_OBJ(ItplFile); + IMPL_MEM_OBJ(AST_Node); IMPL_MEM_OBJ(Statement); IMPL_MEM_OBJ(Block); diff --git a/src/backtrace.cpp b/src/backtrace.cpp index 910c9cc185..9e6f6a5fea 100644 --- a/src/backtrace.cpp +++ b/src/backtrace.cpp @@ -15,7 +15,7 @@ namespace Sass { const Backtrace& trace = traces[i]; // make path relative to the current directory - sass::string rel_path(File::abs2rel(trace.pstate.path, cwd, cwd)); + sass::string rel_path(File::abs2rel(trace.pstate.getPath(), cwd, cwd)); // skip functions on error cases (unsure why ruby sass does this) // if (trace.caller.substr(0, 6) == ", in f") continue; @@ -23,9 +23,9 @@ namespace Sass { if (first) { ss << indent; ss << "on line "; - ss << trace.pstate.line + 1; + ss << trace.pstate.getLine(); ss << ":"; - ss << trace.pstate.column + 1; + ss << trace.pstate.getColumn(); ss << " of " << rel_path; // ss << trace.caller; first = false; @@ -34,9 +34,9 @@ namespace Sass { ss << std::endl; ss << indent; ss << "from line "; - ss << trace.pstate.line + 1; + ss << trace.pstate.getLine(); ss << ":"; - ss << trace.pstate.column + 1; + ss << trace.pstate.getColumn(); ss << " of " << rel_path; } diff --git a/src/context.cpp b/src/context.cpp index b6c56d4f9e..7fa7d78183 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -17,6 +17,7 @@ #include "expand.hpp" #include "parser.hpp" #include "cssize.hpp" +#include "source.hpp" namespace Sass { using namespace Constants; @@ -273,11 +274,11 @@ namespace Sass { // get pointer to the loaded content const char* contents = resources[idx].contents; - // keep a copy of the path around (for parserstates) - // ToDo: we clean it, but still not very elegant!? - strings.push_back(sass_copy_c_string(inc.abs_path.c_str())); + SourceFileObj source = SASS_MEMORY_NEW(SourceFile, + inc.abs_path.c_str(), contents, idx); + // create the initial parser state from resource - SourceSpan pstate(strings.back(), contents, idx); + SourceSpan pstate(source); // check existing import stack for possible recursion for (size_t i = 0; i < import_stack.size() - 2; ++i) { @@ -298,7 +299,7 @@ namespace Sass { } // create a parser instance from the given c_str buffer - Parser p(Parser::from_c_str(contents, *this, traces, pstate)); + Parser p(source, *this, traces); // do not yet dispose these buffers sass_import_take_source(import); sass_import_take_srcmap(import); @@ -441,7 +442,7 @@ namespace Sass { if (const char* err_message = sass_import_get_error_message(include_ent)) { if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, pstate); if (line == sass::string::npos && column == sass::string::npos) error(err_message, pstate, traces); - else error(err_message, SourceSpan(ctx_path, source, Position(line, column)), traces); + else { error(err_message, { pstate.source, { line, column } }, traces); } } // content for import was set else if (source) { diff --git a/src/debugger.hpp b/src/debugger.hpp index 26a0d2aed4..703d387183 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -310,9 +310,10 @@ inline sass::string longToHex(long long t) { inline sass::string pstate_source_position(AST_Node* node) { sass::sstream str; - Position start(node->pstate()); - Position end(start + node->pstate().offset); - str << (start.file == sass::string::npos ? 99999999 : start.file) + Offset start(node->pstate().position); + Offset end(start + node->pstate().offset); + size_t file = node->pstate().getSrcId(); + str << (file == sass::string::npos ? 99999999 : file) << "@[" << start.line << ":" << start.column << "]" << "-[" << end.line << ":" << end.column << "]"; #ifdef DEBUG_SHARED_PTR @@ -419,7 +420,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) std::cerr << ind << "Parent_Reference " << selector; std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; - std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << std::endl; } else if (Cast(node)) { PseudoSelector* selector = Cast(node); @@ -460,7 +461,6 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) std::cerr << " (" << pstate_source_position(node) << ")"; std::cerr << " <" << selector->hash() << ">"; std::cerr << " <<" << selector->ns_name() << ">>"; - std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">"; std::cerr << std::endl; } else if (Cast(node)) { @@ -600,8 +600,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) Comment* block = Cast(node); std::cerr << ind << "Comment " << block; std::cerr << " (" << pstate_source_position(node) << ")"; - std::cerr << " " << block->tabs() << - " <" << prettyprint(block->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << " " << block->tabs() << std::endl; debug_ast(block->text(), ind + "// ", env); } else if (Cast(node)) { If* block = Cast(node); @@ -881,7 +880,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; if (expression->quote_mark()) std::cerr << " [quote_mark: " << expression->quote_mark() << "]"; - std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << std::endl; } else if (Cast(node)) { String_Constant* expression = Cast(node); std::cerr << ind << "String_Constant " << expression; @@ -892,7 +891,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) std::cerr << " [" << prettyprint(expression->value()) << "]"; if (expression->is_delayed()) std::cerr << " [delayed]"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; - std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << std::endl; } else if (Cast(node)) { String_Schema* expression = Cast(node); std::cerr << ind << "String_Schema " << expression; @@ -905,7 +904,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) if (expression->has_interpolant()) std::cerr << " [has interpolant]"; if (expression->is_left_interpolant()) std::cerr << " [left interpolant] "; if (expression->is_right_interpolant()) std::cerr << " [right interpolant] "; - std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << std::endl; for(const auto& i : expression->elements()) { debug_ast(i, ind + " ", env); } } else if (Cast(node)) { String* expression = Cast(node); @@ -913,7 +912,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env) std::cerr << " " << expression->concrete_type(); std::cerr << " (" << pstate_source_position(node) << ")"; if (expression->is_interpolant()) std::cerr << " [interpolant]"; - std::cerr << " <" << prettyprint(expression->pstate().token.ws_before()) << ">" << std::endl; + std::cerr << std::endl; } else if (Cast(node)) { Expression* expression = Cast(node); std::cerr << ind << "Expression " << expression; diff --git a/src/error_handling.cpp b/src/error_handling.cpp index 52f0c37744..d96fe529eb 100644 --- a/src/error_handling.cpp +++ b/src/error_handling.cpp @@ -18,8 +18,8 @@ namespace Sass { prefix("Error"), pstate(pstate), traces(traces) { } - InvalidSass::InvalidSass(SourceSpan pstate, Backtraces traces, sass::string msg, char* owned_src) - : Base(pstate, msg, traces), owned_src(owned_src) + InvalidSass::InvalidSass(SourceSpan pstate, Backtraces traces, sass::string msg) + : Base(pstate, msg, traces) { } @@ -164,11 +164,11 @@ namespace Sass { void warning(sass::string msg, SourceSpan pstate) { sass::string cwd(Sass::File::get_cwd()); - sass::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); - sass::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); - sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); + sass::string abs_path(Sass::File::rel2abs(pstate.getPath(), cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(pstate.getPath(), cwd, cwd)); + sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.getPath())); - std::cerr << "WARNING on line " << pstate.line+1 << ", column " << pstate.column+1 << " of " << output_path << ":" << std::endl; + std::cerr << "WARNING on line " << pstate.getLine() << ", column " << pstate.getColumn() << " of " << output_path << ":" << std::endl; std::cerr << msg << std::endl << std::endl; } @@ -180,24 +180,24 @@ namespace Sass { void deprecated_function(sass::string msg, SourceSpan pstate) { sass::string cwd(Sass::File::get_cwd()); - sass::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); - sass::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); - sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); + sass::string abs_path(Sass::File::rel2abs(pstate.getPath(), cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(pstate.getPath(), cwd, cwd)); + sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.getPath())); std::cerr << "DEPRECATION WARNING: " << msg << std::endl; std::cerr << "will be an error in future versions of Sass." << std::endl; - std::cerr << " on line " << pstate.line+1 << " of " << output_path << std::endl; + std::cerr << " on line " << pstate.getLine() << " of " << output_path << std::endl; } void deprecated(sass::string msg, sass::string msg2, bool with_column, SourceSpan pstate) { sass::string cwd(Sass::File::get_cwd()); - sass::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); - sass::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); - sass::string output_path(Sass::File::path_for_console(rel_path, pstate.path, pstate.path)); + sass::string abs_path(Sass::File::rel2abs(pstate.getPath(), cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(pstate.getPath(), cwd, cwd)); + sass::string output_path(Sass::File::path_for_console(rel_path, pstate.getPath(), pstate.getPath())); - std::cerr << "DEPRECATION WARNING on line " << pstate.line + 1; - if (with_column) std::cerr << ", column " << pstate.column + pstate.offset.column + 1; + std::cerr << "DEPRECATION WARNING on line " << pstate.getLine(); + // if (with_column) std::cerr << ", column " << pstate.column + pstate.offset.column + 1; if (output_path.length()) std::cerr << " of " << output_path; std::cerr << ":" << std::endl; std::cerr << msg << std::endl; @@ -208,12 +208,12 @@ namespace Sass { void deprecated_bind(sass::string msg, SourceSpan pstate) { sass::string cwd(Sass::File::get_cwd()); - sass::string abs_path(Sass::File::rel2abs(pstate.path, cwd, cwd)); - sass::string rel_path(Sass::File::abs2rel(pstate.path, cwd, cwd)); - sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.path)); + sass::string abs_path(Sass::File::rel2abs(pstate.getPath(), cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(pstate.getPath(), cwd, cwd)); + sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, pstate.getPath())); std::cerr << "WARNING: " << msg << std::endl; - std::cerr << " on line " << pstate.line+1 << " of " << output_path << std::endl; + std::cerr << " on line " << pstate.getLine() << " of " << output_path << std::endl; std::cerr << "This will be an error in future versions of Sass." << std::endl; } diff --git a/src/error_handling.hpp b/src/error_handling.hpp index b185fac3ef..a7e8efc8ca 100644 --- a/src/error_handling.hpp +++ b/src/error_handling.hpp @@ -41,20 +41,8 @@ namespace Sass { class InvalidSass : public Base { public: - InvalidSass(InvalidSass& other) : Base(other), owned_src(other.owned_src) { - // Assumes that `this` will outlive `other`. - other.owned_src = nullptr; - } - - // Required because the copy constructor's argument is not const. - // Can't use `std::move` here because we build on Visual Studio 2013. - InvalidSass(InvalidSass &&other) : Base(other), owned_src(other.owned_src) { - other.owned_src = nullptr; - } - - InvalidSass(SourceSpan pstate, Backtraces traces, sass::string msg, char* owned_src = nullptr); - virtual ~InvalidSass() throw() { sass_free_memory(owned_src); }; - char *owned_src; + InvalidSass(SourceSpan pstate, Backtraces traces, sass::string msg); + virtual ~InvalidSass() throw() {}; }; class InvalidParent : public Base { diff --git a/src/eval.cpp b/src/eval.cpp index 50503afcbd..080bfa74eb 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -344,9 +344,9 @@ namespace Sass { // add call stack entry callee_stack().push_back({ "@warn", - w->pstate().path, - w->pstate().line + 1, - w->pstate().column + 1, + w->pstate().getPath(), + w->pstate().getLine(), + w->pstate().getColumn(), SASS_CALLEE_FUNCTION, { env } }); @@ -392,9 +392,9 @@ namespace Sass { // add call stack entry callee_stack().push_back({ "@error", - e->pstate().path, - e->pstate().line + 1, - e->pstate().column + 1, + e->pstate().getPath(), + e->pstate().getLine(), + e->pstate().getColumn(), SASS_CALLEE_FUNCTION, { env } }); @@ -436,9 +436,9 @@ namespace Sass { // add call stack entry callee_stack().push_back({ "@debug", - d->pstate().path, - d->pstate().line + 1, - d->pstate().column + 1, + d->pstate().getPath(), + d->pstate().getLine(), + d->pstate().getColumn(), SASS_CALLEE_FUNCTION, { env } }); @@ -462,12 +462,12 @@ namespace Sass { } sass::string result(unquote(message->to_sass())); - sass::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd(), cwd())); - sass::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd(), cwd())); - sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path)); + sass::string abs_path(Sass::File::rel2abs(d->pstate().getPath(), cwd(), cwd())); + sass::string rel_path(Sass::File::abs2rel(d->pstate().getPath(), cwd(), cwd())); + sass::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().getPath())); options().output_style = outstyle; - std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result; + std::cerr << output_path << ":" << d->pstate().getLine() << " DEBUG: " << result; std::cerr << std::endl; return 0; } @@ -1043,9 +1043,9 @@ namespace Sass { traces.push_back(Backtrace(c->pstate(), msg)); callee_stack().push_back({ c->name().c_str(), - c->pstate().path, - c->pstate().line + 1, - c->pstate().column + 1, + c->pstate().getPath(), + c->pstate().getLine(), + c->pstate().getColumn(), SASS_CALLEE_FUNCTION, { env } }); @@ -1083,9 +1083,9 @@ namespace Sass { traces.push_back(Backtrace(c->pstate(), msg)); callee_stack().push_back({ c->name().c_str(), - c->pstate().path, - c->pstate().line + 1, - c->pstate().column + 1, + c->pstate().getPath(), + c->pstate().getLine(), + c->pstate().getColumn(), SASS_CALLEE_C_FUNCTION, { env } }); @@ -1122,7 +1122,7 @@ namespace Sass { // link back to function definition // only do this for custom functions - if (result->pstate().file == sass::string::npos) + if (result->pstate().getSrcId() == sass::string::npos) result->pstate(c->pstate()); result = result->perform(this); @@ -1503,9 +1503,9 @@ namespace Sass { ExpressionObj sel = s->contents()->perform(this); sass::string result_str(sel->to_string(options())); result_str = unquote(Util::rtrim(result_str)); - char* temp_cstr = sass_copy_c_string(result_str.c_str()); - ctx.strings.push_back(temp_cstr); // attach to context - Parser p = Parser::from_c_str(temp_cstr, ctx, traces, s->pstate()); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, + result_str.c_str(), s->pstate()); + Parser p(source, ctx, traces); // If a schema contains a reference to parent it is already // connected to it, so don't connect implicitly anymore diff --git a/src/expand.cpp b/src/expand.cpp index 569ccbb5c3..b9731782a5 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -258,9 +258,9 @@ namespace Sass { { ExpressionObj mq = eval(m->schema()); sass::string str_mq(mq->to_css(ctx.c_options)); - char* str = sass_copy_c_string(str_mq.c_str()); - ctx.strings.push_back(str); - Parser parser(Parser::from_c_str(str, ctx, traces, mq->pstate())); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, + str_mq.c_str(), m->pstate()); + Parser parser(source, ctx, traces); // Create a new CSS only representation of the media rule CssMediaRuleObj css = SASS_MEMORY_NEW(CssMediaRule, m->pstate(), m->block()); sass::vector parsed = parser.parseCssMediaQueries(); @@ -786,9 +786,9 @@ namespace Sass { traces.push_back(Backtrace(c->pstate(), msg)); ctx.callee_stack.push_back({ c->name().c_str(), - c->pstate().path, - c->pstate().line + 1, - c->pstate().column + 1, + c->pstate().getPath(), + c->pstate().getLine(), + c->pstate().getColumn(), SASS_CALLEE_MIXIN, { env } }); diff --git a/src/extender.cpp b/src/extender.cpp index 1e77ac0b52..937ea5bb00 100644 --- a/src/extender.cpp +++ b/src/extender.cpp @@ -388,7 +388,7 @@ namespace Sass { CssMediaRuleObj mediaContext; if (mediaContexts.hasKey(rule)) mediaContext = mediaContexts.get(rule); SelectorListObj ext = extendList(rule, newExtensions, mediaContext); - // If no extends actually happenedit (for example becaues unification + // If no extends actually happened (for example because unification // failed), we don't need to re-register the selector. if (ObjEqualityFn(oldValue, ext)) continue; rule->elements(ext->elements()); @@ -1063,7 +1063,7 @@ namespace Sass { // TODO(nweiz): I think there may be a way to get perfect trimming // without going quadratic by building some sort of trie-like // data structure that can be used to look up superselectors. - // TODO(mgreter): Check how this perfoms in C++ (up the limit) + // TODO(mgreter): Check how this performs in C++ (up the limit) if (selectors.size() > 100) return selectors; // This is n² on the sequences, but only comparing between separate sequences diff --git a/src/fn_selectors.cpp b/src/fn_selectors.cpp index 46f541a78f..7494451e0e 100644 --- a/src/fn_selectors.cpp +++ b/src/fn_selectors.cpp @@ -36,7 +36,8 @@ namespace Sass { str->quote_mark(0); } sass::string exp_src = exp->to_string(ctx.c_options); - SelectorListObj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate()); + SelectorListObj sel = Parser::parse_selector(source, ctx, traces); parsedSelectors.push_back(sel); } @@ -90,9 +91,8 @@ namespace Sass { str->quote_mark(0); } sass::string exp_src = exp->to_string(); - SelectorListObj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces, - exp->pstate(), pstate.src, - /*allow_parent=*/true); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate()); + SelectorListObj sel = Parser::parse_selector(source, ctx, traces, true); for (auto& complex : sel->elements()) { if (complex->empty()) { diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index 6c53641a71..bcf5363973 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -10,12 +10,13 @@ namespace Sass { Definition* make_native_function(Signature sig, Native_Function func, Context& ctx) { - Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, SourceSpan("[built-in function]")); + SourceFile* source = SASS_MEMORY_NEW(SourceFile, "[built-in function]", sig, std::string::npos); + Parser sig_parser(source, ctx, ctx.traces); sig_parser.lex(); sass::string name(Util::normalize_underscores(sig_parser.lexed)); Parameters_Obj params = sig_parser.parse_parameters(); return SASS_MEMORY_NEW(Definition, - SourceSpan("[built-in function]"), + SourceSpan(source), sig, name, params, @@ -26,9 +27,9 @@ namespace Sass { Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx) { using namespace Prelexer; - const char* sig = sass_function_get_signature(c_func); - Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, SourceSpan("[c function]")); + SourceFile* source = SASS_MEMORY_NEW(SourceFile, "[c function]", sig, std::string::npos); + Parser sig_parser(source, ctx, ctx.traces); // allow to overload generic callback plus @warn, @error and @debug with custom functions sig_parser.lex < alternatives < identifier, exactly <'*'>, exactly < Constants::warn_kwd >, @@ -38,7 +39,7 @@ namespace Sass { sass::string name(Util::normalize_underscores(sig_parser.lexed)); Parameters_Obj params = sig_parser.parse_parameters(); return SASS_MEMORY_NEW(Definition, - SourceSpan("[c function]"), + SourceSpan(source), sig, name, params, @@ -130,7 +131,8 @@ namespace Sass { str->quote_mark(0); } sass::string exp_src = exp->to_string(ctx.c_options); - return Parser::parse_selector(exp_src.c_str(), ctx, traces, exp->pstate(), pstate.src, /*allow_parent=*/false); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate()); + return Parser::parse_selector(source, ctx, traces, false); } CompoundSelectorObj get_arg_sel(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces, Context& ctx) { @@ -144,7 +146,8 @@ namespace Sass { str->quote_mark(0); } sass::string exp_src = exp->to_string(ctx.c_options); - SelectorListObj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces, exp->pstate(), pstate.src, /*allow_parent=*/false); + ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate()); + SelectorListObj sel_list = Parser::parse_selector(source, ctx, traces, false); if (sel_list->length() == 0) return {}; return sel_list->first()->first(); } diff --git a/src/mapping.hpp b/src/mapping.hpp index 54fb4a0f75..d6a3336aa7 100644 --- a/src/mapping.hpp +++ b/src/mapping.hpp @@ -2,6 +2,7 @@ #define SASS_MAPPING_H #include "position.hpp" +#include "backtrace.hpp" namespace Sass { diff --git a/src/memory/allocator.cpp b/src/memory/allocator.cpp index bbbbde5e6e..7ad4a542ab 100644 --- a/src/memory/allocator.cpp +++ b/src/memory/allocator.cpp @@ -1,5 +1,6 @@ #include "../sass.hpp" -#include "../memory.hpp" +#include "allocator.hpp" +#include "memory_pool.hpp" #if defined (_MSC_VER) // Visual studio #define thread_local __declspec( thread ) diff --git a/src/memory/allocator.hpp b/src/memory/allocator.hpp index a6bde56066..a830457107 100644 --- a/src/memory/allocator.hpp +++ b/src/memory/allocator.hpp @@ -133,7 +133,6 @@ namespace std { }; } - #endif #endif diff --git a/src/memory/memory_pool.hpp b/src/memory/memory_pool.hpp index bd534c4ce4..cd6d325fa0 100644 --- a/src/memory/memory_pool.hpp +++ b/src/memory/memory_pool.hpp @@ -1,9 +1,11 @@ #ifndef SASS_MEMORY_POOL_H #define SASS_MEMORY_POOL_H -#include "../sass.hpp" -#include "../memory.hpp" +#include +#include +#include #include +#include namespace Sass { diff --git a/src/output.cpp b/src/output.cpp index a43bbf5d14..04819bad4d 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -137,8 +137,8 @@ namespace Sass { if (opt.source_comments) { sass::ostream ss; append_indentation(); - sass::string path(File::abs2rel(r->pstate().path)); - ss << "/* line " << r->pstate().line + 1 << ", " << path << " */"; + sass::string path(File::abs2rel(r->pstate().getPath())); + ss << "/* line " << r->pstate().getLine() << ", " << path << " */"; append_string(ss.str()); append_optional_linefeed(); } diff --git a/src/parser.cpp b/src/parser.cpp index 4847d81f62..2dd3c59601 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -23,45 +23,39 @@ namespace Sass { using namespace Constants; using namespace Prelexer; - Parser Parser::from_c_str(const char* beg, Context& ctx, Backtraces traces, SourceSpan pstate, const char* source, bool allow_parent) - { - pstate.offset.column = 0; - pstate.offset.line = 0; - Parser p(ctx, pstate, traces, allow_parent); - p.source = source ? source : beg; - p.position = beg ? beg : p.source; - p.end = p.position + strlen(p.position); - Block_Obj root = SASS_MEMORY_NEW(Block, pstate); - p.block_stack.push_back(root); - root->is_root(true); - return p; - } - Parser Parser::from_c_str(const char* beg, const char* end, Context& ctx, Backtraces traces, SourceSpan pstate, const char* source, bool allow_parent) + Parser::Parser(SourceData* source, Context& ctx, Backtraces traces, bool allow_parent) : + SourceSpan(source), + ctx(ctx), + source(source), + begin(source->begin()), + position(source->begin()), + end(source->end()), + before_token(0, 0), + after_token(0, 0), + pstate(source->getSourceSpan()), + traces(traces), + indentation(0), + nestings(0), + allow_parent(allow_parent) { - pstate.offset.column = 0; - pstate.offset.line = 0; - Parser p(ctx, pstate, traces, allow_parent); - p.source = source ? source : beg; - p.position = beg ? beg : p.source; - p.end = end ? end : p.position + strlen(p.position); Block_Obj root = SASS_MEMORY_NEW(Block, pstate); - p.block_stack.push_back(root); + stack.push_back(Scope::Root); + block_stack.push_back(root); root->is_root(true); - return p; } - void Parser::advanceToNextToken() { + void Parser::advanceToNextToken() { lex < css_comments >(false); // advance to position - pstate += pstate.offset; + pstate.position += pstate.offset; pstate.offset.column = 0; pstate.offset.line = 0; } - SelectorListObj Parser::parse_selector(const char* beg, Context& ctx, Backtraces traces, SourceSpan pstate, const char* source, bool allow_parent) + SelectorListObj Parser::parse_selector(SourceData* source, Context& ctx, Backtraces traces, bool allow_parent) { - Parser p = Parser::from_c_str(beg, ctx, traces, pstate, source, allow_parent); + Parser p(source, ctx, traces, allow_parent); // ToDo: remap the source-map entries somehow return p.parseSelectorList(false); } @@ -72,18 +66,6 @@ namespace Sass { && ! peek_css>(start); } - Parser Parser::from_token(Token t, Context& ctx, Backtraces traces, SourceSpan pstate, const char* source) - { - Parser p(ctx, pstate, traces); - p.source = source ? source : t.begin; - p.position = t.begin ? t.begin : p.source; - p.end = t.end ? t.end : p.position + strlen(p.position); - Block_Obj root = SASS_MEMORY_NEW(Block, pstate); - p.block_stack.push_back(root); - root->is_root(true); - return p; - } - /* main entry point to parse root block */ Block_Obj Parser::parse() { @@ -96,7 +78,7 @@ namespace Sass { // report invalid utf8 if (it != end) { - pstate += Offset::init(position, it); + pstate.position += Offset::init(position, it); traces.push_back(Backtrace(pstate)); throw Exception::InvalidSass(pstate, traces, "Invalid UTF-8 sequence"); } @@ -107,7 +89,7 @@ namespace Sass { // check seems a bit esoteric but works if (ctx.resources.size() == 1) { // apply headers only on very first include - ctx.apply_custom_headers(root, path, pstate); + ctx.apply_custom_headers(root, getPath(), pstate); } // parse children nodes @@ -372,9 +354,9 @@ namespace Sass { imp->urls().push_back(location.second); } // check if custom importers want to take over the handling - else if (!ctx.call_importers(unquote(location.first), path, pstate, imp)) { + else if (!ctx.call_importers(unquote(location.first), getPath(), pstate, imp)) { // nobody wants it, so we do our import - ctx.import_url(imp, location.first, path); + ctx.import_url(imp, location.first, getPath()); } } @@ -571,7 +553,7 @@ namespace Sass { if (i < p) { sass::string parsed(i, p); String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed); - pstate += Offset(parsed); + pstate.position += Offset(parsed); str->update_pstate(pstate); schema->append(str); } @@ -584,15 +566,16 @@ namespace Sass { css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was "); } // pass inner expression to the parser to resolve nested interpolations - pstate.add(p, p+2); - ExpressionObj interpolant = Parser::from_c_str(p+2, j, ctx, traces, pstate).parse_list(); + LocalOption partEnd(end, j); + LocalOption partBeg(position, p + 2); + ExpressionObj interpolant = parse_list(); // set status on the list expression interpolant->is_interpolant(true); // schema->has_interpolants(true); // add to the string schema schema->append(interpolant); // advance parser state - pstate.add(p+2, j); + pstate.position.add(p+2, j); // advance position i = j; } @@ -603,7 +586,7 @@ namespace Sass { if (i < end_of_selector) { sass::string parsed(i, end_of_selector); String_Constant_Obj str = SASS_MEMORY_NEW(String_Constant, pstate, parsed); - pstate += Offset(parsed); + pstate.position += Offset(parsed); str->update_pstate(pstate); i = end_of_selector; schema->append(str); @@ -620,7 +603,7 @@ namespace Sass { selector_schema->update_pstate(pstate); schema->update_pstate(pstate); - after_token = before_token = pstate; + after_token = before_token = pstate.position; // return parsed result return selector_schema.detach(); @@ -966,7 +949,7 @@ namespace Sass { } SourceSpan ps = map->pstate(); - ps.offset = pstate - ps + pstate.offset; + ps.offset = pstate.position - ps.position + pstate.offset; map->pstate(ps); return map; @@ -1106,7 +1089,7 @@ namespace Sass { if (operands.size() == 0) return conj; // fold all operands into one binary expression ExpressionObj ex = fold_operands(conj, operands, { Sass_OP::OR }); - state.offset = pstate - state + pstate.offset; + state.offset = pstate.position - state.position + pstate.offset; ex->pstate(state); return ex; } @@ -1129,7 +1112,7 @@ namespace Sass { if (operands.size() == 0) return rel; // fold all operands into one binary expression ExpressionObj ex = fold_operands(rel, operands, { Sass_OP::AND }); - state.offset = pstate - state + pstate.offset; + state.offset = pstate.position - state.position + pstate.offset; ex->pstate(state); return ex; } @@ -1178,7 +1161,7 @@ namespace Sass { // single nested items. So we cannot set delay on the // returned result here, as we have lost nestings ... ExpressionObj ex = fold_operands(lhs, operands, operators); - state.offset = pstate - state + pstate.offset; + state.offset = pstate.position - state.position + pstate.offset; ex->pstate(state); return ex; } @@ -1227,7 +1210,7 @@ namespace Sass { if (operands.size() == 0) return lhs; ExpressionObj ex = fold_operands(lhs, operands, operators); - state.offset = pstate - state + pstate.offset; + state.offset = pstate.position - state.position + pstate.offset; ex->pstate(state); return ex; } @@ -1257,7 +1240,7 @@ namespace Sass { } // operands and operators to binary expression ExpressionObj ex = fold_operands(factor, operands, operators); - state.offset = pstate - state + pstate.offset; + state.offset = pstate.position - state.position + pstate.offset; ex->pstate(state); return ex; } @@ -1583,7 +1566,9 @@ namespace Sass { const char* j = skip_over_scopes< exactly, exactly >(p + 2, chunk.end); // find the closing brace if (j) { --j; // parse the interpolant and accumulate it - ExpressionObj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(); + LocalOption partEnd(end, j); + LocalOption partBeg(position, p + 2); + ExpressionObj interp_node = parse_list(); interp_node->is_interpolant(true); schema->append(interp_node); i = j; @@ -1706,7 +1691,9 @@ namespace Sass { const char* j = skip_over_scopes< exactly, exactly >(p+2, str.end); // find the closing brace if (j) { // parse the interpolant and accumulate it - ExpressionObj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(); + LocalOption partEnd(end, j); + LocalOption partBeg(position, p + 2); + ExpressionObj interp_node = parse_list(); interp_node->is_interpolant(true); schema->append(interp_node); i = j; @@ -1884,7 +1871,9 @@ namespace Sass { const char* j = skip_over_scopes< exactly, exactly >(p+2, id.end); // find the closing brace if (j) { // parse the interpolant and accumulate it - ExpressionObj interp_node = Parser::from_token(Token(p+2, j), ctx, traces, pstate, source).parse_list(DELAYED); + LocalOption partEnd(end, j); + LocalOption partBeg(position, p + 2); + ExpressionObj interp_node = parse_list(DELAYED); interp_node->is_interpolant(true); schema->append(interp_node); // schema->has_interpolants(true); @@ -2072,7 +2061,7 @@ namespace Sass { css_error("Invalid CSS", " after ", ": expected identifier, was "); } // return object - return token; + return lexed; } // helper to parse identifier Token Parser::lex_identifier() @@ -2082,7 +2071,7 @@ namespace Sass { css_error("Invalid CSS", " after ", ": expected identifier, was "); } // return object - return token; + return lexed; } EachRuleObj Parser::parse_each_directive() @@ -2764,51 +2753,51 @@ namespace Sass { size_t skip = 0; sass::string encoding; bool utf_8 = false; - switch ((unsigned char) source[0]) { + switch ((unsigned char)position[0]) { case 0xEF: - skip = check_bom_chars(source, end, utf_8_bom, 3); + skip = check_bom_chars(position, end, utf_8_bom, 3); encoding = "UTF-8"; utf_8 = true; break; case 0xFE: - skip = check_bom_chars(source, end, utf_16_bom_be, 2); + skip = check_bom_chars(position, end, utf_16_bom_be, 2); encoding = "UTF-16 (big endian)"; break; case 0xFF: - skip = check_bom_chars(source, end, utf_16_bom_le, 2); - skip += (skip ? check_bom_chars(source, end, utf_32_bom_le, 4) : 0); + skip = check_bom_chars(position, end, utf_16_bom_le, 2); + skip += (skip ? check_bom_chars(position, end, utf_32_bom_le, 4) : 0); encoding = (skip == 2 ? "UTF-16 (little endian)" : "UTF-32 (little endian)"); break; case 0x00: - skip = check_bom_chars(source, end, utf_32_bom_be, 4); + skip = check_bom_chars(position, end, utf_32_bom_be, 4); encoding = "UTF-32 (big endian)"; break; case 0x2B: - skip = check_bom_chars(source, end, utf_7_bom_1, 4) - | check_bom_chars(source, end, utf_7_bom_2, 4) - | check_bom_chars(source, end, utf_7_bom_3, 4) - | check_bom_chars(source, end, utf_7_bom_4, 4) - | check_bom_chars(source, end, utf_7_bom_5, 5); + skip = check_bom_chars(position, end, utf_7_bom_1, 4) + | check_bom_chars(position, end, utf_7_bom_2, 4) + | check_bom_chars(position, end, utf_7_bom_3, 4) + | check_bom_chars(position, end, utf_7_bom_4, 4) + | check_bom_chars(position, end, utf_7_bom_5, 5); encoding = "UTF-7"; break; case 0xF7: - skip = check_bom_chars(source, end, utf_1_bom, 3); + skip = check_bom_chars(position, end, utf_1_bom, 3); encoding = "UTF-1"; break; case 0xDD: - skip = check_bom_chars(source, end, utf_ebcdic_bom, 4); + skip = check_bom_chars(position, end, utf_ebcdic_bom, 4); encoding = "UTF-EBCDIC"; break; case 0x0E: - skip = check_bom_chars(source, end, scsu_bom, 3); + skip = check_bom_chars(position, end, scsu_bom, 3); encoding = "SCSU"; break; case 0xFB: - skip = check_bom_chars(source, end, bocu_1_bom, 3); + skip = check_bom_chars(position, end, bocu_1_bom, 3); encoding = "BOCU-1"; break; case 0x84: - skip = check_bom_chars(source, end, gb_18030_bom, 4); + skip = check_bom_chars(position, end, gb_18030_bom, 4); encoding = "GB-18030"; break; default: break; @@ -2891,24 +2880,10 @@ namespace Sass { return base; } - void Parser::error(sass::string msg, Position pos) - { - Position p(pos.line ? pos : before_token); - SourceSpan pstate(path, source, p, Offset(0, 0)); - // `pstate.src` may not outlive stack unwind so we must copy it. - // This is needed since we often parse dynamically generated code, - // e.g. for interpolations, and we normally don't want to keep this - // memory around after we parsed the AST tree successfully. Only on - // errors we want to preserve them for better error reporting. - char *src_copy = sass_copy_c_string(pstate.src); - pstate.src = src_copy; - traces.push_back(Backtrace(pstate)); - throw Exception::InvalidSass(pstate, traces, msg, src_copy); - } - void Parser::error(sass::string msg) { - error(msg, pstate); + traces.push_back(Backtrace(pstate)); + throw Exception::InvalidSass(pstate, traces, msg); } // print a css parsing error with actual context information from parsed source @@ -2921,13 +2896,13 @@ namespace Sass { if (!pos) pos = position; const char* last_pos(pos); - if (last_pos > source) { - utf8::prior(last_pos, source); + if (last_pos > begin) { + utf8::prior(last_pos, begin); } // backup position to last significant char - while (trim && last_pos > source && last_pos < end) { + while (trim && last_pos > begin&& last_pos < end) { if (!Util::ascii_isspace(static_cast(*last_pos))) break; - utf8::prior(last_pos, source); + utf8::prior(last_pos, begin); } bool ellipsis_left = false; @@ -2936,9 +2911,9 @@ namespace Sass { if (*pos_left) utf8::next(pos_left, end); if (*end_left) utf8::next(end_left, end); - while (pos_left > source) { + while (pos_left > begin) { if (utf8::distance(pos_left, end_left) >= max_len) { - utf8::prior(pos_left, source); + utf8::prior(pos_left, begin); ellipsis_left = *(pos_left) != '\n' && *(pos_left) != '\r'; utf8::next(pos_left, end); @@ -2946,13 +2921,13 @@ namespace Sass { } const char* prev = pos_left; - utf8::prior(prev, source); + utf8::prior(prev, begin); if (*prev == '\r') break; if (*prev == '\n') break; pos_left = prev; } - if (pos_left < source) { - pos_left = source; + if (pos_left < begin) { + pos_left = begin; } bool ellipsis_right = false; @@ -2976,8 +2951,6 @@ namespace Sass { size_t right_subpos = right.size() > 15 ? right.size() - 15 : 0; if (left_subpos && ellipsis_left) left = ellipsis + left.substr(left_subpos); if (right_subpos && ellipsis_right) right = right.substr(right_subpos) + ellipsis; - // Hotfix when source is null, probably due to interpolation parsing!? - if (source == NULL || *source == 0) source = pstate.src; // now pass new message to the more generic error function error(msg + prefix + quote(left) + middle + quote(right)); } diff --git a/src/parser.hpp b/src/parser.hpp index e35e4286b6..25c39b968f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -13,6 +13,7 @@ #include "context.hpp" #include "position.hpp" #include "prelexer.hpp" +#include "source.hpp" #ifndef MAX_NESTING // Note that this limit is not an exact science @@ -42,33 +43,23 @@ namespace Sass { Context& ctx; sass::vector block_stack; sass::vector stack; - const char* source; + SourceDataObj source; + const char* begin; const char* position; const char* end; - Position before_token; - Position after_token; + Offset before_token; + Offset after_token; SourceSpan pstate; Backtraces traces; size_t indentation; size_t nestings; bool allow_parent; - Token lexed; - Parser(Context& ctx, const SourceSpan& pstate, Backtraces traces, bool allow_parent = true) - : SourceSpan(pstate), ctx(ctx), block_stack(), stack(0), - source(0), position(0), end(0), before_token(pstate), after_token(pstate), - pstate(pstate), traces(traces), indentation(0), nestings(0), allow_parent(allow_parent) - { - stack.push_back(Scope::Root); - } + Parser(SourceData* source, Context& ctx, Backtraces, bool allow_parent = true); - // static Parser from_string(const sass::string& src, Context& ctx, SourceSpan pstate = SourceSpan("[STRING]")); - static Parser from_c_str(const char* src, Context& ctx, Backtraces, SourceSpan pstate = SourceSpan("[CSTRING]"), const char* source = nullptr, bool allow_parent = true); - static Parser from_c_str(const char* beg, const char* end, Context& ctx, Backtraces, SourceSpan pstate = SourceSpan("[CSTRING]"), const char* source = nullptr, bool allow_parent = true); - static Parser from_token(Token t, Context& ctx, Backtraces, SourceSpan pstate = SourceSpan("[TOKEN]"), const char* source = nullptr); // special static parsers to convert strings into certain selectors - static SelectorListObj parse_selector(const char* src, Context& ctx, Backtraces, SourceSpan pstate = SourceSpan("[SELECTOR]"), const char* source = nullptr, bool allow_parent = true); + static SelectorListObj parse_selector(SourceData* source, Context& ctx, Backtraces, bool allow_parent = true); #ifdef __clang__ @@ -189,7 +180,7 @@ namespace Sass { after_token.add(it_before_token, it_after_token); // ToDo: could probably do this incremental on original object (API wants offset?) - pstate = SourceSpan(path, source, lexed, before_token, after_token - before_token); + pstate = SourceSpan(source, before_token, after_token - before_token); // advance internal char iterator return position = it_after_token; @@ -206,8 +197,8 @@ namespace Sass { Token prev = lexed; // store previous pointer const char* oldpos = position; - Position bt = before_token; - Position at = after_token; + Offset bt = before_token; + Offset at = after_token; SourceSpan op = pstate; // throw away comments // update srcmap position @@ -241,7 +232,6 @@ namespace Sass { #endif void error(sass::string msg); - void error(sass::string msg, Position pos); // generate message with given and expected sample // text before and in the middle are configurable void css_error(const sass::string& msg, diff --git a/src/parser_selectors.cpp b/src/parser_selectors.cpp index 1d1312a699..6f60e616c4 100644 --- a/src/parser_selectors.cpp +++ b/src/parser_selectors.cpp @@ -148,7 +148,7 @@ namespace Sass { if (!seq->empty()) { sel = seq->last()->to_string({ NESTED, 5 }); } // ToDo: parser should throw parser exceptions error("Invalid CSS after \"" + sel + "\": expected \"{\", was \"" + found + "\"\n\n" - "\"" + found + "\" may only be used at the beginning of a compound selector.", state); + "\"" + found + "\" may only be used at the beginning of a compound selector."); } // parse functional else if (match < re_functional >()) diff --git a/src/permutate.hpp b/src/permutate.hpp index 2a7f05c69a..387704f510 100644 --- a/src/permutate.hpp +++ b/src/permutate.hpp @@ -7,13 +7,17 @@ namespace Sass { // Returns a list of all possible paths through the given lists. // - // For example, given `[[1, 2], [3, 4], [5]]`, this returns: + // For example, given `[[1, 2], [3, 4], [5, 6]]`, this returns: // // ``` // [[1, 3, 5], // [2, 3, 5], // [1, 4, 5], - // [2, 4, 5]] + // [2, 4, 5], + // [1, 3, 6], + // [2, 3, 6], + // [1, 4, 6], + // [2, 4, 6]] // ``` // // Note: called `paths` in dart-sass @@ -74,7 +78,22 @@ namespace Sass { } // EO permutate - // ToDo: this variant is used in resolve_parent_refs + // ToDo: this variant is used in resolveParentSelectors + // Returns a list of all possible paths through the given lists. + // + // For example, given `[[1, 2], [3, 4], [5, 6]]`, this returns: + // + // ``` + // [[1, 3, 5], + // [1, 3, 6], + // [1, 4, 5], + // [1, 4, 6], + // [2, 3, 5], + // [2, 3, 6], + // [2, 4, 5], + // [2, 4, 6]] + // ``` + // template sass::vector> permutateAlt(const sass::vector>& in) { @@ -89,7 +108,7 @@ namespace Sass { } size_t* state = new size_t[L]; - sass::vector< sass::vector> out; + sass::vector> out; // First initialize all states for every permutation group for (size_t i = 0; i < L; i += 1) { diff --git a/src/position.cpp b/src/position.cpp index ae7a1e9b54..33efdf90e4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -3,6 +3,7 @@ #include "sass.hpp" #include "position.hpp" +#include "source.hpp" namespace Sass { @@ -56,7 +57,7 @@ namespace Sass { // skip over 10xxxxxx // is 1st bit not set if ((chr & 128) == 0) { - // regular ascii char + // regular ASCII char column += 1; } // is 2nd bit not set @@ -117,14 +118,11 @@ namespace Sass { : Offset(line, column), file(file) { } - SourceSpan::SourceSpan(const char* path, const char* src, const size_t file) - : Position(file, 0, 0), path(path), src(src), offset(0, 0), token() { } + SourceSpan::SourceSpan(const char* path) + : source(SASS_MEMORY_NEW(SynthFile, path)), position(0, 0), offset(0, 0) { } - SourceSpan::SourceSpan(const char* path, const char* src, const Position& position, Offset offset) - : Position(position), path(path), src(src), offset(offset), token() { } - - SourceSpan::SourceSpan(const char* path, const char* src, const Token& token, const Position& position, Offset offset) - : Position(position), path(path), src(src), offset(offset), token(token) { } + SourceSpan::SourceSpan(SourceDataObj source, const Offset& position, const Offset& offset) + : source(source), position(position), offset(offset) { } Position Position::add(const char* begin, const char* end) { @@ -164,21 +162,4 @@ namespace Sass { return Offset(line - off.line, off.line == line ? column - off.column : column); } - /* not used anymore - remove? - std::ostream& operator<<(std::ostream& strm, const Offset& off) - { - if (off.line == string::npos) strm << "-1:"; else strm << off.line << ":"; - if (off.column == string::npos) strm << "-1"; else strm << off.column; - return strm; - } */ - - /* not used anymore - remove? - std::ostream& operator<<(std::ostream& strm, const Position& pos) - { - if (pos.file != string::npos) strm << pos.file << ":"; - if (pos.line == string::npos) strm << "-1:"; else strm << pos.line << ":"; - if (pos.column == string::npos) strm << "-1"; else strm << pos.column; - return strm; - } */ - } diff --git a/src/position.hpp b/src/position.hpp index 4b513db1f5..45d78a0494 100644 --- a/src/position.hpp +++ b/src/position.hpp @@ -3,7 +3,8 @@ #include #include -// #include +#include "source_data.hpp" +#include "ast_fwd_decl.hpp" namespace Sass { @@ -99,23 +100,45 @@ namespace Sass { bool operator==(Token t) { return to_string() == t.to_string(); } }; - class SourceSpan : public Position { + class SourceSpan { - public: // c-tor - SourceSpan(const char* path, const char* src = 0, const size_t file = sass::string::npos); - SourceSpan(const char* path, const char* src, const Position& position, Offset offset = Offset(0, 0)); - SourceSpan(const char* path, const char* src, const Token& token, const Position& position, Offset offset = Offset(0, 0)); + public: - public: // down casts - Offset off() { return *this; } - Position pos() { return *this; } - SourceSpan pstate() { return *this; } + SourceSpan(const char* path); - public: - const char* path; - const char* src; + SourceSpan(SourceDataObj source, + const Offset& position = Offset(0, 0), + const Offset& offset = Offset(0, 0)); + + const char* getPath() const { + return source->getPath(); + } + + const char* getRawData() const { + return source->getRawData(); + } + + Offset getPosition() const { + return position; + } + + size_t getLine() const { + return position.line + 1; + } + + size_t getColumn() const { + return position.column + 1; + } + + size_t getSrcId() const { + return source == nullptr + ? std::string::npos + : source->getSrcId(); + } + + SourceDataObj source; + Offset position; Offset offset; - Token token; }; diff --git a/src/sass.cpp b/src/sass.cpp index 6da122408b..35383ebf08 100644 --- a/src/sass.cpp +++ b/src/sass.cpp @@ -46,6 +46,7 @@ extern "C" { char* ADDCALL sass_copy_c_string(const char* str) { + if (str == nullptr) return nullptr; size_t len = strlen(str) + 1; char* cpy = (char*) sass_alloc_memory(len); std::memcpy(cpy, str, len); diff --git a/src/sass_context.cpp b/src/sass_context.cpp index 80874befa3..e10f046345 100644 --- a/src/sass_context.cpp +++ b/src/sass_context.cpp @@ -65,24 +65,25 @@ namespace Sass { if (e.traces.empty()) { // we normally should have some traces, still here as a fallback - sass::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(e.pstate.getPath(), cwd, cwd)); msg_stream << sass::string(msg_prefix.size() + 2, ' '); - msg_stream << " on line " << e.pstate.line + 1 << " of " << rel_path << "\n"; + msg_stream << " on line " << e.pstate.getLine() << " of " << rel_path << "\n"; } else { - sass::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd)); + sass::string rel_path(Sass::File::abs2rel(e.pstate.getPath(), cwd, cwd)); msg_stream << traces_to_string(e.traces, " "); } // now create the code trace (ToDo: maybe have util functions?) - if (e.pstate.line != sass::string::npos && - e.pstate.column != sass::string::npos && - e.pstate.src != nullptr) { - size_t lines = e.pstate.line; + if (e.pstate.position.line != sass::string::npos && + e.pstate.position.column != sass::string::npos && + e.pstate.source != nullptr) { + Offset offset(e.pstate.position); + size_t lines = offset.line; // scan through src until target line // move line_beg pointer to line start const char* line_beg; - for (line_beg = e.pstate.src; *line_beg != '\0'; ++line_beg) { + for (line_beg = e.pstate.getRawData(); *line_beg != '\0'; ++line_beg) { if (lines == 0) break; if (*line_beg == '\n') --lines; } @@ -96,12 +97,12 @@ namespace Sass { size_t move_in = 0; size_t shorten = 0; size_t left_chars = 42; size_t max_chars = 76; // reported excerpt should not exceed `max_chars` chars - if (e.pstate.column > line_len) left_chars = e.pstate.column; - if (e.pstate.column > left_chars) move_in = e.pstate.column - left_chars; + if (offset.column > line_len) left_chars = offset.column; + if (offset.column > left_chars) move_in = offset.column - left_chars; if (line_len > max_chars + move_in) shorten = line_len - move_in - max_chars; utf8::advance(line_beg, move_in, line_end); utf8::retreat(line_end, shorten, line_beg); - sass::string sanitized; sass::string marker(e.pstate.column - move_in, '-'); + sass::string sanitized; sass::string marker(offset.column - move_in, '-'); utf8::replace_invalid(line_beg, line_end, std::back_inserter(sanitized)); msg_stream << ">> " << sanitized << "\n"; msg_stream << " " << marker << "^\n"; @@ -109,9 +110,9 @@ namespace Sass { JsonNode* json_err = json_mkobject(); json_append_member(json_err, "status", json_mknumber(1)); - json_append_member(json_err, "file", json_mkstring(e.pstate.path)); - json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line + 1))); - json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column + 1))); + json_append_member(json_err, "file", json_mkstring(e.pstate.getPath())); + json_append_member(json_err, "line", json_mknumber((double)(e.pstate.getLine()))); + json_append_member(json_err, "column", json_mknumber((double)(e.pstate.getColumn()))); json_append_member(json_err, "message", json_mkstring(e.what())); json_append_member(json_err, "formatted", json_mkstream(msg_stream)); try { c_ctx->error_json = json_stringify(json_err, " "); } @@ -119,10 +120,10 @@ namespace Sass { c_ctx->error_message = sass_copy_string(msg_stream.str()); c_ctx->error_text = sass_copy_c_string(e.what()); c_ctx->error_status = 1; - c_ctx->error_file = sass_copy_c_string(e.pstate.path); - c_ctx->error_line = e.pstate.line + 1; - c_ctx->error_column = e.pstate.column + 1; - c_ctx->error_src = sass_copy_c_string(e.pstate.src); + c_ctx->error_file = sass_copy_c_string(e.pstate.getPath()); + c_ctx->error_line = e.pstate.getLine(); + c_ctx->error_column = e.pstate.getColumn(); + c_ctx->error_src = sass_copy_c_string(e.pstate.getRawData()); c_ctx->output_string = 0; c_ctx->source_map_string = 0; json_delete(json_err); diff --git a/src/sass_values.cpp b/src/sass_values.cpp index 6a9efa7d50..55bcb4d6a9 100644 --- a/src/sass_values.cpp +++ b/src/sass_values.cpp @@ -340,12 +340,10 @@ extern "C" { rv = Operators::op_colors(op, *l_c, *r_c, options, l_c->pstate()); } else /* convert other stuff to string and apply operation */ { - Value* l_v = Cast(lhs); - Value* r_v = Cast(rhs); - rv = Operators::op_strings(op, *l_v, *r_v, options, l_v->pstate()); + rv = Operators::op_strings(op, *lhs, *rhs, options, lhs->pstate()); } - // ToDo: maybe we should should return null value? + // ToDo: maybe we should return null value? if (!rv) return sass_make_error("invalid return value"); // convert result back to ast node diff --git a/src/source.cpp b/src/source.cpp new file mode 100644 index 0000000000..1ffab30b94 --- /dev/null +++ b/src/source.cpp @@ -0,0 +1,69 @@ +#include +#include +#include "source.hpp" +#include "utf8/checked.h" +#include "position.hpp" + +namespace Sass { + + SourceData::SourceData() + : SharedObj() + { + } + + SourceFile::SourceFile( + const char* path, + const char* data, + size_t srcid) : + SourceData(), + path(sass_copy_c_string(path)), + data(sass_copy_c_string(data)), + length(0), + srcid(srcid) + { + length = strlen(data); + } + + SourceFile::~SourceFile() { + sass_free_memory(path); + sass_free_memory(data); + } + + const char* SourceFile::end() const + { + return data + length; + } + + const char* SourceFile::begin() const + { + return data; + } + + const char* SourceFile::getRawData() const + { + return data; + } + + SourceSpan SourceFile::getSourceSpan() + { + return SourceSpan(this); + } + + ItplFile::ItplFile(const char* data, const SourceSpan& pstate) : + SourceFile(pstate.getPath(), + data, pstate.getSrcId()), + pstate(pstate) + {} + + const char* ItplFile::getRawData() const + { + return pstate.getRawData(); + } + + SourceSpan ItplFile::getSourceSpan() + { + return SourceSpan(pstate); + } + +} + diff --git a/src/source.hpp b/src/source.hpp new file mode 100644 index 0000000000..77c591e250 --- /dev/null +++ b/src/source.hpp @@ -0,0 +1,95 @@ +#ifndef SASS_SOURCE_H +#define SASS_SOURCE_H + +#include "sass.hpp" +#include "memory.hpp" +#include "position.hpp" +#include "source_data.hpp" + +namespace Sass { + + class SourceFile : + public SourceData { + protected: + char* path; + char* data; + size_t length; + size_t srcid; + public: + + SourceFile( + const char* path, + const char* data, + size_t srcid); + + ~SourceFile(); + + const char* end() const override final; + const char* begin() const override final; + virtual const char* getRawData() const override; + virtual SourceSpan getSourceSpan() override; + + size_t size() const override final { + return length; + } + + virtual const char* getPath() const override { + return path; + } + + virtual size_t getSrcId() const override { + return srcid; + } + + }; + + class SynthFile : + public SourceData { + protected: + const char* path; + public: + + SynthFile( + const char* path) : + path(path) + {} + + ~SynthFile() {} + + const char* end() const override final { return nullptr; } + const char* begin() const override final { return nullptr; }; + virtual const char* getRawData() const override { return nullptr; }; + virtual SourceSpan getSourceSpan() override { return SourceSpan(path); }; + + size_t size() const override final { + return 0; + } + + virtual const char* getPath() const override { + return path; + } + + virtual size_t getSrcId() const override { + return std::string::npos; + } + + }; + + + class ItplFile : + public SourceFile { + private: + SourceSpan pstate; + public: + + ItplFile(const char* data, + const SourceSpan& pstate); + + // Offset getPosition() const override final; + const char* getRawData() const override final; + SourceSpan getSourceSpan() override final; + }; + +} + +#endif diff --git a/src/source_data.hpp b/src/source_data.hpp new file mode 100644 index 0000000000..c52b02141d --- /dev/null +++ b/src/source_data.hpp @@ -0,0 +1,32 @@ +#ifndef SASS_SOURCE_DATA_H +#define SASS_SOURCE_DATA_H + +#include "sass.hpp" +#include "memory.hpp" + +namespace Sass { + + class SourceSpan; + + class SourceData : + public SharedObj { + public: + SourceData(); + virtual size_t size() const = 0; + virtual size_t getSrcId() const = 0; + virtual const char* end() const = 0; + virtual const char* begin() const = 0; + virtual const char* getPath() const = 0; + // virtual Offset getPosition() const = 0; + virtual const char* getRawData() const = 0; + virtual SourceSpan getSourceSpan() = 0; + + sass::string to_string() const override { + return sass::string{ begin(), end() }; + } + ~SourceData() {} + }; + +} + +#endif diff --git a/src/source_map.cpp b/src/source_map.cpp index 5031a7c915..285d77f839 100644 --- a/src/source_map.cpp +++ b/src/source_map.cpp @@ -175,23 +175,27 @@ namespace Sass { void SourceMap::add_open_mapping(const AST_Node* node) { - mappings.push_back(Mapping(node->pstate(), current_position)); + const SourceSpan& span(node->pstate()); + Position from(span.getSrcId(), span.position); + mappings.push_back(Mapping(from, current_position)); } void SourceMap::add_close_mapping(const AST_Node* node) { - mappings.push_back(Mapping(node->pstate() + node->pstate().offset, current_position)); + const SourceSpan& span(node->pstate()); + Position to(span.getSrcId(), span.position + span.offset); + mappings.push_back(Mapping(to, current_position)); } SourceSpan SourceMap::remap(const SourceSpan& pstate) { for (size_t i = 0; i < mappings.size(); ++i) { if ( - mappings[i].generated_position.file == pstate.file && - mappings[i].generated_position.line == pstate.line && - mappings[i].generated_position.column == pstate.column - ) return SourceSpan(pstate.path, pstate.src, mappings[i].original_position, pstate.offset); + mappings[i].generated_position.file == pstate.getSrcId() && + mappings[i].generated_position.line == pstate.position.line && + mappings[i].generated_position.column == pstate.position.column + ) return SourceSpan(pstate.source, mappings[i].original_position, pstate.offset); } - return SourceSpan(pstate.path, pstate.src, Position(-1, -1, -1), Offset(0, 0)); + return SourceSpan(pstate.source, Position(-1, -1, -1), Offset(0, 0)); } diff --git a/src/source_map.hpp b/src/source_map.hpp index a6ec2342aa..6472fd2a60 100644 --- a/src/source_map.hpp +++ b/src/source_map.hpp @@ -9,6 +9,9 @@ #include "position.hpp" #include "mapping.hpp" +#include "backtrace.hpp" +#include "memory.hpp" + #define VECTOR_PUSH(vec, ins) vec.insert(vec.end(), ins.begin(), ins.end()) #define VECTOR_UNSHIFT(vec, ins) vec.insert(vec.begin(), ins.begin(), ins.end()) @@ -49,7 +52,7 @@ namespace Sass { class OutputBuffer { public: OutputBuffer(void) - : buffer(""), + : buffer(), smap() { } public: diff --git a/src/utf8_string.cpp b/src/utf8_string.cpp index ceef8e95ed..3464d93214 100644 --- a/src/utf8_string.cpp +++ b/src/utf8_string.cpp @@ -11,7 +11,6 @@ namespace Sass { namespace UTF_8 { - using sass::string; // naming conventions: // offset: raw byte offset (0 based) @@ -19,25 +18,25 @@ namespace Sass { // index: code point offset (1 based or negative) // function that will count the number of code points (utf-8 characters) from the given beginning to the given end - size_t code_point_count(const string& str, size_t start, size_t end) { + size_t code_point_count(const sass::string& str, size_t start, size_t end) { return utf8::distance(str.begin() + start, str.begin() + end); } - size_t code_point_count(const string& str) { + size_t code_point_count(const sass::string& str) { return utf8::distance(str.begin(), str.end()); } // function that will return the byte offset at a code point position - size_t offset_at_position(const string& str, size_t position) { - string::const_iterator it = str.begin(); + size_t offset_at_position(const sass::string& str, size_t position) { + sass::string::const_iterator it = str.begin(); utf8::advance(it, position, str.end()); return std::distance(str.begin(), it); } // function that returns number of bytes in a character at offset - size_t code_point_size_at_offset(const string& str, size_t offset) { + size_t code_point_size_at_offset(const sass::string& str, size_t offset) { // get iterator from string and forward by offset - string::const_iterator stop = str.begin() + offset; + sass::string::const_iterator stop = str.begin() + offset; // check if beyond boundary if (stop == str.end()) return 0; // advance by one code point @@ -78,9 +77,9 @@ namespace Sass { using std::wstring; // convert from utf16/wide string to utf8 string - string convert_from_utf16(const wstring& utf16) + sass::string convert_from_utf16(const wstring& utf16) { - string utf8; + sass::string utf8; // pre-allocate expected memory utf8.reserve(sizeof(utf16)/2); utf8::utf16to8(utf16.begin(), utf16.end(), @@ -89,7 +88,7 @@ namespace Sass { } // convert from utf8 string to utf16/wide string - wstring convert_to_utf16(const string& utf8) + wstring convert_to_utf16(const sass::string& utf8) { wstring utf16; // pre-allocate expected memory diff --git a/src/utf8_string.hpp b/src/utf8_string.hpp index 22dc129256..88b10f9b0b 100644 --- a/src/utf8_string.hpp +++ b/src/utf8_string.hpp @@ -3,6 +3,7 @@ #include #include "utf8.h" +#include "memory.hpp" namespace Sass { namespace UTF_8 { diff --git a/win/libsass.targets b/win/libsass.targets index 0a781af46c..6aa17d1203 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -60,6 +60,7 @@ + @@ -128,6 +129,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 6897471e7e..8396b45150 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -195,6 +195,9 @@ Headers + + Headers + Headers @@ -377,6 +380,9 @@ Sources + + Sources + Sources