34 Commits

Author SHA1 Message Date
58b3553251 forgot gemfile 2015-10-07 15:04:54 +03:00
1c6bd05aea upped version, would be a major version if it were over 1 2015-10-07 15:04:23 +03:00
14cf3a140d low climate is a climate bug, don't advertise it 2015-10-06 00:38:47 +03:00
6246753c27 add another simple function test 2015-10-06 00:22:18 +03:00
34691f36d1 add class_fields as separate syntax 2015-09-27 12:05:35 +03:00
97d9d83715 remove unused code 2015-09-27 11:26:11 +03:00
e8bc570d25 wrapping class / module expressions in own node 2015-09-20 16:03:27 +03:00
20b6c9b476 fix class functions
some extra tests in the process
2015-09-20 15:51:08 +03:00
c331bdd80a fix field default values 2015-09-20 14:43:08 +03:00
d0b950eed9 preparing test 2015-09-20 14:29:24 +03:00
f51563e99b restrict root_body a bit, but add to function 2015-09-20 14:25:06 +03:00
ea6472c28f rename field to parameter in parameter_list
also field to field_def (wip)
and lots of whitespace due to ws fix
2015-09-20 12:56:06 +03:00
be444bc687 add field access with tests 2015-09-20 12:50:06 +03:00
8e07a7568f fix array in if_false 2015-09-19 17:11:15 +03:00
dab32bc307 remove puts 2015-09-19 16:25:42 +03:00
9aa27d491d some more to_syms, and removing arrays, which become children 2015-09-19 14:55:03 +03:00
692b51a9de way to fix current test cases (if known to be correct) 2015-09-19 14:54:22 +03:00
e2054660ce thought to be useful sat addition 2015-09-19 14:53:59 +03:00
e952495eb1 update ast 2015-09-19 14:53:37 +03:00
21b652456d fix all the cases, much white noise, array to list, string to sym stuff 2015-09-19 14:53:30 +03:00
3b0b91f2fb use the new inspect 2015-09-19 14:40:08 +03:00
3bfcd830b0 small clean 2015-09-19 13:15:32 +03:00
296c9fbf98 output computed result if test fails (remove old tests)
so that if it is actually correct (as often is after changing the
grammar)
the result can be pasted into the test
2015-09-18 22:21:17 +03:00
a11e59668d use own outputted (ast gem) 2015-09-18 22:19:42 +03:00
71affacfba separate tag/nodes for conditions and remove arrays 2015-09-18 22:04:08 +03:00
22e3c59674 change test framework to use files for in and out (s-exp) 2015-09-18 21:55:02 +03:00
396a843a5e add return and argument types 2015-09-18 00:02:52 +03:00
4d195a5f44 make 1.9 save 2015-09-15 20:03:21 +03:00
7f126ab996 fix gemfile 2015-09-15 19:45:20 +03:00
08ceb86b24 Merge branch 'master' into parslet 2015-09-15 19:30:01 +03:00
b938c7ace5 fix all tests 2015-09-15 18:57:31 +03:00
3b484aa8ff add ast gem 2015-09-15 18:57:21 +03:00
eca1e6b1af remove own sat 2015-09-15 18:56:55 +03:00
9c89415857 limbo 2015-08-30 17:28:30 +03:00
145 changed files with 1693 additions and 2798 deletions

View File

@ -3,8 +3,10 @@ source "http://rubygems.org"
gem "rake"
gem "salama-reader" , :path => "."
gem "citrus" , :github => "salama/citrus" , :branch => "gemspec-readme"
gem "ast" , :path => "../ast"
# use this for debugging, the printout is better (cut/paste)
gem "ast" , :github => "dancinglightning/ast" , :branch => :new_inspect
#gem "ast"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.

View File

@ -1,29 +1,28 @@
GIT
remote: git://github.com/salama/citrus.git
revision: 34276150a67a89f84cab091fe0be7bb6a390e768
branch: gemspec-readme
remote: git://github.com/dancinglightning/ast.git
revision: a9bc29377a94d2194e92596aceb9be7c7db4c8f8
branch: new_inspect
specs:
citrus (3.0.3)
ast (2.1.0)
PATH
remote: .
specs:
salama-reader (0.2.0)
citrus (~> 3.0.3)
PATH
remote: ../ast
specs:
ast (2.1.0)
salama-reader (0.3.0)
ast (~> 2.1.0)
parslet (~> 1.7.0)
GEM
remote: http://rubygems.org/
specs:
blankslate (3.1.3)
codeclimate-test-reporter (0.4.6)
simplecov (>= 0.7.1, < 1.0.0)
docile (1.1.5)
minitest (5.6.1)
multi_json (1.11.2)
parslet (1.7.1)
blankslate (>= 2.0, <= 4.0)
rake (10.4.2)
rubygems-tasks (0.2.4)
simplecov (0.9.2)
@ -37,7 +36,6 @@ PLATFORMS
DEPENDENCIES
ast!
citrus!
codeclimate-test-reporter
minitest
rake
@ -45,4 +43,4 @@ DEPENDENCIES
salama-reader!
BUNDLED WITH
1.10.5
1.10.6

115
README.md
View File

