Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Dispatch special forms such as def

  • Loading branch information...
commit e742674399ce6d40b103a240fa600e52dd68a13f 1 parent deb3c6a
@txus authored
View
10 lib/lambra/bootstrap.rb
@@ -4,24 +4,26 @@ class Function
def initialize(&block)
@block = block
end
+
def call(*args)
@block.call(*args)
end
end
module GlobalScope
- def self.bootstrap
- {
+ Bootstrap = {
+ ##
+ # Symbol Function body
+ ##
:println => Function.new { |*args| puts *args },
:+ => Function.new { |*args| args.inject(:+) },
:- => Function.new { |*args| args.inject(:-) },
:/ => Function.new { |a, b| a / b },
:* => Function.new { |a, b| a * b },
}
- end
end
-Scope = GlobalScope.bootstrap
+Scope = GlobalScope::Bootstrap
class Keyword
def initialize(name)
View
26 lib/lambra/bytecode_compiler.rb
@@ -3,6 +3,8 @@ class BytecodeCompiler
attr_reader :generator
alias g generator
+ SPECIAL_FORMS = %w(def)
+
def initialize
@generator = Rubinius::Generator.new
end
@@ -34,11 +36,14 @@ def visit_List(o)
return g.push_nil if o.elements.count.zero?
car = o.elements[0]
cdr = o.elements[1..-1]
+
+ return visit_SpecialForm(car.name, cdr) if special_form?(car.name)
+
args = cdr.count
visit_Symbol(car)
- # TODO: lazy evaluation
+ # # TODO: lazy evaluation
cdr.each do |arg|
arg.accept(self)
end
@@ -46,6 +51,19 @@ def visit_List(o)
g.send :call, args
end
+ def visit_SpecialForm(car, cdr)
+ case car.to_s
+ when 'def'
+ name = cdr.shift.name
+
+ g.push_cpath_top
+ g.find_const :Scope
+ g.push_literal name
+ cdr.first.accept(self)
+ g.send :[]=, 2
+ end
+ end
+
def visit_Symbol(o)
set_line(o)
g.push_cpath_top
@@ -173,5 +191,11 @@ def debug(gen = self.g)
end
p '**end**'
end
+
+ private
+
+ def special_form?(name)
+ SPECIAL_FORMS.include?(name.to_s)
+ end
end
end
View
2  lib/lambra/parser/lambra.kpeg
@@ -86,7 +86,7 @@ expr = list
| literal
many_expr = comment:e many_expr:m { [e] + m }
- | expr:e many_expr:m { [e] + m }
+ | expr:e sp many_expr:m { [e] + m }
| expr:e { [e] }
sequence = many_expr:e { e.size > 1 ? seq(current_line, current_column, e) : e.first }
View
9 lib/lambra/parser/parser.rb
@@ -1399,7 +1399,7 @@ def _expr
return _tmp
end
- # many_expr = (comment:e many_expr:m { [e] + m } | expr:e many_expr:m { [e] + m } | expr:e { [e] })
+ # many_expr = (comment:e many_expr:m { [e] + m } | expr:e sp many_expr:m { [e] + m } | expr:e { [e] })
def _many_expr
_save = self.pos
@@ -1438,6 +1438,11 @@ def _many_expr
self.pos = _save2
break
end
+ _tmp = apply(:_sp)
+ unless _tmp
+ self.pos = _save2
+ break
+ end
_tmp = apply(:_many_expr)
m = @result
unless _tmp
@@ -1655,7 +1660,7 @@ def _root
Rules[:_set] = rule_info("set", "(\"\#{\" expr_list:e \"}\" {set(current_line, current_column, e)} | \"\#{\" \"}\" {set(current_line, current_column, [])})")
Rules[:_map] = rule_info("map", "(\"{\" expr_list:e \"}\" {map(current_line, current_column, Hash[*e])} | \"{\" \"}\" {map(current_line, current_column, {})})")
Rules[:_expr] = rule_info("expr", "(list | literal)")
- Rules[:_many_expr] = rule_info("many_expr", "(comment:e many_expr:m { [e] + m } | expr:e many_expr:m { [e] + m } | expr:e { [e] })")
+ Rules[:_many_expr] = rule_info("many_expr", "(comment:e many_expr:m { [e] + m } | expr:e sp many_expr:m { [e] + m } | expr:e { [e] })")
Rules[:_sequence] = rule_info("sequence", "many_expr:e { e.size > 1 ? seq(current_line, current_column, e) : e.first }")
Rules[:_expr_list_b] = rule_info("expr_list_b", "(expr:e br-sp expr_list_b:l { [e] + l } | expr:e { [e] })")
Rules[:_expr_list] = rule_info("expr_list", "br-sp expr_list_b:b br-sp { b }")
View
4 spec/compiler_spec.rb
@@ -11,4 +11,8 @@
'(* 8 4)'.should eval_to 32
'(/ 8 4)'.should eval_to 2
end
+
+ it 'defines def' do
+ '(def x 42) x'.should eval_to 42
+ end
end
View
2  spec/custom/matchers/compile_as.rb
@@ -22,7 +22,7 @@ def failure_message
actual_stream = @actual.stream.map(&instruction_to_name)
expected_stream = @expected.stream.map(&instruction_to_name)
- actual_literals = @actual.literals.map(&:inspect).join(', ')
+ actual_literals = @actual.literals.map(&:inspect).join(', ')
expected_literals = @expected.literals.map(&:inspect).join(', ')
["Expected:\n\t#{actual_stream.join("\n\t")}\nLITERALS: #{actual_literals}\n",
View
20 spec/custom/matchers/eval_to.rb
@@ -14,8 +14,28 @@ def failure_message
end
end
+class EvalToKindOfMatcher
+ def initialize(expected)
+ @expected = expected
+ end
+
+ def matches?(actual)
+ @actual = Lambra::CodeLoader.evaluate actual
+ @actual.is_a?(@expected)
+ end
+
+ def failure_message
+ ["Expected:\n#{@actual.inspect}\n",
+ "to evaluate to a kind of:\n#{@expected.inspect}"]
+ end
+end
+
class Object
def eval_to(result)
EvalToMatcher.new result
end
+
+ def eval_to_kind_of(klass)
+ EvalToKindOfMatcher.new klass
+ end
end
Please sign in to comment.
Something went wrong with that request. Please try again.