Skip to content

Commit

Permalink
Refactor implementation
Browse files Browse the repository at this point in the history
Thank you @asterite

#7008 (comment)
#7008 (comment)

Split `LocStackPragma` into `LocPushPragma` and `LocPopPragma`
Rename `invisible_loc_pragmas` to `macro_expansion_pragmas`
  • Loading branch information
makenowjust committed Nov 3, 2018
1 parent a10b27f commit 313c40e
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 53 deletions.
4 changes: 2 additions & 2 deletions spec/compiler/macro/macro_expander_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,11 @@ describe "MacroExpander" do
node.location = Location.new "foo.cr", 10, 20
assert_macro "node", %({{node}}), [node] of ASTNode, "42", {
0 => [
Lexer::LocStackPragma::Push,
Lexer::LocPushPragma.new,
Lexer::LocSetPragma.new("foo.cr", 10, 20),
] of Lexer::LocPragma,
2 => [
Lexer::LocStackPragma::Pop,
Lexer::LocPopPragma.new,
] of Lexer::LocPragma,
}
end
Expand Down
14 changes: 7 additions & 7 deletions spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -108,26 +108,26 @@ def assert_error(str, message, inject_primitives = true)
end
end

def assert_macro(macro_args, macro_body, call_args, expected, expected_loc_pragmas = nil, flags = nil)
assert_macro(macro_args, macro_body, expected, expected_loc_pragmas, flags) { call_args }
def assert_macro(macro_args, macro_body, call_args, expected, expected_pragmas = nil, flags = nil)
assert_macro(macro_args, macro_body, expected, expected_pragmas, flags) { call_args }
end

def assert_macro(macro_args, macro_body, expected, expected_loc_pragmas = nil, flags = nil)
def assert_macro(macro_args, macro_body, expected, expected_pragmas = nil, flags = nil)
program = Program.new
program.flags = flags if flags
sub_node = yield program
assert_macro_internal program, sub_node, macro_args, macro_body, expected, expected_loc_pragmas
assert_macro_internal program, sub_node, macro_args, macro_body, expected, expected_pragmas
end

def assert_macro_internal(program, sub_node, macro_args, macro_body, expected, expected_loc_pragmas)
def assert_macro_internal(program, sub_node, macro_args, macro_body, expected, expected_pragmas)
macro_def = "macro foo(#{macro_args});#{macro_body};end"
a_macro = Parser.parse(macro_def).as(Macro)

call = Call.new(nil, "", sub_node)
result, result_loc_pragmas = program.expand_macro a_macro, call, program, program
result, result_pragmas = program.expand_macro a_macro, call, program, program
result = result.chomp(';')
result.should eq(expected)
result_loc_pragmas.should eq(expected_loc_pragmas) if expected_loc_pragmas
result_pragmas.should eq(expected_pragmas) if expected_pragmas
end

def codegen(code, inject_primitives = true, debug = Crystal::Debug::None)
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/crystal/macros/interpreter.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Crystal
class MacroInterpreter < Visitor
getter last : ASTNode
property free_vars : Hash(String, TypeVar)?
property invisible_loc_pragmas : Hash(Int32, Array(Lexer::LocPragma))
property macro_expansion_pragmas : Hash(Int32, Array(Lexer::LocPragma))? = nil

def self.new(program, scope : Type, path_lookup : Type, a_macro : Macro, call, a_def : Def? = nil, in_macro = false)
vars = {} of String => ASTNode
Expand Down Expand Up @@ -79,7 +79,6 @@ module Crystal
@vars = {} of String => ASTNode, @block : Block? = nil, @def : Def? = nil,
@in_macro = false)
@str = IO::Memory.new(512) # Can't be String::Builder because of `{{debug}}`
@invisible_loc_pragmas = {} of Int32 => Array(Lexer::LocPragma)
@last = Nop.new
end

