Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Simplify pattern matching and make it more elegant

  • Loading branch information...
commit a53c30ce72304bee66370e394b76305dc85e6db6 1 parent 9721626
@txus authored
View
38 lib/lambra/bytecode_compiler.rb
@@ -325,7 +325,10 @@ def visit_Match(o)
o.patterns.each do |pattern|
failure = g.new_label
g.dup_top
- pattern.accept(self, success, failure)
+
+ pattern.match(self, failure)
+ pattern.execute(self, success)
+
failure.set!
end
@@ -341,39 +344,6 @@ def visit_Match(o)
done.set!
end
- def visit_ValuePattern(o, success, failure)
- o.value.accept(self)
- g.swap_stack
- g.send :==, 1
- g.gif failure
-
- # Pattern match succeeded!
- o.actions.each_with_index do |action, idx|
- action.accept(self)
- g.pop unless o.actions.count - 1 == idx
- end
- g.goto success
- end
-
- def visit_SymbolPattern(o, success, _)
- unbound = o.value.name == :_
-
- args_vector = Lambra::AST::Vector.new(o.value.line, o.value.column, unbound ? [] : [o.value])
- arguments = Lambra::AST::ClosureArguments.new(args_vector.line, args_vector.column, args_vector)
- body = o.actions.size > 1 ? Lambra::AST::Sequence.new(o.actions.first.line, o.actions.first.column, o.actions[1..-1]) : o.actions.first
- closure = Lambra::AST::Closure.new(arguments.line, arguments.column, arguments, body)
-
- closure.accept(self)
- g.swap_stack
- if unbound
- g.pop
- g.send :call, 0
- else
- g.send :call, 1
- end
- g.goto success
- end
-
def finalize
g.local_names = g.state.scope.local_names
g.local_count = g.state.scope.local_count
View
62 lib/lambra/syntax/ast.rb
@@ -157,6 +157,8 @@ def self.from(list)
ValuePattern.new(car, cdr)
when Symbol
SymbolPattern.new(car, cdr)
+ when Vector
+ VectorPattern.new(car, cdr)
else
raise "Can't generate pattern from #{car.inspect}"
end
@@ -168,12 +170,72 @@ def initialize(value, actions)
@value = value
@actions = actions
end
+
+ def bound
+ []
+ end
+
+ def execute(compiler, success, g=compiler.g)
+ if bound.empty?
+ actions.each_with_index do |action, idx|
+ action.accept(compiler)
+ g.pop unless actions.count - 1 == idx
+ end
+ else
+ execution_closure.accept(compiler)
+ g.swap_stack
+ g.send :call, bound.size
+ end
+ g.goto success
+ end
+
+ private
+
+ def execution_closure
+ args_vector = Vector.new(value.line, value.column, bound)
+ arguments = ClosureArguments.new(args_vector.line, args_vector.column, args_vector)
+ body = actions.size > 1 ? Sequence.new(actions.first.line, actions.first.column, actions[1..-1]) : actions.first
+ Closure.new(arguments.line, arguments.column, arguments, body)
+ end
end
class ValuePattern < Pattern
+ def match(compiler, failure, g=compiler.g)
+ value.accept(compiler)
+ g.swap_stack
+ g.send :==, 1
+ g.gif failure
+ end
end
class SymbolPattern < Pattern
+ def match(compiler, failure)
+ # always matches
+ end
+
+ def bound
+ value.name == :_ ? [] : [self.value]
+ end
+ end
+
+ class VectorPattern < Pattern
+ def match(compiler, failure, g=compiler.g)
+ match_length(g, failure)
+ end
+
+ def execute(compiler, success, g=compiler.g)
+ g.push 3
+ g.goto success
+ end
+
+ private
+
+ def match_length(g, failure)
+ g.send :length, 0
+ g.push value.elements.length
+ g.send :==, 1
+ g.gif failure
+ end
end
attr_reader :expression, :patterns
View
7 spec/compiler_spec.rb
@@ -67,6 +67,13 @@
}.should eval_to 99
end
+ it 'destructures simple vectors' do
+ %q{
+ (match [1 2 3]
+ ([_ 2 x] x))
+ }.should eval_to 3
+ end
+
it 'can fail the pattern match' do
proc {
Lambra::Compiler.eval %q{
Please sign in to comment.
Something went wrong with that request. Please try again.