Permalink
Browse files

Implement variable lookups and function calls. For bin/lupin.rb, set …

…the 'exit' variable to Kernel.exit so it can be called from Lua.

Also fix () and [] precedence issue where foo()['k'] and foo['k']() wouldn't work.
Also remove shambles of metamethods implementation. I'll figure it out later.
  • Loading branch information...
1 parent 056f60f commit ce08e10b6eeac4104792a997f0ffd78358b92ca9 @Twisol committed Feb 24, 2011
View
@@ -8,6 +8,8 @@
# Extremely basic, stupid-simple REPL.
lua = Lupin::State.new
+lua.globals['exit'] = Kernel.method(:exit)
+
loop do
print '> '
begin
View
@@ -1,11 +1,17 @@
module Lupin::AST
- class FunctionCall
+ class Call
def initialize (func, args)
@func, @args = func, args
end
+ def bytecode (g)
+ @func.bytecode(g)
+ @args.each {|arg| arg.bytecode(g)}
+ g.call(@args.count)
+ end
+
def sexp
- [:call, @func.sexp, args.map {|arg| arg.sexp}]
+ [:call, @func.sexp, @args.map {|arg| arg.sexp}]
end
end
end
View
@@ -15,7 +15,7 @@ def bytecode (g)
g.dup_top
k.bytecode(g)
v.bytecode(g)
- g.set_table
+ g.set_variable
g.pop
end
end
@@ -26,21 +26,4 @@ def sexp
[:table, *fields]
end
end
-
- class TableGet
- def initialize (tbl, key)
- @tbl = tbl
- @key = key
- end
-
- def bytecode (g)
- @tbl.bytecode(g)
- @key.bytecode(g)
- g.get_table
- end
-
- def sexp
- [:[], @tbl.sexp, @key.sexp]
- end
- end
end
View
@@ -1,16 +1,37 @@
module Lupin::AST
class Variable
- def initialize (identifier)
+ def initialize (parent, identifier)
+ @parent = parent
@name = identifier
end
def bytecode (g)
- # TODO: Add variable lookup.
- g.push_nil
+ push_parent(g)
+ @name.bytecode(g)
+ g.get_variable
+ end
+
+ def set_value (g)
+ push_parent(g)
+ swap_stack
+
+ @name.bytecode(g)
+ swap_stack
+
+ g.set_variable
end
def sexp
- [:variable, @name.sexp]
+ [:variable, @parent ? @parent.sexp : nil, @name.sexp]
+ end
+
+ protected
+ def push_parent(g)
+ if @parent == nil
+ g.push_environment
+ else
+ @parent.bytecode(g)
+ end
end
end
end
View
@@ -6,7 +6,10 @@ class Generator
def initialize (lstate)
@state = lstate
@g = Rubinius::Generator.new
- @env = Lupin::Types::Table.new(@state)
+ end
+
+ def push_environment
+ g.push_literal @state.globals
end
def push_number (num)
@@ -18,7 +21,7 @@ def push_string (str)
end
def push_table
- g.push_literal Lupin::Types::Table.new(@state)
+ g.push_literal Lupin::Types::Table.new
end
def push_bool (bool)
@@ -91,11 +94,11 @@ def neq
eq
end
- def get_table
+ def get_variable
g.send :[], 1
end
- def set_table
+ def set_variable
g.send :[]=, 2
end
@@ -104,6 +107,10 @@ def concat
g.push_literal "Hello from the unfinished concatenation routine"
end
+ def call (count)
+ g.send :call, count
+ end
+
def assemble (name, file, line)
g.name = name.to_sym
g.file = file.to_sym
@@ -114,7 +121,6 @@ def assemble (name, file, line)
g.package Rubinius::CompiledMethod
end
- private
# Used intermittently for debugging. Equivalent to p(arg)
def puts_top
g.dup
@@ -122,46 +122,35 @@ grammar Lupin::Parser::Lua
rule basic_expr
( primitive
- | functioncall
- | indexer
+ | function_expr
| value_expr
)
end
+ rule function_expr
+ ( lhs:value_expr
+ list:( op:('') { Lupin::AST::Call }
+ rhs:( ('(' WS? ')') { [] }
+ | ('(' WS? explist WS? ')') { explist.value }
+ | (WS? table) { [table.value] }
+ | (WS? string) { [string] }
+ )
+ | op:('') { Lupin::AST::Variable }
+ rhs:( (WS? '[' WS? expression WS? ']') { expression.value }
+ | (WS? '.' WS? identifier) { identifier.value }
+ )
+ )+
+ ) <Lupin::Parser::LeftAssoc>
+ end
+
rule value_expr
( ('(' WS? expression WS? ')') { expression.value }
| variable
)
end
- rule indexer
- ( var:value_expr
- args:( (WS? '[' WS? expression WS? ']') { expression.value }
- | (WS? '.' WS? identifier) { identifier.value }
- )+
- ) {
- t = var.value
- args.matches.each {|a| t = Lupin::AST::TableGet.new(t, a.value)}
- t
- }
- end
-
- rule functioncall
- ( var:value_expr
- args:( (WS? '(' WS? explist WS? ')') { explist.value }
- | (WS? '(' WS? ')') { [] }
- | (WS? table) { [table] }
- | (WS? string) { [string] }
- )+
- ) {
- f = var.value
- args.matches.each {|a| f = Lupin::AST::FunctionCall.new(f, a.value)}
- f
- }
- end
-
rule variable
- ('' identifier) { Lupin::AST::Variable.new(identifier.value) }
+ ('' identifier) { Lupin::AST::Variable.new(nil, identifier.value) }
end
rule identifier
View
@@ -5,7 +5,7 @@ class State
attr_reader :metatables
def initialize
- @metatables = {}
+ @env = Lupin::Types::Table.new
end
def compile (ast)
@@ -17,24 +17,15 @@ def compile (ast)
Code.new(g.assemble("<eval>", :dynamic, 1))
end
- def getmetamethod (obj, name)
- case obj
- when Lupin::Types::Table, Lupin::Types::Userdatum
- mt = @metatables[obj]
- else
- mt = @metatables[obj.class]
- end
-
- mt && mt[name]
+ def globals
+ @env
end
end
class Code
- attr_reader :cm
-
def initialize (cm)
- @cm = cm
Rubinius.add_method :call, cm, Rubinius.object_metaclass(self), :public
+ @cm = cm
end
# Execute the compiled method
View
@@ -1,26 +1,15 @@
module Lupin::Types
class Table < Value
- def initialize (_L)
- @_L = _L
+ def initialize
@hash = Hash.new(Nil)
end
def [] (key)
- __index = _L.getmetamethod(self, :__index)
- if __index
- __index.call(self, key)
- else
- rawget(key)
- end
+ rawget(key)
end
def []= (key, value)
- __newindex = _L.getmetamethod(self, :__newindex)
- if __newindex
- __newindex.call(self, key, value)
- else
- rawset(key, value)
- end
+ rawset(key, value)
end
def rawget (key)
@@ -36,10 +25,5 @@ def to_s
str << @hash.to_a.map {|k, v| "[#{k}] = #{v}"}.join(', ')
str << '}'
end
-
- protected
- def _L
- @_L
- end
end
end

0 comments on commit ce08e10

Please sign in to comment.