Expand All @@ -103,11 +102,12 @@ module Crystal
if node.output?
is_yield = node.exp.is_a?(Yield) && !@last.is_a?(Nop)
if (loc = @last.location) && loc.filename.is_a?(String) || is_yield
(@invisible_loc_pragmas[@str.pos.to_i32] ||= [] of Lexer::LocPragma) << Lexer::LocStackPragma::Push
macro_expansion_pragmas = @macro_expansion_pragmas ||= {} of Int32 => Array(Lexer::LocPragma)
(macro_expansion_pragmas[@str.pos.to_i32] ||= [] of Lexer::LocPragma) << Lexer::LocPushPragma.new
@str << "begin " if is_yield
@last.to_s(@str, emit_loc_pragma: @invisible_loc_pragmas, emit_doc: true)
@last.to_s(@str, macro_expansion_pragmas: macro_expansion_pragmas, emit_doc: true)
@str << " end" if is_yield
(@invisible_loc_pragmas[@str.pos.to_i32] ||= [] of Lexer::LocPragma) << Lexer::LocStackPragma::Pop
(macro_expansion_pragmas[@str.pos.to_i32] ||= [] of Lexer::LocPragma) << Lexer::LocPopPragma.new
else
@last.to_s(@str)
end
Expand Down
12 changes: 6 additions & 6 deletions src/compiler/crystal/macros/macros.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ class Crystal::Program
def expand_macro(a_macro : Macro, call : Call, scope : Type, path_lookup : Type? = nil, a_def : Def? = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, a_macro, call, a_def, in_macro: true
a_macro.body.accept interpreter
{interpreter.to_s, interpreter.invisible_loc_pragmas}
{interpreter.to_s, interpreter.macro_expansion_pragmas}
end

def expand_macro(node : ASTNode, scope : Type, path_lookup : Type? = nil, free_vars = nil, a_def : Def? = nil)
interpreter = MacroInterpreter.new self, scope, path_lookup || scope, node.location, def: a_def, in_macro: false
interpreter.free_vars = free_vars
node.accept interpreter
{interpreter.to_s, interpreter.invisible_loc_pragmas}
{interpreter.to_s, interpreter.macro_expansion_pragmas}
end

def parse_macro_source(generated_source, invisible_loc_pragmas, the_macro, node, vars, current_def = nil, inside_type = false, inside_exp = false, mode : MacroExpansionMode = MacroExpansionMode::Normal)
parse_macro_source(generated_source, invisible_loc_pragmas, the_macro, node, vars, current_def, inside_type, inside_exp) do |parser|
def parse_macro_source(generated_source, macro_expansion_pragmas, the_macro, node, vars, current_def = nil, inside_type = false, inside_exp = false, mode : MacroExpansionMode = MacroExpansionMode::Normal)
parse_macro_source(generated_source, macro_expansion_pragmas, the_macro, node, vars, current_def, inside_type, inside_exp) do |parser|
case mode
when .lib?
parser.parse_lib_body
Expand All @@ -64,11 +64,11 @@ class Crystal::Program
end
end

def parse_macro_source(generated_source, invisible_loc_pragmas, the_macro, node, vars, current_def = nil, inside_type = false, inside_exp = false)
def parse_macro_source(generated_source, macro_expansion_pragmas, the_macro, node, vars, current_def = nil, inside_type = false, inside_exp = false)
begin
parser = Parser.new(generated_source, @program.string_pool, [vars.dup])
parser.filename = VirtualFile.new(the_macro, generated_source, node.location)
parser.invisible_loc_pragmas = invisible_loc_pragmas
parser.macro_expansion_pragmas = macro_expansion_pragmas
parser.visibility = node.visibility
parser.def_nest = 1 if current_def
parser.type_nest = 1 if inside_type
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/crystal/macros/methods.cr
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ module Crystal
end

def interpret_skip_file(node)
raise SkipMacroException.new(@str.to_s, invisible_loc_pragmas)
raise SkipMacroException.new(@str.to_s, macro_expansion_pragmas)
end

def interpret_system(node)
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/exception.cr
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ module Crystal

class SkipMacroException < ::Exception
getter expanded_before_skip : String
getter invisible_loc_pragmas : Hash(Int32, Array(Lexer::LocPragma))
getter macro_expansion_pragmas : Hash(Int32, Array(Lexer::LocPragma))?

def initialize(@expanded_before_skip, @invisible_loc_pragmas)
def initialize(@expanded_before_skip, @macro_expansion_pragmas)
super()
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/crystal/semantic/method_missing.cr
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ module Crystal
block: block_node.is_a?(Block) ? block_node : nil)
fake_call = Call.new(nil, "method_missing", [call] of ASTNode)

expanded_macro, invisible_loc_pragmas = program.expand_macro method_missing, fake_call, self, self
expanded_macro, macro_expansion_pragmas = program.expand_macro method_missing, fake_call, self, self

# Check if the expanded macro is a def. We do this
# by just lexing the result and seeing if the first
# token is `def`
expands_to_def = starts_with_def?(expanded_macro)
generated_nodes =
program.parse_macro_source(expanded_macro, invisible_loc_pragmas, method_missing, method_missing, args_nodes_names) do |parser|
program.parse_macro_source(expanded_macro, macro_expansion_pragmas, method_missing, method_missing, args_nodes_names) do |parser|
if expands_to_def
parser.parse
else
Expand Down
10 changes: 5 additions & 5 deletions src/compiler/crystal/semantic/semantic_visitor.cr
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,9 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
generated_nodes = expand_macro(the_macro, node) do
old_args = node.args
node.args = args
expanded_macro, invisible_loc_pragmas = @program.expand_macro the_macro, node, expansion_scope, expansion_scope, @untyped_def
expanded_macro, macro_expansion_pragmas = @program.expand_macro the_macro, node, expansion_scope, expansion_scope, @untyped_def
node.args = old_args
{expanded_macro, invisible_loc_pragmas}
{expanded_macro, macro_expansion_pragmas}
end
@exp_nest += 1

