diff --git a/lib/ast/compound_expressions.rb b/lib/ast/compound_expressions.rb new file mode 100644 index 00000000..5e197961 --- /dev/null +++ b/lib/ast/compound_expressions.rb @@ -0,0 +1,39 @@ +module Ast + + class ArrayExpression < Expression + attr_reader :values + def initialize vals + @values = vals + end + def inspect + self.class.name + ".new(" + values.to_s+ ")" + end + def compile context + to.do + end + def attributes + [:values] + end + end + class AssociationExpression < Expression + attr_reader :key , :value + def initialize key , value + @key , @value = key , value + end + def inspect + self.class.name + ".new(" + key.inspect + " , " + value.inspect + ")" + end + def compile context + to.do + end + def attributes + [:key , :value] + end + + end + class HashExpression < ArrayExpression + def compile context + to.do + end + end +end \ No newline at end of file diff --git a/lib/ast/expression.rb b/lib/ast/expression.rb index 282b5d58..728374a6 100644 --- a/lib/ast/expression.rb +++ b/lib/ast/expression.rb @@ -15,9 +15,6 @@ module Ast def compile context raise "abstract #{self}" end - def inspectt - self.class.name + ".new(" + self.attributes.collect{|m| self.send(m).inspect }.join( ",") +")" - end def attributes raise "abstract #{self}" end @@ -36,6 +33,7 @@ module Ast end require_relative "basic_expressions" +require_relative "compound_expressions" require_relative "conditional_expression" require_relative "while_expression" require_relative "function_expression" diff --git a/lib/parser/basic_types.rb b/lib/parser/basic_types.rb index 4204e659..ec774e85 100644 --- a/lib/parser/basic_types.rb +++ b/lib/parser/basic_types.rb @@ -1,7 +1,5 @@ module Parser # Basic types are numbers and strings - # later maybe arrays and hashes - # floats ? module BasicTypes include Parslet # space really is just space. ruby is newline sensitive, so there is more whitespace footwork @@ -35,19 +33,10 @@ module Parser nonquote.as(:char) ).repeat(1).as(:string) >> quote } - -# rule(:string_special) { match['\0\t\n\r"\\\\'] } -# rule(:escaped_special) { str("\\") >> match['0tnr"\\\\'] } - - #anything in double quotes -# rule(:string){ -# double_quote >> -# ( escaped_special | string_special.absent? >> any ).repeat.as(:string) >> -# double_quote >> space? -# } rule(:integer) { sign.maybe >> digit.repeat(1).as(:integer) >> space? } rule(:float) { integer >> dot >> integer >> (exponent >> sign.maybe >> digit.repeat(1,3)).maybe >> space?} + rule(:basic_type){ integer | name | string | float } end end \ No newline at end of file diff --git a/lib/parser/compound_types.rb b/lib/parser/compound_types.rb new file mode 100644 index 00000000..82f08244 --- /dev/null +++ b/lib/parser/compound_types.rb @@ -0,0 +1,20 @@ +module Parser + # Compound types are Arrays and Hashes + module CompundTypes + include Parslet + + rule(:array) do + left_bracket >> + ( ((operator_expression|value_expression).as(:element) >> space? >> + (comma >> space? >> (operator_expression|value_expression).as(:element)).repeat(0)).repeat(0,1)).as(:array) >> + space? >> right_bracket + end + + + rule(:hash_pair) { basic_type.as(:argument) >> association >> (operator_expression|value_expression).as(:element) } + rule(:hash) { left_brace >> ((hash_pair.as(:hash_pair) >> + (comma >> space? >> hash_pair.as(:hash_pair)).repeat(0)).repeat(0,1)).as(:hash)>> + space? >> right_brace } + + end +end \ No newline at end of file diff --git a/lib/parser/control.rb b/lib/parser/control.rb index 58be133d..cd231544 100644 --- a/lib/parser/control.rb +++ b/lib/parser/control.rb @@ -3,13 +3,13 @@ module Parser include Parslet rule(:conditional) do keyword_if >> - (( (simple_expression|operator_expression).as(:conditional) ) | - left_parenthesis >> (operator_expression|simple_expression).as(:conditional) >> right_parenthesis) >> + (( (value_expression|operator_expression).as(:conditional) ) | + left_parenthesis >> (operator_expression|value_expression).as(:conditional) >> right_parenthesis) >> newline >> expressions_else.as(:if_true) >> newline >> expressions_end.as(:if_false) end rule(:while_do) do - keyword_while >> left_parenthesis >> (operator_expression|simple_expression).as(:while_cond) >> + keyword_while >> left_parenthesis >> (operator_expression|value_expression).as(:while_cond) >> right_parenthesis >> keyword_do >> newline >> expressions_end.as(:body) end diff --git a/lib/parser/crystal.rb b/lib/parser/crystal.rb index 440c714a..1e4c6198 100644 --- a/lib/parser/crystal.rb +++ b/lib/parser/crystal.rb @@ -1,4 +1,5 @@ require_relative "basic_types" +require_relative "compound_types" require_relative "tokens" require_relative "keywords" require_relative "control" @@ -19,6 +20,7 @@ module Parser class Crystal < Parslet::Parser include BasicTypes + include CompundTypes include Tokens include Keywords include Control diff --git a/lib/parser/expression.rb b/lib/parser/expression.rb index dfebdf16..bbe4a54e 100644 --- a/lib/parser/expression.rb +++ b/lib/parser/expression.rb @@ -2,7 +2,7 @@ module Parser module Expression include Parslet - rule(:simple_expression) { function_call | integer | string | name } + rule(:value_expression) { function_call | basic_type } rule(:expression) { (while_do | conditional | operator_expression | function_call ) >> newline } diff --git a/lib/parser/function_call.rb b/lib/parser/function_call.rb index 3378c80f..89795a5b 100644 --- a/lib/parser/function_call.rb +++ b/lib/parser/function_call.rb @@ -4,8 +4,8 @@ module Parser rule(:argument_list) { left_parenthesis >> - ( (simple_expression.as(:argument) >> space? >> - (comma >> space? >> simple_expression.as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >> + ( (value_expression.as(:argument) >> space? >> + (comma >> space? >> value_expression.as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >> space? >> right_parenthesis } diff --git a/lib/parser/operators.rb b/lib/parser/operators.rb index 4098b278..2d0a6d36 100644 --- a/lib/parser/operators.rb +++ b/lib/parser/operators.rb @@ -23,7 +23,7 @@ module Parser #infix doing the heavy lifting here, # is defined as an expressions and array of [atoms,priority,binding] triples - rule(:operator_expression) do infix_expression(simple_expression, + rule(:operator_expression) do infix_expression(value_expression, [exponent, 120, :left] , [multiply, 120, :left] , [plus, 110, :left], diff --git a/lib/parser/tokens.rb b/lib/parser/tokens.rb index 70d60dc2..da9b5e04 100644 --- a/lib/parser/tokens.rb +++ b/lib/parser/tokens.rb @@ -8,7 +8,10 @@ module Parser rule(:right_parenthesis) { str(')') >> space? } rule(:left_brace) { str('{') >> space? } rule(:right_brace) { str('}') >> space? } + rule(:left_bracket) { str('[') >> space? } + rule(:right_bracket) { str(']') >> space? } + rule(:association) { str("=>") >> space? } rule(:comma) { str(',') >> space? } rule(:colon) { str(':') >> space? } rule(:semicolon) { str(';') >> space? } diff --git a/lib/parser/transform.rb b/lib/parser/transform.rb index 3938b541..5b84c5d2 100644 --- a/lib/parser/transform.rb +++ b/lib/parser/transform.rb @@ -10,6 +10,12 @@ module Parser rule(:integer => simple(:value)) { Ast::IntegerExpression.new(value.to_i) } rule(:name => simple(:name)) { Ast::NameExpression.new(name.to_s) } + rule(:array => sequence(:array) ) { Ast::ArrayExpression.new(array) } + rule(:element => simple(:element)) { element } + rule(:hash => sequence(:hash) ) { Ast::HashExpression.new(hash) } + rule(:argument => simple(:argument) , :element => simple(:element)) { Ast::AssociationExpression.new(argument,element) } + rule(:hash_pair => simple(:hash_pair) ) { hash_pair } + rule(:argument => simple(:argument)) { argument } rule(:argument_list => sequence(:argument_list)) { argument_list } diff --git a/test/parser/test_all.rb b/test/parser/test_all.rb index e721df79..43d132b9 100644 --- a/test/parser/test_all.rb +++ b/test/parser/test_all.rb @@ -1,5 +1,6 @@ require_relative "test_basic" +require_relative "test_compund" require_relative "test_arguments" require_relative "test_expressions" require_relative "test_function_call" diff --git a/test/parser/test_compound.rb b/test/parser/test_compound.rb new file mode 100644 index 00000000..437b93e3 --- /dev/null +++ b/test/parser/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=>[{:element=>{:integer=>"42"}}]} + @transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)]) + @parser = @parser.array + end + + def test_array_list + @string_input = '[42, foo]' + @parse_output = {:array=>[{:element=>{:integer=>"42"}}, {:element=>{:name=>"foo"}}]} + @transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new("foo")]) + @parser = @parser.array + end + + def test_array_ops + @string_input = '[ 3 + 4 , foo(22) ]' + @parse_output = {:array=>[{:element=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"4"}}}, {:element=>{:function_call=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"22"}}]}}]} + @transform_output = Ast::ArrayExpression.new( + [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)), + Ast::FuncallExpression.new("foo", [Ast::IntegerExpression.new(22)] )]) + @parser = @parser.array + end + + def test_hash + @string_input = '{ foo => 33 }' + @parse_output = {:hash=>[{:hash_pair=>{:argument=>{:name=>"foo"}, :element=>{:integer=>"33"}}}]} + @transform_output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33))]) + @parser = @parser.hash + end + + def test_hash_list + @string_input = "{foo => 33 , bar => 42}" + @parse_output = {:hash=>[{:hash_pair=>{:argument=>{:name=>"foo"}, :element=>{:integer=>"33"}}}, {:hash_pair=>{:argument=>{:name=>"bar"}, :element=>{: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 + end + +end \ No newline at end of file diff --git a/test/runners/fibo_while.rb b/test/runners/fibo_while.rb index fc491e88..922ea5ab 100644 --- a/test/runners/fibo_while.rb +++ b/test/runners/fibo_while.rb @@ -1,11 +1,11 @@ def fibonaccit(n) a = 0 b = 1 - while n > 1 do + while( n > 1 ) do tmp = a a = b b = tmp + b - puts b + puts(b) n = n - 1 end end