@ -1,16 +1,46 @@
[![Build Status](https://travis-ci.org/salama/salama-reader.svg?branch=master)](https://travis-ci.org/salama/salama-reader)
[![Gem Version](https://badge.fury.io/rb/salama-reader.svg)](http://badge.fury.io/rb/salama-reader)
[![Code Climate](https://codeclimate.com/github/salama/salama-reader/badges/gpa.svg)](https://codeclimate.com/github/salama/salama-reader)
[![Test Coverage](https://codeclimate.com/github/salama/salama-reader/badges/coverage.svg)](https://codeclimate.com/github/salama/salama-reader)
## Salama Reader
The parser part of salama is now a standalone gem. It parses ruby using Citrus and no other dependencies.
This is interesting if you want to generate executable code, like salama, but also for other things, like code analysis.
The parser part of salama is now a standalone gem. It parses Phisol using Parslet and no other dependencies.
Also it is very educational, as it is very readable code, and not too much of it.
## Phisol Phi System Object Language
Phisol is just forming after realizing the (unfortunate) need for an oo system language.
(I really didn't want to do yet another language)
The need comes from these three things:
- a language is needed to translate to. Meaning a software layer is needed, but to understand how
that layer works, a syntax is needed. Thus is born a language.
- Upward compatible memory and calling conventions are needed
- Multiple return addresses are needed
From these comes the name: A phi node is the opposite of what you may think of as an if. Actually an
if statement is always a branch (the if part) and a rejoining of the two branches (the phi part).
In Phisol a function call is not necessarily a part of linear code. A call may return to several
addresses, making the call more like an if statement.
### Syntax
Syntax (and semantics) of Phisol are just forming, but some things are clear:
- statically typed (in the beginning with just two types) meaning all variable declarations,
functions and arguments shall be typed.
- objects but without data hiding
- probably nil objects
- static blocks (a bit ala crystal)
- call syntax as already discussed, ie message based
Some things we shall leave behind from the ruby approach are a lot of sugar, like missing brackets,
random code everywhere, expressions galore . . .
### Parser
The main parser per se is in parser/salama , but it just pulls in all the parts.
@ -29,76 +59,25 @@ Most names are quite self explanatory, but here is a list:
- return statement are straightforward
- while still needs a do, though i think in ruby a newline is sufficient
**Transform** defines how the rules map to Ast objects.
### Ast
The Abtract Syntax Tree (ast) layer puts the parsed code into objects, so they are nice and easy to work with.
The ast layer now uses the ast gem. That approach is to use a single class to represent all
types of node and use a type symbol (instead of different classes)
The Classes don't really define any functionality, that is done in Salama, or can be done in any code using this. Salama just adds a compile function to each class, but a visitor pattern would do just as well.
This works well, and is much less work.
The functionality that is in there is mainly to do with testing. Equality is defined, but also **inspect** in such a way that it's output (which you get from a failing test) can be pasted straight into the test case as the expected result.
The following step of compiling use the same kind of visitor approach as before
### Parslet
### Citrus
Citrus is really great in that it:
- does not generate code but instead gives a syntax to define a grammar
Parslet is really great in that it:
- does not generate code but instead gives a clean dsl to define a grammar
- uses ruby modules so one can split the grammars up
- has support for binary operators with precedence and binding
- has a separate transform stage to generate an ast layer
### Todo
A random list of things left for the future
- extract commonality of function call/definition,array, hash and multi assignment comma lists
- break and next
- blocks
- more loops, i'm not even sure what ruby supports
- ifs without else, also elsif
- negative tests
### Operators
See the operators.rb for details. Below is a list from the web of how it should be.
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
Especially the last point is great. Since it is separate 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 transformation process.

View File

@ -1,135 +0,0 @@
# collection of the simple ones, int and strings and such
module Ast
class IntegerExpression < Expression
attr_reader :value
def initialize val
@value = val
end
def attributes
[:value]
end
def to_s
value.to_s
end
end
class TrueExpression < Expression
def to_s
""
end
def attributes
[]
end
end
class FalseExpression < Expression
def to_s
""
end
def attributes
[]
end
end
class NilExpression < Expression
def to_s
""
end
def attributes
[]
end
end
class NameExpression < Expression
attr_reader :name
def initialize name
@name = name.to_sym
end
def attributes
[:name]
end
def inspect
"#{self.class.name}.new(#{name.inspect})"
end
def to_s
name.to_s
end
end
class TypedName < NameExpression
attr_reader :type
def initialize type , name
super(name)
@type = type.to_sym
end
def attributes
[:type, :name]
end
def inspect
"#{self.class.name}.new(#{type.inspect},#{name.inspect})"
end
def to_s
inspect
end
end
class VariableDefinition < TypedName
attr_reader :right
def initialize type , name , right
super(type , name)
@right = right
end
def attributes
super + [:right]
end
def inspect
self.class.name + ".new(" + type.inspect + "," + name.inspect + "," + right.inspect + ")"
end
def to_s
inspect
end
end
class VariableExpression < NameExpression
end
class AssignmentExpression < NameExpression
attr_reader :right
def initialize name, right
super(name)
@right = right
end
def attributes
super + [:right]
end
def inspect
self.class.name + ".new(" + name.inspect + "," + right.inspect + ")"
end
def to_s
"#{left} = #{right}"
end
end
class ModuleName < NameExpression
end
class StringExpression < Expression
attr_reader :string
def initialize str
@string = str
end
def attributes
[:string]
end
def inspect
self.class.name + '.new("' + string + '")'
end
def to_s
'"' + string.to_s + '"'
end
end
end

View File

@ -1,21 +0,0 @@
module Ast
class BlockExpression < Expression
attr_reader :call_exp, :args , :body_exp
def initialize call_exp, args , body_exp
@call_exp = call_exp.to_sym
@args = args
@body_exp = body_exp
end
def attributes
[:call_exp , :args , :body_exp]
end
def to_s
call_exp.inspect + ", ["+
args.collect{|m| m.inspect }.join( ",") + "] ," + body_exp.inspect
end
end
end

View File

@ -1,35 +0,0 @@
module Ast
class FieldExpression < Expression
attr_reader :receiver , :name
def initialize receiver , name
@receiver = receiver
@name = name.to_sym
end
def attributes
[:receiver , :name]
end
def to_s
receiver.inspect + "," + name.inspect
end
end
class CallSiteExpression < Expression
attr_reader :field , :args
def initialize field, args
@field = field
@args = args
end
def attributes
[:field , :args]
end
def to_s
field.inspect + ", ["+
args.collect{|m| m.inspect }.join( ",") + "] "
end
end
end

View File

@ -1,34 +0,0 @@
module Ast
class ArrayExpression < Expression
attr_reader :values
def attributes
[:values]
end
def initialize vals
@values = vals
end
def to_s
values.to_s
end
end
class AssociationExpression < Expression
attr_reader :key , :value
def initialize key , value
@key , @value = key , value
end
def attributes
[:key , :value]
end
def to_s
key.inspect + " , " + value.inspect
end
end
class HashExpression < ArrayExpression
end
end

View File

@ -1,82 +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
Array.class_eval do
def to_basic
collect do |item|
item.to_basic
end
end
end
Symbol.class_eval do
def to_basic
to_s
end
end
String.class_eval do
def to_basic
to_s
end
end
module Ast
class Expression
def attributes
raise "abstract called for #{self}"
end
def to_basic()
data = { "class" => self.class.name }
attributes.each do |name|
val = instance_variable_get("@#{name}".to_sym)
res = val.to_basic
data[name] = res
end
data
end
def self.from_basic(hash)
clazz = hash.delete("class")
keys = hash.keys
klass = clazz.split("::").inject(Object) {|o,c| o.const_get(c)}
keys.delete("class")
values = keys.collect{|k| read_basic(hash[k]) }
klass.new(*values)
end
def self.read_basic val
return from_basic(val) if val.is_a?(Hash)
return val.collect{|i| from_basic(i)} if(val.is_a? Array )
val
end
def inspect
self.class.name + ".new(#{to_s})"
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"
require_relative "expression_list"

View File

@ -1,17 +0,0 @@
module Ast
class ExpressionList < Expression
attr_reader :expressions
def initialize expressions
@expressions = expressions
end
def attributes
[:expressions]
end
def to_s
"["+ expressions.collect(&:inspect).join( ",") +"]"
end
end
end

View File

@ -1,19 +0,0 @@
module Ast
class FunctionExpression < Expression
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 to_s
name.inspect + ", ["+
params.collect{|m| m.inspect }.join( ",") +"] , [" +
body.collect{|m| m.inspect }.join( ",") +"] ,"+ receiver.inspect
end
end
end

View File

@ -1,15 +0,0 @@
module Ast
class IfExpression < Expression
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 attributes
[:cond, :if_true, :if_false]
end
def to_s
cond.inspect + ", " + if_true.inspect + "," + if_false.inspect
end
end
end

View File

@ -1,37 +0,0 @@
module Ast
class ModuleExpression < Expression
attr_reader :name ,:expressions
def initialize name , expressions
@name = name.to_sym
@expressions = expressions
end
def attributes
[:name , :expressions]
end
def to_s
name.inspect + " ," + expressions.inspect
end
end
class ClassExpression < ModuleExpression
def initialize name , derived , expressions
super(name , expressions)
@derived_from = derived
end
def attributes
[:name , :derived_from , :expressions]
end
def derived_from
@derived_from ? @derived_from : :Object
end
def to_s
name.inspect + " ," + derived_from.inspect + ", " + expressions.inspect
end
end
end

View File

@ -1,19 +0,0 @@
module Ast
class OperatorExpression < Expression
attr_reader :operator, :left, :right
def initialize operator, left, right
@operator, @left, @right = operator, left, right
end
def attributes
[:operator, :left, :right]
end
def to_s
operator.inspect + ", " + left.inspect + "," + right.inspect
end
end
end

View File

@ -1,15 +0,0 @@
module Ast
class ReturnExpression < Expression
attr_reader :expression
def initialize expression
@expression = expression
end
def attributes
[:expression]
end
def to_s
expression.inspect
end
end
end

View File

@ -1,17 +0,0 @@
module Ast
class WhileExpression < Expression
attr_reader :condition, :body
def initialize condition, body
@condition , @body = condition , body
end
def attributes
[:condition, :body]
end
def to_s
condition.inspect + ", " + body.inspect
end
end
end

62
lib/parser/basic_types.rb Normal file
View File

@ -0,0 +1,62 @@
module Parser
# Basic types are numbers and strings
module BasicTypes
include Parslet
# unicode generalized categories , according to regex ruby page
rule(:lower) { match "[[:lower:]]" } # Lowercase alphabetical character
rule(:upper) { match "[[:upper:]]" } # Uppercase alphabetical
rule(:alnum) { match "[[:alnum:]]" } # Alphabetic and numeric character
rule(:alpha) { match "[[:alpha:]]" } # Alphabetic character
rule(:blank) { match "[[:blank:]]" } # Space or tab
rule(:space) { match("[[:space:]]").repeat } # Whitespace character ([:blank:], newline, carriage return, etc.)
rule(:digit) { match "[[:digit:]]" } # Digit
rule(:graph) { match "[[:graph:]]" } # Non-blank character (excludes spaces, control characters, and similar)
rule(:print) { match "[[:print:]]" } # Like [:graph:], but includes the space character
rule(:xdigit) { match "[[:xdigit:]]"} # Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
# rule of thumb is that anything eats space behind it, but only space, no newlines
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) >> space? }
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')) }
rule(:type) { (str("int") | str("ref")).as(:type) >> space }
# 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|type).absent? >> (match['a-z_'] >> match['a-zA-Z0-9_'].repeat).as(:name) >> space? }
# fields have type
rule(:field) { type >> name >> (assign >> value_expression.as(:value) ).maybe}
rule(:class_field) { keyword_field >> field }
# and class/module names must start with capital
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 | field | module_name |
keyword_true | keyword_false | keyword_nil }
end
end

View File

@ -1,244 +0,0 @@
grammar Bosl
# unicode generalized categories , according to regex ruby page
rule lower /[[:lower:]]/ end # Lowercase alphabetical character
rule upper /[[:upper:]]/ end # Uppercase alphabetical
rule alnum /[[:alnum:]]/ end # Alphabetic and numeric character
rule alpha /[[:alpha:]]/ end # Alphabetic character
rule blank /[[:blank:]]/ end # Space or tab
rule space /[[:space:]]/ end # Whitespace character ([:blank:], newline, carriage return, etc.)
rule digit /[[:digit:]]/ end # Digit
rule graph /[[:graph:]]/ end # Non-blank character (excludes spaces, control characters, and similar)
rule print /[[:print:]]/ end # Like [:graph:], but includes the space character
rule xdigit /[[:xdigit:]]/ end # Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
rule linebreak (!blank space) end #define in regex terms for utf
rule comment #don't include the newline (which ends the comment)
"#" /.*/
end
rule name_expression
(name:([a-z_] [a-zA-Z0-9_]*) space*) { capture(:name).to_str}
end
rule aspect_name_expression
(name:([A-Z] [a-zA-Z0-9_]*) space*) { s(:aspect , capture(:name).to_str)}
end
rule digits
[0-9] [0-9]*
end
rule integer_expression
(digits space*) { s(:int , to_str.to_i) }
end
rule string_expression
#"'" (/.*/ !"'") "'"
('"' str:(!'"' .)* '"') {s(:string , capture(:str).to_str) }
end
rule basic_expression
name_expression | integer_expression |
aspect_name_expression | string_expression
end
rule keyword_begin 'begin' space* end
rule keyword_class 'class' space* end
rule keyword_def 'def' space* end
rule keyword_do 'do' space* end
rule keyword_else 'else' space* end
rule keyword_end 'end' space* end
rule keyword_if 'if' end
rule keyword_rescue 'rescue' space* end
rule keyword_return 'return' space* end
rule keyword_aspect 'aspect' space* end
rule keyword_unless 'unless' space* end
rule keyword_while 'while' space* end
rule keyword_nil
('nil' space* ){ s(:nil) }
end
rule keyword_false
('false' space*) { s(:false) }
end
rule keyword_true
('true' space*) { s(:true) }
end
# 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 ('begin' | 'def' | 'do' | 'else' | 'end' |
'false' | 'if' | 'rescue' | 'true' | 'nil' |
'unless' | 'until' | 'while') space*
end
rule keyword_expression
keyword_true | keyword_false | keyword_nil | basic_expression
end
# Tokens are single or double character combinations with "meaning"
# braces, comman, point, questionmark , quotes, that kind of thing
# operator symbols are separate in Opreators
rule left_parenthesis
'(' space*
end
rule right_parenthesis
')' space*
end
rule left_brace
'{' space*
end
rule right_brace
'}' space*
end
rule left_bracket
'[' space*
end
rule right_bracket
']' space*
end
rule association
"=>" space*
end
rule comma
',' space*
end
rule colon
':' space*
end
rule semicolon
';' space*
end
rule question_mark
'?' space*
end
rule excamation_mark
'!' space*
end
rule more_args
(comma basic_expression )* {
captures(:basic_expression).collect{|u| u.value }
}
end
rule argument_list
(left_parenthesis basic_expression? more_args right_parenthesis){
args = [ ]
args << capture(:basic_expression).value if capture(:basic_expression)
args += capture(:more_args).value if capture(:more_args)
args
}
end
rule call_site
(field_expression argument_list space?) {
s(:call , capture(:field_expression).value , capture(:argument_list).value )
}
end
rule field_expression
(basic_expression "." name_expression space?) {
s(:field , capture(:basic_expression).value ,
capture(:name_expression).value )
}
end
rule value_expression
call_site | basic_expression
end
rule function_definition
keyword_def name:function_name parameter_list newline expressions_end newline
end
rule parameter_list
left_parenthesis parameter_list:( name:parameter? (comma name:parameter)* ) right_parenthesis
end
rule more_typed_args
(comma typed_arg )* {
captures(:typed_arg).collect{|u| u.value }
}
end
rule typed_argument_list
(left_parenthesis typed_arg? more_typed_args right_parenthesis){
args = [ ]
args << capture(:typed_arg).value if capture(:typed_arg)
args += capture(:more_typed_args).value if capture(:more_typed_args)
args
}
end
rule type
(typ:("int" | "ref") space*) { capture(:typ).to_s }
end
rule typed_arg
(type name_expression) {
s(:type , capture(:type).value , capture(:name_expression).value)
}
end
rule variable_definition
(typed_arg ("=" space* value_expression)?) {
value = capture(:value_expression) ? capture(:value_expression).value : nil
s(:variable , capture(:typed_arg).value , value )
}
end
rule assignment
(name_expression "=" space* value_expression){
s(:assign , capture(:name_expression).value.to_sym , capture(:value_expression).value)
}
end
rule conditional
(keyword_if left_parenthesis value_expression right_parenthesis
body
keyword_end) {
s(:if , s(:cond , capture(:value_expression).value ) , s(:then , capture(:body).value) )
}
end
rule while
keyword_while left_parenthesis value_expression right_parenthesis keyword_do
body
keyword_end
end
rule return
keyword_return value_expression newline
end
rule body
(statement+){
captures(:statement).collect{|u| u.value }
}
end
rule statement
conditional | while | return | variable_definition | assignment | call_site
end
end

18
lib/parser/call_site.rb Normal file
View File

@ -0,0 +1,18 @@
module Parser
module CallSite
include Parslet
rule(:argument_list) {
left_parenthesis >>
( (basic_type.as(:argument) >>
(comma >> basic_type.as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >>
right_parenthesis
}
rule(:call_site) { (basic_type.as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:call_site) >> argument_list >> comment.maybe}
rule(:field_access) { name.as(:receiver) >> str(".") >> name.as(:field) }
end
end

View File

@ -1,7 +1,7 @@
module Parser
# Compound types are Arrays and Hashes
module CompoundTypes
include output
include Parslet
rule(:array_constant) do
left_bracket >>

View File

@ -1,17 +1,21 @@
module Parser
module Control
include output
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)
left_parenthesis >> (operator_expression|value_expression).as(:conditional) >> right_parenthesis >>
expressions_else.as(:if_true) >> expressions_end.as(:if_false)
end
rule(:small_conditional) do
keyword_if >>
left_parenthesis >> (operator_expression|value_expression).as(:conditional) >> right_parenthesis >>
expressions_end.as(:if_true)
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)
right_parenthesis >> expressions_end.as(:body)
end
rule(:simple_return) do
keyword_return >> (operator_expression|value_expression).as(:return_expression)

View File

@ -1,10 +1,12 @@
module Parser
module Expression
include output
include Parslet
rule(:value_expression) { call_site | basic_type }
rule(:value_expression) { call_site | field_access |basic_type }
rule(:expression) { (simple_return | while_do | conditional | operator_expression | call_site ) >> newline }
rule(:expression) { (simple_return | while_do | small_conditional | conditional |
operator_expression | call_site | class_field | field |
hash_constant | array_constant) }
def delimited_expressions( delimit )
( (delimit.absent? >> expression).repeat(1)).as(:expressions) >> delimit

View File

@ -0,0 +1,16 @@
module Parser
module FunctionDefinition
include Parslet
rule(:function_definition) {
type >> ((module_name|name).as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:function_name) >> left_parenthesis >>
parameter_list.maybe >> right_parenthesis >> expressions_end >> space?
}
rule(:parameter_list) {
((field.as(:parameter) >> (comma >> field.as(:parameter)).repeat(0)).repeat(0,1)).as(:parameter_list)
}
end
end

View File

@ -1,28 +1,28 @@
module Parser
module Keywords
include output
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_false) { str('false').as(:false) }
rule(:keyword_field) { str('field').as(:field) >> space? }
rule(:keyword_if) { str('if').as(:if) }
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_true) { str('true').as(:true) }
rule(:keyword_module) { str('module') >> space? }
rule(:keyword_nil) { str('nil').as(:nil) >> space?}
rule(:keyword_nil) { str('nil').as(:nil) }
rule(:keyword_unless) { str('unless').as(:unless) >> space?}
rule(:keyword_until) { str('until').as(:until) >> space?}
rule(:keyword_while) { str('while').as(:while) >> space?}
rule(:keyword_while) { str('while').as(:while) }
# 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')}
str('unless')| str('until')| str('while') | str('field')}
end
end

View File

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

View File

@ -1,6 +1,6 @@
module Parser
module Operators
include output
include Parslet
rule(:exponent) { str('**') >> space?}
rule(:multiply) { match['*/%'] >> space? }
rule(:plus) { match['+-'] >> space? }
@ -42,11 +42,7 @@ module Parser
[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])
[op_assign, 20, :right] ) >> space?
end
end
end

View File

@ -1,11 +1,38 @@
require "ast"
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
Citrus::Match.include AST::Sexp
# 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
Citrus.require "parser/bosl"
class Salama < 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 | operator_expression | call_site )}
rule(:root) { root_body.repeat.as(:expression_list) }
end
end

