remove the parse code and fix the rest to work with the gem (from git for now)

This commit is contained in:
Torsten Ruger 2014-06-04 22:03:45 +03:00
parent e9d2724f62
commit 7cc4c6344c
45 changed files with 33 additions and 1708 deletions

View File

@ -1,6 +1,7 @@
source "http://rubygems.org" source "http://rubygems.org"
gem "parslet" , :git => 'https://github.com/NigelThorne/parslet.git' gem "parslet" , :git => 'https://github.com/NigelThorne/parslet.git'
gem "crystal-reader" , "0.1.0" , :require => "parser" , :git => "https://github.com/ruby-in-ruby/crystal-reader.git"
group :development do group :development do
gem "minitest" gem "minitest"

View File

@ -5,6 +5,12 @@ GIT
parslet (1.7.0) parslet (1.7.0)
blankslate (~> 2.0) blankslate (~> 2.0)
GIT
remote: https://github.com/ruby-in-ruby/crystal-reader.git
revision: b25d5ab99250965883d3a71163961ea75431778f
specs:
crystal-reader (0.1.0)
GEM GEM
remote: http://rubygems.org/ remote: http://rubygems.org/
specs: specs:
@ -81,6 +87,7 @@ PLATFORMS
x64-mingw32 x64-mingw32
DEPENDENCIES DEPENDENCIES
crystal-reader (= 0.1.0)!
jeweler jeweler
minitest minitest
parslet! parslet!

10
lib/ast/all.rb Normal file
View File

@ -0,0 +1,10 @@
require "ast/expression"
require_relative "basic_expressions"
require_relative "call_site_expression"
require_relative "compound_expressions"
require_relative "if_expression"
require_relative "function_expression"
require_relative "module_expression"
require_relative "operator_expressions"
require_relative "return_expression"
require_relative "while_expression"

View File

@ -3,67 +3,31 @@
module Ast module Ast
class IntegerExpression < Expression class IntegerExpression < Expression
attr_reader :value # attr_reader :value
def initialize val
@value = val
end
def inspect
self.class.name + ".new(" + value.to_s+ ")"
end
def to_s
value.to_s
end
def compile context , into def compile context , into
Vm::IntegerConstant.new value Vm::IntegerConstant.new value
end end
def attributes
[:value]
end
end end
class NameExpression < Expression class NameExpression < Expression
attr_reader :name # attr_reader :name
def initialize name
@name = name.to_sym
end
# compiling a variable resolves it. # compiling a variable resolves it.
# if it wasn't defined, nli is returned # if it wasn't defined, nli is returned
def compile context , into def compile context , into
context.locals[name] context.locals[name]
end end
def inspect
"#{self.class.name}.new(#{name})"
end
def to_s
name.to_s
end
def attributes
[:name]
end
end end
class ModuleName < NameExpression class ModuleName < NameExpression
end end
class StringExpression < Expression class StringExpression < Expression
attr_reader :string # attr_reader :string
def initialize str
@string = str
end
def inspect
self.class.name + '.new("' + string + '")'
end
def to_s
'"' + string.to_s + '"'
end
def compile context , into def compile context , into
value = Vm::StringConstant.new(string) value = Vm::StringConstant.new(string)
context.object_space.add_object value context.object_space.add_object value
value value
end end
def attributes
[:string]
end end
end end
end

View File

@ -2,13 +2,7 @@ module Ast
# assignment, like operators are really function calls # assignment, like operators are really function calls
class CallSiteExpression < Expression class CallSiteExpression < Expression
attr_reader :name, :args , :receiver # attr_reader :name, :args , :receiver
def initialize name, args , receiver = Ast::NameExpression.new(:self)
@name = name.to_sym
@args = args
@receiver = receiver
end
def compile context , into def compile context , into
params = args.collect{ |a| a.compile(context, into) } params = args.collect{ |a| a.compile(context, into) }
@ -37,28 +31,10 @@ module Ast
puts "compile call #{function.return_type}" puts "compile call #{function.return_type}"
function.return_type function.return_type
end end
def inspect
self.class.name + ".new(" + name.inspect + ", ["+
args.collect{|m| m.inspect }.join( ",") + "] ," + receiver.inspect + ")"
end
def to_s
"#{name}(" + args.join(",") + ")"
end
def attributes
[:name , :args , :receiver]
end
end end
class VariableExpression < CallSiteExpression class VariableExpression < CallSiteExpression
# super( :_get_instance_variable , [StringExpression.new(name)] )
def initialize name
super( :_get_instance_variable , [StringExpression.new(name)] )
end
def inspect
self.class.name + ".new(" + args[0].string.inspect + ")"
end
end end
end end

