diff --git a/lib/arm/assembler.rb b/lib/arm/assembler.rb index e4217468..a6a3c650 100644 --- a/lib/arm/assembler.rb +++ b/lib/arm/assembler.rb @@ -63,6 +63,7 @@ module Arm # return the block of the given name # or raise an exception, as this is meant to be called when the block is available def get_block name + name = name.to_sym block = @blocks.find {|b| b.name == name} raise "No block found for #{name} (in #{blocks.collect{|b|b.name}.join(':')})" unless block block diff --git a/lib/ast/basic_expressions.rb b/lib/ast/basic_expressions.rb index 2f87f421..67e79f50 100644 --- a/lib/ast/basic_expressions.rb +++ b/lib/ast/basic_expressions.rb @@ -24,7 +24,7 @@ module Ast class NameExpression < Expression attr_reader :name def initialize name - @name = name + @name = name.to_sym end # compiling a variable resolves it. # if it wasn't defined, nli is returned @@ -32,7 +32,7 @@ module Ast context.locals[name] end def inspect - self.class.name + '.new("' + name + '")' + "#{self.class.name}.new(#{name})" end def to_s name diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index f9c01be8..b537c020 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -5,7 +5,9 @@ module Ast attr_reader :name, :args , :receiver def initialize name, args , receiver = Ast::NameExpression.new(:self) - @name , @args , @receiver = name.to_sym , args , receiver + @name = name.to_sym + @args = args + @receiver = receiver end def compile context , into @@ -14,6 +16,7 @@ module Ast r = context.current_class.name if !receiver.nil? and receiver.name != :self r = receiver.name + raise "uups #{receiver.class}.#{receiver.name.class}" unless r.is_a? Symbol end clazz = context.object_space.get_or_create_class r diff --git a/lib/ast/module_expression.rb b/lib/ast/module_expression.rb index 101da84e..0ca2a01e 100644 --- a/lib/ast/module_expression.rb +++ b/lib/ast/module_expression.rb @@ -1,6 +1,8 @@ module Ast class ModuleExpression < Expression + attr_reader :name ,:expressions + def initialize name , expressions @name = name.to_sym @expressions = expressions diff --git a/lib/vm/boot_class.rb b/lib/vm/boot_class.rb index d83a25ec..d2bcc58c 100644 --- a/lib/vm/boot_class.rb +++ b/lib/vm/boot_class.rb @@ -1,15 +1,19 @@ +require_relative "meta_class" + module Vm # class is mainly a list of functions with a name (for now) # layout of object is seperated into Layout class BootClass < Code - def initialize name , context , superclass = :Object + def initialize name , context , super_class = :Object + super() @context = context # class functions @functions = [] @name = name.to_sym - @superclass = superclass + @super_class = super_class + @meta_class = MetaClass.new(self) end - attr_reader :name , :functions + attr_reader :name , :functions , :meta_class def add_function function raise "not a function #{function}" unless function.is_a? Function @@ -22,11 +26,11 @@ module Vm @functions.detect{ |f| f.name == name } end - # preferred way of creating new functions (also forward declarations, will flag unresolved later) + # way of creating new functions that have not been parsed. def get_or_create_function name fun = get_function name unless fun or name == :Object - supr = @context.object_space.get_or_create_class(@superclass) + supr = @context.object_space.get_or_create_class(@super_class) fun = supr.get_function name puts "#{supr.functions.collect(&:name)} for #{name} GOT #{fun.class}" if name == :index_of end diff --git a/lib/vm/meta_class.rb b/lib/vm/meta_class.rb new file mode 100644 index 00000000..1442de37 --- /dev/null +++ b/lib/vm/meta_class.rb @@ -0,0 +1,33 @@ +module Vm + # class that acts like a class, but is really the object + + # described in the ruby language book as the eigenclass, what you get with + # class MyClass + # class << self <--- this is called the eigenclass, or metaclass, and really is just the class object + # .... but gives us the ability to use the syntax as if it were a class + # PS: can't say i fancy the << self syntax and am considerernig adding a keyword for it, like meta + # In effect it is a very similar construct to def self.function(...) + # So one could write def meta.function(...) and thus define on the meta-class + class MetaClass < Code + # no name, nor nothing. as this is just the object really + + def initialize(object) + super() + @functions = [] + @me_self = object + end + + # in a non-booting version this should map to _add_singleton_method + def add_function function + raise "not a function #{function}" unless function.is_a? Function + raise "syserr " unless function.name.is_a? Symbol + @functions << function + end + + def get_function name + name = name.to_sym + @functions.detect{ |f| f.name == name } + end + + end +end diff --git a/test/parser/test_basic.rb b/test/parser/test_basic.rb index 49606c09..4caa1071 100644 --- a/test/parser/test_basic.rb +++ b/test/parser/test_basic.rb @@ -35,7 +35,7 @@ class TestBasic < MiniTest::Test def test_instance_variable @string_input = '@foo_bar ' @parse_output = {:instance_variable=>{:name=>"foo_bar"}} - @transform_output = Ast::VariableExpression.new('foo_bar') + @transform_output = Ast::VariableExpression.new(:foo_bar) @parser = @parser.instance_variable end diff --git a/test/parser/test_call_site.rb b/test/parser/test_call_site.rb index f6712008..12619a47 100644 --- a/test/parser/test_call_site.rb +++ b/test/parser/test_call_site.rb @@ -22,7 +22,7 @@ class TestCallSite < MiniTest::Test def test_single_instance @string_input = '@var.foo(42)' @parse_output = {:receiver=>{:instance_variable=>{:name=>"var"}}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]} - @transform_output = Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::VariableExpression.new("var")) + @transform_output = Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::VariableExpression.new(:var)) @parser = @parser.call_site end @@ -96,7 +96,7 @@ class TestCallSite < MiniTest::Test def test_call_chaining_instance @string_input = '@class.new(self.get(4))' @parse_output = {:receiver=>{:instance_variable=>{:name=>"class"}}, :call_site=>{:name=>"new"}, :argument_list=>[{:argument=>{:receiver=>{:name=>"self"}, :call_site=>{:name=>"get"}, :argument_list=>[{:argument=>{:integer=>"4"}}]}}]} - @transform_output = Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new("self"))] ,Ast::VariableExpression.new("class")) + @transform_output = Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new("self"))] ,Ast::VariableExpression.new(:class)) @parser = @parser.call_site end diff --git a/test/parser/test_class.rb b/test/parser/test_class.rb index 5d3f65ab..183a5f3a 100644 --- a/test/parser/test_class.rb +++ b/test/parser/test_class.rb @@ -25,7 +25,7 @@ class Opers end HERE @parse_output = {:module_name=>"Opers", :class_expressions=>[{:function_name=>{:name=>"foo"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"} - @transform_output = Ast::ClassExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::OperatorExpression.new("=", Ast::VariableExpression.new("abba"),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] )] ) + @transform_output = Ast::ClassExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::OperatorExpression.new("=", Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] )] ) @parser = @parser.class_definition end @@ -56,7 +56,7 @@ class Pifi end HERE @parse_output = {:module_name=>"Pifi", :class_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}, {:function_name=>{:name=>"ofthen"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}, {:parmeter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"} - @transform_output =Ast::ClassExpression.new(:Pifi ,[Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new("var")] ), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n"),Ast::NameExpression.new("m")] , [Ast::IntegerExpression.new(44)] )] ) + @transform_output =Ast::ClassExpression.new(:Pifi ,[Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n"),Ast::NameExpression.new("m")] , [Ast::IntegerExpression.new(44)] )] ) @parser = @parser.class_definition end def test_class_module @@ -68,7 +68,7 @@ class Foo end HERE @parse_output = {:module_name=>"Foo", :class_expressions=>[{:module_name=>"Boo", :module_expressions=>[{:call_site=>{:name=>"funcall"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}], :end=>"end"}], :end=>"end"} - @transform_output = Ast::ClassExpression.new(:Foo ,[Ast::ModuleExpression.new(:Boo ,[Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new("var")] )] )] ) + @transform_output = Ast::ClassExpression.new(:Foo ,[Ast::ModuleExpression.new(:Boo ,[Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] )] )] ) @parser = @parser.class_definition end end \ No newline at end of file diff --git a/test/parser/test_function_definition.rb b/test/parser/test_function_definition.rb index 84b5911b..21a6de97 100644 --- a/test/parser/test_function_definition.rb +++ b/test/parser/test_function_definition.rb @@ -22,7 +22,7 @@ def String.length(x) end HERE @parse_output = {:receiver=>{:module_name=>"String"}, :function_name=>{:name=>"length"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:instance_variable=>{:name=>"length"}}], :end=>"end"} - @transform_output = Ast::FunctionExpression.new(:length, [Ast::NameExpression.new("x")] , [Ast::VariableExpression.new("length")] ,Ast::ModuleName.new("String") ) + @transform_output = Ast::FunctionExpression.new(:length, [Ast::NameExpression.new("x")] , [Ast::VariableExpression.new(:length)] ,Ast::ModuleName.new("String") ) @parser = @parser.function_definition end diff --git a/test/parser/test_module.rb b/test/parser/test_module.rb index 35cb2650..9089d0a6 100644 --- a/test/parser/test_module.rb +++ b/test/parser/test_module.rb @@ -36,7 +36,7 @@ module Opers end HERE @parse_output = {:module_name=>"Opers", :module_expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}], :end=>"end"} - @transform_output = Ast::ModuleExpression.new(:Opers ,[Ast::OperatorExpression.new("=", Ast::VariableExpression.new("abba"),Ast::IntegerExpression.new(5))] ) + @transform_output = Ast::ModuleExpression.new(:Opers ,[Ast::OperatorExpression.new("=", Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5))] ) @parser = @parser.module_definition end diff --git a/test/parser/test_operators.rb b/test/parser/test_operators.rb index 523e0d19..6d3c7d7f 100644 --- a/test/parser/test_operators.rb +++ b/test/parser/test_operators.rb @@ -31,25 +31,25 @@ class TestExpressions < MiniTest::Test def test_op_variable @string_input = "a + 35" @parse_output = {:l=>{:name=>"a"}, :o=>"+ ", :r=>{:integer=>"35"}} - @transform_output = Ast::OperatorExpression.new("+", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(35)) + @transform_output = Ast::OperatorExpression.new("+", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(35)) @parser = @parser.operator_expression end def test_op_two_variable @string_input = "a - b" @parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:name=>"b"}} - @transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new("a"),Ast::NameExpression.new("b")) + @transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::NameExpression.new("b")) @parser = @parser.operator_expression end def test_op_instance_variable @string_input = "@a - 5" @parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"- ", :r=>{:integer=>"5"}} - @transform_output = Ast::OperatorExpression.new("-", Ast::VariableExpression.new("a"),Ast::IntegerExpression.new(5)) + @transform_output = Ast::OperatorExpression.new("-", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5)) @parser = @parser.operator_expression end def test_op_variable_string @string_input = 'a - "st"' @parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:string=>[{:char=>"s"}, {:char=>"t"}]}} - @transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new("a"),Ast::StringExpression.new("st")) + @transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::StringExpression.new("st")) @parser = @parser.operator_expression end def test_two_same_ops @@ -73,13 +73,13 @@ class TestExpressions < MiniTest::Test def test_assignment @string_input = "a = 5" @parse_output = {:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}} - @transform_output = Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(5)) + @transform_output = Ast::OperatorExpression.new("=", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5)) @parser = @parser.operator_expression end def test_assignment_instance @string_input = "@a = 5" @parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"= ", :r=>{:integer=>"5"}} - @transform_output = Ast::OperatorExpression.new("=", Ast::VariableExpression.new("a"),Ast::IntegerExpression.new(5)) + @transform_output = Ast::OperatorExpression.new("=", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5)) @parser = @parser.operator_expression end