View File

@ -3,7 +3,7 @@ module Parser
# braces, comman, point, questionmark , quotes, that kind of thing
# operator symbols are separate in Opreators
module Tokens
include output
include Parslet
rule(:left_parenthesis) { str('(') >> space? }
rule(:right_parenthesis) { str(')') >> space? }
rule(:left_brace) { str('{') >> space? }

View File

@ -1,24 +1,35 @@
require 'parslet'
require 'ast/expression'
#include is private in 1.9, who'd have known without travis
Parslet::Context.send :include , AST::Sexp
module Parser
class Transform < output::Transform
rule(:string => sequence(:chars)) { Ast::StringExpression.new chars.join }
class Transform < Parslet::Transform
rule(:string => sequence(:chars)) { s(:string , chars.join) }
rule(:esc => simple(:esc)) { '\\' + esc }
rule(char: simple(:char)) { char }
rule(:true => simple(:true)) { Ast::TrueExpression.new() }
rule(:false => simple(:false)) { Ast::FalseExpression.new() }
rule(:nil => simple(:nil)) { Ast::NilExpression.new() }
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(:true => simple(:true)) { s(:true) }
rule(:false => simple(:false)) { s(:false) }
rule(:nil => simple(:nil)) { s(:nil) }
rule(:integer => simple(:value)) { s(:int ,value.to_i) }
rule(:name => simple(:name)) { s(:name , name.to_sym) }
# local variables
rule(:type => simple(:type), :name => simple(:name)) { s(:field_def , type.to_sym , name.to_sym) }
rule(:type => simple(:type), :name => simple(:name) , :value => simple(:value)) {
s(:field_def , type.to_sym , name.to_sym , value ) }
# class field
rule(:field => simple(:field) , :type => simple(:type), :name => simple(:name)) {
s(:class_field , type.to_sym , name.to_sym) }
rule(:field => simple(:field) , :type => simple(:type), :name => simple(:name) , :value => simple(:value)) {
s(:class_field , type.to_sym , name.to_sym , value ) }
rule(:array_constant => sequence(:array_constant) ) { Ast::ArrayExpression.new(array_constant) }
rule(:module_name => simple(:module_name)) { s(:module,module_name.to_s) }
rule(:array_constant => sequence(:array_constant) ) { s(:array , *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_constant => sequence(:hash_constant) ) { s(:hash , *hash_constant) }
rule(:hash_key => simple(:hash_key) , :hash_value => simple(:hash_value)) { s(:assoc , hash_key , hash_value) }
rule(:hash_pair => simple(:hash_pair) ) { hash_pair }
rule(:argument => simple(:argument)) { argument }
@ -27,71 +38,80 @@ module Parser
#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 )
s(:call , call_site, s(:arguments , *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)
s(:call , call_site, s(:arguments , *argument_list) , s(:receiver , receiver))
end
rule( :receiver => simple(:receiver) , :field => simple(:field) ) do
s(:field_access , s(:receiver , receiver) , s(:field , field) )
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
s(:if , s(:condition, conditional), s(:if_true, *if_true), s(:if_false , *if_false))
end
rule(:if => simple(:if), :conditional => simple(:conditional),
:if_true => {:expressions => sequence(:if_true) , :end => simple(:e) }) do
s(:if , s(:condition, conditional), s(:if_true, *if_true), s(:if_false , nil) )
end
rule(:while => simple(:while),
:while_cond => simple(:while_cond) , :do => simple(:do) ,
:while_cond => simple(:while_cond) ,
:body => {:expressions => sequence(:body) , :end => simple(:e) }) do
Ast::WhileExpression.new(while_cond, body)
s(:while , s(:condition , while_cond), s(:expressions , *body))
end
rule(:return => simple(:return) , :return_expression => simple(:return_expression))do
Ast::ReturnExpression.new(return_expression)
s(:return , return_expression)
end
rule(:parameter => simple(:parameter)) { parameter }
rule(:parameter_list => sequence(:parameter_list)) { parameter_list }
rule(:parameter => simple(:parameter)) { s(:parameter , *parameter) }
# Also two rules for function definitions, unqualified and qualified
rule(:function_name => simple(:function_name),
:parameter_list => sequence(:parameter_list),
:expressions => sequence(:expressions) , :end => simple(:e)) do
Ast::FunctionExpression.new(function_name.name, parameter_list, expressions)
end
rule(:function_name => simple(:function_name),
:expressions => sequence(:expressions) , :end => simple(:e)) do
Ast::FunctionExpression.new(function_name.name, [], expressions)
end
rule(:receiver=> simple(:receiver),
rule(:type => simple(:type) ,
:function_name => simple(:function_name),
:parameter_list => sequence(:parameter_list),
:expressions => sequence(:expressions) , :end => simple(:e)) do
Ast::FunctionExpression.new(function_name.name, parameter_list, expressions , receiver)
s(:function, type.to_sym , function_name, s(:parameters , *parameter_list ),
s(:expressions , *expressions))
end
rule(:type => simple(:type) ,
:receiver=> simple(:receiver),
:function_name => simple(:function_name),
:parameter_list => sequence(:parameter_list),
:expressions => sequence(:expressions) , :end => simple(:e)) do
s(:function, type.to_sym , function_name, s(:parameters , *parameter_list ),
s(:expressions , *expressions) , s(:receiver , *receiver))
end
rule(l: simple(:l), o: simple(:o) , r: simple(:r)) do
op = o.to_s.strip
if op == "="
Ast::AssignmentExpression.new( l ,r)
s(:assign , l ,r)
else
Ast::OperatorExpression.new( op , l ,r)
s(:operator, op , l ,r)
end
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) , :derived_name => simple(:derived_name) , :class_expressions => sequence(:class_expressions) , :end=>"end") do
Ast::ClassExpression.new(module_name , derived_name ? derived_name.name : nil , class_expressions)
s(:class , module_name.to_s.to_sym ,
s(:derives, derived_name ? derived_name.to_a.first.to_sym : nil) ,
s(:expressions, *class_expressions) )
end
rule( :module_name => simple(:module_name) , :module_expressions => sequence(:module_expressions) , :end=>"end") do
s(:module , module_name.to_s.to_sym , s(:expressions, *module_expressions))
end
rule(:expression_list => sequence(:expression_list)) {
Ast::ExpressionList.new(expression_list)
s(:expressions , *expression_list)
}
#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

View File

@ -1,3 +1,4 @@
require 'citrus'
require 'parslet'
require 'parser/salama'
#require 'parser/transform'
require "ast"
require 'parser/transform'

View File

@ -1,49 +0,0 @@
module Parser
# Basic types are numbers and strings
module BasicTypes
include output
# 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 |
keyword_true | keyword_false | keyword_nil }
end
end

View File

@ -1,17 +0,0 @@
module Parser
module CallSite
include output
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|basic_type).as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:call_site) >> argument_list >> comment.maybe}
end
end

View File

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

View File

@ -2,7 +2,7 @@
Gem::Specification.new do |s|
s.name = 'salama-reader'
s.version = '0.2.0'
s.version = '0.3.0'
s.authors = ['Torsten Ruger']
s.email = 'torsten@villataika.fi'
@ -13,6 +13,7 @@ Gem::Specification.new do |s|
s.require_paths = ['lib']
s.summary = 'Ruby parser for the salama machine'
s.add_dependency 'citrus', '~> 3.0.3'
s.add_dependency 'parslet', '~> 1.7.0'
s.add_dependency 'ast', '~> 2.1.0'
end

View File

@ -43,10 +43,10 @@ test method. See test_basic for easy example.
Example:
def test_number
@input = '42 '
@string_input = '42 '
@test_output = {:integer => '42'}
@output = Parser::IntegerExpression.new(42)
@root = :integer
@transform_output = Parser::IntegerExpression.new(42)
@parser = @parser.integer
end
The first three lines define the data as described above.

View File

@ -0,0 +1,4 @@
FooBar
-- -- --
s(:expressions,
s(:module, "FooBar"))

View File

@ -0,0 +1,4 @@
foo
-- -- --
s(:expressions,
s(:name, :foo))

View File

@ -0,0 +1,4 @@
foo_bar
-- -- --
s(:expressions,
s(:name, :foo_bar))

View File

@ -0,0 +1,4 @@
_bar
-- -- --
s(:expressions,
s(:name, :_bar))

View File

@ -0,0 +1,4 @@
42
-- -- --
s(:expressions,
s(:int, 42))

View File

@ -0,0 +1,4 @@
"hello"
-- -- --
s(:expressions,
s(:string, "hello"))

View File

@ -0,0 +1,4 @@
"hello \nyou"
-- -- --
s(:expressions,
s(:string, "hello \\nyou"))

View File

@ -0,0 +1,8 @@
puts(3 , a )
-- -- --
s(:expressions,
s(:call,
s(:name, :puts),
s(:arguments,
s(:int, 3),
s(:name, :a))))

View File

@ -0,0 +1,8 @@
baz(42, foo)
-- -- --
s(:expressions,
s(:call,
s(:name, :baz),
s(:arguments,
s(:int, 42),
s(:name, :foo))))

View File

@ -0,0 +1,7 @@
puts( "hello")
-- -- --
s(:expressions,
s(:call,
s(:name, :puts),
s(:arguments,
s(:string, "hello"))))

View File

@ -0,0 +1,8 @@
message.self
-- -- --
s(:expressions,
s(:field_access,
s(:receiver,
s(:name, :message)),
s(:field,
s(:name, :self))))

View File

@ -0,0 +1,8 @@
42.put()
-- -- --
s(:expressions,
s(:call,
s(:name, :put),
s(:arguments),
s(:receiver,
s(:int, 42))))

View File

@ -0,0 +1,7 @@
puts( 5)
-- -- --
s(:expressions,
s(:call,
s(:name, :puts),
s(:arguments,
s(:int, 5))))

View File

@ -0,0 +1,7 @@
foo(42)
-- -- --
s(:expressions,
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 42))))

View File

@ -0,0 +1,9 @@
Object.foo(42)
-- -- --
s(:expressions,
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 42)),
s(:receiver,
s(:module, "Object"))))

View File

@ -0,0 +1,9 @@
my_my.foo(42)
-- -- --
s(:expressions,
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 42)),
s(:receiver,
s(:name, :my_my))))

View File

@ -0,0 +1,9 @@
self.foo(42)
-- -- --
s(:expressions,
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 42)),
s(:receiver,
s(:name, :self))))

View File

@ -0,0 +1,8 @@
"hello".puts()
-- -- --
s(:expressions,
s(:call,
s(:name, :puts),
s(:arguments),
s(:receiver,
s(:string, "hello"))))

View File