View File

@ -1,35 +1,16 @@
module Ast module Ast
class ArrayExpression < Expression class ArrayExpression < Expression
attr_reader :values # attr_reader :values
def initialize vals
@values = vals
end
def inspect
self.class.name + ".new(" + values.to_s+ ")"
end
def compile context def compile context
to.do to.do
end end
def attributes
[:values]
end
end end
class AssociationExpression < Expression class AssociationExpression < Expression
attr_reader :key , :value # 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 def compile context
to.do to.do
end end
def attributes
[:key , :value]
end
end end
class HashExpression < ArrayExpression class HashExpression < ArrayExpression
def compile context def compile context

View File

@ -1,43 +0,0 @@
# abstract syntax tree (ast)
# This Layer is semi automagically created by parslet using the transform
# It in turn is responsible for the transformation to the next layer, vm code
# This happens in the compile function which must return a Vm::Code derivative
# PS: compare is only for tests and should be factored out to there
module Ast
class Expression
def compile context , into
raise "abstract #{self}"
end
def compile context , into
raise "abstract #{self}"
end
def attributes
raise "abstract #{self}"
end
def == other
return false unless other.class == self.class
attributes.each do |a|
left = send(a)
right = other.send(a)
return false unless left.class == right.class
return false unless left == right
end
return true
end
end
end
require_relative "basic_expressions"
require_relative "call_site_expression"
require_relative "compound_expressions"
require_relative "if_expression"
require_relative "function_expression"
require_relative "module_expression"
require_relative "operator_expressions"
require_relative "return_expression"
require_relative "while_expression"

View File

@ -1,26 +1,6 @@
module Ast module Ast
class FunctionExpression < Expression class FunctionExpression < Expression
attr_reader :name, :params, :body , :receiver # attr_reader :name, :params, :body , :receiver
def initialize name, params, body , receiver = nil
@name = name.to_sym
@params = params
@body = body
@receiver = receiver
end
def attributes
[:name, :params, :body , :receiver]
end
def inspect
self.class.name + ".new(" + name.inspect + ", ["+
params.collect{|m| m.inspect }.join( ",") +"] , [" +
body.collect{|m| m.inspect }.join( ",") +"] ,"+ receiver.inspect + " )"
end
def to_s
ret = "def "
ret += "#{receiver}." if receiver
ret + "#{name}( " + params.join(",") + ") \n" + body.join("\n") + "end\n"
end
def compile context , into def compile context , into
raise "function does not compile into anything #{self}" if into raise "function does not compile into anything #{self}" if into
args = [] args = []
@ -67,6 +47,5 @@ module Ast
context.function = parent_function context.function = parent_function
function function
end end
end end
end end

View File

@ -1,16 +1,6 @@
module Ast module Ast
class IfExpression < Expression class IfExpression < Expression
attr_reader :cond, :if_true, :if_false # attr_reader :cond, :if_true, :if_false
def initialize cond, if_true, if_false
@cond, @if_true, @if_false = cond, if_true, if_false
end
def inspect
self.class.name + ".new(" + cond.inspect + ", "+
if_true.inspect + "," + if_false.inspect + " )"
end
def attributes
[:cond, :if_true, :if_false]
end
def compile context , into def compile context , into
# to execute the logic as the if states it, the blocks are the other way around # to execute the logic as the if states it, the blocks are the other way around
# so we can the jump over the else if true ,and the else joins unconditionally after the true_block # so we can the jump over the else if true ,and the else joins unconditionally after the true_block

View File

@ -1,21 +1,6 @@
module Ast module Ast
class ModuleExpression < Expression class ModuleExpression < Expression
# attr_reader :name ,:expressions
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 def compile context , into
clazz = context.object_space.get_or_create_class name clazz = context.object_space.get_or_create_class name
puts "Created class #{clazz.name.inspect}" puts "Created class #{clazz.name.inspect}"

View File

