diff --git a/lib/natalie/compiler/pass1.rb b/lib/natalie/compiler/pass1.rb index 38deb3b4c..7fed9a17f 100644 --- a/lib/natalie/compiler/pass1.rb +++ b/lib/natalie/compiler/pass1.rb @@ -109,10 +109,6 @@ def expand_macros(node) @macro_expander.expand(node, locals: locals, depth: @depth, file: @file) end - def current_locals - @locals_stack.last - end - def transform_body(body, location:, used:) return transform_begin_node(body, used:) if body.is_a?(Prism::BeginNode) body = body.body if body.is_a?(Prism::StatementsNode) @@ -2005,8 +2001,10 @@ def transform_match_last_line_node(node, used:) end def transform_match_required_node(node, used:) - match_required_node_compiler = Transformers::MatchRequiredNode.new(self) - instructions = match_required_node_compiler.call(node) + match_required_node_compiler = Transformers::MatchRequiredNode.new + code_str = match_required_node_compiler.call(node) + parser = Natalie::Parser.new(code_str, @file.path, locals: @locals_stack.last) + instructions = transform_expression(parser.ast.statements, used: false) instructions << PushNilInstruction.new if used instructions end diff --git a/lib/natalie/compiler/transformers/match_required_node.rb b/lib/natalie/compiler/transformers/match_required_node.rb index 372507535..14720f35c 100644 --- a/lib/natalie/compiler/transformers/match_required_node.rb +++ b/lib/natalie/compiler/transformers/match_required_node.rb @@ -4,12 +4,6 @@ module Natalie class Compiler module Transformers class MatchRequiredNode - attr_reader :compiler - - def initialize(compiler) - @compiler = compiler - end - def call(node) case node.pattern.type when :array_pattern_node @@ -30,7 +24,7 @@ def transform_array_pattern_node(node, value) # Transform `expr => [a, b] into `a, b = ->(expr) { expr.deconstruct }.call(expr)` target = node.requireds.map(&:name).join(', ') - code_str = <<~RUBY + <<~RUBY #{target} = lambda do |result| values = result.deconstruct if values.size != #{node.requireds.size} @@ -41,32 +35,26 @@ def transform_array_pattern_node(node, value) raise ::NoMatchingPatternError, "\#{result}: \#{result} does not respond to #deconstruct" end.call(#{value.location.slice}) RUBY - parser = Natalie::Parser.new(code_str, compiler.file.path, locals: compiler.current_locals) - compiler.transform_expression(parser.ast.statements, used: false) end def transform_eqeqeq_check(node, value) # Transform `expr => var` into `->(res, var) { res === var }.call(expr, var)` - code_str = <<~RUBY + <<~RUBY lambda do |result, expect| unless expect === result raise ::NoMatchingPatternError, "\#{result}: \#{expect} === \#{result} does not return true" end end.call(#{value.location.slice}, #{node.location.slice}) RUBY - parser = Natalie::Parser.new(code_str, compiler.file.path, locals: compiler.current_locals) - compiler.transform_expression(parser.ast.statements, used: false) end def transform_local_variable_target_node(node, value) # Transform `expr => var` into `var = ->(res) { res }.call(expr)` - code_str = <<~RUBY + <<~RUBY #{node.name} = lambda do |result| result end.call(#{value.location.slice}) RUBY - parser = Natalie::Parser.new(code_str, compiler.file.path, locals: [node.name]) - compiler.transform_expression(parser.ast.statements, used: false) end end end diff --git a/test/natalie/pattern_matching_test.rb b/test/natalie/pattern_matching_test.rb index e46e44d55..88e4d2788 100644 --- a/test/natalie/pattern_matching_test.rb +++ b/test/natalie/pattern_matching_test.rb @@ -1,5 +1,9 @@ require_relative '../spec_helper' +module PatternMatchingHelper + def self.one = 1 +end + # NATFIXME: Temprorary file until we can run some things in `language/pattern_matching_spec.rb` describe 'pattern matching' do it 'can assign a single value' do @@ -7,6 +11,22 @@ a.should == 1 end + it 'can assign a single value from an expression' do + 1 + 1 => a + a.should == 2 + end + + it 'can assign a single value from a variable' do + a = 1 + a => b + b.should == 1 + end + + it 'can assign a single value from a method call' do + PatternMatchingHelper.one => a + a.should == 1 + end + it 'does not define a local variable if the expression fails' do -> { (raise RuntimeError, 'expected error'; 2) => a