Expand All @@ -310,7 +310,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
end

def expand_macro(the_macro, node, mode = nil)
expanded_macro, invisible_loc_pragmas =
expanded_macro, macro_expansion_pragmas =
eval_macro(node) do
yield
end
Expand All @@ -323,7 +323,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
Program::MacroExpansionMode::Normal
end

generated_nodes = @program.parse_macro_source(expanded_macro, invisible_loc_pragmas, the_macro, node, Set.new(@vars.keys),
generated_nodes = @program.parse_macro_source(expanded_macro, macro_expansion_pragmas, the_macro, node, Set.new(@vars.keys),
current_def: @typed_def,
inside_type: !current_type.is_a?(Program),
inside_exp: @exp_nest > 0,
Expand Down Expand Up @@ -400,7 +400,7 @@ abstract class Crystal::SemanticVisitor < Crystal::Visitor
@program.expand_macro node, (@scope || current_type), @path_lookup, free_vars, @untyped_def
rescue ex : SkipMacroException
skip_macro_exception = ex
{ex.expanded_before_skip, ex.invisible_loc_pragmas}
{ex.expanded_before_skip, ex.macro_expansion_pragmas}
end
end

Expand Down
34 changes: 17 additions & 17 deletions src/compiler/crystal/syntax/lexer.cr
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,9 @@ module Crystal
# Heredocs pushed when found. Should be processed when encountering a newline
getter heredocs = [] of {Token::DelimiterState, HeredocItem}

property invisible_loc_pragmas : Hash(Int32, Array(LocPragma))? = nil
property macro_expansion_pragmas : Hash(Int32, Array(LocPragma))? = nil

alias LocPragma = LocStackPragma | LocSetPragma

enum LocStackPragma
Pop
Push

def run_pragma(lexer)
case self
when Pop
lexer.pop_location
when Push
lexer.push_location
end
end
end
alias LocPragma = LocSetPragma | LocPushPragma | LocPopPragma

record LocSetPragma,
filename : String,
Expand All @@ -53,6 +39,18 @@ module Crystal
end
end

record LocPushPragma do
def run_pragma(lexer)
lexer.push_location
end
end

record LocPopPragma do
def run_pragma(lexer)
lexer.pop_location
end
end

def initialize(string, string_pool : StringPool? = nil)
@reader = Char::Reader.new(string)
@token = Token.new
Expand Down Expand Up @@ -117,7 +115,9 @@ module Crystal
end

start = current_pos
if pragmas = invisible_loc_pragmas.try &.[start]?

# Fix location by `macro_expansion_pragmas`.
if pragmas = macro_expansion_pragmas.try &.[start]?
pragmas.each &.run_pragma self
end

Expand Down
12 changes: 6 additions & 6 deletions src/compiler/crystal/syntax/to_s.cr
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ module Crystal
to_s(io)
end

def to_s(io, emit_loc_pragma = nil, emit_doc = false)
visitor = ToSVisitor.new(io, emit_loc_pragma: emit_loc_pragma, emit_doc: emit_doc)
def to_s(io, macro_expansion_pragmas = nil, emit_doc = false)
visitor = ToSVisitor.new(io, macro_expansion_pragmas: macro_expansion_pragmas, emit_doc: emit_doc)
self.accept visitor
end
end

class ToSVisitor < Visitor
@str : IO
@emit_loc_pragma : Hash(Int32, Array(Lexer::LocPragma))?
@macro_expansion_pragmas : Hash(Int32, Array(Lexer::LocPragma))?

def initialize(@str = IO::Memory.new, @emit_loc_pragma = nil, @emit_doc = false)
def initialize(@str = IO::Memory.new, @macro_expansion_pragmas = nil, @emit_doc = false)
@indent = 0
@inside_macro = 0
@inside_lib = false
Expand All @@ -33,8 +33,8 @@ module Crystal
@str.puts
end

if (emit_loc_pragma = @emit_loc_pragma) && (loc = node.location) && (filename = loc.filename).is_a?(String)
pragmas = emit_loc_pragma[@str.pos.to_i32] ||= [] of Lexer::LocPragma
if (macro_expansion_pragmas = @macro_expansion_pragmas) && (loc = node.location) && (filename = loc.filename).is_a?(String)
pragmas = macro_expansion_pragmas[@str.pos.to_i32] ||= [] of Lexer::LocPragma
pragmas << Lexer::LocSetPragma.new(filename, loc.line_number, loc.column_number)
end

Expand Down

0 comments on commit 313c40e

Please sign in to comment.