@ -0,0 +1,161 @@
class String
ref self.new_string(int len )
len = len << 2
return super.new_object( len)
end
int length()
return self.length
end
int plus(ref str)
my_length = self.length
str_len = str.length()
my_length = str_len + my_length
new_string = self.new_string(my_length )
i = 0
while( i < my_length)
char = get(i)
new_string.set(i , char)
i = i + 1
end
i = 0
while( i < str_len)
char = str.get(i)
len = i + my_length
new_string.set( len , char)
i = i + 1
end
return new_string
end
end
-- -- --
s(:expressions,
s(:class, :String,
s(:derives, nil),
s(:expressions,
s(:function, :ref,
s(:name, :new_string),
s(:parameters,
s(:parameter, :int, :len)),
s(:expressions,
s(:assign,
s(:name, :len),
s(:operator, "<<",
s(:name, :len),
s(:int, 2))),
s(:return,
s(:call,
s(:name, :new_object),
s(:arguments,
s(:name, :len)),
s(:receiver,
s(:name, :super))))),
s(:receiver, :self)),
s(:function, :int,
s(:name, :length),
s(:parameters),
s(:expressions,
s(:return,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :length)))))),
s(:function, :int,
s(:name, :plus),
s(:parameters,
s(:parameter, :ref, :str)),
s(:expressions,
s(:assign,
s(:name, :my_length),
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :length)))),
s(:assign,
s(:name, :str_len),
s(:call,
s(:name, :length),
s(:arguments),
s(:receiver,
s(:name, :str)))),
s(:assign,
s(:name, :my_length),
s(:operator, "+",
s(:name, :str_len),
s(:name, :my_length))),
s(:assign,
s(:name, :new_string),
s(:call,
s(:name, :new_string),
s(:arguments,
s(:name, :my_length)),
s(:receiver,
s(:name, :self)))),
s(:assign,
s(:name, :i),
s(:int, 0)),
s(:while,
s(:condition,
s(:operator, "<",
s(:name, :i),
s(:name, :my_length))),
s(:expressions,
s(:assign,
s(:name, :char),
s(:call,
s(:name, :get),
s(:arguments,
s(:name, :i)))),
s(:call,
s(:name, :set),
s(:arguments,
s(:name, :i),
s(:name, :char)),
s(:receiver,
s(:name, :new_string))),
s(:assign,
s(:name, :i),
s(:operator, "+",
s(:name, :i),
s(:int, 1))))),
s(:assign,
s(:name, :i),
s(:int, 0)),
s(:while,
s(:condition,
s(:operator, "<",
s(:name, :i),
s(:name, :str_len))),
s(:expressions,
s(:assign,
s(:name, :char),
s(:call,
s(:name, :get),
s(:arguments,
s(:name, :i)),
s(:receiver,
s(:name, :str)))),
s(:assign,
s(:name, :len),
s(:operator, "+",
s(:name, :i),
s(:name, :my_length))),
s(:call,
s(:name, :set),
s(:arguments,
s(:name, :len),
s(:name, :char)),
s(:receiver,
s(:name, :new_string))),
s(:assign,
s(:name, :i),
s(:operator, "+",
s(:name, :i),
s(:int, 1))))),
s(:return,
s(:name, :new_string)))))))

View File

@ -0,0 +1,29 @@
class Foo < Object
field int fff = 3
int func()
return self.fff
end
ofthen(3 , var)
end
-- -- --
s(:expressions,
s(:class, :Foo,
s(:derives, :Object),
s(:expressions,
s(:class_field, :int, :fff,
s(:int, 3)),
s(:function, :int,
s(:name, :func),
s(:parameters),
s(:expressions,
s(:return,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :fff)))))),
s(:call,
s(:name, :ofthen),
s(:arguments,
s(:int, 3),
s(:name, :var))))))

View File

@ -0,0 +1,36 @@
class Pifi
ofthen(3 , var)
int self.ofthen(int n , ref m)
n = n + m.index
return n
end
end
-- -- --
s(:expressions,
s(:class, :Pifi,
s(:derives, nil),
s(:expressions,
s(:call,
s(:name, :ofthen),
s(:arguments,
s(:int, 3),
s(:name, :var))),
s(:function, :int,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :int, :n),
s(:parameter, :ref, :m)),
s(:expressions,
s(:assign,
s(:name, :n),
s(:operator, "+",
s(:name, :n),
s(:field_access,
s(:receiver,
s(:name, :m)),
s(:field,
s(:name, :index))))),
s(:return,
s(:name, :n))),
s(:receiver, :self)))))

View File

@ -0,0 +1,30 @@
class Ifi
int ofthen(int n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
-- -- --
s(:expressions,
s(:class, :Ifi,
s(:derives, nil),
s(:expressions,
s(:function, :int,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:if,
s(:condition,
s(:int, 0)),
s(:if_true,
s(:assign,
s(:name, :isit),
s(:int, 42))),
s(:if_false,
s(:assign,
s(:name, :maybenot),
s(:int, 667)))))))))

View File

@ -0,0 +1,15 @@
class Foo < Object
int test()
43
end
end
-- -- --
s(:expressions,
s(:class, :Foo,
s(:derives, :Object),
s(:expressions,
s(:function, :int,
s(:name, :test),
s(:parameters),
s(:expressions,
s(:int, 43))))))

View File

@ -0,0 +1,17 @@
class Foo
module Boo
funcall(3 , var)
end
end
-- -- --
s(:expressions,
s(:class, :Foo,
s(:derives, nil),
s(:expressions,
s(:module, :Boo,
s(:expressions,
s(:call,
s(:name, :funcall),
s(:arguments,
s(:int, 3),
s(:name, :var))))))))

View File

@ -0,0 +1,21 @@
class Opers
int foo(int x)
int abba = 5
abba + 5
end
end
-- -- --
s(:expressions,
s(:class, :Opers,
s(:derives, nil),
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :int, :x)),
s(:expressions,
s(:field_def, :int, :abba,
s(:int, 5)),
s(:operator, "+",
s(:name, :abba),
s(:int, 5)))))))

View File

@ -0,0 +1,9 @@
class Foo
5
end
-- -- --
s(:expressions,
s(:class, :Foo,
s(:derives, nil),
s(:expressions,
s(:int, 5))))

View File

@ -0,0 +1,6 @@
[42, foo]
-- -- --
s(:expressions,
s(:array,
s(:int, 42),
s(:name, :foo)))

View File

@ -0,0 +1,11 @@
[ 3 + 4 , foo(22) ]
-- -- --
s(:expressions,
s(:array,
s(:operator, "+",
s(:int, 3),
s(:int, 4)),
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 22)))))

View File

@ -0,0 +1,7 @@
{ foo => 33 }
-- -- --
s(:expressions,
s(:hash,
s(:assoc,
s(:name, :foo),
s(:int, 33))))

View File

@ -0,0 +1,7 @@
{ foo => true }
-- -- --
s(:expressions,
s(:hash,
s(:assoc,
s(:name, :foo),
s(:true))))

View File

@ -0,0 +1,10 @@
{foo => 33 , bar => 42}
-- -- --
s(:expressions,
s(:hash,
s(:assoc,
s(:name, :foo),
s(:int, 33)),
s(:assoc,
s(:name, :bar),
s(:int, 42))))

View File

@ -0,0 +1,5 @@
[42]
-- -- --
s(:expressions,
s(:array,
s(:int, 42)))

View File

@ -0,0 +1,14 @@
if(0)
42
else
667
end
-- -- --
s(:expressions,
s(:if,
s(:condition,
s(:int, 0)),
s(:if_true,
s(:int, 42)),
s(:if_false,
s(:int, 667))))

View File

@ -0,0 +1,25 @@
if(3 > var)
Object.initialize(3)
else
var.new(33)
end
-- -- --
s(:expressions,
s(:if,
s(:condition,
s(:operator, ">",
s(:int, 3),
s(:name, :var))),
s(:if_true,
s(:call,
s(:name, :initialize),
s(:arguments,
s(:int, 3)),
s(:receiver,
s(:module, "Object")))),
s(:if_false, s(:call,
s(:name, :new),
s(:arguments,
s(:int, 33)),
s(:receiver,
s(:name, :var))))))

View File

@ -0,0 +1,11 @@
if(0)
42
end
-- -- --
s(:expressions,
s(:if,
s(:condition,
s(:int, 0)),
s(:if_true,
s(:int, 42)),
s(:if_false, nil)))

View File

@ -0,0 +1,18 @@
if(3 > var)
Object.initialize(3)
end
-- -- --
s(:expressions,
s(:if,
s(:condition,
s(:operator, ">",
s(:int, 3),
s(:name, :var))),
s(:if_true,
s(:call,
s(:name, :initialize),
s(:arguments,
s(:int, 3)),
s(:receiver,
s(:module, "Object")))),
s(:if_false, nil)))

View File

@ -0,0 +1,6 @@
a = 5
-- -- --
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 5)))

View File

@ -0,0 +1,6 @@
a = 5
-- -- --
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 5)))

View File

@ -0,0 +1,6 @@
a - b
-- -- --
s(:expressions,
s(:operator, "-",
s(:name, :a),
s(:name, :b)))

View File

@ -0,0 +1,6 @@
a - 5
-- -- --
s(:expressions,
s(:operator, "-",
s(:name, :a),
s(:int, 5)))

View File

@ -0,0 +1,6 @@
a - "st"
-- -- --
s(:expressions,
s(:operator, "-",
s(:name, :a),
s(:string, "st")))

View File

@ -0,0 +1,6 @@
a == true
-- -- --
s(:expressions,
s(:operator, "==",
s(:name, :a),
s(:true)))

View File

@ -0,0 +1,6 @@
5 / 3
-- -- --
s(:expressions,
s(:operator, "/",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,6 @@
5 > 3
-- -- --
s(:expressions,
s(:operator, ">",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,6 @@
5 - 3
-- -- --
s(:expressions,
s(:operator, "-",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,6 @@
5 * 3
-- -- --
s(:expressions,
s(:operator, "*",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,6 @@
5 + 3
-- -- --
s(:expressions,
s(:operator, "+",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,6 @@
5 < 3
-- -- --
s(:expressions,
s(:operator, "<",
s(:int, 5),
s(:int, 3)))

View File

@ -0,0 +1,8 @@
2 + 3 * 4
-- -- --
s(:expressions,
s(:operator, "+",
s(:int, 2),
s(:operator, "*",
s(:int, 3),
s(:int, 4))))

View File

@ -0,0 +1,8 @@
2 * 3 + 4
-- -- --
s(:expressions,
s(:operator, "+",
s(:operator, "*",
s(:int, 2),
s(:int, 3)),
s(:int, 4)))

View File

@ -0,0 +1,8 @@
2 + 3 + 4
-- -- --
s(:expressions,
s(:operator, "+",
s(:operator, "+",
s(:int, 2),
s(:int, 3)),
s(:int, 4)))

View File

@ -0,0 +1,12 @@
int self.length( ref x )
length
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :length),
s(:parameters,
s(:parameter, :ref, :x)),
s(:expressions,
s(:name, :length)),
s(:receiver, :self)))

View File

@ -0,0 +1,50 @@
int fibonaccit(int n)
a = 0
b = 1
while( n > 1 )
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 0)),
s(:assign,
s(:name, :b),
s(:int, 1)),
s(:while,
s(:condition,
s(:operator, ">",
s(:name, :n),
s(:int, 1))),
s(:expressions,
s(:assign,
s(:name, :tmp),
s(:name, :a)),
s(:assign,
s(:name, :a),
s(:name, :b)),
s(:assign,
s(:name, :b),
s(:operator, "+",
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assign,
s(:name, :n),
s(:operator, "-",
s(:name, :n),
s(:int, 1))))))))

View File

@ -0,0 +1,22 @@
int foo(int x)
int a = 5
return a
end
3.foo( 4 )
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :int, :x)),
s(:expressions,
s(:field_def, :int, :a,
s(:int, 5)),
s(:return,
s(:name, :a)))),
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 4)),
s(:receiver,
s(:int, 3))))

View File

@ -0,0 +1,25 @@
ref ofthen(int n)
if(0)
isit = 42
else
maybenot = 667
end
end
-- -- --
s(:expressions,
s(:function, :ref,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:if,
s(:condition,
s(:int, 0)),
s(:if_true,
s(:assign,
s(:name, :isit),
s(:int, 42))),
s(:if_false,
s(:assign,
s(:name, :maybenot),
s(:int, 667)))))))

View File

@ -0,0 +1,10 @@
int foo()
5
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters),
s(:expressions,
s(:int, 5))))

View File

@ -0,0 +1,16 @@
int foo(int x)
int abba = 5
abba + 5
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :int, :x)),
s(:expressions,
s(:field_def, :int, :abba,
s(:int, 5)),
s(:operator, "+",
s(:name, :abba),
s(:int, 5)))))

View File

@ -0,0 +1,19 @@
int retvar(ref n)
int i = n.layout
return i
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :retvar),
s(:parameters,
s(:parameter, :ref, :n)),
s(:expressions,
s(:field_def, :int, :i,
s(:field_access,
s(:receiver,
s(:name, :n)),
s(:field,
s(:name, :layout)))),
s(:return,
s(:name, :i)))))

View File

@ -0,0 +1,25 @@
int retvar(int n)
if( n > 5)
return 10
else
return 20
end
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :retvar),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:if,
s(:condition,
s(:operator, ">",
s(:name, :n),
s(:int, 5))),
s(:if_true,
s(:return,
s(:int, 10))),
s(:if_false,
s(:return,
s(:int, 20)))))))

