From 7ab293cb62e1b076a8b479d4715e9b3a190c81e3 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Wed, 4 Jun 2014 19:56:50 +0300 Subject: [PATCH] add the test code from crystal --- test/README.markdown | 38 +++++++++ test/parse_helper.rb | 65 ++++++++++++++++ test/test_all.rb | 14 ++++ test/test_arguments.rb | 37 +++++++++ test/test_basic.rb | 73 +++++++++++++++++ test/test_call_site.rb | 103 ++++++++++++++++++++++++ test/test_class.rb | 74 ++++++++++++++++++ test/test_compound.rb | 44 +++++++++++ test/test_conditional.rb | 41 ++++++++++ test/test_expressions.rb | 40 ++++++++++ test/test_fails.rb | 26 +++++++ test/test_function_definition.rb | 130 +++++++++++++++++++++++++++++++ test/test_module.rb | 86 ++++++++++++++++++++ test/test_operators.rb | 86 ++++++++++++++++++++ test/test_return.rb | 28 +++++++ test/test_root.rb | 118 ++++++++++++++++++++++++++++ test/test_while.rb | 48 ++++++++++++ 17 files changed, 1051 insertions(+) create mode 100644 test/README.markdown create mode 100644 test/parse_helper.rb create mode 100644 test/test_all.rb create mode 100644 test/test_arguments.rb create mode 100644 test/test_basic.rb create mode 100644 test/test_call_site.rb create mode 100644 test/test_class.rb create mode 100644 test/test_compound.rb create mode 100644 test/test_conditional.rb create mode 100644 test/test_expressions.rb create mode 100644 test/test_fails.rb create mode 100644 test/test_function_definition.rb create mode 100644 test/test_module.rb create mode 100644 test/test_operators.rb create mode 100644 test/test_return.rb create mode 100644 test/test_root.rb create mode 100644 test/test_while.rb diff --git a/test/README.markdown b/test/README.markdown new file mode 100644 index 0000000..ae655ce --- /dev/null +++ b/test/README.markdown @@ -0,0 +1,38 @@ +Parsing +------- + +Some sanity is emerging in the testing of parsers + (Parsers are fiddly in respect to space and order, small changes may and do have unexpected effects) + +Parsing is a two step process with parslet: + - parse takes an input and outputs hashes/arrays with basic types + - tramsform takes the output of parse and generates an ast (as specified by the transformation) + +A test tests both phases seperately and again together. +Each test must thus specify (as instance variables): +- the string input +- the parse output +- the transform output + +Magic +----- + +Test are grouped by functionality into cases (classes) and define methods test_* +Test cases must include ParserHelper, which includes the magic to write the 3 test methods for each +test method. See test_basic for easy example. + +Example: + + def test_number + @string_input = '42 ' + @test_output = {:integer => '42'} + @transform_output = Parser::IntegerExpression.new(42) + @parser = @parser.integer + end + +The first three lines define the data as described above. +The last line tells the parser what to parse. This is off couse only needed when a non-root rule is tested +and should be left out if possible. + +As can be seen, there are no asserts. All asserting is done by the created methods, which call +the check_* methods in helper. \ No newline at end of file diff --git a/test/parse_helper.rb b/test/parse_helper.rb new file mode 100644 index 0000000..5f058dc --- /dev/null +++ b/test/parse_helper.rb @@ -0,0 +1,65 @@ +require_relative "../helper" +require "parslet/convenience" + +# remove the line numbers on assert fails, so it's easy to copy paste the result as the expected result +Parslet::Slice.class_eval do + def inspect + '"' + to_s + '"' + end +end +# Included in parser test will create tests methods +module ParserHelper + + def self.included(base) + base.send :include, InstanceMethods #provides helpers and setup + base.send :extend, ClassMethods #gets the method creation going + end + + module InstanceMethods + def setup + @parser = Parser::Crystal.new + @transform = Parser::Transform.new + end + + # check that @string_input parses correctly to @parse_output + def check_parse + is = @parser.parse_with_debug(@string_input) + assert_equal @parse_output , is + end + + #check that @parse_output transforms to @transform_output + def check_transform + is = @transform.apply @parse_output + #puts is.transform + assert_equal @transform_output , is + end + + # check that @string_input parses and transforms to @transform_output + def check_ast + syntax = @parser.parse(@string_input) + is = @transform.apply(syntax) + #puts is.inspect + assert_equal @transform_output , is + end + end + + module ClassMethods + # this creates test methods dynamically. For each test_* method we create + # three test_*[ast/parse/transf] methods that in turn check the three phases. + # runnable_methods is called by minitest to determine which tests to run + def runnable_methods + tests = [] + public_instance_methods(true).grep(/^test_/).map(&:to_s).each do |test| + ["ast" , "transform" , "parse"].each do |what| + name = "#{test}_#{what}" + tests << name + self.send(:define_method, name ) do + send(test) + send("check_#{what}") + end + end + end + tests + end + end +end diff --git a/test/test_all.rb b/test/test_all.rb new file mode 100644 index 0000000..568dcf2 --- /dev/null +++ b/test/test_all.rb @@ -0,0 +1,14 @@ + +require_relative "test_arguments" +require_relative "test_basic" +require_relative "test_call_site" +require_relative "test_class" +require_relative "test_compound" +require_relative "test_conditional" +require_relative "test_expressions" +require_relative "test_function_definition" +require_relative "test_module" +require_relative "test_operators" +require_relative "test_return" +require_relative "test_root" +require_relative "test_while" diff --git a/test/test_arguments.rb b/test/test_arguments.rb new file mode 100644 index 0000000..b11eb97 --- /dev/null +++ b/test/test_arguments.rb @@ -0,0 +1,37 @@ +require_relative "helper" + +class TestArguments < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_one_argument + @string_input = '(42)' + @parse_output = {:argument_list => [{:argument => {:integer => '42'}}] } + @transform_output = [Ast::IntegerExpression.new(42) ] + @parser = @parser.argument_list + end + + def test_argument_list + @string_input = '(42, foo)' + @parse_output = {:argument_list => [{:argument => {:integer => '42'}}, + {:argument => {:name => 'foo'}}]} + @transform_output = [Ast::IntegerExpression.new(42), Ast::NameExpression.new('foo')] + @parser = @parser.argument_list + end + + def test_parmeter + @string_input = "(foo)" + @parse_output = {:parmeter_list => [{:parmeter => { :name => "foo"}} ]} + @transform_output = [Ast::NameExpression.new('foo')] + @parser = @parser.parmeter_list + end + + def test_parmeter_list + @string_input = "( foo , bar)" + @parse_output = {:parmeter_list => [{:parmeter => { :name => "foo"}}, + {:parmeter => { :name => "bar"}} ]} + @transform_output = [Ast::NameExpression.new('foo') , Ast::NameExpression.new('bar')] + @parser = @parser.parmeter_list + end + +end \ No newline at end of file diff --git a/test/test_basic.rb b/test/test_basic.rb new file mode 100644 index 0000000..4caa107 --- /dev/null +++ b/test/test_basic.rb @@ -0,0 +1,73 @@ +require_relative "helper" + +class TestBasic < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_number + @string_input = '42 ' + @parse_output = {:integer => '42'} + @transform_output = Ast::IntegerExpression.new(42) + @parser = @parser.integer + end + + def test_name + @string_input = 'foo ' + @parse_output = {:name => 'foo'} + @transform_output = Ast::NameExpression.new('foo') + @parser = @parser.name + end + + def test_name_underscode_start + @string_input = '_bar ' + @parse_output = {:name => '_bar'} + @transform_output = Ast::NameExpression.new('_bar') + @parser = @parser.name + end + + def test_name_underscode_middle + @string_input = 'foo_bar ' + @parse_output = {:name => 'foo_bar'} + @transform_output = Ast::NameExpression.new('foo_bar') + @parser = @parser.name + end + + def test_instance_variable + @string_input = '@foo_bar ' + @parse_output = {:instance_variable=>{:name=>"foo_bar"}} + @transform_output = Ast::VariableExpression.new(:foo_bar) + @parser = @parser.instance_variable + end + + def test_module_name + @string_input = 'FooBar ' + @parse_output = {:module_name=>"FooBar"} + @transform_output = Ast::ModuleName.new("FooBar") + @parser = @parser.module_name + end + + def test_comment + out = "# i am a comment \n" + @string_input = out.dup #NEEDS the return, which is what delimits the comment + @parse_output = out + @transform_output = @parse_output #dont transform + @parser = @parser.comment + end + + def test_string + @string_input = "\"hello\"" + @parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]} + @transform_output = Ast::StringExpression.new('hello') + @parser = @parser.string + end + + def test_string_escapes + out = 'hello \nyou' + @string_input = '"' + out + '"' + @parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}, + {:char=>" "}, {:char=>" "}, {:esc=>"n"}, {:char=>"y"}, {:char=>"o"}, {:char=>"u"}]} + @transform_output = Ast::StringExpression.new(out) + @parser = @parser.string + end + +end \ No newline at end of file diff --git a/test/test_call_site.rb b/test/test_call_site.rb new file mode 100644 index 0000000..12619a4 --- /dev/null +++ b/test/test_call_site.rb @@ -0,0 +1,103 @@ +require_relative "helper" + +class TestCallSite < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_single_argument + @string_input = 'foo(42)' + @parse_output = {: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_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_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)) + @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' }, + :argument_list => [{:argument => {:integer => '42'}}, + {:argument => {:name => 'foo'}}]} + @transform_output = Ast::CallSiteExpression.new :baz, + [Ast::IntegerExpression.new(42), Ast::NameExpression.new("foo") ] + @parser = @parser.call_site + end + + def test_call_site_string + @string_input = 'puts( "hello")' + @parse_output = {:call_site => {:name => 'puts' }, + :argument_list => [{:argument => + {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}}]} + @transform_output = Ast::CallSiteExpression.new "puts", [Ast::StringExpression.new("hello")] + @parser = @parser.call_site + end + + def test_call_operator + @string_input = 'puts( 3 + 5)' + @parse_output = {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}]} + @transform_output = Ast::CallSiteExpression.new(:puts, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5))] ) + @parser = @parser.call_site + end + + def test_call_two_operators + @string_input = 'puts(3 + 5 , a - 3)' + @parse_output = {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}, {:argument=>{:l=>{:name=>"a"}, :o=>"- ", :r=>{:integer=>"3"}}}]} + @transform_output = Ast::CallSiteExpression.new(:puts, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("-", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(3))] ) + @parser = @parser.call_site + end + + def test_call_chaining + @string_input = 'puts(putint(3 + 5 ), a - 3)' + @parse_output = {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:call_site=>{:name=>"putint"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}]}}, {:argument=>{:l=>{:name=>"a"}, :o=>"- ", :r=>{:integer=>"3"}}}]} + @transform_output = Ast::CallSiteExpression.new(:puts, [Ast::CallSiteExpression.new(:putint, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5))] ),Ast::OperatorExpression.new("-", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(3))] ) + @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 + 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)) + @parser = @parser.call_site + end + +end \ No newline at end of file diff --git a/test/test_class.rb b/test/test_class.rb new file mode 100644 index 0000000..183a5f3 --- /dev/null +++ b/test/test_class.rb @@ -0,0 +1,74 @@ +require_relative "helper" + +class TestClassDef < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_simplest_class + @string_input = <"Foo", :class_expressions=>[{:integer=>"5"}], :end=>"end"} + @transform_output = Ast::ClassExpression.new(:Foo ,[Ast::IntegerExpression.new(5)] ) + @parser = @parser.class_definition + end + + def test_class_ops + @string_input = <"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))] )] ) + @parser = @parser.class_definition + end + + def test_class_if + @string_input = <"Ifi", :class_expressions=>[{:function_name=>{:name=>"ofthen"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:l=>{:name=>"isit"}, :o=>"= ", :r=>{:integer=>"42"}}], :else=>"else"}, :if_false=>{:expressions=>[{:l=>{:name=>"maybenot"}, :o=>"= ", :r=>{:integer=>"667"}}], :end=>"end"}}], :end=>"end"}], :end=>"end"} + @transform_output = Ast::ClassExpression.new(:Ifi ,[Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n")] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("isit"),Ast::IntegerExpression.new(42))],[Ast::OperatorExpression.new("=", Ast::NameExpression.new("maybenot"),Ast::IntegerExpression.new(667))] )] )] ) + @parser = @parser.class_definition + end + + def test_class_function + @string_input = <"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)] )] ) + @parser = @parser.class_definition + end + def test_class_module + @string_input = <"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)] )] )] ) + @parser = @parser.class_definition + end +end \ No newline at end of file diff --git a/test/test_compound.rb b/test/test_compound.rb new file mode 100644 index 0000000..03121e7 --- /dev/null +++ b/test/test_compound.rb @@ -0,0 +1,44 @@ +require_relative "helper" + +class TestCompound < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_one_array + @string_input = '[42]' + @parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}]} + @transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)]) + @parser = @parser.array_constant + end + + def test_array_list + @string_input = '[42, foo]' + @parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:name=>"foo"}}]} + @transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new("foo")]) + @parser = @parser.array_constant + end + + def test_array_ops + @string_input = '[ 3 + 4 , foo(22) ]' + @parse_output = {:array_constant=>[{:array_element=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"4"}}}, {:array_element=>{:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"22"}}]}}]} + @transform_output = Ast::ArrayExpression.new( + [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)), + Ast::CallSiteExpression.new("foo", [Ast::IntegerExpression.new(22)] )]) + @parser = @parser.array_constant + end + + def test_hash + @string_input = '{ foo => 33 }' + @parse_output = {:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}]} + @transform_output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33))]) + @parser = @parser.hash_constant + end + + def test_hash_list + @string_input = "{foo => 33 , bar => 42}" + @parse_output = {:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}, {:hash_pair=>{:hash_key=>{:name=>"bar"}, :hash_value=>{:integer=>"42"}}}]} + @transform_output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33)),Ast::AssociationExpression.new(Ast::NameExpression.new("bar") , Ast::IntegerExpression.new(42))]) + @parser = @parser.hash_constant + end + +end \ No newline at end of file diff --git a/test/test_conditional.rb b/test/test_conditional.rb new file mode 100644 index 0000000..4882e6c --- /dev/null +++ b/test/test_conditional.rb @@ -0,0 +1,41 @@ +require_relative "helper" + +class TestConditional < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_conditional_brackets + check("(0)") + end + def test_conditional_no_brackets + check("0") + end + + def check cond + input = <"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/test_expressions.rb b/test/test_expressions.rb new file mode 100644 index 0000000..0eee563 --- /dev/null +++ b/test/test_expressions.rb @@ -0,0 +1,40 @@ +require_relative "helper" + +class TestExpressions < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_expression_else + @string_input = <[{:name=>"dud"}, + {:call_site=>{:name=>"fuu"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}], + :else=>"else"} + @transform_output ={:expressions=>[Ast::NameExpression.new("dud"), + Ast::CallSiteExpression.new("fuu", [Ast::IntegerExpression.new(3)] )], :else=>"else"} + @parser = @parser.expressions_else + end + + def test_expression_end + @string_input = <[{:name=>"name"}, + {:call_site=>{:name=>"call"}, :argument_list=>[{:argument=>{:integer=>"4"}}, {:argument=>{:integer=>"6"}}]}], + :end=>"end"} + @transform_output = {:expressions=>[Ast::NameExpression.new("name"), + Ast::CallSiteExpression.new("call", [Ast::IntegerExpression.new(4),Ast::IntegerExpression.new(6)] )], + :end=>"end"} + + @parser = @parser.expressions_end + end + + +end \ No newline at end of file diff --git a/test/test_fails.rb b/test/test_fails.rb new file mode 100644 index 0000000..76cf65a --- /dev/null +++ b/test/test_fails.rb @@ -0,0 +1,26 @@ +require_relative "helper" + +# some cases that fail, and fail badly. + +# These make the parse "hang", ie there is some looping going on in the parser, but not straight down, as theey don't +# throw even StackError + +# Annoyingly, the user error is quite small, a missing bracket or things + +class TestFails < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_fail_function + @string_input = < test method translation), see there + include ParserHelper + + def test_simplest_function + @string_input = <{:name=>"foo"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:integer=>"5"}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::IntegerExpression.new(5)] ) + @parser = @parser.function_definition + end + + def test_class_function + @string_input = <{: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") ) + @parser = @parser.function_definition + end + + def test_function_ops + @string_input = <{:name=>"foo"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("abba"),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil ) + @parser = @parser.function_definition + end + + def test_function_if + @string_input = <{:name=>"ofthen"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:l=>{:name=>"isit"}, :o=>"= ", :r=>{:integer=>"42"}}], :else=>"else"}, :if_false=>{:expressions=>[{:l=>{:name=>"maybenot"}, :o=>"= ", :r=>{:integer=>"667"}}], :end=>"end"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n")] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("isit"),Ast::IntegerExpression.new(42))],[Ast::OperatorExpression.new("=", Ast::NameExpression.new("maybenot"),Ast::IntegerExpression.new(667))] )] ,nil ) + @parser = @parser.function_definition + end + + def test_function_return + @string_input = <{:name=>"retvar"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"i"}, :o=>"= ", :r=>{:integer=>"5"}}, {:return=>"return", :return_expression=>{:name=>"i"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new("n")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("i"),Ast::IntegerExpression.new(5)),Ast::ReturnExpression.new(Ast::NameExpression.new("i") )] ) + @parser = @parser.function_definition + end + + def test_function_return_if + @string_input = < 5) + return 10 + else + return 20 + end +end +HERE + @parse_output = {:function_name=>{:name=>"retvar"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:if=>"if", :conditional=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"5"}}, :if_true=>{:expressions=>[{:return=>"return", :return_expression=>{:integer=>"10"}}], :else=>"else"}, :if_false=>{:expressions=>[{:return=>"return", :return_expression=>{:integer=>"20"}}], :end=>"end"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new("n")] , [Ast::IfExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(5)), [Ast::ReturnExpression.new(Ast::IntegerExpression.new(10) )],[Ast::ReturnExpression.new(Ast::IntegerExpression.new(20) )] )] ) + @parser = @parser.function_definition + end + + def test_function_return_while + @string_input = < 5) do + n = n + 1 + return n + end +end +HERE + @parse_output = {:function_name=>{:name=>"retvar"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:while=>"while", :while_cond=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"5"}}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"+ ", :r=>{:integer=>"1"}}}, {:return=>"return", :return_expression=>{:name=>"n"}}], :end=>"end"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new("n")] , [Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(5)), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("n"),Ast::OperatorExpression.new("+", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1))), Ast::ReturnExpression.new(Ast::NameExpression.new("n") )] )] ) + @parser = @parser.function_definition + end + + def test_function_while + @string_input = <{:name=>"fibonaccit"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}, {:while=>"while", :while_cond=>{:name=>"n"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"some"}, :o=>"= ", :r=>{:integer=>"43"}}, {:l=>{:name=>"other"}, :o=>"= ", :r=>{:l=>{:name=>"some"}, :o=>"* ", :r=>{:integer=>"4"}}}], :end=>"end"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new("n")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(0)),Ast::WhileExpression.new(Ast::NameExpression.new("n"), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("some"),Ast::IntegerExpression.new(43)), Ast::OperatorExpression.new("=", Ast::NameExpression.new("other"),Ast::OperatorExpression.new("*", Ast::NameExpression.new("some"),Ast::IntegerExpression.new(4)))] )] ,nil ) + @parser = @parser.function_definition + end + + def test_function_big_while + @string_input = < 1 ) do + tmp = a + a = b + b = tmp + b + puts(b) + n = n - 1 + end +end +HERE + @parse_output = {:function_name=>{:name=>"fibonaccit"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:integer=>"1"}}, {: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"}}], :end=>"end"} + @transform_output = Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new("n")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(0)),Ast::OperatorExpression.new("=", Ast::NameExpression.new("b"),Ast::IntegerExpression.new(1)),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)))] )] ) + @parser = @parser.function_definition + end +end \ No newline at end of file diff --git a/test/test_module.rb b/test/test_module.rb new file mode 100644 index 0000000..9089d0a --- /dev/null +++ b/test/test_module.rb @@ -0,0 +1,86 @@ +require_relative "helper" + +class TestModuleDef < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_simplest_module + @string_input = <"Simple", :module_expressions=>[{:integer=>"5"}], :end=>"end"} + @transform_output = Ast::ModuleExpression.new(:Simple ,[Ast::IntegerExpression.new(5)] ) + @parser = @parser.module_definition + end + + def test_module_ops + @string_input = <"Opers", :module_expressions=>[{:function_name=>{:name=>"foo"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"} + @transform_output = Ast::ModuleExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("abba"),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] )] ) + @parser = @parser.module_definition + end + + def test_module_assign_instance + @string_input = <"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))] ) + @parser = @parser.module_definition + end + + def test_module_if + @string_input = <"Foo", :module_expressions=>[{:function_name=>{:name=>"ofthen"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:l=>{:name=>"isit"}, :o=>"= ", :r=>{:integer=>"42"}}], :else=>"else"}, :if_false=>{:expressions=>[{:l=>{:name=>"maybenot"}, :o=>"= ", :r=>{:integer=>"667"}}], :end=>"end"}}], :end=>"end"}], :end=>"end"} + @transform_output = Ast::ModuleExpression.new(:Foo ,[Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n")] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::OperatorExpression.new("=", Ast::NameExpression.new("isit"),Ast::IntegerExpression.new(42))],[Ast::OperatorExpression.new("=", Ast::NameExpression.new("maybenot"),Ast::IntegerExpression.new(667))] )] )] ) + @parser = @parser.module_definition + end + + def test_module_function + @string_input = <"Soho", :module_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::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 = <"Foo", :module_expressions=>[{:module_name=>"Bar", :class_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::ModuleExpression.new(:Foo ,[Ast::ClassExpression.new(:Bar ,[Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new("var")] )] )] ) + @parser = @parser.module_definition + end +end \ No newline at end of file diff --git a/test/test_operators.rb b/test/test_operators.rb new file mode 100644 index 0000000..6d3c7d7 --- /dev/null +++ b/test/test_operators.rb @@ -0,0 +1,86 @@ +require_relative "helper" + +class TestExpressions < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def simple_op op + @string_input = "5 #{op} 3" + @parse_output = {:l=>{:integer=>"5"}, :o=>"#{op} ", :r=>{:integer=>"3"}} + @transform_output = Ast::OperatorExpression.new(op, Ast::IntegerExpression.new(5),Ast::IntegerExpression.new(3)) + @parser = @parser.operator_expression + end + def test_simple_multiply + simple_op "*" + end + def test_simple_devide + simple_op "/" + end + def test_simple_plus + simple_op "+" + end + def test_simple_minus + simple_op "-" + end + def test_simple_greater + simple_op ">" + end + def test_simple_smaller + simple_op "<" + end + 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)) + @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")) + @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)) + @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")) + @parser = @parser.operator_expression + end + def test_two_same_ops + @string_input = '2 + 3 + 4' + @parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}} + @transform_output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4)) + @parser = @parser.operator_expression + end + def test_two_different_ops + @string_input = '2 + 3 * 4' + @parse_output = {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:l=>{:integer=>"3"}, :o=>"* ", :r=>{:integer=>"4"}}} + @transform_output = Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4))) + @parser = @parser.operator_expression + end + def test_two_different_ops_order + @string_input = '2 * 3 + 4' + @parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"* ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}} + @transform_output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4)) + @parser = @parser.operator_expression + end + 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)) + @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)) + @parser = @parser.operator_expression + end + +end \ No newline at end of file diff --git a/test/test_return.rb b/test/test_return.rb new file mode 100644 index 0000000..18819c2 --- /dev/null +++ b/test/test_return.rb @@ -0,0 +1,28 @@ +require_relative "helper" + +class TestReturn < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_return_int + @string_input = 'return 42' + @parse_output = {:return=>"return", :return_expression=>{:integer=>"42"}} + @transform_output = Ast::ReturnExpression.new(Ast::IntegerExpression.new(42) ) + @parser = @parser.simple_return + end + + def test_return_variable + @string_input = 'return foo' + @parse_output = {:return=>"return", :return_expression=>{:name=>"foo"}} + @transform_output = Ast::ReturnExpression.new(Ast::NameExpression.new("foo") ) + @parser = @parser.simple_return + end + + def test_return_string + @string_input = 'return "hello"' + @parse_output = {:return=>"return", :return_expression=>{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}} + @transform_output = Ast::ReturnExpression.new(Ast::StringExpression.new("hello") ) + @parser = @parser.simple_return + end + +end \ No newline at end of file diff --git a/test/test_root.rb b/test/test_root.rb new file mode 100644 index 0000000..fb0db1d --- /dev/null +++ b/test/test_root.rb @@ -0,0 +1,118 @@ +require_relative "helper" + +class TestRoot < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_double_root + @string_input = <{:name=>"foo"}, + :parmeter_list=>[{:parmeter=>{:name=>"x"}}], + :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}], :end=>"end"}, + {:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}] + @transform_output = [Ast::FunctionExpression.new(:foo, + [Ast::NameExpression.new("x")] , + [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(5))] ), + Ast::CallSiteExpression.new("foo", [Ast::IntegerExpression.new(3)] )] + + end + + def test_comments + @string_input = <{:name=>"foo"}, :parmeter_list=>[{:parmeter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:integer=>"1"}}, {: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=>"putstring"}, :argument_list=>[{:argument=>{:name=>"b"}}]}, {:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"- ", :r=>{:integer=>"1"}}}], :end=>"end"}}], :end=>"end"}, {:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}] + @transform_output = [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(0)),Ast::OperatorExpression.new("=", Ast::NameExpression.new("b"),Ast::IntegerExpression.new(1)),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(:putstring, [Ast::NameExpression.new("b")] ), Ast::OperatorExpression.new("=", Ast::NameExpression.new("n"),Ast::OperatorExpression.new("-", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(1)))] )] ), Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(3)] )] + end + + def test_fibo1 + @string_input = < 1 ) do + tmp = a + a = b + b = tmp + b + puts(b) + n = n - 1 + end +end + +fibonaccit( 10 ) +HERE + @parse_output = [{:function_name=>{:name=>"fibonaccit"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:integer=>"1"}}, {: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"}}], :end=>"end"}, {:call_site=>{:name=>"fibonaccit"}, :argument_list=>[{:argument=>{:integer=>"10"}}]}] + @transform_output = [Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new("n")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(0)),Ast::OperatorExpression.new("=", Ast::NameExpression.new("b"),Ast::IntegerExpression.new(1)),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)))] )] ), Ast::CallSiteExpression.new("fibonaccit", [Ast::IntegerExpression.new(10)] )] + end + + def test_module_method + @string_input = <"Fibo", :module_expressions=>[{:function_name=>{:name=>"fibonaccit"}, :parmeter_list=>[{:parmeter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}], :end=>"end"}, {:call_site=>{:name=>"fibonaccit"}, :argument_list=>[{:argument=>{:integer=>"10"}}]}], :end=>"end"}] + @transform_output = [Ast::ModuleExpression.new(:Fibo ,[Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new("n")] , [Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::IntegerExpression.new(0))] ), Ast::CallSiteExpression.new(:fibonaccit, [Ast::IntegerExpression.new(10)] )] )] + end + + def test_module_assignment + @string_input = <"Fibo", :module_expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:l=>{:integer=>"5"}, :o=>"+ ", :r=>{:name=>"foo"}}}, {:call_site=>{:name=>"bar"}, :argument_list=>[{:argument=>{:name=>"b"}}, {:argument=>{:name=>"a"}}, {:argument=>{:name=>"r"}}]}], :end=>"end"}] + @transform_output = [Ast::ModuleExpression.new(:Fibo ,[Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(5),Ast::NameExpression.new("foo"))), Ast::CallSiteExpression.new(:bar, [Ast::NameExpression.new("b"),Ast::NameExpression.new("a"),Ast::NameExpression.new("r")] )] )] + end + + def test_module_class + @string_input = <"FooBo", :module_expressions=>[{:module_name=>"Bar", :class_expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:l=>{:integer=>"5"}, :o=>"+ ", :r=>{:name=>"foo"}}}], :end=>"end"}], :end=>"end"}] + @transform_output = [Ast::ModuleExpression.new(:FooBo ,[Ast::ClassExpression.new(:Bar ,[Ast::OperatorExpression.new("=", Ast::NameExpression.new("a"),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(5),Ast::NameExpression.new("foo")))] )] )] + end + + def test_class_method + @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/test_while.rb b/test/test_while.rb new file mode 100644 index 0000000..c72e280 --- /dev/null +++ b/test/test_while.rb @@ -0,0 +1,48 @@ +require_relative "helper" + +class TestWhile < MiniTest::Test + # include the magic (setup and parse -> test method translation), see there + include ParserHelper + + def test_while + @string_input = <"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 + + def test_big_while + @string_input = < 1) do + tmp = a + a = b + b = tmp + b + puts(b) + n = n - 1 +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::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