Permalink
Browse files

Implement table indexing, expand the Generator's instruction set, and…

… clean up the representation of literals in the AST.

Fix an occurance where true parses as false and vice versa.
Implement #eql? and #hash on Lupin::Types::Value, allowing for much more natural usage of the Table type.
  • Loading branch information...
1 parent 51192de commit ab02401801e59c769d51fa0303e81eb8a3e52a28 @Twisol committed Feb 21, 2011
View
@@ -6,12 +6,33 @@ def initialize (val)
@value = val
end
- def bytecode (g)
- g.push_literal Lupin::Value.new(@value)
- end
-
def sexp
@value
end
end
+
+ class String < Literal
+ def bytecode (g)
+ g.push_string value
+ end
+ end
+
+ class Number < Literal
+ def bytecode (g)
+ g.push_number value.to_f
+ end
+ end
+
+ class Boolean < Literal
+ def bytecode (g)
+ g.push_bool value
+ end
+ end
+ True = Boolean.new(true)
+ False = Boolean.new(false)
+
+ Nil = Literal.new(nil)
+ def Nil.bytecode (g)
+ g.push_nil
+ end
end
View
@@ -1,12 +1,11 @@
module Lupin::AST
class Table
def initialize (fieldlist=[])
- @fields = {}
current_integer = 0
- fieldlist.each do |k, v|
- k ||= Lupin::AST::Literal.new(current_integer += 1)
- @fields[k] = v
+ fieldlist.each do |a|
+ a[0] ||= Lupin::AST::Number.new(current_integer += 1)
end
+ @fields = fieldlist
end
def bytecode (g)
@@ -30,7 +29,18 @@ def sexp
class TableGet
def initialize (tbl, key)
- @tbl, @key = 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,19 +1,31 @@
-require 'lupin/value'
-
module Lupin
class Generator
+ attr_reader :g, :state
+ private :g
+
def initialize (lstate)
@state = lstate
@g = Rubinius::Generator.new
end
- def push_literal (arg)
- g.push_literal(arg)
+ def push_number (num)
+ g.push_literal Lupin::Types::Number.new(num)
+ end
+
+ def push_string (str)
+ g.push_literal Lupin::Types::String.new(str)
end
def push_table
- g.push_literal Lupin::Types::Table
- g.send :new, 0
+ g.push_literal Lupin::Types::Table.new(@state)
+ end
+
+ def push_bool (bool)
+ g.push_literal Lupin::Types::Boolean.new(bool)
+ end
+
+ def push_nil
+ g.push_literal Lupin::Types::Nil
end
def dup_top
@@ -29,38 +41,42 @@ def ret
end
def add
- math :+, '__add'
+ g.send :+, 1
end
def sub
- math :-, '__sub'
+ g.send :-, 1
end
def mul
- math :*, '__mul'
+ g.send :*, 1
end
def div
- math :/, '__div'
+ g.send :/, 1
end
def mod
- math :%, '__mod'
+ g.send :%, 1
end
def pow
- math :**, '__pow'
+ g.send :**, 1
end
- def concat
- g.pop_many 2
- g.push_literal "Hello from the unfinished concatenation routine"
+ def get_table
+ g.send :[], 1
end
def set_table
g.send :[]=, 2
end
+ def concat
+ g.pop_many 2
+ g.push_literal "Hello from the unfinished concatenation routine"
+ end
+
def assemble (name, file, line)
g.name = name.to_sym
g.file = file.to_sym
@@ -71,51 +87,7 @@ def assemble (name, file, line)
g.package Rubinius::CompiledMethod
end
- attr_reader :g, :state
- private :g
-
private
- # Perform arithmetic on two operands, coercing them to numbers if possible.
- # If one of the operands is not number-like, try to invoke a metamethod.
- def math (op, metamethod)
- else_label = g.new_label
- else2_label = g.new_label
- done_label = g.new_label
-
- # lhs, rhs
- g.send :try_tonumber, 0
- g.dup # lhs, rhs, rhs
- g.send :type, 0 # lhs, rhs, type
- g.push_literal :number # lhs, rhs, type, :number
- g.send :==, 1 # lhs, rhs, (is-number?)
- g.gif else_label
- # lhs, rhs
- g.swap # rhs, lhs
- g.send :try_tonumber, 0
- g.dup # rhs, lhs, lhs
- g.send :type, 0 # rhs, lhs, type
- g.push_literal :number # rhs, lhs, type, :number
- g.send :==, 1 # rhs, lhs, (is-number?)
- g.gif else2_label
- # rhs, lhs
- g.swap # lhs, rhs
- g.send op, 1 # sum
- g.goto done_label
- else2_label.set!
- g.swap # lhs, rhs
- # Fall through to the outer else clause
- else_label.set!
- # lhs, rhs
- # Code will go here for metatables. If the metamethod doesn't exist,
- # raise an error.
- g.pop_many 2
- g.push_self
- g.push_literal "Cannot call #{metamethod}: Metatables aren't implemented yet."
- g.send :raise, 1, true
- done_label.set!
- # result
- end
-
# Used intermittently for debugging. Equivalent to p(arg)
def puts_top
g.dup
@@ -57,25 +57,25 @@ def value
end
end
- Lupin::AST::Literal.new(s)
+ Lupin::AST::String.new(s)
end
end
module LongStringLiteral
def value
- Lupin::AST::Literal.new(match(/\[(=*)\[\n?(.*?)\]\1\]/m)[2])
+ Lupin::AST::String.new(match(/\[(=*)\[\n?(.*?)\]\1\]/m)[2])
end
end
module HexLiteral
def value
- Lupin::AST::Literal.new(to_i(16))
+ Lupin::AST::Number.new(to_i(16))
end
end
module DecimalLiteral
def value
- Lupin::AST::Literal.new(base.value * 10 ** (exponent == '' ? 0 : exponent.value))
+ Lupin::AST::Number.new(base.value * 10 ** (exponent == '' ? 0 : exponent.value))
end
end
@@ -15,27 +15,6 @@ grammar Lupin::Parser::Lua
) { stat.value }
end
- ### Function invocation
- rule functioncall
- (var:( variable
- | ('(' WS? expression WS? ')') { expression.value }
- )
- args:(WS? args)+
- ) {
- f = var.value
- args.matches.each {|a| f = Lupin::AST::FunctionCall.new(f, a.args.value)}
- f
- }
- end
-
- rule args
- ( ('(' WS? explist WS? ')') { explist.value }
- | ('(' WS? ')') { [] }
- | (table) { [table] }
- | (string) { [string] }
- )
- end
-
####
## Expressions (Operators & Precedence)
#
@@ -142,31 +121,55 @@ grammar Lupin::Parser::Lua
end
rule basic_expr
- ( primitive | prefix_expr )
+ ( primitive
+ | functioncall
+ | indexer
+ | value_expr
+ )
end
- rule prefix_expr
+ rule value_expr
( ('(' WS? expression WS? ')') { expression.value }
- | functioncall
- | variable
+ # | variable
)
end
- ### Variable access
- rule variable
- ( identifier
- list:( (WS? '.' WS? identifier) { identifier.value }
- | (WS? '[' WS? expression WS? ']') { expression.value }
- )*
+ rule indexer
+ ( var:value_expr
+ args:( (WS? '[' WS? expression WS? ']') { expression.value }
+ | (WS? '.' WS? identifier) { identifier.value }
+ )+
) {
- t = nil
- [identifier].concat(list.matches).each {|m| t = Lupin::AST::TableGet.new(t, m.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? args)+
+ ) {
+ f = var.value
+ args.matches.each {|a| f = Lupin::AST::FunctionCall.new(f, a.value)}
+ f
+ }
+ end
+
+ rule args
+ ( ('(' WS? explist WS? ')') { explist.value }
+ | ('(' WS? ')') { [] }
+ | (table) { [table] }
+ | (string) { [string] }
+ )
+ end
+
+ rule variable
+ (identifier)
+ end
+
rule identifier
- /[A-Za-z_][A-Za-z_0-9]*/ { Lupin::AST::Literal.new(to_s) }
+ /[A-Za-z_][A-Za-z_0-9]*/ { Lupin::AST::String.new(to_s) }
end
####
@@ -229,14 +232,14 @@ grammar Lupin::Parser::Lua
### Boolean
rule boolean
- ( 'false' { Lupin::AST::Literal.new(false) }
- | 'true' { Lupin::AST::Literal.new(true) }
+ ( 'true' { Lupin::AST::True }
+ | 'false' { Lupin::AST::False }
)
end
### Nil
rule nil
- 'nil' { Lupin::AST::Literal.new(nil) }
+ 'nil' { Lupin::AST::Nil }
end
### Whitespace and comments
View
@@ -16,6 +16,17 @@ 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]
+ end
end
class Code
Oops, something went wrong.

0 comments on commit ab02401

Please sign in to comment.