View File

@ -0,0 +1,26 @@
int retvar(int n )
while( n > 5)
n = n + 1
return n
end
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :retvar),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:while,
s(:condition,
s(:operator, ">",
s(:name, :n),
s(:int, 5))),
s(:expressions,
s(:assign,
s(:name, :n),
s(:operator, "+",
s(:name, :n),
s(:int, 1))),
s(:return,
s(:name, :n)))))))

View File

@ -0,0 +1,12 @@
int foo( int n ,ref m)
n
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :int, :n),
s(:parameter, :ref, :m)),
s(:expressions,
s(:name, :n))))

View File

@ -0,0 +1,29 @@
ref fibonaccit(int n)
a = 0
while(n)
some = 43
other = some * 4
end
end
-- -- --
s(:expressions,
s(:function, :ref,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 0)),
s(:while,
s(:condition,
s(:name, :n)),
s(:expressions,
s(:assign,
s(:name, :some),
s(:int, 43)),
s(:assign,
s(:name, :other),
s(:operator, "*",
s(:name, :some),
s(:int, 4))))))))

View File

@ -0,0 +1,11 @@
int foo(ref x)
5
end
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :ref, :x)),
s(:expressions,
s(:int, 5))))

View File

@ -0,0 +1,11 @@
module Opers
field int abba = 5
field ref baab
end
-- -- --
s(:expressions,
s(:module, :Opers,
s(:expressions,
s(:class_field, :int, :abba,
s(:int, 5)),
s(:class_field, :ref, :baab))))

View File

@ -0,0 +1,17 @@
module Foo
class Bar
funcall(3 , var)
end
end
-- -- --
s(:expressions,
s(:module, :Foo,
s(:expressions,
s(:class, :Bar,
s(:derives, nil),
s(:expressions,
s(:call,
s(:name, :funcall),
s(:arguments,
s(:int, 3),
s(:name, :var))))))))

View File

@ -0,0 +1,23 @@
module Soho
ofthen(3 , var)
int ofthen(int n,ref m )
return 44
end
end
-- -- --
s(:expressions,
s(:module, :Soho,
s(:expressions,
s(:call,
s(:name, :ofthen),
s(:arguments,
s(:int, 3),
s(:name, :var))),
s(:function, :int,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :int, :n),
s(:parameter, :ref, :m)),
s(:expressions,
s(:return,
s(:int, 44)))))))

View File

@ -0,0 +1,29 @@
module Foo
ref ofthen(int n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
-- -- --
s(:expressions,
s(:module, :Foo,
s(:expressions,
s(:function, :ref,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:if,
s(:condition,
s(:int, 0)),
s(:if_true,
s(:assign,
s(:name, :isit),
s(:int, 42))),
s(:if_false,
s(:assign,
s(:name, :maybenot),
s(:int, 667)))))))))

View File

@ -0,0 +1,25 @@
module Opers
int foo(int x)
int abba = self.index
return abba + 5
end
end
-- -- --
s(:expressions,
s(:module, :Opers,
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :int, :x)),
s(:expressions,
s(:field_def, :int, :abba,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :index)))),
s(:return,
s(:operator, "+",
s(:name, :abba),
s(:int, 5))))))))

View File

@ -0,0 +1,8 @@
module Simple
5
end
-- -- --
s(:expressions,
s(:module, :Simple,
s(:expressions,
s(:int, 5))))

View File

@ -0,0 +1,5 @@
return 42
-- -- --
s(:expressions,
s(:return,
s(:int, 42)))

View File

@ -0,0 +1,5 @@
return "hello"
-- -- --
s(:expressions,
s(:return,
s(:string, "hello")))

View File

@ -0,0 +1,5 @@
return foo
-- -- --
s(:expressions,
s(:return,
s(:name, :foo)))

View File

@ -0,0 +1,15 @@
class FooBo
Bar.call(35)
end
-- -- --
s(:expressions,
s(:class, :FooBo,
s(:derives, nil),
s(:expressions,
s(:call,
s(:name, :call),
s(:arguments,
s(:int, 35)),
s(:receiver,
s(:module, "Bar"))))))

View File

@ -0,0 +1,19 @@
int foo(ref x)
a = 5
end
foo( 3 )
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :foo),
s(:parameters,
s(:parameter, :ref, :x)),
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 5)))),
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 3))))

56
test/cases/root/fibo1.tst Normal file
View File

@ -0,0 +1,56 @@
int fibonaccit(int n)
a = 0
b = 1
while( n > 1 )
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
fibonaccit( 10 )
-- -- --
s(:expressions,
s(:function, :int,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:assign,
s(:name, :a),
s(:int, 0)),
s(:assign,
s(:name, :b),
s(:int, 1)),
s(:while,
s(:condition,
s(:operator, ">",
s(:name, :n),
s(:int, 1))),
s(:expressions,
s(:assign,
s(:name, :tmp),
s(:name, :a)),
s(:assign,
s(:name, :a),
s(:name, :b)),
s(:assign,
s(:name, :b),
s(:operator, "+",
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assign,
s(:name, :n),
s(:operator, "-",
s(:name, :n),
s(:int, 1))))))),
s(:call,
s(:name, :fibonaccit),
s(:arguments,
s(:int, 10))))

View File

@ -0,0 +1,20 @@
module Fibo
a = 5 + foo
bar( b , a , r)
end
-- -- --
s(:expressions,
s(:module, :Fibo,
s(:expressions,
s(:assign,
s(:name, :a),
s(:operator, "+",
s(:int, 5),
s(:name, :foo))),
s(:call,
s(:name, :bar),
s(:arguments,
s(:name, :b),
s(:name, :a),
s(:name, :r))))))

View File

@ -0,0 +1,26 @@
module Fibo
int fibonaccit(int n)
int a = 0
return a
end
fibonaccit( 10 )
end
-- -- --
s(:expressions,
s(:module, :Fibo,
s(:expressions,
s(:function, :int,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :int, :n)),
s(:expressions,
s(:field_def, :int, :a,
s(:int, 0)),
s(:return,
s(:name, :a)))),
s(:call,
s(:name, :fibonaccit),
s(:arguments,
s(:int, 10))))))

View File

@ -0,0 +1,18 @@
module FooBo
class Bar
a = 5 + foo
end
end
-- -- --
s(:expressions,
s(:module, :FooBo,
s(:expressions,
s(:class, :Bar,
s(:derives, nil),
s(:expressions,
s(:assign,
s(:name, :a),
s(:operator, "+",
s(:int, 5),
s(:name, :foo))))))))

View File

@ -0,0 +1,35 @@
while( n > 1)
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
-- -- --
s(:expressions,
s(:while,
s(:condition,
s(:operator, ">",
s(:name, :n),
s(:int, 1))),
s(:expressions,
s(:assign,
s(:name, :tmp),
s(:name, :a)),
s(:assign,
s(:name, :a),
s(:name, :b)),
s(:assign,
s(:name, :b),
s(:operator, "+",
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assign,
s(:name, :n),
s(:operator, "-",
s(:name, :n),
s(:int, 1))))))

View File

@ -0,0 +1,17 @@
while(1)
tmp = a
puts(b)
end
-- -- --
s(:expressions,
s(:while,
s(:condition,
s(:int, 1)),
s(:expressions,
s(:assign,
s(:name, :tmp),
s(:name, :a)),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))))))

View File

@ -0,0 +1,23 @@
while(1)
tmp = String.new()
tmp.puts(i)
end
-- -- --
s(:expressions,
s(:while,
s(:condition,
s(:int, 1)),
s(:expressions,
s(:assign,
s(:name, :tmp),
s(:call,
s(:name, :new),
s(:arguments),
s(:receiver,
s(:module, "String")))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :i)),
s(:receiver,
s(:name, :tmp))))))

View File

@ -1,21 +1,87 @@
require_relative "setup"
require "ast"
require "parslet/convenience"
# Included in parser test will create tests methods
# Older test harness
module ParserHelper
include AST::Sexp
def self.included(base)
# base.send :include, InstanceMethods #provides helpers and setup
base.send :include, InstanceMethods #provides helpers and setup
base.send :include, AST::if_true
base.send :extend, ClassMethods #gets the method creation going
end
def setup
@parser = Bosl
module InstanceMethods
def setup
@parser = Parser::Salama.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
def check_write test
dirname = decamelize(self.class.name)[10 .. -1]
test = test[5 .. -1]
syntax = @parser.parse_with_debug(@string_input)
out = Parser::Transform.new.apply(syntax).inspect
dir = File.dirname(__FILE__) + "/" + dirname
FileUtils.mkdir_p(dir) unless File.exists?(dir)
out_file = File.new(dir + "/" + test + ".tst", "w")
out_file.puts @string_input
out_file.puts "-- -- --"
out_file.puts out
out_file.close
end
def decamelize str
str.gsub(/(^|[a-z])([A-Z])/) do
($1.empty?)? $2 : "#{$1}_#{$2}"
end.downcase
end
def camelize str
str.gsub(/(^|_)([a-z])/) { $2.upcase }
end
end
def check rule = :root
parse = @parser.parse(@input , :root => rule)
assert_equal @input , parse
assert_equal @output , parse.value
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|
["write"].each do |what|
name = "#{test}_#{what}"
tests << name
self.send(:define_method, name ) do
send(test)
send("check_#{what}" , test)
end
end
end
tests
end
end
end

View File

@ -1,11 +0,0 @@
require_relative "test_basic"
require_relative "test_call_site"
require_relative "test_class"
require_relative "test_compound"
require_relative "test_conditional"
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,56 +0,0 @@
require_relative "../parser_helper"
class RootTestBasic < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_number
@input = '42 '
@output = Ast::ExpressionList.new( [Ast::IntegerExpression.new(42)])
end
def test_name
@input = 'foo '
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:foo)])
end
def test_name_underscode_start
@input = '_bar '
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:_bar)])
end
def test_name_underscode_middle
@input = 'foo_bar '
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:foo_bar)])
end
def test_instance_variable
@input = '@foo_bar '
@output = Ast::ExpressionList.new( [Ast::VariableExpression.new(:foo_bar)])
end
def test_module_name
@input = 'FooBar '
@output = Ast::ExpressionList.new( [Ast::ModuleName.new(:FooBar)])
end
def ttest_comment
out = "# i am a comment \n"
@input = out.dup #NEEDS the return, which is what delimits the comment
@output = @parse_output #dont transform
end
def test_string
@input = "\"hello\""
@parse_output = {:expression_list=>[{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}]}
@output = Ast::ExpressionList.new( [Ast::StringExpression.new("hello")])
end
def test_string_escapes
out = 'hello \nyou'
@input = '"' + out + '"'
@parse_output = {:expression_list=>[{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}, {:char=>" "}, {:char=>" "}, {:esc=>"n"}, {:char=>"y"}, {:char=>"o"}, {:char=>"u"}]}]}
@output = Ast::ExpressionList.new( [Ast::StringExpression.new(out)])
end
end

View File

@ -1,33 +0,0 @@
require_relative "../parser_helper"
class RootTestBlock < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def pest_block
@input = <<HERE
self.call(1) do |a , b|
tmp = a
puts(b)
end
HERE
@parse_output = nil
@output = nil
@root = :
end
def pest_big_block
@input = <<HERE
self.call( true , false) do | a , b |
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [Ast::BlockExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )])
@root = :
end
end

View File

