From c69a44f316bfa066a56880c7c778c9b5d29e5d5a Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Thu, 29 May 2014 15:57:33 +0300 Subject: [PATCH] define modules and tests, no compiling --- lib/ast/expression.rb | 11 ++++--- lib/ast/module_expression.rb | 34 ++++++++++++++++++++ lib/parser/crystal.rb | 4 ++- lib/parser/keywords.rb | 2 ++ lib/parser/module_def.rb | 9 ++++++ lib/parser/transform.rb | 4 +++ test/parser/helper.rb | 6 ++-- test/parser/test_all.rb | 15 +++++---- test/parser/test_module.rb | 62 ++++++++++++++++++++++++++++++++++++ 9 files changed, 131 insertions(+), 16 deletions(-) create mode 100644 lib/ast/module_expression.rb create mode 100644 lib/parser/module_def.rb create mode 100644 test/parser/test_module.rb diff --git a/lib/ast/expression.rb b/lib/ast/expression.rb index ebe0b7ce..1d37c3ff 100644 --- a/lib/ast/expression.rb +++ b/lib/ast/expression.rb @@ -9,7 +9,7 @@ module Ast class Expression - def eval + def compile context , into raise "abstract #{self}" end def compile context , into @@ -22,7 +22,7 @@ module Ast return false unless other.class == self.class attributes.each do |a| left = send(a) - right = other.send( a) + right = other.send(a) return false unless left.class == right.class return false unless left == right end @@ -33,10 +33,11 @@ module Ast end require_relative "basic_expressions" +require_relative "call_site_expression" require_relative "compound_expressions" require_relative "if_expression" -require_relative "while_expression" -require_relative "return_expression" require_relative "function_expression" +require_relative "module_expression" require_relative "operator_expressions" -require_relative "call_site_expression" +require_relative "return_expression" +require_relative "while_expression" diff --git a/lib/ast/module_expression.rb b/lib/ast/module_expression.rb new file mode 100644 index 00000000..f3ab7c24 --- /dev/null +++ b/lib/ast/module_expression.rb @@ -0,0 +1,34 @@ +module Ast + class ModuleExpression < Expression + attr_reader :name ,:expressions + def initialize name , expressions + @name = name.to_sym + @expressions = expressions + end + def inspect + self.class.name + ".new(" + @name.inspect + " ," + @expressions.inspect + " )" + end + def to_s + "module #{name}\n #{expressions}\nend\n" + end + def attributes + [:name , :expressions] + end + def compile context , into + expression_value = expression.compile(context , into) + puts "compiled return expression #{expression_value.inspect}, now return in 7" + # copied from function expression: TODO make function + + return_reg = Vm::Integer.new(7) + if expression_value.is_a?(Vm::IntegerConstant) or expression_value.is_a?(Vm::StringConstant) + return_reg.load into , expression_value if expression_value.register != return_reg.register + else + return_reg.move( into, expression_value ) if expression_value.register != return_reg.register + end + #function.set_return return_reg + return return_reg + end + end + + +end \ No newline at end of file diff --git a/lib/parser/crystal.rb b/lib/parser/crystal.rb index 10234e68..736f9b1d 100644 --- a/lib/parser/crystal.rb +++ b/lib/parser/crystal.rb @@ -6,6 +6,7 @@ require_relative "control" require_relative "expression" require_relative "call_site" require_relative "function_definition" +require_relative "module_def" require_relative "operators" module Parser @@ -28,7 +29,8 @@ module Parser include CallSite include FunctionDefinition include Operators + include ModuleDef - rule(:root){ (function_definition | expression | call_site | space).repeat } + rule(:root){ (function_definition | expression | call_site ).repeat } end end diff --git a/lib/parser/keywords.rb b/lib/parser/keywords.rb index c339b134..478e3f2f 100644 --- a/lib/parser/keywords.rb +++ b/lib/parser/keywords.rb @@ -3,6 +3,7 @@ module Parser include Parslet rule(:keyword_begin) { str('begin').as(:begin) >> space?} + rule(:keyword_class) { str('class') >> space? } rule(:keyword_def) { str('def') >> space? } rule(:keyword_do) { str('do').as(:do) >> space?} rule(:keyword_else) { str('else').as(:else) >> space? } @@ -12,6 +13,7 @@ module Parser rule(:keyword_rescue) { str('rescue').as(:rescue) >> space?} rule(:keyword_return) { str('return').as(:return) >> space?} rule(:keyword_true) { str('true').as(:true) >> space?} + rule(:keyword_module) { str('module') >> space? } rule(:keyword_nil) { str('nil').as(:nil) >> space?} rule(:keyword_unless) { str('unless').as(:unless) >> space?} rule(:keyword_until) { str('until').as(:until) >> space?} diff --git a/lib/parser/module_def.rb b/lib/parser/module_def.rb new file mode 100644 index 00000000..af22718e --- /dev/null +++ b/lib/parser/module_def.rb @@ -0,0 +1,9 @@ +module Parser + module ModuleDef + include Parslet + rule(:module_def) do + keyword_module >> name >> eol >> + ( (keyword_end.absent? >> root).repeat(1)).as(:module_expressions) >> keyword_end >> newline + end + end +end diff --git a/lib/parser/transform.rb b/lib/parser/transform.rb index d91ab12d..fa533d98 100644 --- a/lib/parser/transform.rb +++ b/lib/parser/transform.rb @@ -53,6 +53,10 @@ module Parser Ast::OperatorExpression.new( o.to_s.strip , l ,r) end + rule( :name => simple(:name) , :module_expressions => sequence(:module_expressions) , :end=>"end") do + Ast::ModuleExpression.new(name , module_expressions) + end + #shortcut to get the ast tree for a given string # optional second arguement specifies a rule that will be parsed (mainly for testing) def self.ast string , rule = :root diff --git a/test/parser/helper.rb b/test/parser/helper.rb index eb862276..5f058dcc 100644 --- a/test/parser/helper.rb +++ b/test/parser/helper.rb @@ -37,9 +37,9 @@ module ParserHelper # check that @string_input parses and transforms to @transform_output def check_ast syntax = @parser.parse(@string_input) - tree = @transform.apply(syntax) - # puts tree.inspect - assert_equal @transform_output , tree + is = @transform.apply(syntax) + #puts is.inspect + assert_equal @transform_output , is end end diff --git a/test/parser/test_all.rb b/test/parser/test_all.rb index 2e1f0522..bbb3b46a 100644 --- a/test/parser/test_all.rb +++ b/test/parser/test_all.rb @@ -1,12 +1,13 @@ -require_relative "test_basic" -require_relative "test_compound" require_relative "test_arguments" -require_relative "test_expressions" +require_relative "test_basic" require_relative "test_call_site" +require_relative "test_compound" require_relative "test_conditional" -require_relative "test_while" -require_relative "test_return" -require_relative "test_operators" +require_relative "test_expressions" require_relative "test_function_definition" -require_relative "test_root" \ No newline at end of file +require_relative "test_module" +require_relative "test_operators" +require_relative "test_return" +require_relative "test_root" +require_relative "test_while" diff --git a/test/parser/test_module.rb b/test/parser/test_module.rb new file mode 100644 index 00000000..b7953ffb --- /dev/null +++ b/test/parser/test_module.rb @@ -0,0 +1,62 @@ +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 = <"foo", :module_expressions=>[{:integer=>"5"}], :end=>"end"} + @transform_output = Ast::ModuleExpression.new("foo" ,[Ast::IntegerExpression.new(5)] ) + @parser = @parser.module_def + end + + def test_module_ops + @string_input = <"ops", :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("ops" ,[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_def + end + + def test_module_if + @string_input = <"sif", :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("sif" ,[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_def + end + + def test_module_function + @string_input = <"sif", :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(:sif ,[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_def + end +end \ No newline at end of file