@ -1,20 +1,6 @@
module Ast module Ast
class OperatorExpression < Expression class OperatorExpression < Expression
attr_reader :operator, :left, :right # attr_reader :operator, :left, :right
def initialize operator, left, right
@operator, @left, @right = operator, left, right
end
def attributes
[:operator, :left, :right]
end
def inspect
self.class.name + ".new(" + operator.inspect + ", " + left.inspect + "," + right.inspect + ")"
end
def to_s
"#{left} #{operator} #{right}"
end
def compile context , into def compile context , into
puts "compiling operator #{to_s}" puts "compiling operator #{to_s}"
r_val = right.compile(context , into) r_val = right.compile(context , into)

View File

@ -1,18 +1,6 @@
module Ast module Ast
class ReturnExpression < Expression class ReturnExpression < Expression
attr_reader :expression # attr_reader :expression
def initialize expression
@expression = expression
end
def inspect
self.class.name + ".new(" + expression.inspect + " )"
end
def to_s
"return #{expression}\n"
end
def attributes
[:expression]
end
def compile context , into def compile context , into
puts "compiling return expression #{expression}, now return in 7" puts "compiling return expression #{expression}, now return in 7"
expression_value = expression.compile(context , into) expression_value = expression.compile(context , into)

View File

@ -1,18 +1,6 @@
module Ast module Ast
class WhileExpression < Expression class WhileExpression < Expression
attr_reader :condition, :body # attr_reader :condition, :body
def initialize condition, body
@condition , @body = condition , body
end
def inspect
self.class.name + ".new(" + condition.inspect + ", " + body.inspect + " )"
end
def to_s
"while(#{condition}) do\n" + body.join("\n") + "\nend\n"
end
def attributes
[:condition, :body]
end
def compile context , into def compile context , into
while_block = into.new_block "#{into.name}_while" while_block = into.new_block "#{into.name}_while"
ret = while_block.new_block "#{into.name}_return" ret = while_block.new_block "#{into.name}_return"

View File

@ -3,6 +3,7 @@ require 'parslet'
require "elf/object_writer" require "elf/object_writer"
require 'parser/crystal' require 'parser/crystal'
require 'parser/transform' require 'parser/transform'
require "ast/all"
require "vm/register_machine" require "vm/register_machine"
require "vm/code" require "vm/code"
require "vm/values" require "vm/values"

View File

@ -1,56 +0,0 @@
Parser
================
This includes the parser and generated ast.
Parslet is really great in that it:
- does not generate code but instean gives a clean dsl to define a grammar
- uses ruby modules so one can split the grammars up
- has support for binary operators with presedence and binding
- has a seperate tranform stage to generate an ast layer
Especially the last point is great. Since it is seperate it does not clutter up the actual grammar.
And it can generate a layer that has no links to the actual parser anymore, thus saving/automating
a complete tranformation process.
Operator list from http://stackoverflow.com/questions/21060234/ruby-operator-precedence-table
N A M Operator(s) Description
- - - ----------- -----------
1 R Y ! ~ + boolean NOT, bitwise complement, unary plus
(unary plus may be redefined from Ruby 1.9 with +@)
2 R Y ** exponentiation
1 R Y - unary minus (redefine with -@)
2 L Y * / % multiplication, division, modulo (remainder)
2 L Y + - addition (or concatenation), subtraction
2 L Y << >> bitwise shift-left (or append), bitwise shift-right
2 L Y & bitwise AND
2 L Y | ^ bitwise OR, bitwise XOR (exclusive OR)
2 L Y < <= >= > ordering
2 N Y == === != =~ !~ <=> equality, pattern matching, comparison
(!= and !~ may not be redefined prior to Ruby 1.9)
2 L N && boolean AND
2 L N || boolean OR
2 N N .. ... range creation (inclusive and exclusive)
and boolean flip-flops
3 R N ? : ternary if-then-else (conditional)
2 L N rescue exception-handling modifier
2 R N = assignment
2 R N **= *= /= %= += -= assignment
2 R N <<= >>= assignment
2 R N &&= &= ||= |= ^= assignment
1 N N defined? test variable definition and type
1 R N not boolean NOT (low precedence)
2 L N and or boolean AND, boolean OR (low precedence)
2 N N if unless while until conditional and loop modifiers

View File