@ -1,111 +0,0 @@
require_relative "../parser_helper"
class RootTestCallSite < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_single_argument
@input = 'foo(42)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_single_self
@input = 'self.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:name=>"self"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_single_instance
@input = '@var.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:instance_variable=>{:name=>"var"}}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::VariableExpression.new(:var))])
@root = :
end
def test_single_name
@input = 'my_my.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:name=>"my_my"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:my_my))])
@root = :
end
def test_int_receiver
@input = '42.put()'
@parse_output = {:expression_list=>[{:receiver=>{:integer=>"42"}, :call_site=>{:name=>"put"}, :argument_list=>[]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:put, [] ,Ast::IntegerExpression.new(42))])
@root = :
end
def test_string_receiver
@input = '"hello".puts()'
@parse_output = {:expression_list=>[{:receiver=>{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}, :call_site=>{:name=>"puts"}, :argument_list=>[]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [] ,Ast::StringExpression.new("hello"))])
@root = :
end
def test_single_class
@input = 'Object.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:module_name=>"Object"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::ModuleName.new(:Object))])
@root = :
end
def test_call_site_multi
@input = 'baz(42, foo)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"baz"}, :argument_list=>[{:argument=>{:integer=>"42"}}, {:argument=>{:name=>"foo"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:baz, [Ast::IntegerExpression.new(42),Ast::NameExpression.new(:foo)] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_site_string
@input = 'puts( "hello")'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::StringExpression.new("hello")] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_operator
@input = 'puts( 3 + 5)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5))] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_two_operators
@input = 'puts(3 + 5 , a - 3)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}, {:argument=>{:l=>{:name=>"a"}, :o=>"- ", :r=>{:integer=>"3"}}}]}]}
@output = Ast::ExpressionList.new( [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))] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_chaining
@input = 'puts(putint(3 + 5 ), a - 3)'
@parse_output = {:expression_list=>[{: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"}}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::CallSiteExpression.new(:putint, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5))] ,Ast::NameExpression.new(:self)),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(3))] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_chaining_name
@input = 'puts(name.putint(4), a)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:receiver=>{:name=>"name"}, :call_site=>{:name=>"putint"}, :argument_list=>[{:argument=>{:integer=>"4"}}]}}, {:argument=>{:name=>"a"}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::CallSiteExpression.new(:putint, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new(:name)),Ast::NameExpression.new(:a)] ,Ast::NameExpression.new(:self))])
@root = :
end
def test_call_chaining_class
@input = 'Class.new(self.get(4))'
@parse_output = {:expression_list=>[{:receiver=>{:module_name=>"Class"}, :call_site=>{:name=>"new"}, :argument_list=>[{:argument=>{:receiver=>{:name=>"self"}, :call_site=>{:name=>"get"}, :argument_list=>[{:argument=>{:integer=>"4"}}]}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new(:self))] ,Ast::ModuleName.new(:Class))])
@root = :
end
def test_call_chaining_instance
@input = '@class.new(self.get(4))'
@parse_output = {:expression_list=>[{:receiver=>{:instance_variable=>{:name=>"class"}}, :call_site=>{:name=>"new"}, :argument_list=>[{:argument=>{:receiver=>{:name=>"self"}, :call_site=>{:name=>"get"}, :argument_list=>[{:argument=>{:integer=>"4"}}]}}]}]}
@output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new(:self))] ,Ast::VariableExpression.new(:class))])
@root = :
end
end

View File

@ -1,90 +0,0 @@
require_relative "../parser_helper"
class RootTestClassDef < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_class
@input = <<HERE
class Foo
5
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>nil, :class_expressions=>[{:integer=>"5"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,nil, [Ast::IntegerExpression.new(5)] )])
end
def test_class_ops
@input = <<HERE
class Opers
def foo(x)
@abba = 5
2 + 5
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Opers", :derived_name=>nil, :class_expressions=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Opers ,nil, [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )] )])
end
def test_class_if
@input = <<HERE
class Ifi
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Ifi", :derived_name=>nil, :class_expressions=>[{:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Ifi ,nil, [Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )] )])
end
def test_class_function
@input = <<HERE
class Pifi
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Pifi", :derived_name=>nil, :class_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}, {:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{:name=>"n"}}, {:parameter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Pifi ,nil, [Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self)), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n),Ast::NameExpression.new(:m)] , [Ast::IntegerExpression.new(44)] ,nil )] )])
end
def test_class_module
@input = <<HERE
class Foo
module Boo
funcall(3+4 , var)
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>nil, :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"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,nil, [Ast::ModuleExpression.new(:Boo ,[Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )] )])
end
def test_class_derived
@input = <<HERE
class Foo < Object
ofthen(3+4 , var)
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>{:module_name=>"Object"}, :class_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,:Object, [Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )])
end
def test_class_method
@input = <<HERE
class Foo < Object
def Foo.test()
43
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>{:module_name=>"Object"}, :class_expressions=>[{:receiver=>{:module_name=>"Foo"}, :function_name=>{:name=>"test"}, :parameter_list=>[], :expressions=>[{:integer=>"43"}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,:Object, [Ast::FunctionExpression.new(:test, [] , [Ast::IntegerExpression.new(43)] ,Ast::ModuleName.new(:Foo) )] )])
end
end

View File

@ -1,43 +0,0 @@
require_relative "../parser_helper"
class RootTestCompound < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_one_array
@input = '[42]'
@parse_output = {:expression_list=>[{:array_constant=>[{:array_element=>{:integer=>"42"}}]}]}
@output = Ast::ExpressionList.new( [Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)])])
end
def test_array_list
@input = '[42, foo]'
@parse_output = {:expression_list=>[{:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:name=>"foo"}}]}]}
@output = Ast::ExpressionList.new( [Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new(:foo)])])
end
def test_array_ops
@input = '[ 3 + 4 , foo(22) ]'
@parse_output = {:expression_list=>[{:array_constant=>[{:array_element=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"4"}}}, {:array_element=>{:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"22"}}]}}]}]}
@output = Ast::ExpressionList.new( [Ast::ArrayExpression.new([Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)), Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(22)] ,Ast::NameExpression.new(:self))])])
end
def test_hash
@input = '{ foo => 33 }'
@parse_output = {:expression_list=>[{:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}]}]}
@output = Ast::ExpressionList.new( [Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new(:foo) , Ast::IntegerExpression.new(33))])])
end
def test_hash2
@input = '{ foo => true }'
@parse_output = {:expression_list=>[{:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:true=>"true"}}}]}]}
@output = Ast::ExpressionList.new( [Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new(:foo) , Ast::TrueExpression.new())])])
end
def test_hash_list
@input = "{foo => 33 , bar => 42}"
@parse_output = {:expression_list=>[{:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}, {:hash_pair=>{:hash_key=>{:name=>"bar"}, :hash_value=>{:integer=>"42"}}}]}]}
@output = Ast::ExpressionList.new( [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))])])
end
end

View File

@ -1,70 +0,0 @@
require_relative "../parser_helper"
class RootTestConditional < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_if_else
@input = <<HERE
if(0)
42
else
667
end
HERE
@parse_output = {:expression_list=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}}]}
@output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@root = :
end
def test_if_else_expressions
@input = <<HERE
if(3 > var)
Object.initialize(3)
else
var.new(33)
end
HERE
@input
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [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))] )])
end
def pest_if_end
@input = <<HERE
if(0)
42
end
HERE
@parse_output = {:expression_list=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}}]}
@output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@root = :
end
def pest_if_end_expressions
@input = <<HERE
if(3 > var)
Object.initialize(3)
end
HERE
@input
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [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))] )])
end
def pest_if_reverse
@input = "42 if(0)"
@parse_output = {:expression_list=>[{:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}}]}
@output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@root = :
end
def pest_if_end_expressions
@input = "Object.initialize(3) if(3 > var)"
@input
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [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))] )])
end
end

View File

@ -1,164 +0,0 @@
require_relative "../parser_helper"
class RootTestFunctionDefinition < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_function
@input = <<HERE
def foo(x)
5
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:integer=>"5"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::IntegerExpression.new(5)] ,nil )])
@root = :
end
def test_function_no_braces
@input = <<HERE
def foo
5
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :expressions=>[{:integer=>"5"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [] , [Ast::IntegerExpression.new(5)] ,nil )])
@root = :
end
def pest_function_no_braces_and_args
@input = <<HERE
def foo n , m
n
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :expressions=>[{:name=>"n"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [] , [Ast::NameExpression.new(:n)] ,nil )])
@root = :
end
def test_class_function
@input = <<HERE
def String.length(x)
@length
end
HERE
@parse_output = {:expression_list=>[{:receiver=>{:module_name=>"String"}, :function_name=>{:name=>"length"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:instance_variable=>{:name=>"length"}}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:length, [Ast::NameExpression.new(:x)] , [Ast::VariableExpression.new(:length)] ,Ast::ModuleName.new(:String) )])
@root = :
end
def pest_function_default_args
@input = <<HERE
def foo(x = true )
abba = 5
2 + 5
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )])
@root = :
end
def test_function_ops
@input = <<HERE
def foo(x)
abba = 5
2 + 5
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )])
@root = :
end
def test_function_if
@input = <<HERE
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )])
@root = :
end
def test_function_return
@input = <<HERE
def retvar(n)
i = 5
return i
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"i"}, :o=>"= ", :r=>{:integer=>"5"}}, {:return=>"return", :return_expression=>{:name=>"i"}}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:i),Ast::IntegerExpression.new(5)),Ast::ReturnExpression.new(Ast::NameExpression.new(:i) )] ,nil )])
@root = :
end
def test_function_return_if
@input = <<HERE
def retvar(n)
if( n > 5)
return 10
else
return 20
end
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [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) )] )] ,nil )])
@root = :
end
def test_function_return_while
@input = <<HERE
def retvar(n)
while( n > 5) do
n = n + 1
return n
end
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(5)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("+", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1))), Ast::ReturnExpression.new(Ast::NameExpression.new(:n) )] )] ,nil )])
@root = :
end
def test_function_while
@input = <<HERE
def fibonaccit(n)
a = 0
while (n) do
some = 43
other = some * 4
end
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"fibonaccit"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::WhileExpression.new(Ast::NameExpression.new(:n), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:some),Ast::IntegerExpression.new(43)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:other),Ast::OperatorExpression.new("*", Ast::NameExpression.new(:some),Ast::IntegerExpression.new(4)))] )] ,nil )])
@root = :
end
def test_function_big_while
@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 = {:expression_list=>[{:function_name=>{:name=>"fibonaccit"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::AssignmentExpression.new(Ast::NameExpression.new(:b),Ast::IntegerExpression.new(1)),Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )] ,nil )])
@root = :
end
end

View File

@ -1,92 +0,0 @@
require_relative "../parser_helper"
class RootTestModuleDef < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_module
@input = <<HERE
module Simple
5
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Simple", :module_expressions=>[{:integer=>"5"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Simple ,[Ast::IntegerExpression.new(5)] )])
end
def test_module_ops
@input = <<HERE
module Opers
def foo(x)
abba = 5
2 + 5
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Opers", :module_expressions=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )] )])
end
def test_module_assign_instance
@input = <<HERE
module Opers
@abba = 5
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Opers", :module_expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Opers ,[Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5))] )])
end
def test_module_if
@input = <<HERE
module Foo
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :module_expressions=>[{:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{: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"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Foo ,[Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )] )])
end
def test_module_function
@input = <<HERE
module Soho
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:expression_list=>[{: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"}, :parameter_list=>[{:parameter=>{:name=>"n"}}, {:parameter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Soho ,[Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self)), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n),Ast::NameExpression.new(:m)] , [Ast::IntegerExpression.new(44)] ,nil )] )])
end
def test_function_without_braces
@input = <<HERE
class Foo
def bar
4
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>nil, :class_expressions=>[{:function_name=>{:name=>"bar"}, :expressions=>[{:integer=>"4"}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,nil, [Ast::FunctionExpression.new(:bar, [] , [Ast::IntegerExpression.new(4)] ,nil )] )])
end
def test_module_class
@input = <<HERE
module Foo
class Bar
funcall(3+4 , var)
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :module_expressions=>[{:module_name=>"Bar", :derived_name=>nil, :class_expressions=>[{:call_site=>{:name=>"funcall"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Foo ,[Ast::ClassExpression.new(:Bar ,nil, [Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )] )])
end
end

View File

@ -1,81 +0,0 @@
require_relative "../parser_helper"
class RootTestExpressions < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def simple_op op
@input = "5 #{op} 3"
@parse_output = {:expression_list=>[{:l=>{:integer=>"5"}, :o=>"#{op} ", :r=>{:integer=>"3"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new(op, Ast::IntegerExpression.new(5),Ast::IntegerExpression.new(3))])
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
@input = "a + 35"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"+ ", :r=>{:integer=>"35"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("+", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(35))])
end
def test_op_two_variable
@input = "a - b"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"- ", :r=>{:name=>"b"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::NameExpression.new(:b))])
end
def test_op_instance_variable
@input = "@a - 5"
@parse_output = {:expression_list=>[{:l=>{:instance_variable=>{:name=>"a"}}, :o=>"- ", :r=>{:integer=>"5"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))])
end
def test_op_variable_string
@input = 'a - "st"'
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"- ", :r=>{:string=>[{:char=>"s"}, {:char=>"t"}]}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::StringExpression.new("st"))])
end
def test_op_variable_true
@input = 'a == true'
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"== ", :r=>{:true=>"true"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("==", Ast::NameExpression.new(:a),Ast::TrueExpression.new())])
end
def test_two_same_ops
@input = '2 + 3 + 4'
@parse_output = {:expression_list=>[{:l=>{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))])
end
def test_two_different_ops
@input = '2 + 3 * 4'
@parse_output = {:expression_list=>[{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:l=>{:integer=>"3"}, :o=>"* ", :r=>{:integer=>"4"}}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)))])
end
def test_two_different_ops_order
@input = '2 * 3 + 4'
@parse_output = {:expression_list=>[{:l=>{:l=>{:integer=>"2"}, :o=>"* ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}]}
@output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))])
end
def test_assignment
@input = "a = 5"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}]}
@output = Ast::ExpressionList.new( [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5))])
end
def test_assignment_instance
@input = "@a = 5"
@parse_output = {:expression_list=>[{:l=>{:instance_variable=>{:name=>"a"}}, :o=>"= ", :r=>{:integer=>"5"}}]}
@output = Ast::ExpressionList.new( [Ast::AssignmentExpression.new(Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))])
end
end

