Skip to content

Commit

Permalink
Handle loaded source code as shared objects
Browse files Browse the repository at this point in the history
Makes them survive our context more easily. This enables
use to safe and cheaply pass them to error handlers.
  • Loading branch information
mgreter committed Nov 14, 2019
1 parent bfafab4 commit 55ab237
Show file tree
Hide file tree
Showing 24 changed files with 364 additions and 162 deletions.
1 change: 1 addition & 0 deletions Makefile.conf
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ SOURCES = \
units.cpp \
values.cpp \
plugins.cpp \
source.cpp \
position.cpp \
lexer.cpp \
parser.cpp \
Expand Down
10 changes: 4 additions & 6 deletions src/ast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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().off(); }
Position pos() { return pstate().pos(); }

// 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);
Expand Down
10 changes: 10 additions & 0 deletions src/ast_fwd_decl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@
/////////////////////////////////////////////
namespace Sass {

class SourceData;
class SourceFile;
class SynthFile;
class ItplFile;

class AST_Node;

class ParentStatement;
Expand Down Expand Up @@ -127,6 +132,11 @@ namespace Sass {
typedef SharedImpl<type> type##Obj; \
typedef SharedImpl<type> 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);
Expand Down
13 changes: 7 additions & 6 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "expand.hpp"
#include "parser.hpp"
#include "cssize.hpp"
#include "source.hpp"

namespace Sass {
using namespace Constants;
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
21 changes: 10 additions & 11 deletions src/debugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<PseudoSelector>(node)) {
PseudoSelector* selector = Cast<PseudoSelector>(node);
Expand Down Expand Up @@ -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<PlaceholderSelector>(node)) {

Expand Down Expand Up @@ -600,8 +600,7 @@ inline void debug_ast(AST_Node* node, sass::string ind, Env* env)
Comment* block = Cast<Comment>(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<If>(node)) {
If* block = Cast<If>(node);
Expand Down Expand Up @@ -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<String_Constant>(node)) {
String_Constant* expression = Cast<String_Constant>(node);
std::cerr << ind << "String_Constant " << expression;
Expand All @@ -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<String_Schema>(node)) {
String_Schema* expression = Cast<String_Schema>(node);
std::cerr << ind << "String_Schema " << expression;
Expand All @@ -905,15 +904,15 @@ 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<String>(node)) {
String* expression = Cast<String>(node);
std::cerr << ind << "String " << expression;
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<Expression>(node)) {
Expression* expression = Cast<Expression>(node);
std::cerr << ind << "Expression " << expression;
Expand Down
4 changes: 2 additions & 2 deletions src/error_handling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{ }


Expand Down
16 changes: 2 additions & 14 deletions src/error_handling.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions src/eval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/expand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<CssMediaQuery_Obj> parsed = parser.parseCssMediaQueries();
Expand Down
8 changes: 4 additions & 4 deletions src/fn_selectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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()) {
Expand Down
17 changes: 10 additions & 7 deletions src/fn_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Prelexer::identifier>();
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,
Expand All @@ -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 >,
Expand All @@ -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,
Expand Down Expand Up @@ -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) {
Expand All @@ -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();
}
Expand Down
Loading

0 comments on commit 55ab237

Please sign in to comment.