@ -1,48 +0,0 @@
module Parser
# Basic types are numbers and strings
module BasicTypes
include Parslet
# space really is just space. ruby is newline sensitive, so there is more whitespace footwork
# rule of thumb is that anything eats space behind it, but only space, no newlines
rule(:space) { (str('\t') | str(' ')).repeat(1) }
rule(:space?) { space.maybe }
rule(:linebreak){ str("\n") >> space? >> linebreak.repeat }
rule(:quote) { str('"') }
rule(:nonquote) { str('"').absent? >> any }
rule(:comment){ match('#') >> (linebreak.absent? >> any).repeat >> linebreak }
rule(:newline) { linebreak | comment }
rule(:eol) { newline | any.absent? }
rule(:double_quote){ str('"') }
rule(:minus) { str('-') }
rule(:plus) { str('+') }
rule(:sign) { plus | minus }
rule(:dot) { str('.') }
rule(:digit) { match('[0-9]') }
rule(:exponent) { (str('e')| str('E')) }
# identifier must start with lower case
# TODO rule forbit names like if_true, because it starts with a keyword. a little looser please!
rule(:name) { keyword.absent? >> (match['a-z_'] >> match['a-zA-Z0-9_'].repeat).as(:name) >> space? }
# instance variables must have the @
rule(:instance_variable) { (str('@') >> name).as(:instance_variable) }
# and class/module names must start with capital
# (admittatly the rule matches constants too, but one step at a time)
rule(:module_name) { keyword.absent? >> (match['A-Z'] >> match['a-zA-Z0-9_'].repeat).as(:module_name) >> space? }
rule(:escape) { str('\\') >> any.as(:esc) }
rule(:string) { quote >> (
escape |
nonquote.as(:char)
).repeat(1).as(:string) >> quote }
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 | instance_variable | module_name }
end
end

View File