View File

@ -1,25 +0,0 @@
require_relative "../parser_helper"
class RootTestReturn < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_return_int
@input = 'return 42'
@parse_output = {:expression_list=>[{:name=>"return"}, {:integer=>"42"}]}
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:return),Ast::IntegerExpression.new(42)])
end
def test_return_variable
@input = 'return foo'
@parse_output = {:expression_list=>[{:name=>"return"}, {:name=>"foo"}]}
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:return),Ast::NameExpression.new(:foo)])
end
def test_return_string
@input = 'return "hello"'
@parse_output = {:expression_list=>[{:name=>"return"}, {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}]}
@output = Ast::ExpressionList.new( [Ast::NameExpression.new(:return),Ast::StringExpression.new("hello")])
end
end

View File

@ -1,111 +0,0 @@
require_relative "../parser_helper"
class RootTestRoot < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_double_root
@input = <<HERE
def foo(x)
a = 5
end
foo( 3 )
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}], :end=>"end"}, {:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5))] ,nil ),Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(3)] ,Ast::NameExpression.new(:self))])
end
def test_comments
@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 = {:expression_list=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{: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"}}]}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::AssignmentExpression.new(Ast::NameExpression.new(:b),Ast::IntegerExpression.new(1)),Ast::WhileExpression.new(Ast::OperatorExpression.new("<", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::NameExpression.new(:self)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )] ,nil ),Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(3)] ,Ast::NameExpression.new(:self))])
end
def test_fibo1
@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 = {:expression_list=>[{:function_name=>{:name=>"fibonaccit"}, :parameter_list=>[{:parameter=>{: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"}}]}]}
@output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::AssignmentExpression.new(Ast::NameExpression.new(:b),Ast::IntegerExpression.new(1)),Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )] ,nil ),Ast::CallSiteExpression.new(:fibonaccit, [Ast::IntegerExpression.new(10)] ,Ast::NameExpression.new(:self))])
end
def test_module_method
@input = <<HERE
module Fibo
def fibonaccit(n)
a = 0
end
fibonaccit( 10 )
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Fibo", :module_expressions=>[{:function_name=>{:name=>"fibonaccit"}, :parameter_list=>[{:parameter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"0"}}], :end=>"end"}, {:call_site=>{:name=>"fibonaccit"}, :argument_list=>[{:argument=>{:integer=>"10"}}]}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Fibo ,[Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0))] ,nil ), Ast::CallSiteExpression.new(:fibonaccit, [Ast::IntegerExpression.new(10)] ,Ast::NameExpression.new(:self))] )])
end
def test_module_assignment
@input = <<HERE
module Fibo
a = 5 + foo
bar( b , a , r)
end
HERE
@parse_output = {:expression_list=>[{: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"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Fibo ,[Ast::AssignmentExpression.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)] ,Ast::NameExpression.new(:self))] )])
end
def test_root_module_class
@input = <<HERE
module FooBo
class Bar
a = 5 + foo
end
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"FooBo", :module_expressions=>[{:module_name=>"Bar", :derived_name=>nil, :class_expressions=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:l=>{:integer=>"5"}, :o=>"+ ", :r=>{:name=>"foo"}}}], :end=>"end"}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:FooBo ,[Ast::ClassExpression.new(:Bar ,nil, [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(5),Ast::NameExpression.new(:foo)))] )] )])
end
def test_class_method
@input = <<HERE
class FooBo
Bar.call(35)
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"FooBo", :derived_name=>nil, :class_expressions=>[{:receiver=>{:module_name=>"Bar"}, :call_site=>{:name=>"call"}, :argument_list=>[{:argument=>{:integer=>"35"}}]}], :end=>"end"}]}
@output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:FooBo ,nil, [Ast::CallSiteExpression.new(:call, [Ast::IntegerExpression.new(35)] ,Ast::ModuleName.new(:Bar))] )])
end
end

View File

@ -1,52 +0,0 @@
require_relative "../parser_helper"
class RootTestWhile < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_while
@input = <<HERE
while(1) do
tmp = a
puts(b)
end
HERE
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )])
@root = :
end
def pest_while_reverse
@input = "puts '1' while true "
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )])
@root = :
end
def test_while_method
@input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.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))] )])
@root = :
end
def test_big_while
@input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@parse_output = {:expression_list=>[{: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"}}]}
@output = Ast::ExpressionList.new( [Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )])
@root = :
end
end

View File

@ -1,2 +1,48 @@
require_relative "unit/test_all"
#require_relative "roots/test_all"
require_relative "setup"
require "parslet/convenience"
require "ast/sexp"
require "pp"
class TestAll < MiniTest::Test
include AST::Sexp
SEPERATOR = "-- -- --"
def check_file file
inn , out = File.new(file).read.split(SEPERATOR)
sexp = eval(out)
syntax = Parser::Salama.new.parse_with_debug(inn)
result = Parser::Transform.new.apply(syntax)
equal = (sexp == result)
unless equal
if ENV["FIX"]
out_file = File.new(file, "w")
out_file.puts inn
out_file.puts SEPERATOR
out_file.puts result.inspect
out_file.close
puts "Fixed #{file}"
sexp = result
else
pp syntax
puts result.inspect
end
end
assert_equal sexp , result
end
# 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 self.runnable_methods
all = Dir["test/cases/*/*.tst"]
tests =[]
all.each do |file|
name = file.sub("test/cases/","").sub("/","_").sub(".tst","")
tests << name
self.send(:define_method, name ) do
send("check_file" , file)
end
end
tests
end
end

View File

@ -1,13 +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_while"

View File

@ -1,37 +0,0 @@
require_relative "../parser_helper"
class TestArguments < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_one_argument
@input = '(42)'
@parse_output = {:argument_list => [{:argument => {:integer => '42'}}] }
@output = [Ast::IntegerExpression.new(42) ]
@root = :argument_list
end
def test_argument_list
@input = '(42, foo)'
@parse_output = {:argument_list => [{:argument => {:integer => '42'}},
{:argument => {:name => 'foo'}}]}
@output = [Ast::IntegerExpression.new(42), Ast::NameExpression.new('foo')]
@root = :argument_list
end
def test_parameter
@input = "(foo)"
@parse_output = {:parameter_list=>[{:parameter=>{:name=>"foo"}}]}
@output = [Ast::NameExpression.new('foo')]
@root = :parameter_list
end
def test_parameter_list
@input = "( foo , bar)"
@parse_output = {:parameter_list => [{:parameter => { :name => "foo"}},
{:parameter => { :name => "bar"}} ]}
@output = [Ast::NameExpression.new('foo') , Ast::NameExpression.new('bar')]
@root = :parameter_list
end
end

View File

@ -1,68 +0,0 @@
require_relative "../parser_helper"
class TestBasic < MiniTest::Test
#test basics and keyword expressions. Keywords includes BasicTypes
include ParserHelper
def test_true
@input = 'true '
@output = s(:true)
check :keyword_true
end
def test_false
@input = 'false '
@output = s(:false)
check :keyword_false
end
def test_nil
@input = 'nil '
@output = s(:nil)
check :keyword_nil
end
def test_integer
@input = '42 '
@output = s(:int , 42)
check :integer_expression
end
def test_name
@input = 'foo '
@output = 'foo'
check :name_expression
end
def test_name_underscode_start
@input = '_bar '
@output = '_bar'
check :name_expression
end
def test_name_underscode_middle
@input = 'foo_bar '
@output = 'foo_bar'
check :name_expression
end
def test_module_name
@input = 'FooBar '
@output = s(:aspect , "FooBar")
check :aspect_name_expression
end
def test_string
@input = '"hello"'
@output = s(:string , 'hello')
check :string_expression
end
def test_string_escapes
out = 'hello \nyou'
@input = '"' + out + '"'
@output = s(:string , out)
check :string_expression
end
end

View File

@ -1,48 +0,0 @@
require_relative "../parser_helper"
class TestBlock < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def pest_block
@input = <<HERE
while(1) do
tmp = a
puts(b)
end
HERE
@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"}}
@output = Ast::BlockExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )
@root = :block
end
def pest_block_method
@input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@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"}}
@output = Ast::BlockExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.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))] )
@root = :block
end
def pest_big_block
@input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@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"}}
@output = Ast::BlockExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )
@root = :block
end
end

View File

@ -1,43 +0,0 @@
require_relative "../parser_helper"
class TestCallSite < MiniTest::Test
include ParserHelper
def test_single_self
@input = 'self.foo(42)'
@output = s(:call, s(:field , "self" , "foo") , [s(:int, 42)])
check :call_site
end
def test_single_name
@input = 'my_my.foo(42)'
@parse_output = {:receiver=>{:name=>"my_my"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}
@output = s(:call, s(:field, "my_my", "foo"), [s(:int, 42)])
check :call_site
end
def test_int_receiver
@input = '42.put()'
@output = s(:call, s(:field, s(:int , 42) , "put") , [])
check :call_site
end
def test_string_receiver
@input = '"hello".puts()'
@output = s(:call , s(:field , s(:string , "hello") , "puts") , [])
check :call_site
end
def test_call_site_2
@input = 'self.baz(42, foo)'
@output = s(:call ,s(:field , "self", "baz") , [s(:int, 42), "foo"])
check :call_site
end
def test_call_site_3
@input = 'self.baz(42, foo , bar)'
@output = s(:call, s(:field, "self", "baz"), [s(:int, 42), "foo", "bar"])
check :call_site
end
end

View File

@ -1,97 +0,0 @@
require_relative "../parser_helper"
class TestClassDef < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_class
@input = <<HERE
class Foo
5
end
HERE
@parse_output = {:module_name=>"Foo", :derived_name=>nil, :class_expressions=>[{:integer=>"5"}], :end=>"end"}
@output = Ast::ClassExpression.new(:Foo ,nil, [Ast::IntegerExpression.new(5)] )
@root = :class_definition
end
def test_class_ops
@input = <<HERE
class Opers
def foo(x)
@abba = 5
2 + 5
end
end
HERE
@parse_output = {:module_name=>"Opers", :derived_name=>nil, :class_expressions=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"}
@output = Ast::ClassExpression.new(:Opers ,nil, [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )] )
@root = :class_definition
end
def test_class_if
@input = <<HERE
class Ifi
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:module_name=>"Ifi", :derived_name=>nil, :class_expressions=>[{:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::ClassExpression.new(:Ifi ,nil, [Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )] )
@root = :class_definition
end
def test_class_function
@input = <<HERE
class Pifi
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:module_name=>"Pifi", :derived_name=>nil, :class_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}, {:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{:name=>"n"}}, {:parameter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"}
@output = Ast::ClassExpression.new(:Pifi ,nil, [Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self)), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n),Ast::NameExpression.new(:m)] , [Ast::IntegerExpression.new(44)] ,nil )] )
@root = :class_definition
end
def test_class_module
@input = <<HERE
class Foo
module Boo
funcall(3+4 , var)
end
end
HERE
@parse_output = {:module_name=>"Foo", :derived_name=>nil, :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"}
@output = Ast::ClassExpression.new(:Foo ,nil, [Ast::ModuleExpression.new(:Boo ,[Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )] )
@root = :class_definition
end
def test_class_derived
@input = <<HERE
class Foo < Object
ofthen(3+4 , var)
end
HERE
@parse_output = {:module_name=>"Foo", :derived_name=>{:module_name=>"Object"}, :class_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}], :end=>"end"}
@output = Ast::ClassExpression.new(:Foo ,:Object, [Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )
@root = :class_definition
end
def test_class_method
@input = <<HERE
class Foo < Object
def Foo.test()
43
end
end
HERE
@parse_output = {:module_name=>"Foo", :derived_name=>{:module_name=>"Object"}, :class_expressions=>[{:receiver=>{:module_name=>"Foo"}, :function_name=>{:name=>"test"}, :parameter_list=>[], :expressions=>[{:integer=>"43"}], :end=>"end"}], :end=>"end"}
@output = Ast::ClassExpression.new(:Foo ,:Object, [Ast::FunctionExpression.new(:test, [] , [Ast::IntegerExpression.new(43)] ,Ast::ModuleName.new(:Foo) )] )
@root = :class_definition
end
end

View File

@ -1,51 +0,0 @@
require_relative "../parser_helper"
class TestCompound < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_one_array
@input = '[42]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}]}
@output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)])
@root = :array_constant
end
def test_array_list
@input = '[42, foo]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:name=>"foo"}}]}
@output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new("foo")])
@root = :array_constant
end
def test_array_list2
@input = '[42, nil]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:nil=>"nil"}}]}
@output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NilExpression.new()])
@root = :array_constant
end
def test_array_ops
@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"}}]}}]}
@output = Ast::ArrayExpression.new(
[Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),
Ast::CallSiteExpression.new("foo", [Ast::IntegerExpression.new(22)] )])
@root = :array_constant
end
def test_hash
@input = '{ foo => 33 }'
@parse_output = {:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}]}
@output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33))])
@root = :hash_constant
end
def test_hash_list
@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"}}}]}
@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))])
@root = :hash_constant
end
end

