diff --git a/lib/ast/call_site_expression.rb b/lib/ast/call_site_expression.rb index 4c3e80e3..c938c6dc 100644 --- a/lib/ast/call_site_expression.rb +++ b/lib/ast/call_site_expression.rb @@ -2,10 +2,12 @@ module Ast # assignment, like operators are really function calls class CallSiteExpression < Expression - attr_reader :name, :args - def initialize name, args - @name , @args = name.to_sym , args + attr_reader :name, :args , :receiver + + def initialize name, args , receiver = Ast::NameExpression.new("self") + @name , @args , @receiver = name.to_sym , args , receiver end + def compile context , into params = args.collect{ |a| a.compile(context, into) } #TOOD, this needs dynamic resolution @@ -23,13 +25,13 @@ module Ast def inspect self.class.name + ".new(" + name.inspect + ", ["+ - args.collect{|m| m.inspect }.join( ",") +"] )" + args.collect{|m| m.inspect }.join( ",") + "] ," + receiver.inspect + ")" end def to_s "#{name}(" + args.join(",") + ")" end def attributes - [:name , :args] + [:name , :args , :receiver] end end diff --git a/lib/parser/call_site.rb b/lib/parser/call_site.rb index eda888a3..154d6f6b 100644 --- a/lib/parser/call_site.rb +++ b/lib/parser/call_site.rb @@ -9,7 +9,8 @@ module Parser space? >> right_parenthesis } - rule(:call_site) { (name.as(:receiver) >> str(".")).repeat(0,1) >> name.as(:call_site) >> argument_list >> comment.maybe} + rule(:call_site) { ((module_name|name).as(:receiver) >> str(".")).maybe >> #possibly qualified + name.as(:call_site) >> argument_list >> comment.maybe} end diff --git a/lib/parser/transform.rb b/lib/parser/transform.rb index 0cbd28a1..5c6225d3 100644 --- a/lib/parser/transform.rb +++ b/lib/parser/transform.rb @@ -23,7 +23,11 @@ module Parser rule( :call_site => simple(:call_site), :argument_list => sequence(:argument_list)) do - Ast::CallSiteExpression.new(call_site.name, argument_list) + Ast::CallSiteExpression.new(call_site.name, argument_list ) + end + rule( :receiver => simple(:receiver) , :call_site => simple(:call_site), + :argument_list => sequence(:argument_list)) do + Ast::CallSiteExpression.new(call_site.name, argument_list , receiver) end rule(:if => simple(:if), :conditional => simple(:conditional), diff --git a/test/parser/test_call_site.rb b/test/parser/test_call_site.rb index 2fa61695..10f525e6 100644 --- a/test/parser/test_call_site.rb +++ b/test/parser/test_call_site.rb @@ -12,6 +12,27 @@ class TestCallSite < MiniTest::Test @parser = @parser.call_site end + def test_single_self + @string_input = 'self.foo(42)' + @parse_output = {:receiver=>{:name=>"self"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]} + @transform_output = Ast::CallSiteExpression.new 'foo', [Ast::IntegerExpression.new(42)] + @parser = @parser.call_site + end + + def test_single_name + @string_input = 'my_my.foo(42)' + @parse_output = {:receiver=>{:name=>"my_my"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]} + @transform_output = Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new("my_my")) + @parser = @parser.call_site + end + + def test_single_class + @string_input = 'Object.foo(42)' + @parse_output = {:receiver=>{:module_name=>"Object"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]} + @transform_output = Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::ModuleName.new("Object")) + @parser = @parser.call_site + end + def test_call_site_multi @string_input = 'baz(42, foo)' @parse_output = {:call_site => {:name => 'baz' }, @@ -52,4 +73,18 @@ class TestCallSite < MiniTest::Test @parser = @parser.call_site end + def test_call_chaining_name + @string_input = 'puts(name.putint(4), a)' + @parse_output = {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:receiver=>{:name=>"name"}, :call_site=>{:name=>"putint"}, :argument_list=>[{:argument=>{:integer=>"4"}}]}}, {:argument=>{:name=>"a"}}]} + @transform_output = Ast::CallSiteExpression.new(:puts, [Ast::CallSiteExpression.new(:putint, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new("name")),Ast::NameExpression.new("a")] ,Ast::NameExpression.new("self")) + @parser = @parser.call_site + end + + def test_call_chaining_class + @string_input = 'Class.new(self.get(4))' + @parse_output = {:receiver=>{:module_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::ModuleName.new("Class")) + @parser = @parser.call_site + end + end \ No newline at end of file diff --git a/test/parser/test_conditional.rb b/test/parser/test_conditional.rb index 9cfac4f7..4882e6c3 100644 --- a/test/parser/test_conditional.rb +++ b/test/parser/test_conditional.rb @@ -20,12 +20,22 @@ else end HERE @string_input = "if #{cond} " + input.chop! - @parse_output = {:if=>"if", :conditional=>{:integer=>"0"}, - :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, - :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}} - @transform_output = Ast::IfExpression.new( Ast::IntegerExpression.new(0), - [Ast::IntegerExpression.new(42)], [Ast::IntegerExpression.new(667)]) + @parse_output = {:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}} + @transform_output = Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] ) + @parser = @parser.conditional + end + def test_conditional_with_calls + @string_input = < var) + Object.initialize(3) +else + var.new(33) +end +HERE + @string_input.chop! + @parse_output = {:if=>"if", :conditional=>{:l=>{:integer=>"3"}, :o=>"> ", :r=>{:name=>"var"}}, :if_true=>{:expressions=>[{:receiver=>{:module_name=>"Object"}, :call_site=>{:name=>"initialize"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}], :else=>"else"}, :if_false=>{:expressions=>[{:receiver=>{:name=>"var"}, :call_site=>{:name=>"new"}, :argument_list=>[{:argument=>{:integer=>"33"}}]}], :end=>"end"}} + @transform_output = Ast::IfExpression.new(Ast::OperatorExpression.new(">", Ast::IntegerExpression.new(3),Ast::NameExpression.new("var")), [Ast::CallSiteExpression.new(:initialize, [Ast::IntegerExpression.new(3)] ,Ast::ModuleName.new("Object"))],[Ast::CallSiteExpression.new(:new, [Ast::IntegerExpression.new(33)] ,Ast::NameExpression.new("var"))] ) @parser = @parser.conditional end end \ No newline at end of file diff --git a/test/parser/test_module.rb b/test/parser/test_module.rb index b19ab9a9..35cb2650 100644 --- a/test/parser/test_module.rb +++ b/test/parser/test_module.rb @@ -70,6 +70,7 @@ HERE @transform_output = Ast::ModuleExpression.new(:Soho ,[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.module_definition end + def test_module_class @string_input = <"FooBo", :class_expressions=>[{:receiver=>{:module_name=>"Bar"}, :call_site=>{:name=>"call"}, :argument_list=>[{:argument=>{:integer=>"35"}}]}], :end=>"end"}] + @transform_output = [Ast::ClassExpression.new(:FooBo ,[Ast::CallSiteExpression.new(:call, [Ast::IntegerExpression.new(35)] ,Ast::ModuleName.new("Bar"))] )] + end + end diff --git a/test/parser/test_while.rb b/test/parser/test_while.rb index c2bb7087..c72e2800 100644 --- a/test/parser/test_while.rb +++ b/test/parser/test_while.rb @@ -12,15 +12,21 @@ while(1) do end HERE @string_input.chop! - @parse_output = {:while=>"while", - :while_cond=>{:integer=>"1"}, - :do=>"do", - :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, - {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}], :end=>"end"}} - @transform_output = Ast::WhileExpression.new( - Ast::IntegerExpression.new(1), - [Ast::OperatorExpression.new("=", Ast::NameExpression.new("tmp"),Ast::NameExpression.new("a")), - Ast::CallSiteExpression.new("puts", [Ast::NameExpression.new("b")] )] ) + @parse_output = {:while=>"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}], :end=>"end"}} + @transform_output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("tmp"),Ast::NameExpression.new("a")), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new("b")] ,Ast::NameExpression.new("self"))] ) + @parser = @parser.while_do + end + + def test_while_method + @string_input = <"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:receiver=>{:module_name=>"String"}, :call_site=>{:name=>"new"}, :argument_list=>[]}}, {:receiver=>{:name=>"tmp"}, :call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"i"}}]}], :end=>"end"}} + @transform_output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("tmp"),Ast::CallSiteExpression.new(:new, [] ,Ast::ModuleName.new("String"))), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new("i")] ,Ast::NameExpression.new("tmp"))] ) @parser = @parser.while_do end @@ -35,23 +41,8 @@ while( n > 1) do end HERE @string_input.chop! - @parse_output = {:while=>"while", - :while_cond=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"1"}}, - :do=>"do", - :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, - {:l=>{:name=>"a"}, :o=>"= ", :r=>{:name=>"b"}}, - {:l=>{:name=>"b"}, :o=>"= ", :r=>{:l=>{:name=>"tmp"}, :o=>"+ ", :r=>{:name=>"b"}}}, - {:call_site=>{:name=>"puts"}, - :argument_list=>[{:argument=>{:name=>"b"}}]}, - {:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"- ", :r=>{:integer=>"1"}}}], - :end=>"end"}} - @transform_output = Ast::WhileExpression.new( - Ast::OperatorExpression.new(">", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1)), - [Ast::OperatorExpression.new("=", Ast::NameExpression.new("tmp"),Ast::NameExpression.new("a")), - Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::NameExpression.new("b")), - Ast::OperatorExpression.new("=", Ast::NameExpression.new("b"),Ast::OperatorExpression.new("+", Ast::NameExpression.new("tmp"), - Ast::NameExpression.new("b"))), Ast::CallSiteExpression.new("puts", [Ast::NameExpression.new("b")] ), - Ast::OperatorExpression.new("=", Ast::NameExpression.new("n"),Ast::OperatorExpression.new("-", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1)))] ) + @parse_output = {:while=>"while", :while_cond=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"1"}}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:l=>{:name=>"a"}, :o=>"= ", :r=>{:name=>"b"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:l=>{:name=>"tmp"}, :o=>"+ ", :r=>{:name=>"b"}}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}, {:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"- ", :r=>{:integer=>"1"}}}], :end=>"end"}} + @transform_output = Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1)), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("tmp"),Ast::NameExpression.new("a")), Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::NameExpression.new("b")), Ast::OperatorExpression.new("=", Ast::NameExpression.new("b"),Ast::OperatorExpression.new("+", Ast::NameExpression.new("tmp"),Ast::NameExpression.new("b"))), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new("b")] ,Ast::NameExpression.new("self")), Ast::OperatorExpression.new("=", Ast::NameExpression.new("n"),Ast::OperatorExpression.new("-", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1)))] ) @parser = @parser.while_do end end \ No newline at end of file