@ -1,17 +0,0 @@
module Parser
module CallSite
include Parslet
rule(:argument_list) {
left_parenthesis >>
( ((operator_expression|value_expression).as(:argument) >> space? >>
(comma >> space? >> (operator_expression|value_expression).as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >>
space? >> right_parenthesis
}
rule(:call_site) { ((module_name|instance_variable|name).as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:call_site) >> argument_list >> comment.maybe}
end
end

View File

@ -1,19 +0,0 @@
module Parser
# Compound types are Arrays and Hashes
module CompoundTypes
include Parslet
rule(:array_constant) do
left_bracket >>
( ((operator_expression|value_expression).as(:array_element) >> space? >>
(comma >> space? >> (operator_expression|value_expression).as(:array_element)).repeat(0)).repeat(0,1)).as(:array_constant) >>
space? >> right_bracket
end
rule(:hash_pair) { basic_type.as(:hash_key) >> association >> (operator_expression|value_expression).as(:hash_value) }
rule(:hash_constant) { left_brace >> ((hash_pair.as(:hash_pair) >>
(comma >> space? >> hash_pair.as(:hash_pair)).repeat(0)).repeat(0,1)).as(:hash_constant)>>
space? >> right_brace }
end
end

View File

@ -1,20 +0,0 @@
module Parser
module Control
include Parslet
rule(:conditional) do
keyword_if >>
(( (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|value_expression).as(:while_cond) >>
right_parenthesis >> keyword_do >> newline >>
expressions_end.as(:body)
end
rule(:simple_return) do
keyword_return >> (operator_expression|value_expression).as(:return_expression)
end
end
end

View File

@ -1,37 +0,0 @@
require_relative "basic_types"
require_relative "compound_types"
require_relative "tokens"
require_relative "keywords"
require_relative "control"
require_relative "expression"
require_relative "call_site"
require_relative "function_definition"
require_relative "module_definition"
require_relative "operators"
module Parser
# obviously a work in progress !!
# We "compose" the parser from bits, divide and hopefully conquer
# a note about .maybe : .maybe is almost every respect the same as .repeat(0,1)
# so either 0, or 1, in other words maybe. Nice feature, but there are strings attached:
# a maybe removes the 0 a sequence (array) to a single (hash). Thus 2 transformations are needed
# More work than the prettiness is worth, so only use .maybe on something that does not need capturing
class Crystal < Parslet::Parser
include BasicTypes
include CompoundTypes
include Tokens
include Keywords
include Control
include Expression
include CallSite
include FunctionDefinition
include Operators
include ModuleDef
rule(:root_body) {(module_definition | class_definition | function_definition | expression | call_site )}
rule(:root) { root_body.repeat() }
end
end

View File

@ -1,18 +0,0 @@
module Parser
module Expression
include Parslet
rule(:value_expression) { call_site | basic_type }
rule(:expression) { (simple_return | while_do | conditional | operator_expression | call_site ) >> newline }
def delimited_expressions( delimit )
( (delimit.absent? >> expression).repeat(1)).as(:expressions) >> delimit
end
rule(:expressions_do) { delimited_expressions(keyword_do) }
rule(:expressions_else) { delimited_expressions(keyword_else) }
rule(:expressions_end) { delimited_expressions(keyword_end) }
end
end

View File

@ -1,17 +0,0 @@
module Parser
module FunctionDefinition
include Parslet
rule(:function_definition) {
keyword_def >> ((module_name|instance_variable|name).as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:function_name) >> parmeter_list.maybe >> newline >> expressions_end >> newline
}
rule(:parmeter_list) {
left_parenthesis >>
((name.as(:parmeter) >> (comma >> name.as(:parmeter)).repeat(0)).repeat(0,1)).as(:parmeter_list) >>
right_parenthesis
}
end
end

View File

@ -1,28 +0,0 @@
module Parser
module Keywords
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? }
rule(:keyword_end) { str('end').as(:end) >> space? }
rule(:keyword_false) { str('false').as(:false) >> space?}
rule(:keyword_if) { str('if').as(:if) >> space? }
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?}
rule(:keyword_while) { str('while').as(:while) >> space?}
# this rule is just to make sure identifiers can't be keywords. Kind of duplication here, but we need the
# space in above rules, so just make sure to add any here too.
rule(:keyword){ str('begin') | str('def') | str('do') | str('else') | str('end') |
str('false')| str('if')| str('rescue')| str('true')| str('nil') |
str('unless')| str('until')| str('while')}
end
end

View File

@ -1,15 +0,0 @@
module Parser
module ModuleDef
include Parslet
rule(:module_definition) do
keyword_module >> module_name >> eol >>
( (keyword_end.absent? >> root_body).repeat()).as(:module_expressions) >> keyword_end >> newline
end
rule(:class_definition) do
keyword_class >> module_name >> eol >>
( (keyword_end.absent? >> root_body).repeat()).as(:class_expressions) >> keyword_end >> newline
end
end
end

View File

@ -1,52 +0,0 @@
module Parser
module Operators
include Parslet
rule(:exponent) { str('**') >> space?}
rule(:multiply) { match['*/%'] >> space? }
rule(:plus) { match['+-'] >> space? }
rule(:shift) { str(">>") | str("<<") >> space?}
rule(:bit_and) { str('&') >> space?}
rule(:bit_or) { str('|') >> space?}
rule(:greater_equal) { str('>=') >> space?}
rule(:less_or_equal) { str('<=') >> space?}
rule(:larger) { str('>') >> space?}
rule(:smaller) { str('<') >> space?}
rule(:identity) { str('===') >> space?}
rule(:equal) { str('==') >> space?}
rule(:not_equal) { str('!=') >> space?}
rule(:boolean_and) { str('&&') | str("and") >> space?}
rule(:boolean_or) { str('||') | str("or") >> space?}
rule(:assign) { str('=') >> space?}
rule(:op_assign) { str('+=')|str('-=')|str('*=')|str('/=')|str('%=') >> space?}
rule(:eclipse) { str('..') |str("...") >> space?}
rule(:assign) { str('=') >> space?}
#infix doing the heavy lifting here,
# is defined as an expressions and array of [atoms,priority,binding] triples
rule(:operator_expression) do infix_expression(value_expression,
[exponent, 120, :left] ,
[multiply, 120, :left] ,
[plus, 110, :left],
[shift, 100, :left],
[bit_and, 90, :left],
[bit_or, 90, :right],
[greater_equal, 80, :left],
[less_or_equal, 80, :left],
[larger, 80, :left],
[smaller, 80, :left],
[identity, 70, :right],
[equal, 70, :right],
[not_equal, 70, :right],
[boolean_and, 60, :left],
[boolean_or, 50, :right],
[eclipse, 40, :right],
[keyword_rescue, 30, :right],
[assign, 20, :right],
[op_assign, 20, :right],
[keyword_until, 10, :right],
[keyword_while, 10, :right],
[keyword_unless, 10, :right],
[keyword_if, 10, :right])
end
end
end

View File

@ -1,22 +0,0 @@
module Parser
# Tokens are single or double character combinations with "meaning"
# braces, comman, point, questionmark , quotes, that kind of thing
# operator symbols are seperate in Opreators
module Tokens
include Parslet
rule(:left_parenthesis) { str('(') >> space? }
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? }
rule(:question_mark) { str('?') >> space? }
rule(:excamation_mark) { str('!') >> space? }
end
end

View File

@ -1,87 +0,0 @@
require 'parslet'
require 'ast/expression'
module Parser
class Transform < Parslet::Transform
rule(:string => sequence(:chars)) { Ast::StringExpression.new chars.join }
rule(:esc => simple(:esc)) { '\\' + esc }
rule(char: simple(:char)) { char }
rule(:integer => simple(:value)) { Ast::IntegerExpression.new(value.to_i) }
rule(:name => simple(:name)) { Ast::NameExpression.new(name.to_s) }
rule(:instance_variable => simple(:instance_variable)) { Ast::VariableExpression.new(instance_variable.name) }
rule(:module_name => simple(:module_name)) { Ast::ModuleName.new(module_name.to_s) }
rule(:array_constant => sequence(:array_constant) ) { Ast::ArrayExpression.new(array_constant) }
rule(:array_element => simple(:array_element)) { array_element }
rule(:hash_constant => sequence(:hash_constant) ) { Ast::HashExpression.new(hash_constant) }
rule(:hash_key => simple(:hash_key) , :hash_value => simple(:hash_value)) { Ast::AssociationExpression.new(hash_key,hash_value) }
rule(:hash_pair => simple(:hash_pair) ) { hash_pair }
rule(:argument => simple(:argument)) { argument }
rule(:argument_list => sequence(:argument_list)) { argument_list }
#Two rules for calls, simple and qualified. Keeps the rules simpler
rule( :call_site => simple(:call_site),
:argument_list => sequence(:argument_list)) do
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),
:if_true => {:expressions => sequence(:if_true) , :else => simple(:else) },
:if_false => {:expressions => sequence(:if_false) , :end => simple(:e) }) do
Ast::IfExpression.new(conditional, if_true, if_false)
end
rule(:while => simple(:while),
:while_cond => simple(:while_cond) , :do => simple(:do) ,
:body => {:expressions => sequence(:body) , :end => simple(:e) }) do
Ast::WhileExpression.new(while_cond, body)
end
rule(:return => simple(:return) , :return_expression => simple(:return_expression))do
Ast::ReturnExpression.new(return_expression)
end
rule(:parmeter => simple(:parmeter)) { parmeter }
rule(:parmeter_list => sequence(:parmeter_list)) { parmeter_list }
# Also two rules for function definitions, unqualified and qualified
rule(:function_name => simple(:function_name),
:parmeter_list => sequence(:parmeter_list),
:expressions => sequence(:expressions) , :end => simple(:e)) do
Ast::FunctionExpression.new(function_name.name, parmeter_list, expressions)
end
rule(:receiver=> simple(:receiver),
:function_name => simple(:function_name),
:parmeter_list => sequence(:parmeter_list),
:expressions => sequence(:expressions) , :end => simple(:e)) do
Ast::FunctionExpression.new(function_name.name, parmeter_list, expressions , receiver)
end
rule(l: simple(:l), o: simple(:o) , r: simple(:r)) do
Ast::OperatorExpression.new( o.to_s.strip , l ,r)
end
#modules and classes are understandibly quite similar Class < Module
rule( :module_name => simple(:module_name) , :module_expressions => sequence(:module_expressions) , :end=>"end") do
Ast::ModuleExpression.new(module_name , module_expressions)
end
rule( :module_name => simple(:module_name) , :class_expressions => sequence(:class_expressions) , :end=>"end") do
Ast::ClassExpression.new(module_name , class_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
syntax = Parser.new.send(rule).parse(string)
tree = Transform.new.apply(syntax)
tree
end
end
end

View File

@ -1,38 +0,0 @@
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.

View File

@ -1,65 +0,0 @@
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

View File

@ -1,14 +0,0 @@
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"

View File

@ -1,37 +0,0 @@
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

View File

@ -1,73 +0,0 @@
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

View File

@ -1,103 +0,0 @@
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

View File

@ -1,74 +0,0 @@
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 = <<HERE
class Foo
5
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
class Opers
def foo(x)
@abba = 5
2 + 5
end
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))] )] )
@parser = @parser.class_definition
end
def test_class_if
@string_input = <<HERE
class Ifi
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
class Pifi
ofthen(3+4 , var)
def ofthen(n,m)
44
end
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)] )] )
@parser = @parser.class_definition
end
def test_class_module
@string_input = <<HERE
class Foo
module Boo
funcall(3+4 , var)
end
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)] )] )] )
@parser = @parser.class_definition
end
end