View File

@ -1,74 +0,0 @@
require_relative "../parser_helper"
class TestConditional < MiniTest::Test
include ParserHelper
def test_assignment
@input = "myvar = 42"
@output = s(:assign, :myvar, s(:int, 42))
check :assignment
end
def test_variable_declaration
@input = "int myvar"
@output = s(:variable,s(:type, "int", "myvar"), nil)
check :variable_definition
end
def test_variable_declaration_value
@input = "int myvar = 42"
@output = s(:variable, s(:type, "int", "myvar"), s(:int, 42))
check :variable_definition
end
def test_if
@input = <<HERE
if( 1 )
int num = 42
end
HERE
@output = s(:if, s(:cond, s(:int, 1)), s(:then, [s(:variable,
s(:type, "int", "num"),
s(:int, 42))]))
check :conditional
end
def test_conditional_with_calls
@input = <<HERE
if(var)
42.add(5)
end
HERE
@output = s(:if,
s(:cond, "var"),
s(:then, [s(:call, s(:field, s(:int, 42), "add"), [s(:int, 5)])]))
check :conditional
end
def ttest_conditional_nil
@input = <<HERE
if(3 == nil)
3
else
4
end
HERE
@input.chop!
@parse_output = {:if=>"if", :conditional=>{:l=>{:integer=>"3"}, :o=>"== ", :r=>{:nil=>"nil"}}, :if_true=>{:expressions=>[{:integer=>"3"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"4"}], :end=>"end"}}
@output = nil
@root = :conditional
end
def pest_simple_if
@input = <<HERE
if(3 == nil)
3
end
HERE
@input.chop!
@parse_output = {:if=>"if", :conditional=>{:l=>{:integer=>"3"}, :o=>"== ", :r=>{:nil=>"nil"}}, :if_true=>{:expressions=>[{:integer=>"3"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"4"}], :end=>"end"}}
@output = nil
@root = :conditional
end
end

View File

@ -1,40 +0,0 @@
require_relative "../parser_helper"
class TestExpressions < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_expression_else
@input = <<HERE
dud
fuu(3)
else
HERE
@input.chop!
@parse_output = {:expressions=>[{:name=>"dud"},
{:call_site=>{:name=>"fuu"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}],
:else=>"else"}
@output ={:expressions=>[Ast::NameExpression.new("dud"),
Ast::CallSiteExpression.new("fuu", [Ast::IntegerExpression.new(3)] )], :else=>"else"}
@root = :expressions_else
end
def test_expression_end
@input = <<HERE
name
call(4,6)
end
HERE
@input.chop!
@parse_output = {:expressions=>[{:name=>"name"},
{:call_site=>{:name=>"call"}, :argument_list=>[{:argument=>{:integer=>"4"}}, {:argument=>{:integer=>"6"}}]}],
:end=>"end"}
@output = {:expressions=>[Ast::NameExpression.new("name"),
Ast::CallSiteExpression.new("call", [Ast::IntegerExpression.new(4),Ast::IntegerExpression.new(6)] )],
:end=>"end"}
@root = :expressions_end
end
end

View File

@ -1,26 +0,0 @@
require_relative "../parser_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
@input = <<HERE
class Foo
def bar
4
end
end
HERE
@parse_output = nil
@output = nil
@root = :root
end
end

View File

@ -1,130 +0,0 @@
require_relative "../parser_helper"
class TestFunctionDefinition < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_function
@input = <<HERE
def foo(x)
5
end
HERE
@parse_output = {:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:integer=>"5"}], :end=>"end"}
@output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::IntegerExpression.new(5)] )
@root = :function_definition
end
def test_class_function
@input = <<HERE
def String.length(x)
@length
end
HERE
@parse_output = {:receiver=>{:module_name=>"String"}, :function_name=>{:name=>"length"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:instance_variable=>{:name=>"length"}}], :end=>"end"}
@output = Ast::FunctionExpression.new(:length, [Ast::NameExpression.new("x")] , [Ast::VariableExpression.new(:length)] ,Ast::ModuleName.new("String") )
@root = :function_definition
end
def test_function_ops
@input = <<HERE
def foo(x)
abba = 5
2 + 5
end
HERE
@parse_output = {:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}
@output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )
@root = :function_definition
end
def test_function_if
@input = <<HERE
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
HERE
@parse_output = {:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )
@root = :function_definition
end
def test_function_return
@input = <<HERE
def retvar(n)
i = 5
return i
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"i"}, :o=>"= ", :r=>{:integer=>"5"}}, {:return=>"return", :return_expression=>{:name=>"i"}}], :end=>"end"}
@output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:i),Ast::IntegerExpression.new(5)),Ast::ReturnExpression.new(Ast::NameExpression.new(:i) )] ,nil )
@root = :function_definition
end
def test_function_return_if
@input = <<HERE
def retvar(n)
if( n > 5)
return 10
else
return 20
end
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{: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"}
@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) )] )] )
@root = :function_definition
end
def test_function_return_while
@input = <<HERE
def retvar(n)
while( n > 5) do
n = n + 1
return n
end
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(5)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("+", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1))), Ast::ReturnExpression.new(Ast::NameExpression.new(:n) )] )] ,nil )
@root = :function_definition
end
def test_function_while
@input = <<HERE
def fibonaccit(n)
a = 0
while (n) do
some = 43
other = some * 4
end
end
HERE
@parse_output = {:function_name=>{:name=>"fibonaccit"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::WhileExpression.new(Ast::NameExpression.new(:n), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:some),Ast::IntegerExpression.new(43)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:other),Ast::OperatorExpression.new("*", Ast::NameExpression.new(:some),Ast::IntegerExpression.new(4)))] )] ,nil )
@root = :function_definition
end
def test_function_big_while
@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"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::FunctionExpression.new(:fibonaccit, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(0)),Ast::AssignmentExpression.new(Ast::NameExpression.new(:b),Ast::IntegerExpression.new(1)),Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )] ,nil )
@root = :function_definition
end
end

View File

@ -1,86 +0,0 @@
require_relative "../parser_helper"
class TestModuleDef < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_module
@input = <<HERE
module Simple
5
end
HERE
@parse_output = {:module_name=>"Simple", :module_expressions=>[{:integer=>"5"}], :end=>"end"}
@output = Ast::ModuleExpression.new(:Simple ,[Ast::IntegerExpression.new(5)] )
@root = :module_definition
end
def test_module_ops
@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"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"}
@output = Ast::ModuleExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )] )
@root = :module_definition
end
def test_module_assign_instance
@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"}
@output = Ast::ModuleExpression.new(:Opers ,[Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5))] )
@root = :module_definition
end
def test_module_if
@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"}, :parameter_list=>[{:parameter=>{: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"}
@output = Ast::ModuleExpression.new(:Foo ,[Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new(:n)] , [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:isit),Ast::IntegerExpression.new(42))],[Ast::AssignmentExpression.new(Ast::NameExpression.new(:maybenot),Ast::IntegerExpression.new(667))] )] ,nil )] )
@root = :module_definition
end
def test_module_function
@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"}, :parameter_list=>[{:parameter=>{:name=>"n"}}, {:parameter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"}
@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)] )] )
@root = :module_definition
end
def test_module_class
@input = <<HERE
module Foo
class Bar
funcall(3+4 , var)
end
end
HERE
@parse_output = {:module_name=>"Foo", :module_expressions=>[{:module_name=>"Bar", :derived_name=>nil, :class_expressions=>[{:call_site=>{:name=>"funcall"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}], :end=>"end"}], :end=>"end"}
@output = Ast::ModuleExpression.new(:Foo ,[Ast::ClassExpression.new(:Bar ,nil, [Ast::CallSiteExpression.new(:funcall, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new(:var)] ,Ast::NameExpression.new(:self))] )] )
@root = :module_definition
end
end

View File

@ -1,86 +0,0 @@
require_relative "../parser_helper"
class TestExpressions < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def simple_op op
@input = "5 #{op} 3"
@parse_output = {:l=>{:integer=>"5"}, :o=>"#{op} ", :r=>{:integer=>"3"}}
@output = Ast::OperatorExpression.new(op, Ast::IntegerExpression.new(5),Ast::IntegerExpression.new(3))
@root = :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
@input = "a + 35"
@parse_output = {:l=>{:name=>"a"}, :o=>"+ ", :r=>{:integer=>"35"}}
@output = Ast::OperatorExpression.new("+", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(35))
@root = :operator_expression
end
def test_op_two_variable
@input = "a - b"
@parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:name=>"b"}}
@output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::NameExpression.new("b"))
@root = :operator_expression
end
def test_op_instance_variable
@input = "@a - 5"
@parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"- ", :r=>{:integer=>"5"}}
@output = Ast::OperatorExpression.new("-", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))
@root = :operator_expression
end
def test_op_variable_string
@input = 'a - "st"'
@parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:string=>[{:char=>"s"}, {:char=>"t"}]}}
@output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::StringExpression.new("st"))
@root = :operator_expression
end
def test_two_same_ops
@input = '2 + 3 + 4'
@parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}
@output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))
@root = :operator_expression
end
def test_two_different_ops
@input = '2 + 3 * 4'
@parse_output = {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:l=>{:integer=>"3"}, :o=>"* ", :r=>{:integer=>"4"}}}
@output = Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)))
@root = :operator_expression
end
def test_two_different_ops_order
@input = '2 * 3 + 4'
@parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"* ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}
@output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))
@root = :operator_expression
end
def test_assignment
@input = "a = 5"
@parse_output = {:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}
@output = Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5))
@root = :operator_expression
end
def test_assignment_instance
@input = "@a = 5"
@parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"= ", :r=>{:integer=>"5"}}
@output = Ast::AssignmentExpression.new(Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))
@root = :operator_expression
end
end

View File

@ -1,35 +0,0 @@
require_relative "../parser_helper"
class TestReturn < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_return_int
@input = 'return 42'
@parse_output = {:return=>"return", :return_expression=>{:integer=>"42"}}
@output = Ast::ReturnExpression.new(Ast::IntegerExpression.new(42) )
@root = :simple_return
end
def test_return_variable
@input = 'return foo'
@parse_output = {:return=>"return", :return_expression=>{:name=>"foo"}}
@output = Ast::ReturnExpression.new(Ast::NameExpression.new("foo") )
@root = :simple_return
end
def test_return_string
@input = 'return "hello"'
@parse_output = {:return=>"return", :return_expression=>{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}}
@output = Ast::ReturnExpression.new(Ast::StringExpression.new("hello") )
@root = :simple_return
end
def test_return_true
@input = 'return true'
@parse_output = {:return=>"return", :return_expression=>{:true=>"true"}}
@output = Ast::ReturnExpression.new(Ast::TrueExpression.new() )
@root = :simple_return
end
end

View File

@ -1,55 +0,0 @@
require_relative "../parser_helper"
class TestWhile < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_while
@input = <<HERE
while(1) do
tmp = a
puts(b)
end
HERE
@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"}}
@output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )
@root = :while_do
end
def pest_while_reverse
@input = "puts '1' while true "
@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"}}
@output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )
@root = :while_do
end
def test_while_method
@input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@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"}}
@output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.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))] )
@root = :while_do
end
def test_big_while
@input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@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"}}
@output = Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::NameExpression.new(:b)), Ast::AssignmentExpression.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::AssignmentExpression.new(Ast::NameExpression.new(:n),Ast::OperatorExpression.new("-", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)))] )
@root = :while_do
end
end