View File

@ -1,44 +0,0 @@
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

View File

@ -1,41 +0,0 @@
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 = <<HERE
42
else
667
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)] )
@parser = @parser.conditional
end
def test_conditional_with_calls
@string_input = <<HERE
if(3 > 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

View File

@ -1,40 +0,0 @@
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 = <<HERE
dud
fuu(3)
else
HERE
@string_input.chop!
@parse_output = {:expressions=>[{: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 = <<HERE
name
call(4,6)
end
HERE
@string_input.chop!
@parse_output = {:expressions=>[{: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

View File

@ -1,26 +0,0 @@
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 = <<HERE
class Foo
def bar
4
end
end
HERE
@parse_output = nil
@transform_output = nil
@parser = @parser.root
end
end

View File

@ -1,130 +0,0 @@
require_relative "helper"
class TestFunctionDefinition < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_function
@string_input = <<HERE
def foo(x)
5
end
HERE
@parse_output = {:function_name=>{: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 = <<HERE
def String.length(x)
@length
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") )
@parser = @parser.function_definition
end
def test_function_ops
@string_input = <<HERE
def foo(x)
abba = 5
2 + 5
end
HERE
@parse_output = {: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"}
@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 = <<HERE
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
HERE
@parse_output = {: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"}
@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 = <<HERE
def retvar(n)
i = 5
return i
end
HERE
@parse_output = {:function_name=>{: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 = <<HERE
def retvar(n)
if( n > 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 = <<HERE
def retvar(n)
while( n > 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 = <<HERE
def fibonaccit(n)
a = 0
while (n) do
some = 43
other = some * 4
end
end
HERE
@parse_output = {:function_name=>{: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 = <<HERE
def fibonaccit(n)
a = 0
b = 1
while( n > 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

View File

@ -1,86 +0,0 @@
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 = <<HERE
module Simple
5
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
module Opers
def foo(x)
abba = 5
2 + 5
end
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
module Opers
@abba = 5
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))] )
@parser = @parser.module_definition
end
def test_module_if
@string_input = <<HERE
module Foo
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
module Soho
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:module_name=>"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 = <<HERE
module Foo
class Bar
funcall(3+4 , var)
end
end
HERE
@parse_output = {:module_name=>"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

View File

@ -1,86 +0,0 @@
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

View File

@ -1,28 +0,0 @@
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

View File

@ -1,118 +0,0 @@
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 = <<HERE
def foo(x)
a = 5
end
foo( 3 )
HERE
@parse_output = [{:function_name=>{: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 = <<HERE
def foo(x) #here
a = 0 # a == r1
b = 1 # b = r2
while(n<1) do #comment
tmp = a # r3 <- r1
a = b # r1 <- r2
b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4
putstring(b)
n = n - 1 #me
end #no
end #anywhere
foo( 3 ) #and more
HERE
@parse_output = [{:function_name=>{: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 = <<HERE
def fibonaccit(n)
a = 0
b = 1
while( n > 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 = <<HERE
module Fibo
def fibonaccit(n)
a = 0
end
fibonaccit( 10 )
end
HERE
@parse_output = [{:module_name=>"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 = <<HERE
module Fibo
a = 5 + foo
bar( b , a , r)
end
HERE
@parse_output = [{:module_name=>"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 = <<HERE
module FooBo
class Bar
a = 5 + foo
end
end
HERE
@parse_output = [{:module_name=>"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 = <<HERE
class FooBo
Bar.call(35)
end
HERE
@parse_output = [{:module_name=>"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

View File

@ -1,48 +0,0 @@
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 = <<HERE
while(1) do
tmp = a
puts(b)
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")] ,Ast::NameExpression.new("self"))] )
@parser = @parser.while_do
end
def test_while_method
@string_input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@string_input.chop!
@parse_output = {:while=>"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 = <<HERE
while( n > 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

View File

@ -1,4 +1,3 @@
require_relative "arm/test_all" require_relative "arm/test_all"
require_relative "fragments/test_all" require_relative "fragments/test_all"
require_relative "parser/test_all"
require_relative "test_intel" require_relative "test_intel"