Compare commits

...

100 Commits

Author SHA1 Message Date
Torsten Ruger 56a02bd6ea use ast that produces ruby output 2016-12-08 19:34:59 +02:00
Torsten Ruger f5b54c5fca add cli for soml->s-exp 2016-12-08 18:54:27 +02:00
Torsten Ruger 5c03db709f fix if false logic 2016-03-07 11:51:58 +02:00
Torsten Ruger 324c9c2eae better handling of statement lists 2016-03-07 11:32:28 +02:00
Torsten Ruger c9d25fcf81 easier constructor 2016-03-07 11:32:09 +02:00
Torsten Ruger f51ed376c4 add missing as types 2016-03-06 14:07:25 +02:00
Torsten Ruger 4a9b492dd9 move to typed structure
on the way to removing the language, the at needs to be replaced with a
typed structure.
2016-03-06 09:40:41 +02:00
Torsten Ruger 9ca03ef115 hopefully fix travis issue 2015-11-30 20:07:11 +02:00
Torsten Ruger d38a9c626f renamed to soml-parser 2015-11-30 19:55:48 +02:00
Torsten Ruger 6ae4b624b0 leaving the name for field defs
so we can reuse that expression
so we can highlight it in the debugger
2015-11-02 20:10:05 +02:00
Torsten Ruger 335a6b1e37 update parsley 2015-11-02 20:09:13 +02:00
Torsten Ruger 6710567af9 fix test after syntax changes 2015-10-19 15:21:23 +03:00
Torsten Ruger 3061ddfed9 same syntax change for while_xxx
xxx can be any string for the parser
the language will restrict if somewhat later
2015-10-19 15:21:11 +03:00
Torsten Ruger 7cc7ab5c18 adding condition to if statement
new syntax is if_true( . .. . )
where any string is allowed in case of true
2015-10-19 15:10:38 +03:00
Torsten Ruger 72ed05254e move control into statements 2015-10-19 14:57:03 +03:00
Torsten Ruger ab0a94bd51 change type to class name
although int is still allowed for integers (gets replaced though)
2015-10-14 15:48:53 +03:00
Torsten Ruger 1b2802ecf4 use bundlers rake tasks 2015-10-10 21:52:14 +03:00
Torsten Ruger 6bd5e9b5ee version bump for lots of incompatible changes 2015-10-09 17:34:10 +03:00
Torsten Ruger be07cd615a transform changes for what was basically a rewrite 2015-10-09 17:32:55 +03:00
Torsten Ruger e9a7b1f6da fix root, much tighter now 2015-10-09 17:32:34 +03:00
Torsten Ruger 3651856fc5 fix class defs 2015-10-09 17:32:05 +03:00
Torsten Ruger 60746383ee expressions are now statements 2015-10-09 17:31:08 +03:00
Torsten Ruger b424306156 fix array and hash constants, now seperated out 2015-10-09 17:29:24 +03:00
Torsten Ruger dff0e8fab4 fix function definition 2015-10-09 17:28:47 +03:00
Torsten Ruger 48a6dfabff fix while and if statements 2015-10-09 17:28:13 +03:00
Torsten Ruger 7f2f64c713 fix call site and now seperated assignment (was bunged as operator) 2015-10-09 17:27:22 +03:00
Torsten Ruger c9942ec516 test field access seperately (was mixed in) 2015-10-09 17:25:43 +03:00
Torsten Ruger af8febe456 fix operators, only binary 2015-10-09 17:25:09 +03:00
Torsten Ruger ba7ecbfa7b fix basic types 2015-10-09 17:24:23 +03:00
Torsten Ruger 97cf5e5bea retrying with the root of the directory
comes from finally tightning the root and not allowing random
expression code ala ruby
2015-10-09 17:23:43 +03:00
Torsten Ruger f7dcf2a2ff renameing to match expressions 2015-10-09 17:21:15 +03:00
Torsten Ruger 85adfa7107 may call with r_value 2015-10-09 12:47:03 +03:00
Torsten Ruger 308c0efc05 rename value_expression to r_value 2015-10-09 12:42:50 +03:00
Torsten Ruger 77cb8ce90a restrict the root, but expand for testing 2015-10-09 12:39:31 +03:00
Torsten Ruger 486e24514b there goes the module
it was ruby after all
should be reborn as twins: namespace and aspect
2015-10-08 22:57:39 +03:00
Torsten Ruger 58b3553251 forgot gemfile 2015-10-07 15:04:54 +03:00
Torsten Ruger 1c6bd05aea upped version, would be a major version if it were over 1 2015-10-07 15:04:23 +03:00
Torsten Ruger 14cf3a140d low climate is a climate bug, don't advertise it 2015-10-06 00:38:47 +03:00
Torsten Ruger 6246753c27 add another simple function test 2015-10-06 00:22:18 +03:00
Torsten Ruger 34691f36d1 add class_fields as separate syntax 2015-09-27 12:05:35 +03:00
Torsten Ruger 97d9d83715 remove unused code 2015-09-27 11:26:11 +03:00
Torsten Ruger e8bc570d25 wrapping class / module expressions in own node 2015-09-20 16:03:27 +03:00
Torsten Ruger 20b6c9b476 fix class functions
some extra tests in the process
2015-09-20 15:51:08 +03:00
Torsten Ruger c331bdd80a fix field default values 2015-09-20 14:43:08 +03:00
Torsten Ruger d0b950eed9 preparing test 2015-09-20 14:29:24 +03:00
Torsten Ruger f51563e99b restrict root_body a bit, but add to function 2015-09-20 14:25:06 +03:00
Torsten Ruger 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
Torsten Ruger be444bc687 add field access with tests 2015-09-20 12:50:06 +03:00
Torsten Ruger 8e07a7568f fix array in if_false 2015-09-19 17:11:15 +03:00
Torsten Ruger dab32bc307 remove puts 2015-09-19 16:25:42 +03:00
Torsten Ruger 9aa27d491d some more to_syms, and removing arrays, which become children 2015-09-19 14:55:03 +03:00
Torsten Ruger 692b51a9de way to fix current test cases (if known to be correct) 2015-09-19 14:54:22 +03:00
Torsten Ruger e2054660ce thought to be useful sat addition 2015-09-19 14:53:59 +03:00
Torsten Ruger e952495eb1 update ast 2015-09-19 14:53:37 +03:00
Torsten Ruger 21b652456d fix all the cases, much white noise, array to list, string to sym stuff 2015-09-19 14:53:30 +03:00
Torsten Ruger 3b0b91f2fb use the new inspect 2015-09-19 14:40:08 +03:00
Torsten Ruger 3bfcd830b0 small clean 2015-09-19 13:15:32 +03:00
Torsten Ruger 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
Torsten Ruger a11e59668d use own outputted (ast gem) 2015-09-18 22:19:42 +03:00
Torsten Ruger 71affacfba separate tag/nodes for conditions and remove arrays 2015-09-18 22:04:08 +03:00
Torsten Ruger 22e3c59674 change test framework to use files for in and out (s-exp) 2015-09-18 21:55:02 +03:00
Torsten Ruger 396a843a5e add return and argument types 2015-09-18 00:02:52 +03:00
Torsten Ruger 4d195a5f44 make 1.9 save 2015-09-15 20:03:21 +03:00
Torsten Ruger 7f126ab996 fix gemfile 2015-09-15 19:45:20 +03:00
Torsten Ruger 08ceb86b24 Merge branch 'master' into parslet 2015-09-15 19:30:01 +03:00
Torsten Ruger b938c7ace5 fix all tests 2015-09-15 18:57:31 +03:00
Torsten Ruger 3b484aa8ff add ast gem 2015-09-15 18:57:21 +03:00
Torsten Ruger eca1e6b1af remove own sat 2015-09-15 18:56:55 +03:00
Torsten Ruger 0df098ef7d using sat gem 2015-09-15 12:27:54 +03:00
Torsten Ruger d5d26a3ac4 unify to_s inspect stuff 2015-09-14 19:50:39 +03:00
Torsten Ruger d0980265fd unify grammar file 2015-09-14 17:15:14 +03:00
Torsten Ruger 114817602e remove the keywords citrus file (less clutter) 2015-09-14 17:00:36 +03:00
Torsten Ruger acf4046225 start conditionals 2015-09-14 16:47:22 +03:00
Torsten Ruger 11a218449d fix three args for call 2015-09-13 20:13:36 +03:00
Torsten Ruger 40f9ab78e5 fix or remove tests (language syntax changing) 2015-09-13 19:02:18 +03:00
Torsten Ruger 5e9743be6c first call passes 2015-09-13 18:48:48 +03:00
Torsten Ruger c538679c67 adding tokens to basic types 2015-09-12 19:33:21 +03:00
Torsten Ruger 9c89415857 limbo 2015-08-30 17:28:30 +03:00
Torsten Ruger ca8e63d8f3 use utf safe regex basics , some renaming 2015-08-30 01:13:48 +03:00
Torsten Ruger b3b2d1be6a basics back 2015-08-29 16:30:15 +03:00
Torsten Ruger 4b82189255 more basics rolling home 2015-08-29 16:08:28 +03:00
Torsten Ruger fa27ebebdf keyword expressions
and smaller new harness
2015-08-29 11:45:16 +03:00
Torsten Ruger d5a0736f48 switch to hosted gem 2015-08-29 10:49:51 +03:00
Torsten Ruger 99792220e9 disable tests that dont work 2015-08-29 08:53:05 +03:00
Torsten Ruger 95d92b51a7 rename test vars to input and output 2015-08-28 23:37:25 +03:00
Torsten Ruger 61b9dd95e4 update read me 2015-08-28 23:36:48 +03:00
Torsten Ruger 69e29efbd4 citifying test harness 2015-08-27 21:02:00 +03:00
Torsten Ruger 00600d5364 mostly not working tests yet 2015-08-27 21:01:30 +03:00
Torsten Ruger 5261edbd30 change to citrus wip 2015-08-27 21:01:12 +03:00
Torsten Ruger 619780a913 transform first couple of grammar files 2015-08-27 21:00:30 +03:00
Torsten Ruger 2e988380e4 move to local citrus as gem is broken 2015-08-27 21:00:11 +03:00
Torsten Ruger 841592c667 add cc token 2015-07-18 13:10:00 +03:00
Torsten Ruger ba4a04fcc7 add badges and code climate 2015-07-18 13:09:16 +03:00
Torsten Ruger f790b5d76a add travis 2015-07-18 12:00:21 +03:00
Torsten Ruger 34f8d2409b to and from basic types (json didn't work)
still not all, but enough for debug experiment to work
2015-07-12 10:00:29 +03:00
Torsten Ruger 95fbc3de1a move attributes under contractor
as it is essential that attributes are in the same order for the json
to work
2015-07-11 22:00:11 +03:00
Torsten Ruger 657d6319ad start on to_json and json_create 2015-07-11 21:59:36 +03:00
Torsten Ruger 99493865c1 bumped and added parslet as dep 2015-07-09 22:14:25 +03:00
Torsten Ruger d6d8403829 update parsley version 2015-05-20 17:34:13 +03:00
Torsten Ruger 663154ba24 fix small glitch/typo 2015-05-20 17:33:38 +03:00
147 changed files with 1800 additions and 2645 deletions

10
.travis.yml Normal file
View File

@ -0,0 +1,10 @@
language: ruby
sudo: false
cache: bundler
script:
- CODECLIMATE_REPO_TOKEN=2944f33533382d45c9667054d0f521b41d0d0df9b7b7f360911df8f7db76682d ruby test/test_all.rb
rvm:
- 1.9.3
- 2.0.0
- 2.1.5
- 2.2.0

View File

@ -1,10 +1,15 @@
source "http://rubygems.org"
gem "parslet"
gem "rake"
gem "soml-parser" , :path => "."
# use this for debugging, the printout is better (cut/paste)
gem "ast" , :github => "dancinglightning/ast"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "codeclimate-test-reporter", require: nil
gem "minitest"
gem "rubygems-tasks"
end

View File

@ -1,16 +1,43 @@
GIT
remote: git://github.com/dancinglightning/ast.git
revision: 3814fb102af82a30bf334005ebe17332744f9dad
specs:
ast (2.1.0)
PATH
remote: .
specs:
soml-parser (0.5.0)
ast (~> 2.1.0)
parslet (~> 1.7.1)
GEM
remote: http://rubygems.org/
specs:
blankslate (2.1.2.4)
minitest (5.3.2)
parslet (1.6.1)
blankslate (~> 2.0)
rubygems-tasks (0.2.4)
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)
simplecov (0.9.2)
docile (~> 1.1.0)
multi_json (~> 1.0)
simplecov-html (~> 0.9.0)
simplecov-html (0.9.0)
PLATFORMS
ruby
DEPENDENCIES
ast!
codeclimate-test-reporter
minitest
parslet
rubygems-tasks
rake
soml-parser!
BUNDLED WITH
1.13.5

103
README.md
View File

@ -1,13 +1,37 @@
## Salama Reader*
[![Build Status](https://travis-ci.org/salama/soml-parser.svg?branch=master)](https://travis-ci.org/salama/soml-parser)
[![Gem Version](https://badge.fury.io/rb/soml-parser.svg)](http://badge.fury.io/rb/soml-parser)
[![Test Coverage](https://codeclimate.com/github/salama/soml-parser/badges/coverage.svg)](https://codeclimate.com/github/salama/soml-parser)
The parser part of salama is now a standalone gem. It parses ruby using Parslet and no other dependencies.
## Soml Parser
This is interesting if you want to generate executable code, like salama, but also for other things, like code analysis.
The parser part of soml is a standalone gem to allow independent development.
It parses Soml using Parslet and no other dependencies.
Also it is very educational, as it is very readable code, and not too much of it.
*
It looks into it's salama ball and all it sees is red. A red salama . . . ruby, yes.
## Soml: Salama Object Machine Language
Soml is Still forming after realizing the need for an oo system 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
In Soml 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 Soml are described on the [salama site](http://salama-vm.org/soml/soml.html)
- statically typed so all variable declarations, functions and arguments are typed.
- objects but without data hiding
- static blocks (a bit ala crystal)
- call syntax as already discussed, ie message based
- no semicolns and stuff, but not ruby either
### Parser
@ -20,10 +44,10 @@ Most names are quite self explanatory, but here is a list:
- call_site is a function call. May be qualified, but currently must still have braches
- compound types are hash and array definitions. Hashes still need curlies
- control is if statement which still must have an else
- expression is a helper for all code allowed in a function
- statement is a helper for all code allowed in a function
- function definition must have braces too
- keywords is just a list of them
- operator expression are binary operators (see also below). There's a surprising amount
- operator statement are binary operators (see also below). There's a surprising amount
- return statement are straightforward
- while still needs a do, though i think in ruby a newline is sufficient
@ -31,12 +55,12 @@ Most names are quite self explanatory, but here is a list:
### 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.
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.
This works well, and is much less work.
The following step of compiling use the same kind of visitor approach as before
### Parslet
@ -49,60 +73,3 @@ Parslet is really great in that it:
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.
### 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
Parslets operator support is **outstanding** and such it was a breeze to implement most of rubies operators very simply. 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

View File

@ -11,9 +11,7 @@ rescue Bundler::BundlerError => e
end
require 'rake'
require 'rubygems/tasks'
Gem::Tasks.new
require "bundler/gem_tasks"
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
@ -29,7 +27,7 @@ Rake::RDocTask.new do |rdoc|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
rdoc.rdoc_dir = 'rdoc'
rdoc.title = "salama-reader #{version}"
rdoc.title = "soml-parser #{version}"
rdoc.rdoc_files.include('README*')
rdoc.rdoc_files.include('lib/**/*.rb')
end

View File

@ -1,75 +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 inspect
self.class.name + ".new(" + value.to_s+ ")"
end
def to_s
value.to_s
end
def attributes
[:value]
end
end
class TrueExpression < Expression
def to_s
"true"
end
end
class FalseExpression < Expression
def to_s
"false"
end
end
class NilExpression < Expression
def to_s
"nil"
end
end
class NameExpression < Expression
attr_reader :name
def initialize name
@name = name.to_sym
end
def inspect
"#{self.class.name}.new(#{name.inspect})"
end
def to_s
name.to_s
end
def attributes
[:name]
end
end
class VariableExpression < NameExpression
end
class ModuleName < NameExpression
end
class StringExpression < Expression
attr_reader :string
def initialize str
@string = str
end
def inspect
self.class.name + '.new("' + string + '")'
end
def to_s
'"' + string.to_s + '"'
end
def attributes
[:string]
end
end
end

View File

@ -1,26 +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 inspect
self.class.call_exp + ".new(" + call_exp.inspect + ", ["+
args.collect{|m| m.inspect }.join( ",") + "] ," + body_exp.inspect + ")"
end
def to_s
"#{call_exp}(" + args.join(",") + ")"
end
def attributes
[:call_exp , :args , :body_exp]
end
end
end

View File

@ -1,24 +0,0 @@
module Ast
# assignment, like operators are really function calls
class CallSiteExpression < Expression
attr_reader :name, :args , :receiver
def initialize name, args , receiver = Ast::NameExpression.new(:self)
@name = name.to_sym
@args = args
@receiver = receiver
end
def inspect
self.class.name + ".new(" + name.inspect + ", ["+
args.collect{|m| m.inspect }.join( ",") + "] ," + receiver.inspect + ")"
end
def to_s
"#{name}(" + args.join(",") + ")"
end
def attributes
[:name , :args , :receiver]
end
end
end

View File

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

View File

@ -1,41 +0,0 @@
# abstract syntax tree (ast)
# This Layer is semi automagically created by parslet using the transform
# It in turn is responsible for the transformation to the next layer, vm code
# This happens in the compile function which must return a Vm::Code derivative
# PS: compare is only for tests and should be factored out to there
module Ast
class Expression
def attributes
[]
end
def inspect
self.class.name + ".new()"
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,18 +0,0 @@
module Ast
class ExpressionList < Expression
attr_reader :expressions
def initialize expressions
@expressions = expressions
end
def attributes
[:expressions]
end
def inspect
self.class.name + ".new( ["+ expressions.collect(&:inspect).join( ",") +"])"
end
def to_s
expressions.collect(&:inspect).join("\n")
end
end
end

View File

@ -1,25 +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 inspect
self.class.name + ".new(" + name.inspect + ", ["+
params.collect{|m| m.inspect }.join( ",") +"] , [" +
body.collect{|m| m.inspect }.join( ",") +"] ,"+ receiver.inspect + " )"
end
def to_s
ret = "def "
ret += "#{receiver}." if receiver
ret + "#{name}( " + params.join(",") + ") \n" + body.join("\n") + "end\n"
end
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 inspect
self.class.name + ".new(" + cond.inspect + ", "+
if_true.inspect + "," + if_false.inspect + " )"
end
def attributes
[:cond, :if_true, :if_false]
end
end
end

View File

@ -1,41 +0,0 @@
module Ast
class ModuleExpression < Expression
attr_reader :name ,:expressions
def initialize name , expressions
@name = name.to_sym
@expressions = expressions
end
def inspect
self.class.name + ".new(" + @name.inspect + " ," + @expressions.inspect + " )"
end
def to_s
"module #{name}\n #{expressions}\nend\n"
end
def attributes
[:name , :expressions]
end
end
class ClassExpression < ModuleExpression
def initialize name , derived , expressions
super(name , expressions)
@derived_from = derived
end
def inspect
self.class.name + ".new(" + @name.inspect + " ," +
@derived_from.inspect + ", " + @expressions.inspect + " )"
end
def derived_from
@derived_from ? @derived_from : :Object
end
def to_s
s = "class #{name} < #{derived_from}\n #{expressions}\nend\n"
end
def attributes
[:name , :derived_from , :expressions]
end
end
end

View File

@ -1,37 +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 inspect
self.class.name + ".new(" + operator.inspect + ", " + left.inspect + "," + right.inspect + ")"
end
def to_s
"#{left} #{operator} #{right}"
end
end
class AssignmentExpression < Expression
attr_reader :left, :right
def initialize left, right
@left, @right = left, right
end
def attributes
[:left, :right]
end
def inspect
self.class.name + ".new(" + left.inspect + "," + right.inspect + ")"
end
def to_s
"#{left} = #{right}"
end
end
end

View File

@ -1,17 +0,0 @@
module Ast
class ReturnExpression < Expression
attr_reader :expression
def initialize expression
@expression = expression
end
def inspect
self.class.name + ".new(" + expression.inspect + " )"
end
def to_s
"return #{expression}\n"
end
def attributes
[:expression]
end
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 inspect
self.class.name + ".new(" + condition.inspect + ", " + body.inspect + " )"
end
def to_s
"while(#{condition}) do\n" + body.join("\n") + "\nend\n"
end
def attributes
[:condition, :body]
end
end
end

View File

@ -2,19 +2,31 @@ module Parser
# Basic types are numbers and strings
module BasicTypes
include Parslet
# space really is just space. ruby is newline sensitive, so there is more whitespace footwork
# 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) { (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(:newline) { (linebreak | comment) >> space? }
rule(:eol) { newline | any.absent? }
rule(:double_quote){ str('"') }
rule(:minus) { str('-') }
rule(:plus) { str('+') }
@ -23,27 +35,30 @@ module Parser
rule(:dot) { str('.') }
rule(:digit) { match('[0-9]') }
rule(:exponent) { (str('e')| str('E')) }
rule(:type) { (str("int") | class_name).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.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? }
# TODO rule forbit names like true_statements, 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
# and class/module names must start with capital
rule(:class_name) { keyword.absent? >> (match['A-Z'] >> match['a-zA-Z0-9_'].repeat).as(:class_name) >> space? }
rule(:escape) { str('\\') >> any.as(:esc) }
rule(:string) { quote >> (
escape |
escape |
nonquote.as(:char)
).repeat(1).as(:string) >> quote }
).repeat(1).as(:string) >> quote >> space? }
rule(:integer) { sign.maybe >> digit.repeat(1).as(:integer) >> space? }
rule(:float) { integer >> dot >> integer >>
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 }
rule(:field_access) { name.as(:receiver) >> str(".") >> name.as(:field) }
rule(:basic_type){ integer | name | string | float | class_name |
((keyword_true | keyword_false | keyword_nil) >> space? ) }
end
end
end

View File

@ -2,16 +2,22 @@ module Parser
module CallSite
include Parslet
rule(:r_value) { operator_value | call_site | field_access | basic_type }
rule(:assign) { str('=') >> space?}
rule(:assignment){ (field_access|name).as(:l_value) >> assign.as(:assign) >> r_value.as(:r_value) }
rule(:field_def) { type >> name >> (assign >> r_value.as(:value) ).maybe}
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
( (basic_type.as(:argument) >>
(comma >> r_value.as(:argument)).repeat(0)).repeat(0,1)).as(:argument_list) >>
right_parenthesis
}
rule(:call_site) { ((module_name|instance_variable|basic_type).as(:receiver) >> str(".")).maybe >> #possibly qualified
rule(:call_site) { (basic_type.as(:receiver) >> str(".")).maybe >> #possibly qualified
name.as(:call_site) >> argument_list >> comment.maybe}
end
end

View File

@ -0,0 +1,16 @@
module Parser
module ModuleDef
include Parslet
rule(:class_field) { keyword_field >> field_def }
rule(:class_body) {
function_definition | class_field
}
rule(:class_definition) do
keyword_class >> class_name >> (str("<") >> space >> class_name).maybe.as(:derived_name) >>
( (keyword_end.absent? >> class_body).repeat()).as(:class_statements) >> keyword_end
end
end
end

View File

@ -5,15 +5,15 @@ module Parser
rule(:array_constant) do
left_bracket >>
( ((operator_expression|value_expression).as(:array_element) >> space? >>
(comma >> space? >> (operator_expression|value_expression).as(:array_element)).repeat(0)).repeat(0,1)).as(:array_constant) >>
( (r_value.as(:array_element) >> space? >>
(comma >> space? >> r_value.as(:array_element)).repeat(0)).repeat(0,1)).as(:array_constant) >>
space? >> right_bracket
end
rule(:hash_pair) { basic_type.as(:hash_key) >> association >> (operator_expression|value_expression).as(:hash_value) }
rule(:hash_constant) { left_brace >> ((hash_pair.as(:hash_pair) >>
(comma >> space? >> hash_pair.as(:hash_pair)).repeat(0)).repeat(0,1)).as(:hash_constant)>>
rule(:hash_pair) { basic_type.as(:hash_key) >> association >> r_value.as(:hash_value) }
rule(:hash_constant) { left_brace >> ((hash_pair.as(:hash_pair) >>
(comma >> space? >> hash_pair.as(:hash_pair)).repeat(0)).repeat(0,1)).as(:hash_constant)>>
space? >> right_brace }
end
end
end

View File

@ -1,20 +0,0 @@
module Parser
module Control
include Parslet
rule(:conditional) do
keyword_if >>
(( (value_expression|operator_expression).as(:conditional) ) |
left_parenthesis >> (operator_expression|value_expression).as(:conditional) >> right_parenthesis) >>
newline >> expressions_else.as(:if_true) >> newline >> expressions_end.as(:if_false)
end
rule(:while_do) do
keyword_while >> left_parenthesis >> (operator_expression|value_expression).as(:while_cond) >>
right_parenthesis >> keyword_do >> newline >>
expressions_end.as(:body)
end
rule(:simple_return) do
keyword_return >> (operator_expression|value_expression).as(:return_expression)
end
end
end

View File

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

View File

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

View File

@ -1,28 +1,21 @@
module Parser
module Keywords
include Parslet
rule(:keyword_begin) { str('begin').as(:begin) >> space?}
rule(:keyword_class) { str('class') >> space? }
rule(:keyword_def) { str('def') >> space? }
rule(:keyword_do) { str('do').as(:do) >> space?}
rule(:keyword_else) { str('else').as(:else) >> space? }
rule(:keyword_end) { str('end').as(:end) >> space? }
rule(:keyword_false) { str('false').as(:false) >> space?}
rule(:keyword_if) { str('if').as(:if) >> space? }
rule(:keyword_rescue) { str('rescue').as(:rescue) >> space?}
rule(:keyword_end) { str('end').as(:end) >> space? }
rule(:keyword_false) { str('false').as(:false) }
rule(:keyword_field) { str('field').as(:field) >> space? }
rule(:keyword_return) { str('return').as(:return) >> space?}
rule(:keyword_true) { str('true').as(:true) >> space?}
rule(:keyword_module) { str('module') >> space? }
rule(:keyword_nil) { str('nil').as(:nil) >> space?}
rule(:keyword_unless) { str('unless').as(:unless) >> space?}
rule(:keyword_until) { str('until').as(:until) >> space?}
rule(:keyword_while) { str('while').as(:while) >> space?}
# this rule is just to make sure identifiers can't be keywords. Kind of duplication here, but we need the
rule(:keyword_true) { str('true').as(:true) }
rule(:keyword_nil) { str('nil').as(:nil) }
# 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')}
rule(:keyword){ str('if_') | str('else') | str('end') | str('while_') |
str('false') | str('true')| str('nil') | str("class") |
str('return')| str('int')| str('field')}
end
end
end

View File

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

View File

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

View File

@ -2,18 +2,17 @@ require_relative "basic_types"
require_relative "compound_types"
require_relative "tokens"
require_relative "keywords"
require_relative "control"
require_relative "expression"
require_relative "statement"
require_relative "call_site"
require_relative "function_definition"
require_relative "module_definition"
require_relative "class_definition"
require_relative "operators"
module Parser
# obviously a work in progress !!
# We "compose" the parser from bits, divide and hopefully conquer
# a note about .maybe : .maybe is almost every respect the same as .repeat(0,1)
# so either 0, or 1, in other words maybe. Nice feature, but there are strings attached:
# a maybe removes the 0 a sequence (array) to a single (hash). Thus 2 transformations are needed
@ -24,15 +23,13 @@ module Parser
include CompoundTypes
include Tokens
include Keywords
include Control
include Expression
include Statement
include CallSite
include FunctionDefinition
include Operators
include ModuleDef
rule(:root_body) {(module_definition | class_definition | function_definition | expression |
operator_expression | call_site | basic_type | hash_constant | array_constant )}
rule(:root) { root_body.repeat.as(:expression_list) }
rule(:root_body) {( class_definition | function_definition )}
rule(:root) { root_body.repeat.as(:statement_list) }
end
end

46
lib/parser/statement.rb Normal file
View File

@ -0,0 +1,46 @@
module Parser
module Statement
include Parslet
rule( :keyword_while) do
str("while_") >> alpha.repeat.as(:condition) >> space
end
rule(:while_statement) do
keyword_while >> left_parenthesis >> r_value.as(:conditional) >>
right_parenthesis >> statements_end.as(:body)
end
rule( :keyword_if) do
str("if_") >> alpha.repeat.as(:condition) >> space
end
rule(:if_statement) do
keyword_if >>
left_parenthesis >> r_value.as(:conditional) >> right_parenthesis >>
statements_else.as(:true_statements) >> statements_end.as(:false_statements)
end
rule(:small_conditional) do
keyword_if >>
left_parenthesis >> r_value.as(:conditional) >> right_parenthesis >>
statements_end.as(:true_statements)
end
rule(:return_statement) do
keyword_return >> r_value.as(:return_statement)
end
rule(:statement) { (return_statement | while_statement | small_conditional | if_statement |
assignment | class_field | field_def | call_site |
hash_constant | array_constant) }
def delimited_statements( delimit )
( (delimit.absent? >> statement).repeat(1)).as(:statements) >> delimit
end
rule(:statements_do) { delimited_statements(keyword_do) }
rule(:statements_else) { delimited_statements(keyword_else) }
rule(:statements_end) { delimited_statements(keyword_end) }
end
end

View File

@ -1,99 +1,126 @@
require 'parslet'
require 'ast/expression'
#include is private in 1.9, who'd have known without travis
Parslet::Context.send :include , AST::Sexp
Parslet::Context.class_eval do
def type_sym t
if( t.is_a? AST::Node )
t = t.children.first
else
t = t.to_sym
t = :Integer if t == :int
end
t
end
end
module Parser
class Transform < Parslet::Transform
rule(:string => sequence(:chars)) { Ast::StringExpression.new chars.join }
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_sym(type) , s(:name , name.to_sym)) }
rule(:type => simple(:type), :name => simple(:name) , :value => simple(:value)) {
s(:field_def , type_sym(type) , s(:name , name.to_sym) , value ) }
# class field
rule(:field => simple(:field) , :type => simple(:type), :name => simple(:name)) {
s(:class_field , type_sym(type) , name.to_sym) }
rule(:field => simple(:field) , :type => simple(:type), :name => simple(:name) , :value => simple(:value)) {
s(:class_field , type_sym(type) , name.to_sym , value ) }
rule(:array_constant => sequence(:array_constant) ) { Ast::ArrayExpression.new(array_constant) }
rule(:l_value => simple(:l_value) , :assign => simple(:assign) , :r_value => simple(:r_value)) {
s(:assignment , l_value , r_value)
}
rule( :left => simple(:left) , :operator => simple(:operator) ,
:right => simple(:right)) { s(:operator_value , operator.to_sym , left , right )}
rule(:class_name => simple(:class_name)) { s(:class_name,class_name.to_s.to_sym) }
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 }
rule(:argument_list => sequence(:argument_list)) { argument_list }
#Two rules for calls, simple and qualified. Keeps the rules simpler
rule( :call_site => simple(:call_site),
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),
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
rule(:condition => simple(:condition) ,
:conditional => simple(:conditional),
:body => {:statements => sequence(:body) , :end => simple(:e) }) do
s(:while_statement,condition.to_s.to_sym, s(:conditional , conditional), s(:statements , *body))
end
rule(:while => simple(:while),
:while_cond => simple(:while_cond) , :do => simple(:do) ,
:body => {:expressions => sequence(:body) , :end => simple(:e) }) do
Ast::WhileExpression.new(while_cond, body)
end
rule(:condition => simple(:condition), :conditional => simple(:conditional),
:true_statements => {:statements => sequence(:true_statements) , :else => simple(:else) },
:false_statements => {:statements => sequence(:false_statements) , :end => simple(:e) }) do
s(:if_statement, condition.to_s.to_sym,
s(:condition, conditional),
s(:true_statements, *true_statements),
s(:false_statements , *false_statements))
end
rule(:return => simple(:return) , :return_expression => simple(:return_expression))do
Ast::ReturnExpression.new(return_expression)
rule(:condition => simple(:condition), :conditional => simple(:conditional),
:true_statements => {:statements => sequence(:true_statements) , :end => simple(:e) }) do
s(:if_statement, condition.to_s.to_sym, s(:condition, conditional),
s(:true_statements, *true_statements), s(:false_statements , nil) )
end
rule(:return => simple(:return) , :return_statement => simple(:return_statement))do
s(:return , return_statement)
end
rule(:parameter => simple(:parameter)) { parameter }
rule(:parameter_list => sequence(:parameter_list)) { parameter_list }
rule(:parameter => simple(:parameter)) { s(:parameter , parameter.children[0] , parameter.children[1].children[0]) }
# 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)
:statements => sequence(:statements) , :end => simple(:e)) do
s(:function, type_sym(type) , function_name, s(:parameters , *parameter_list ),
s(:statements , *statements))
end
rule(l: simple(:l), o: simple(:o) , r: simple(:r)) do
op = o.to_s.strip
if op == "="
Ast::AssignmentExpression.new( l ,r)
else
Ast::OperatorExpression.new( op , l ,r)
end
rule(:type => simple(:type) ,
:receiver=> simple(:receiver),
:function_name => simple(:function_name),
:parameter_list => sequence(:parameter_list),
:statements => sequence(:statements) , :end => simple(:e)) do
s(:function, type_sym(type) , function_name, s(:parameters , *parameter_list ),
s(:statements , *statements) , s(:receiver , *receiver))
end
rule( :class_name => simple(:class_name) , :derived_name => simple(:derived_name) , :class_statements => sequence(:class_statements) , :end=>"end") do
s(:class , class_name.to_s.to_sym ,
s(:derives, derived_name ? derived_name.to_a.first.to_sym : nil) ,
s(:statements, *class_statements) )
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)
end
rule(:expression_list => sequence(:expression_list)) {
Ast::ExpressionList.new(expression_list)
rule(:statement_list => sequence(:statement_list)) {
s(:statements , *statement_list)
}
#shortcut to get the ast tree for a given string
# optional second arguement specifies a rule that will be parsed (mainly for testing)
# optional second arguement specifies a rule that will be parsed (mainly for testing)
def self.ast string , rule = :root
syntax = Parser.new.send(rule).parse(string)
tree = Transform.new.apply(syntax)

View File

@ -1,3 +0,0 @@
require 'parslet'
require 'parser/salama'
require 'parser/transform'

5
lib/soml-parser.rb Normal file
View File

@ -0,0 +1,5 @@
require 'parslet'
require 'parser/soml'
require "ast"
require 'parser/transform'
require "soml/code/code"

View File

@ -0,0 +1,13 @@
module Soml
class Assignment < Statement
attr_accessor :name , :value
def initialize(n = nil , v = nil )
@name , @value = n , v
end
end
class FieldDef < Statement
attr_accessor :name , :type , :value
end
end

View File

@ -0,0 +1,39 @@
module Soml
class IntegerExpression < Expression
attr_accessor :value
def initialize(value)
@value = value
end
end
class FloatExpression < Expression
attr_accessor :value
def initialize(value)
@value = value
end
end
class TrueExpression < Expression
end
class FalseExpression < Expression
end
class NilExpression < Expression
end
class StringExpression < Expression
attr_accessor :value
def initialize(value)
@value = value
end
end
class NameExpression < Expression
attr_accessor :value
alias :name :value
def initialize(value)
@value = value
end
end
class ClassExpression < Expression
attr_accessor :value
def initialize(value)
@value = value
end
end
end

View File

@ -0,0 +1,5 @@
module Soml
class CallSite < Expression
attr_accessor :name , :receiver , :arguments
end
end

View File

@ -0,0 +1,9 @@
module Soml
class ClassStatement < Statement
attr_accessor :name , :derives , :statements
end
class ClassField < Statement
attr_accessor :name , :type
end
end

27
lib/soml/code/code.rb Normal file
View File

@ -0,0 +1,27 @@
# Base class for Expresssion and Statement
module Soml
class Code
end
class Statement < Code
end
class Expression < Code
end
end
require_relative "while_statement"
require_relative "if_statement"
require_relative "return_statement"
require_relative "statements"
require_relative "operator_expression"
require_relative "field_access"
require_relative "call_site"
require_relative "basic_values"
require_relative "assignment"
require_relative "class_statement"
require_relative "function_statement"
require_relative "to_code"

View File

@ -0,0 +1,5 @@
module Soml
class FieldAccess < Expression
attr_accessor :receiver , :field
end
end

View File

@ -0,0 +1,5 @@
module Soml
class FunctionStatement < Statement
attr_accessor :return_type , :name , :parameters, :statements , :receiver
end
end

View File

@ -0,0 +1,5 @@
module Soml
class IfStatement < Statement
attr_accessor :branch_type , :condition , :if_true , :if_false
end
end

View File

@ -0,0 +1,5 @@
module Soml
class OperatorExpression < Expression
attr_accessor :operator , :left_expression , :right_expression
end
end

View File

@ -0,0 +1,5 @@
module Soml
class ReturnStatement < Statement
attr_accessor :return_value
end
end

View File

@ -0,0 +1,5 @@
module Soml
class Statements < Statement
attr_accessor :statements
end
end

163
lib/soml/code/to_code.rb Normal file
View File

@ -0,0 +1,163 @@
module Soml
def self.ast_to_code statement
compiler = ToCode.new
compiler.process statement
end
class ToCode < AST::Processor
def handler_missing node
raise "No handler on_#{node.type}(node)"
end
def on_class statement
name , derives , statements = *statement
w = ClassStatement.new()
w.name = name
w.derives = derives.children.first
w.statements = process(statements)
w
end
def on_function statement
return_type , name , parameters, statements , receiver = *statement
w = FunctionStatement.new()
w.return_type = return_type
w.name = name.children.first
w.parameters = parameters.to_a.collect do |p|
raise "error, argument must be a identifier, not #{p}" unless p.type == :parameter
p.children
end
w.statements = process(statements)
w.receiver = receiver
w
end
def on_field_def statement
type , name , value = *statement
w = FieldDef.new()
w.type = type
w.name = process(name)
w.value = process(value) if value
w
end
def on_class_field statement
type , name = *statement
w = ClassField.new()
w.type = type
w.name = name
w
end
def on_while_statement statement
branch_type , condition , statements = *statement
w = WhileStatement.new()
w.branch_type = branch_type
w.condition = process(condition)
w.statements = process(statements)
w
end
def on_if_statement statement
branch_type , condition , if_true , if_false = *statement
w = IfStatement.new()
w.branch_type = branch_type
w.condition = process(condition)
w.if_true = process(if_true)
w.if_false = process(if_false)
w
end
def process_first code
raise "Too many children #{code.inspect}" if code.children.length != 1
process code.children.first
end
alias :on_conditional :process_first
alias :on_condition :process_first
alias :on_field :process_first
def on_statements statement
w = Statements.new()
return w unless statement.children
return w unless statement.children.first
w.statements = process_all(statement.children)
w
end
alias :on_true_statements :on_statements
alias :on_false_statements :on_statements
def on_return statement
w = ReturnStatement.new()
w.return_value = process(statement.children.first)
w
end
def on_operator_value statement
operator , left_e , right_e = *statement
w = OperatorExpression.new()
w.operator = operator
w.left_expression = process(left_e)
w.right_expression = process(right_e)
w
end
def on_field_access statement
receiver_ast , field_ast = *statement
w = FieldAccess.new()
w.receiver = process(receiver_ast)
w.field = process(field_ast)
w
end
def on_receiver expression
process expression.children.first
end
def on_call statement
name_s , arguments , receiver = *statement
w = CallSite.new()
w.name = name_s.children.first
w.arguments = process_all(arguments)
w.receiver = process(receiver)
w
end
def on_int expression
IntegerExpression.new(expression.children.first)
end
def on_true expression
TrueExpression.new
end
def on_false expression
FalseExpression.new
end
def on_nil expression
NilExpression.new
end
def on_name statement
NameExpression.new(statement.children.first)
end
def on_string expression
StringExpression.new(expression.children.first)
end
def on_class_name expression
ClassExpression.new(expression.children.first)
end
def on_assignment statement
name , value = *statement
w = Assignment.new()
w.name = process name
w.value = process(value)
w
end
end
end

View File

@ -0,0 +1,5 @@
module Soml
class WhileStatement < Statement
attr_accessor :branch_type , :condition , :statements
end
end

View File

@ -1,16 +1,19 @@
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = 'salama-reader'
s.version = '0.0.3'
s.name = 'soml-parser'
s.version = '0.5.0'
s.authors = ['Torsten Ruger']
s.email = 'torsten@villataika.fi'
s.extra_rdoc_files = ['README.md']
s.files = %w(README.md LICENSE) + Dir.glob("lib/**/*")
s.homepage = 'https://github.com/salama/salama-reader'
s.homepage = 'https://github.com/salama/soml-parser'
s.license = 'GNU v3'
s.require_paths = ['lib']
s.summary = 'Ruby parser for the salama machine'
s.summary = 'Ruby parser for the salama object system language'
s.add_dependency 'parslet', '~> 1.7.1'
s.add_dependency 'ast', '~> 2.1.0'
end

View File

@ -8,8 +8,10 @@ to run just a single, replace all with what you want to test. Minitest accept a
ruby test/test_class.rb -n test_class_ops_parse
Notice tough the "_parse" at the end, while you will find no such function. The Magic (explained below) renerates three
functions per case. Your options are "_parse" , "_transform" , or if it's really bad, "_ast" (this should really work when the previous two work)
Notice tough the "_parse" at the end, while you will find no such function.
The Magic (explained below) generates three functions per case.
Your options are "_parse" , "_transform" , or if it's really bad, "_ast"
(this should really work when the previous two work)
### Directories
@ -26,7 +28,7 @@ Apart from just plain more tests, two additional directories are planned. One is
Parsing is a two step process with parslet:
- parse takes an input and outputs hashes/arrays with basic types
- tramsform takes the output of parse and generates an ast (as specified by the transformation)
- transform takes the output of parse and generates an ast (as specified by the transformation)
A test tests both phases separately and again together.
Each test must thus specify (as instance variables):

View File

@ -0,0 +1,9 @@
self.a = 5
-- -- --
s(:assignment,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :a))),
s(:int, 5))

View File

@ -0,0 +1,5 @@
name = 10
-- -- --
s(:assignment,
s(:name, :name),
s(:int, 10))

View File

@ -0,0 +1,3 @@
FooBar
-- -- --
s(:class_name, :FooBar)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,8 @@
Object.foo(42)
-- -- --
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 42)),
s(:receiver,
s(:class_name, :Object)))

View File

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

View File

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

View File

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

View File

@ -0,0 +1,161 @@
class String
String self.new_string(int len )
len = len << 2
return super.new_object( len)
end
int length()
return self.length
end
int plus(String 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_plus( i - my_length)
char = get(i)
new_string.set(i , char)
i = i + 1
end
i = 0
while_plus( 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(:statements,
s(:class, :String,
s(:derives, nil),
s(:statements,
s(:function, :String,
s(:name, :new_string),
s(:parameters,
s(:parameter, :Integer, :len)),
s(:statements,
s(:assignment,
s(:name, :len),
s(:operator_value, :<<,
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, :Integer,
s(:name, :length),
s(:parameters),
s(:statements,
s(:return,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :length)))))),
s(:function, :Integer,
s(:name, :plus),
s(:parameters,
s(:parameter, :String, :str)),
s(:statements,
s(:assignment,
s(:name, :my_length),
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :length)))),
s(:assignment,
s(:name, :str_len),
s(:call,
s(:name, :length),
s(:arguments),
s(:receiver,
s(:name, :str)))),
s(:assignment,
s(:name, :my_length),
s(:operator_value, :+,
s(:name, :str_len),
s(:name, :my_length))),
s(:assignment,
s(:name, :new_string),
s(:call,
s(:name, :new_string),
s(:arguments,
s(:name, :my_length)),
s(:receiver,
s(:name, :self)))),
s(:assignment,
s(:name, :i),
s(:int, 0)),
s(:while_statement, :plus,
s(:conditional,
s(:operator_value, :-,
s(:name, :i),
s(:name, :my_length))),
s(:statements,
s(:assignment,
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(:assignment,
s(:name, :i),
s(:operator_value, :+,
s(:name, :i),
s(:int, 1))))),
s(:assignment,
s(:name, :i),
s(:int, 0)),
s(:while_statement, :plus,
s(:conditional,
s(:operator_value, :-,
s(:name, :i),
s(:name, :str_len))),
s(:statements,
s(:assignment,
s(:name, :char),
s(:call,
s(:name, :get),
s(:arguments,
s(:name, :i)),
s(:receiver,
s(:name, :str)))),
s(:assignment,
s(:name, :len),
s(:operator_value, :+,
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(:assignment,
s(:name, :i),
s(:operator_value, :+,
s(:name, :i),
s(:int, 1))))),
s(:return,
s(:name, :new_string)))))))

View File

@ -0,0 +1,23 @@
class Foo < Object
field int fff = 3
int func()
return self.fff
end
end
-- -- --
s(:statements,
s(:class, :Foo,
s(:derives, :Object),
s(:statements,
s(:class_field, :Integer, :fff,
s(:int, 3)),
s(:function, :Integer,
s(:name, :func),
s(:parameters),
s(:statements,
s(:return,
s(:field_access,
s(:receiver,
s(:name, :self)),
s(:field,
s(:name, :fff)))))))))

View File

@ -0,0 +1,30 @@
class Pifi
int self.ofthen(int n , Object m)
n = n + m.index
return n
end
end
-- -- --
s(:statements,
s(:class, :Pifi,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :Integer, :n),
s(:parameter, :Object, :m)),
s(:statements,
s(:assignment,
s(:name, :n),
s(:operator_value, :+,
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_zero(0)
isit = 42
else
maybenot = 667
end
end
end
-- -- --
s(:statements,
s(:class, :Ifi,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:if_statement, :zero,
s(:condition,
s(:int, 0)),
s(:true_statements,
s(:assignment,
s(:name, :isit),
s(:int, 42))),
s(:false_statements,
s(:assignment,
s(:name, :maybenot),
s(:int, 667)))))))))

View File

@ -0,0 +1,16 @@
class Foo < Object
int test()
return 43
end
end
-- -- --
s(:statements,
s(:class, :Foo,
s(:derives, :Object),
s(:statements,
s(:function, :Integer,
s(:name, :test),
s(:parameters),
s(:statements,
s(:return,
s(:int, 43)))))))

View File

@ -0,0 +1,23 @@
class Opers
int foo(int x)
int abba = 5
return abba + 5
end
end
-- -- --
s(:statements,
s(:class, :Opers,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :Integer, :x)),
s(:statements,
s(:field_def, :Integer,
s(:name, :abba),
s(:int, 5)),
s(:return,
s(:operator_value, :+,
s(:name, :abba),
s(:int, 5))))))))

View File

@ -0,0 +1,9 @@
class Foo
field int x
end
-- -- --
s(:statements,
s(:class, :Foo,
s(:derives, nil),
s(:statements,
s(:class_field, :Integer, :x))))

View File

@ -0,0 +1,7 @@
foo.bar
-- -- --
s(:field_access,
s(:receiver,
s(:name, :foo)),
s(:field,
s(:name, :bar)))

View File

@ -0,0 +1,13 @@
int self.length( Object x )
return 5
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :length),
s(:parameters,
s(:parameter, :Object, :x)),
s(:statements,
s(:return,
s(:int, 5))),
s(:receiver, :self)))

View File

@ -0,0 +1,48 @@
int fibonaccit(int n)
a = 0
b = 1
while_positive( n )
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:assignment,
s(:name, :a),
s(:int, 0)),
s(:assignment,
s(:name, :b),
s(:int, 1)),
s(:while_statement, :positive,
s(:conditional,
s(:name, :n)),
s(:statements,
s(:assignment,
s(:name, :tmp),
s(:name, :a)),
s(:assignment,
s(:name, :a),
s(:name, :b)),
s(:assignment,
s(:name, :b),
s(:operator_value, :+,
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assignment,
s(:name, :n),
s(:operator_value, :-,
s(:name, :n),
s(:int, 1))))))))

View File

@ -0,0 +1,16 @@
int foo(int x)
int a = 5
return a
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :Integer, :x)),
s(:statements,
s(:field_def, :Integer,
s(:name, :a),
s(:int, 5)),
s(:return,
s(:name, :a)))))

View File

@ -0,0 +1,25 @@
int ofthen(int n)
if_plus(0)
isit = 42
else
maybenot = 667
end
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :ofthen),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:if_statement, :plus,
s(:condition,
s(:int, 0)),
s(:true_statements,
s(:assignment,
s(:name, :isit),
s(:int, 42))),
s(:false_statements,
s(:assignment,
s(:name, :maybenot),
s(:int, 667)))))))

View File

@ -0,0 +1,11 @@
int foo()
return 5
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters),
s(:statements,
s(:return,
s(:int, 5)))))

View File

@ -0,0 +1,19 @@
int foo(int x)
int abba = 5
abba = abba + 5
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :Integer, :x)),
s(:statements,
s(:field_def, :Integer,
s(:name, :abba),
s(:int, 5)),
s(:assignment,
s(:name, :abba),
s(:operator_value, :+,
s(:name, :abba),
s(:int, 5))))))

View File

@ -0,0 +1,20 @@
int retvar(Object n)
int i = n.layout
return i
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :retvar),
s(:parameters,
s(:parameter, :Object, :n)),
s(:statements,
s(:field_def, :Integer,
s(:name, :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_positive( n - 5)
return 10
else
return 20
end
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :retvar),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:if_statement, :positive,
s(:condition,
s(:operator_value, :-,
s(:name, :n),
s(:int, 5))),
s(:true_statements,
s(:return,
s(:int, 10))),
s(:false_statements,
s(:return,
s(:int, 20)))))))

View File

@ -0,0 +1,26 @@
int retvar(int n )
while_positive( n - 5)
n = n + 1
return n
end
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :retvar),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:while_statement, :positive,
s(:conditional,
s(:operator_value, :-,
s(:name, :n),
s(:int, 5))),
s(:statements,
s(:assignment,
s(:name, :n),
s(:operator_value, :+,
s(:name, :n),
s(:int, 1))),
s(:return,
s(:name, :n)))))))

View File

@ -0,0 +1,13 @@
int foo( int n ,String m)
return n
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :Integer, :n),
s(:parameter, :String, :m)),
s(:statements,
s(:return,
s(:name, :n)))))

View File

@ -0,0 +1,29 @@
Biggie fibonaccit(int n)
a = 0
while_ok(n)
some = 43
other = some * 4
end
end
-- -- --
s(:statements,
s(:function, :Biggie,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:assignment,
s(:name, :a),
s(:int, 0)),
s(:while_statement, :ok,
s(:conditional,
s(:name, :n)),
s(:statements,
s(:assignment,
s(:name, :some),
s(:int, 43)),
s(:assignment,
s(:name, :other),
s(:operator_value, :*,
s(:name, :some),
s(:int, 4))))))))

View File

@ -0,0 +1,13 @@
int foo(Class x)
a = 1
end
-- -- --
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :Class, :x)),
s(:statements,
s(:assignment,
s(:name, :a),
s(:int, 1)))))

View File

@ -0,0 +1,17 @@
if_true(0)
fourty = 10
else
twenty = 5
end
-- -- --
s(:if_statement, :true,
s(:condition,
s(:int, 0)),
s(:true_statements,
s(:assignment,
s(:name, :fourty),
s(:int, 10))),
s(:false_statements,
s(:assignment,
s(:name, :twenty),
s(:int, 5))))

View File

@ -0,0 +1,25 @@
if_yes(3 > var)
Object.initialize(3)
else
var.new(33)
end
-- -- --
s(:if_statement, :yes,
s(:condition,
s(:operator_value, :>,
s(:int, 3),
s(:name, :var))),
s(:true_statements,
s(:call,
s(:name, :initialize),
s(:arguments,
s(:int, 3)),
s(:receiver,
s(:class_name, :Object)))),
s(:false_statements,
s(:call,
s(:name, :new),
s(:arguments,
s(:int, 33)),
s(:receiver,
s(:name, :var)))))

View File

@ -0,0 +1,9 @@
foo.bar - gumbar
-- -- --
s(:operator_value, :-,
s(:field_access,
s(:receiver,
s(:name, :foo)),
s(:field,
s(:name, :bar))),
s(:name, :gumbar))

View File

@ -0,0 +1,9 @@
5 % foo.bar
-- -- --
s(:operator_value, :%,
s(:int, 5),
s(:field_access,
s(:receiver,
s(:name, :foo)),
s(:field,
s(:name, :bar))))

View File

@ -0,0 +1,5 @@
3 > var
-- -- --
s(:operator_value, :>,
s(:int, 3),
s(:name, :var))

View File

@ -0,0 +1,5 @@
5 + 7
-- -- --
s(:operator_value, :+,
s(:int, 5),
s(:int, 7))

View File

@ -0,0 +1,5 @@
a - b
-- -- --
s(:operator_value, :-,
s(:name, :a),
s(:name, :b))

View File

@ -0,0 +1,5 @@
a - 5
-- -- --
s(:operator_value, :-,
s(:name, :a),
s(:int, 5))

View File

@ -0,0 +1,5 @@
a - "st"
-- -- --
s(:operator_value, :-,
s(:name, :a),
s(:string, "st"))

View File

@ -0,0 +1,5 @@
a == true
-- -- --
s(:operator_value, :==,
s(:name, :a),
s(:true))

View File

@ -0,0 +1,5 @@
5 / 3
-- -- --
s(:operator_value, :/,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,5 @@
5 > 3
-- -- --
s(:operator_value, :>,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,5 @@
5 - 3
-- -- --
s(:operator_value, :-,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,5 @@
5 * 3
-- -- --
s(:operator_value, :*,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,5 @@
5 + 3
-- -- --
s(:operator_value, :+,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,5 @@
5 < 3
-- -- --
s(:operator_value, :<,
s(:int, 5),
s(:int, 3))

View File

@ -0,0 +1,9 @@
gumbar & foo.bar
-- -- --
s(:operator_value, :&,
s(:name, :gumbar),
s(:field_access,
s(:receiver,
s(:name, :foo)),
s(:field,
s(:name, :bar))))

View File

@ -0,0 +1,5 @@
bar - gumbar
-- -- --
s(:operator_value, :-,
s(:name, :bar),
s(:name, :gumbar))

View File

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

View File

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

View File

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

View File

@ -0,0 +1,21 @@
class FooBo
int main()
Bar.call(35)
end
end
-- -- --
s(:statements,
s(:class, :FooBo,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :main),
s(:parameters),
s(:statements,
s(:call,
s(:name, :call),
s(:arguments,
s(:int, 35)),
s(:receiver,
s(:class_name, :Bar))))))))

View File

@ -0,0 +1,34 @@
class Object
int foo(String x)
a = 5
end
end
class Other < Object
int foo()
foo( 3 )
end
end
-- -- --
s(:statements,
s(:class, :Object,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters,
s(:parameter, :String, :x)),
s(:statements,
s(:assignment,
s(:name, :a),
s(:int, 5)))))),
s(:class, :Other,
s(:derives, :Object),
s(:statements,
s(:function, :Integer,
s(:name, :foo),
s(:parameters),
s(:statements,
s(:call,
s(:name, :foo),
s(:arguments,
s(:int, 3))))))))

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

@ -0,0 +1,65 @@
class Object
int fibonaccit(int n)
a = 0
b = 1
while_plus( n )
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
int main()
fibonaccit( 10 )
end
end
-- -- --
s(:statements,
s(:class, :Object,
s(:derives, nil),
s(:statements,
s(:function, :Integer,
s(:name, :fibonaccit),
s(:parameters,
s(:parameter, :Integer, :n)),
s(:statements,
s(:assignment,
s(:name, :a),
s(:int, 0)),
s(:assignment,
s(:name, :b),
s(:int, 1)),
s(:while_statement, :plus,
s(:conditional,
s(:name, :n)),
s(:statements,
s(:assignment,
s(:name, :tmp),
s(:name, :a)),
s(:assignment,
s(:name, :a),
s(:name, :b)),
s(:assignment,
s(:name, :b),
s(:operator_value, :+,
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assignment,
s(:name, :n),
s(:operator_value, :-,
s(:name, :n),
s(:int, 1))))))),
s(:function, :Integer,
s(:name, :main),
s(:parameters),
s(:statements,
s(:call,
s(:name, :fibonaccit),
s(:arguments,
s(:int, 10))))))))

View File

@ -0,0 +1,12 @@
if_zero(0)
four = 42
end
-- -- --
s(:if_statement, :zero,
s(:condition,
s(:int, 0)),
s(:true_statements,
s(:assignment,
s(:name, :four),
s(:int, 42))),
s(:false_statements, nil))

View File

@ -0,0 +1,17 @@
if_overflow(3 + 100000 )
Object.initialize(3)
end
-- -- --
s(:if_statement, :overflow,
s(:condition,
s(:operator_value, :+,
s(:int, 3),
s(:int, 100000))),
s(:true_statements,
s(:call,
s(:name, :initialize),
s(:arguments,
s(:int, 3)),
s(:receiver,
s(:class_name, :Object)))),
s(:false_statements, nil))

View File

@ -0,0 +1,34 @@
while_allgood( n > 1)
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
-- -- --
s(:while_statement, :allgood,
s(:conditional,
s(:operator_value, :>,
s(:name, :n),
s(:int, 1))),
s(:statements,
s(:assignment,
s(:name, :tmp),
s(:name, :a)),
s(:assignment,
s(:name, :a),
s(:name, :b)),
s(:assignment,
s(:name, :b),
s(:operator_value, :+,
s(:name, :tmp),
s(:name, :b))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b))),
s(:assignment,
s(:name, :n),
s(:operator_value, :-,
s(:name, :n),
s(:int, 1)))))

View File

@ -0,0 +1,16 @@
while_false(1)
tmp = a
puts(b)
end
-- -- --
s(:while_statement, :false,
s(:conditional,
s(:int, 1)),
s(:statements,
s(:assignment,
s(:name, :tmp),
s(:name, :a)),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :b)))))

View File

@ -0,0 +1,22 @@
while_true(1)
tmp = String.new()
tmp.puts(i)
end
-- -- --
s(:while_statement, :true,
s(:conditional,
s(:int, 1)),
s(:statements,
s(:assignment,
s(:name, :tmp),
s(:call,
s(:name, :new),
s(:arguments),
s(:receiver,
s(:class_name, :String)))),
s(:call,
s(:name, :puts),
s(:arguments,
s(:name, :i)),
s(:receiver,
s(:name, :tmp)))))

View File

@ -1,20 +1,17 @@
require_relative "setup"
require "parslet/convenience"
# remove the line numbers on assert fails, so it's easy to copy paste the result as the expected result
Parslet::Slice.class_eval do
def inspect
'"' + to_s + '"'
end
end
# Included in parser test will create tests methods
# Older test harness
module ParserHelper
def self.included(base)
base.send :include, InstanceMethods #provides helpers and setup
base.send :include, AST::true_statements
base.send :extend, ClassMethods #gets the method creation going
end
module InstanceMethods
def setup
@parser = Parser::Salama.new
@ -38,24 +35,49 @@ module ParserHelper
def check_ast
syntax = @parser.parse(@string_input)
is = @transform.apply(syntax)
#puts is.inspect
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
module ClassMethods
# this creates test methods dynamically. For each test_* method we create
# this creates test methods dynamically. For each test_* method we create
# three test_*[ast/parse/transf] methods that in turn check the three phases.
# runnable_methods is called by minitest to determine which tests to run
def runnable_methods
tests = []
public_instance_methods(true).grep(/^test_/).map(&:to_s).each do |test|
["ast" , "transform" , "parse"].each do |what|
["write"].each do |what|
name = "#{test}_#{what}"
tests << name
self.send(:define_method, name ) do
send(test)
send("check_#{what}")
send("check_#{what}" , test)
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,63 +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
@string_input = '42 '
@parse_output = {:expression_list=>[{:integer=>"42"}]}
@transform_output = Ast::ExpressionList.new( [Ast::IntegerExpression.new(42)])
end
def test_name
@string_input = 'foo '
@parse_output = {:expression_list=>[{:name=>"foo"}]}
@transform_output = Ast::ExpressionList.new( [Ast::NameExpression.new(:foo)])
end
def test_name_underscode_start
@string_input = '_bar '
@parse_output = {:expression_list=>[{:name=>"_bar"}]}
@transform_output = Ast::ExpressionList.new( [Ast::NameExpression.new(:_bar)])
end
def test_name_underscode_middle
@string_input = 'foo_bar '
@parse_output = {:expression_list=>[{:name=>"foo_bar"}]}
@transform_output = Ast::ExpressionList.new( [Ast::NameExpression.new(:foo_bar)])
end
def test_instance_variable
@string_input = '@foo_bar '
@parse_output = {:expression_list=>[{:instance_variable=>{:name=>"foo_bar"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::VariableExpression.new(:foo_bar)])
end
def test_module_name
@string_input = 'FooBar '
@parse_output = {:expression_list=>[{:module_name=>"FooBar"}]}
@transform_output = Ast::ExpressionList.new( [Ast::ModuleName.new(:FooBar)])
end
def ttest_comment
out = "# i am a comment \n"
@string_input = out.dup #NEEDS the return, which is what delimits the comment
@parse_output = out
@transform_output = @parse_output #dont transform
end
def test_string
@string_input = "\"hello\""
@parse_output = {:expression_list=>[{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::StringExpression.new("hello")])
end
def test_string_escapes
out = 'hello \nyou'
@string_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"}]}]}
@transform_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
@string_input = <<HERE
self.call(1) do |a , b|
tmp = a
puts(b)
end
HERE
@parse_output = nil
@transform_output = nil
@parser = @parser
end
def pest_big_block
@string_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"}}]}
@transform_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)))] )])
@parser = @parser
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
@string_input = 'foo(42)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:self))])
@parser = @parser
end
def test_single_self
@string_input = 'self.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:name=>"self"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:self))])
@parser = @parser
end
def test_single_instance
@string_input = '@var.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:instance_variable=>{:name=>"var"}}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::VariableExpression.new(:var))])
@parser = @parser
end
def test_single_name
@string_input = 'my_my.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:name=>"my_my"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::NameExpression.new(:my_my))])
@parser = @parser
end
def test_int_receiver
@string_input = '42.put()'
@parse_output = {:expression_list=>[{:receiver=>{:integer=>"42"}, :call_site=>{:name=>"put"}, :argument_list=>[]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:put, [] ,Ast::IntegerExpression.new(42))])
@parser = @parser
end
def test_string_receiver
@string_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=>[]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [] ,Ast::StringExpression.new("hello"))])
@parser = @parser
end
def test_single_class
@string_input = 'Object.foo(42)'
@parse_output = {:expression_list=>[{:receiver=>{:module_name=>"Object"}, :call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:foo, [Ast::IntegerExpression.new(42)] ,Ast::ModuleName.new(:Object))])
@parser = @parser
end
def test_call_site_multi
@string_input = 'baz(42, foo)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"baz"}, :argument_list=>[{:argument=>{:integer=>"42"}}, {:argument=>{:name=>"foo"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:baz, [Ast::IntegerExpression.new(42),Ast::NameExpression.new(:foo)] ,Ast::NameExpression.new(:self))])
@parser = @parser
end
def test_call_site_string
@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"}]}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::StringExpression.new("hello")] ,Ast::NameExpression.new(:self))])
@parser = @parser
end
def test_call_operator
@string_input = 'puts( 3 + 5)'
@parse_output = {:expression_list=>[{:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"5"}}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:puts, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(5))] ,Ast::NameExpression.new(:self))])
@parser = @parser
end
def test_call_two_operators
@string_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"}}}]}]}
@transform_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))])
@parser = @parser
end
def test_call_chaining
@string_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"}}}]}]}
@transform_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))])
@parser = @parser
end
def test_call_chaining_name
@string_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"}}]}]}
@transform_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))])
@parser = @parser
end
def test_call_chaining_class
@string_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"}}]}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new(:self))] ,Ast::ModuleName.new(:Class))])
@parser = @parser
end
def test_call_chaining_instance
@string_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"}}]}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::CallSiteExpression.new(:new, [Ast::CallSiteExpression.new(:get, [Ast::IntegerExpression.new(4)] ,Ast::NameExpression.new(:self))] ,Ast::VariableExpression.new(:class))])
@parser = @parser
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
@string_input = <<HERE
class Foo
5
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Foo", :derived_name=>nil, :class_expressions=>[{:integer=>"5"}], :end=>"end"}]}
@transform_output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,nil, [Ast::IntegerExpression.new(5)] )])
end
def test_class_ops
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_input = '[42]'
@parse_output = {:expression_list=>[{:array_constant=>[{:array_element=>{:integer=>"42"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)])])
end
def test_array_list
@string_input = '[42, foo]'
@parse_output = {:expression_list=>[{:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:name=>"foo"}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new(:foo)])])
end
def test_array_ops
@string_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"}}]}}]}]}
@transform_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
@string_input = '{ foo => 33 }'
@parse_output = {:expression_list=>[{:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new(:foo) , Ast::IntegerExpression.new(33))])])
end
def test_hash2
@string_input = '{ foo => true }'
@parse_output = {:expression_list=>[{:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:true=>"true"}}}]}]}
@transform_output = Ast::ExpressionList.new( [Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new(:foo) , Ast::TrueExpression.new())])])
end
def test_hash_list
@string_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"}}}]}]}
@transform_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
@string_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"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@parser = @parser
end
def test_if_else_expressions
@string_input = <<HERE
if(3 > var)
Object.initialize(3)
else
var.new(33)
end
HERE
@string_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"}}]}
@transform_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
@string_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"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@parser = @parser
end
def pest_if_end_expressions
@string_input = <<HERE
if(3 > var)
Object.initialize(3)
end
HERE
@string_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"}}]}
@transform_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
@string_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"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )])
@parser = @parser
end
def pest_if_end_expressions
@string_input = "Object.initialize(3) if(3 > var)"
@string_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"}}]}
@transform_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
@string_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"}]}
@transform_output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::IntegerExpression.new(5)] ,nil )])
@parser = @parser
end
def test_function_no_braces
@string_input = <<HERE
def foo
5
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :expressions=>[{:integer=>"5"}], :end=>"end"}]}
@transform_output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [] , [Ast::IntegerExpression.new(5)] ,nil )])
@parser = @parser
end
def pest_function_no_braces_and_args
@string_input = <<HERE
def foo n , m
n
end
HERE
@parse_output = {:expression_list=>[{:function_name=>{:name=>"foo"}, :expressions=>[{:name=>"n"}], :end=>"end"}]}
@transform_output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:foo, [] , [Ast::NameExpression.new(:n)] ,nil )])
@parser = @parser
end
def test_class_function
@string_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"}]}
@transform_output = Ast::ExpressionList.new( [Ast::FunctionExpression.new(:length, [Ast::NameExpression.new(:x)] , [Ast::VariableExpression.new(:length)] ,Ast::ModuleName.new(:String) )])
@parser = @parser
end
def pest_function_default_args
@string_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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_ops
@string_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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_if
@string_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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_return
@string_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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_return_if
@string_input = <<HERE
def retvar(n)
if( n > 5)
return 10
else
return 20
end
end
HERE
@parse_output = {: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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_return_while
@string_input = <<HERE
def retvar(n)
while( n > 5) do
n = n + 1
return n
end
end
HERE
@parse_output = {: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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_while
@string_input = <<HERE
def fibonaccit(n)
a = 0
while (n) do
some = 43
other = some * 4
end
end
HERE
@parse_output = {: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"}]}
@transform_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 )])
@parser = @parser
end
def test_function_big_while
@string_input = <<HERE
def fibonaccit(n)
a = 0
b = 1
while( n > 1 ) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
HERE
@parse_output = {: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"}]}
@transform_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 )])
@parser = @parser
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
@string_input = <<HERE
module Simple
5
end
HERE
@parse_output = {:expression_list=>[{:module_name=>"Simple", :module_expressions=>[{:integer=>"5"}], :end=>"end"}]}
@transform_output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Simple ,[Ast::IntegerExpression.new(5)] )])
end
def test_module_ops
@string_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"}]}
@transform_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
@string_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"}]}
@transform_output = Ast::ExpressionList.new( [Ast::ModuleExpression.new(:Opers ,[Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5))] )])
end
def test_module_if
@string_input = <<HERE
module Foo
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {: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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_output = Ast::ExpressionList.new( [Ast::ClassExpression.new(:Foo ,nil, [Ast::FunctionExpression.new(:bar, [] , [Ast::IntegerExpression.new(4)] ,nil )] )])
end
def test_module_class
@string_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"}]}
@transform_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
@string_input = "5 #{op} 3"
@parse_output = {:expression_list=>[{:l=>{:integer=>"5"}, :o=>"#{op} ", :r=>{:integer=>"3"}}]}
@transform_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
@string_input = "a + 35"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"+ ", :r=>{:integer=>"35"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("+", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(35))])
end
def test_op_two_variable
@string_input = "a - b"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"- ", :r=>{:name=>"b"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::NameExpression.new(:b))])
end
def test_op_instance_variable
@string_input = "@a - 5"
@parse_output = {:expression_list=>[{:l=>{:instance_variable=>{:name=>"a"}}, :o=>"- ", :r=>{:integer=>"5"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))])
end
def test_op_variable_string
@string_input = 'a - "st"'
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"- ", :r=>{:string=>[{:char=>"s"}, {:char=>"t"}]}}]}
@transform_output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::StringExpression.new("st"))])
end
def test_op_variable_true
@string_input = 'a == true'
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"== ", :r=>{:true=>"true"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::OperatorExpression.new("==", Ast::NameExpression.new(:a),Ast::TrueExpression.new())])
end
def test_two_same_ops
@string_input = '2 + 3 + 4'
@parse_output = {:expression_list=>[{:l=>{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}]}
@transform_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
@string_input = '2 + 3 * 4'
@parse_output = {:expression_list=>[{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:l=>{:integer=>"3"}, :o=>"* ", :r=>{:integer=>"4"}}}]}
@transform_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
@string_input = '2 * 3 + 4'
@parse_output = {:expression_list=>[{:l=>{:l=>{:integer=>"2"}, :o=>"* ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}]}
@transform_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
@string_input = "a = 5"
@parse_output = {:expression_list=>[{:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}]}
@transform_output = Ast::ExpressionList.new( [Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5))])
end
def test_assignment_instance
@string_input = "@a = 5"
@parse_output = {:expression_list=>[{:l=>{:instance_variable=>{:name=>"a"}}, :o=>"= ", :r=>{:integer=>"5"}}]}
@transform_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
@string_input = 'return 42'
@parse_output = {:expression_list=>[{:name=>"return"}, {:integer=>"42"}]}
@transform_output = Ast::ExpressionList.new( [Ast::NameExpression.new(:return),Ast::IntegerExpression.new(42)])
end
def test_return_variable
@string_input = 'return foo'
@parse_output = {:expression_list=>[{:name=>"return"}, {:name=>"foo"}]}
@transform_output = Ast::ExpressionList.new( [Ast::NameExpression.new(:return),Ast::NameExpression.new(:foo)])
end
def test_return_string
@string_input = 'return "hello"'
@parse_output = {:expression_list=>[{:name=>"return"}, {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}]}
@transform_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
@string_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"}}]}]}
@transform_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
@string_input = <<HERE
def foo(x) #here
a = 0 # a == r1
b = 1 # b = r2
while(n<1) do #comment
tmp = a # r3 <- r1
a = b # r1 <- r2
b = tmp + b # r4 = r2 + r3 (r4 transient) r2 <- r4
putstring(b)
n = n - 1 #me
end #no
end #anywhere
foo( 3 ) #and more
HERE
@parse_output = {: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"}}]}]}
@transform_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
@string_input = <<HERE
def fibonaccit(n)
a = 0
b = 1
while( n > 1 ) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
fibonaccit( 10 )
HERE
@parse_output = {: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"}}]}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}]}
@transform_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
@string_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"}}]}
@transform_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))] )])
@parser = @parser
end
def pest_while_reverse
@string_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"}}]}
@transform_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))] )])
@parser = @parser
end
def test_while_method
@string_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"}}]}
@transform_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))] )])
@parser = @parser
end
def test_big_while
@string_input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@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"}}]}
@transform_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)))] )])
@parser = @parser
end
end

View File

@ -8,15 +8,12 @@ rescue Bundler::BundlerError => e
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
if ENV['CODECLIMATE_REPO_TOKEN']
require "codeclimate-test-reporter"
CodeClimate::TestReporter.start
end
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'salama-reader'
require 'soml-parser'
require "minitest"
require "minitest/autorun"
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'test'))

View File

@ -1,2 +1,60 @@
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)
begin
syntax = Parser::Salama.new.parse(inn)
rescue
root = file.split("/")[2]
parser = Parser::Salama.new.send root.to_sym
syntax = parser.parse_with_debug(inn )
end
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
check_transform sexp
end
def check_transform sexp
code = Soml.ast_to_code sexp
assert code.is_a?(Soml::Code) , "Returned #{code}"
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
@string_input = '(42)'
@parse_output = {:argument_list => [{:argument => {:integer => '42'}}] }
@transform_output = [Ast::IntegerExpression.new(42) ]
@parser = @parser.argument_list
end
def test_argument_list
@string_input = '(42, foo)'
@parse_output = {:argument_list => [{:argument => {:integer => '42'}},
{:argument => {:name => 'foo'}}]}
@transform_output = [Ast::IntegerExpression.new(42), Ast::NameExpression.new('foo')]
@parser = @parser.argument_list
end
def test_parameter
@string_input = "(foo)"
@parse_output = {:parameter_list=>[{:parameter=>{:name=>"foo"}}]}
@transform_output = [Ast::NameExpression.new('foo')]
@parser = @parser.parameter_list
end
def test_parameter_list
@string_input = "( foo , bar)"
@parse_output = {:parameter_list => [{:parameter => { :name => "foo"}},
{:parameter => { :name => "bar"}} ]}
@transform_output = [Ast::NameExpression.new('foo') , Ast::NameExpression.new('bar')]
@parser = @parser.parameter_list
end
end

View File

@ -1,92 +0,0 @@
require_relative "../parser_helper"
class TestBasic < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_true
@string_input = 'true '
@parse_output = {:true => 'true'}
@transform_output = Ast::TrueExpression.new()
@parser = @parser.basic_type
end
def test_false
@string_input = 'false '
@parse_output = {:false => 'false'}
@transform_output = Ast::FalseExpression.new()
@parser = @parser.basic_type
end
def test_nil
@string_input = 'nil '
@parse_output = {:nil => 'nil'}
@transform_output = Ast::NilExpression.new()
@parser = @parser.basic_type
end
def test_number
@string_input = '42 '
@parse_output = {:integer => '42'}
@transform_output = Ast::IntegerExpression.new(42)
@parser = @parser.integer
end
def test_name
@string_input = 'foo '
@parse_output = {:name => 'foo'}
@transform_output = Ast::NameExpression.new('foo')
@parser = @parser.name
end
def test_name_underscode_start
@string_input = '_bar '
@parse_output = {:name => '_bar'}
@transform_output = Ast::NameExpression.new('_bar')
@parser = @parser.name
end
def test_name_underscode_middle
@string_input = 'foo_bar '
@parse_output = {:name => 'foo_bar'}
@transform_output = Ast::NameExpression.new('foo_bar')
@parser = @parser.name
end
def test_instance_variable
@string_input = '@foo_bar '
@parse_output = {:instance_variable=>{:name=>"foo_bar"}}
@transform_output = Ast::VariableExpression.new(:foo_bar)
@parser = @parser.instance_variable
end
def test_module_name
@string_input = 'FooBar '
@parse_output = {:module_name=>"FooBar"}
@transform_output = Ast::ModuleName.new("FooBar")
@parser = @parser.module_name
end
def test_comment
out = "# i am a comment \n"
@string_input = out.dup #NEEDS the return, which is what delimits the comment
@parse_output = out
@transform_output = @parse_output #dont transform
@parser = @parser.comment
end
def test_string
@string_input = "\"hello\""
@parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}
@transform_output = Ast::StringExpression.new('hello')
@parser = @parser.string
end
def test_string_escapes
out = 'hello \nyou'
@string_input = '"' + out + '"'
@parse_output = {:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"},
{:char=>" "}, {:char=>" "}, {:esc=>"n"}, {:char=>"y"}, {:char=>"o"}, {:char=>"u"}]}
@transform_output = Ast::StringExpression.new(out)
@parser = @parser.string
end
end

View File

@ -1,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
@string_input = <<HERE
while(1) do
tmp = a
puts(b)
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}], :end=>"end"}}
@transform_output = Ast::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))] )
@parser = @parser.block
end
def pest_block_method
@string_input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:receiver=>{:module_name=>"String"}, :call_site=>{:name=>"new"}, :argument_list=>[]}}, {:receiver=>{:name=>"tmp"}, :call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"i"}}]}], :end=>"end"}}
@transform_output = Ast::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))] )
@parser = @parser.block
end
def pest_big_block
@string_input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"1"}}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:l=>{:name=>"a"}, :o=>"= ", :r=>{:name=>"b"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:l=>{:name=>"tmp"}, :o=>"+ ", :r=>{:name=>"b"}}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}, {:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"- ", :r=>{:integer=>"1"}}}], :end=>"end"}}
@transform_output = Ast::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)))] )
@parser = @parser.block
end
end

View File

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

View File

@ -1,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
@string_input = <<HERE
class Foo
5
end
HERE
@parse_output = {:module_name=>"Foo", :derived_name=>nil, :class_expressions=>[{:integer=>"5"}], :end=>"end"}
@transform_output = Ast::ClassExpression.new(:Foo ,nil, [Ast::IntegerExpression.new(5)] )
@parser = @parser.class_definition
end
def test_class_ops
@string_input = <<HERE
class Opers
def foo(x)
@abba = 5
2 + 5
end
end
HERE
@parse_output = {:module_name=>"Opers", :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"}
@transform_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 )] )
@parser = @parser.class_definition
end
def test_class_if
@string_input = <<HERE
class Ifi
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:module_name=>"Ifi", :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"}
@transform_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 )] )
@parser = @parser.class_definition
end
def test_class_function
@string_input = <<HERE
class Pifi
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:module_name=>"Pifi", :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"}
@transform_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 )] )
@parser = @parser.class_definition
end
def test_class_module
@string_input = <<HERE
class Foo
module Boo
funcall(3+4 , var)
end
end
HERE
@parse_output = {:module_name=>"Foo", :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"}
@transform_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))] )] )
@parser = @parser.class_definition
end
def test_class_derived
@string_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"}
@transform_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))] )
@parser = @parser.class_definition
end
def test_class_method
@string_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"}
@transform_output = Ast::ClassExpression.new(:Foo ,:Object, [Ast::FunctionExpression.new(:test, [] , [Ast::IntegerExpression.new(43)] ,Ast::ModuleName.new(:Foo) )] )
@parser = @parser.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
@string_input = '[42]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}]}
@transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42)])
@parser = @parser.array_constant
end
def test_array_list
@string_input = '[42, foo]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:name=>"foo"}}]}
@transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NameExpression.new("foo")])
@parser = @parser.array_constant
end
def test_array_list2
@string_input = '[42, nil]'
@parse_output = {:array_constant=>[{:array_element=>{:integer=>"42"}}, {:array_element=>{:nil=>"nil"}}]}
@transform_output = Ast::ArrayExpression.new([Ast::IntegerExpression.new(42), Ast::NilExpression.new()])
@parser = @parser.array_constant
end
def test_array_ops
@string_input = '[ 3 + 4 , foo(22) ]'
@parse_output = {:array_constant=>[{:array_element=>{:l=>{:integer=>"3"}, :o=>"+ ", :r=>{:integer=>"4"}}}, {:array_element=>{:call_site=>{:name=>"foo"}, :argument_list=>[{:argument=>{:integer=>"22"}}]}}]}
@transform_output = Ast::ArrayExpression.new(
[Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),
Ast::CallSiteExpression.new("foo", [Ast::IntegerExpression.new(22)] )])
@parser = @parser.array_constant
end
def test_hash
@string_input = '{ foo => 33 }'
@parse_output = {:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}]}
@transform_output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33))])
@parser = @parser.hash_constant
end
def test_hash_list
@string_input = "{foo => 33 , bar => 42}"
@parse_output = {:hash_constant=>[{:hash_pair=>{:hash_key=>{:name=>"foo"}, :hash_value=>{:integer=>"33"}}}, {:hash_pair=>{:hash_key=>{:name=>"bar"}, :hash_value=>{:integer=>"42"}}}]}
@transform_output = Ast::HashExpression.new([Ast::AssociationExpression.new(Ast::NameExpression.new("foo") , Ast::IntegerExpression.new(33)),Ast::AssociationExpression.new(Ast::NameExpression.new("bar") , Ast::IntegerExpression.new(42))])
@parser = @parser.hash_constant
end
end

View File

@ -1,74 +0,0 @@
require_relative "../parser_helper"
class TestConditional < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_conditional_brackets
check("(0)")
end
def test_conditional_no_brackets
check("0")
end
def check cond
input = <<HERE
42
else
667
end
HERE
@string_input = "if #{cond} " + input.chop!
@parse_output = {:if=>"if", :conditional=>{:integer=>"0"}, :if_true=>{:expressions=>[{:integer=>"42"}], :else=>"else"}, :if_false=>{:expressions=>[{:integer=>"667"}], :end=>"end"}}
@transform_output = Ast::IfExpression.new(Ast::IntegerExpression.new(0), [Ast::IntegerExpression.new(42)],[Ast::IntegerExpression.new(667)] )
@parser = @parser.conditional
end
def test_conditional_with_calls
@string_input = <<HERE
if(3 > var)
Object.initialize(3)
else
var.new(33)
end
HERE
@string_input.chop!
@parse_output = {:if=>"if", :conditional=>{:l=>{:integer=>"3"}, :o=>"> ", :r=>{:name=>"var"}}, :if_true=>{:expressions=>[{:receiver=>{:module_name=>"Object"}, :call_site=>{:name=>"initialize"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}], :else=>"else"}, :if_false=>{:expressions=>[{:receiver=>{:name=>"var"}, :call_site=>{:name=>"new"}, :argument_list=>[{:argument=>{:integer=>"33"}}]}], :end=>"end"}}
@transform_output = Ast::IfExpression.new(Ast::OperatorExpression.new(">", Ast::IntegerExpression.new(3),Ast::NameExpression.new("var")), [Ast::CallSiteExpression.new(:initialize, [Ast::IntegerExpression.new(3)] ,Ast::ModuleName.new("Object"))],[Ast::CallSiteExpression.new(:new, [Ast::IntegerExpression.new(33)] ,Ast::NameExpression.new("var"))] )
@parser = @parser.conditional
end
def test_conditional_nil
@string_input = <<HERE
if(3 == nil)
3
else
4
end
HERE
@string_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"}}
@transform_output = Ast::IfExpression.new(Ast::OperatorExpression.new("==", Ast::IntegerExpression.new(3),Ast::NilExpression.new()), [Ast::IntegerExpression.new(3)],[Ast::IntegerExpression.new(4)] )
@parser = @parser.conditional
end
def pest_simple_if
@string_input = <<HERE
if(3 == nil)
3
end
HERE
@string_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"}}
@transform_output = Ast::IfExpression.new(Ast::OperatorExpression.new("==", Ast::IntegerExpression.new(3),Ast::NilExpression.new()), [Ast::IntegerExpression.new(3)],[Ast::IntegerExpression.new(4)] )
@parser = @parser.conditional
end
def pest_reverse_if
@string_input = "3 if(3 == nil)"
@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"}}
@transform_output = Ast::IfExpression.new(Ast::OperatorExpression.new("==", Ast::IntegerExpression.new(3),Ast::NilExpression.new()), [Ast::IntegerExpression.new(3)],[Ast::IntegerExpression.new(4)] )
@parser = @parser.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
@string_input = <<HERE
dud
fuu(3)
else
HERE
@string_input.chop!
@parse_output = {:expressions=>[{:name=>"dud"},
{:call_site=>{:name=>"fuu"}, :argument_list=>[{:argument=>{:integer=>"3"}}]}],
:else=>"else"}
@transform_output ={:expressions=>[Ast::NameExpression.new("dud"),
Ast::CallSiteExpression.new("fuu", [Ast::IntegerExpression.new(3)] )], :else=>"else"}
@parser = @parser.expressions_else
end
def test_expression_end
@string_input = <<HERE
name
call(4,6)
end
HERE
@string_input.chop!
@parse_output = {:expressions=>[{:name=>"name"},
{:call_site=>{:name=>"call"}, :argument_list=>[{:argument=>{:integer=>"4"}}, {:argument=>{:integer=>"6"}}]}],
:end=>"end"}
@transform_output = {:expressions=>[Ast::NameExpression.new("name"),
Ast::CallSiteExpression.new("call", [Ast::IntegerExpression.new(4),Ast::IntegerExpression.new(6)] )],
:end=>"end"}
@parser = @parser.expressions_end
end
end

View File

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

View File

@ -1,130 +0,0 @@
require_relative "../parser_helper"
class TestFunctionDefinition < MiniTest::Test
# include the magic (setup and parse -> test method translation), see there
include ParserHelper
def test_simplest_function
@string_input = <<HERE
def foo(x)
5
end
HERE
@parse_output = {:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:integer=>"5"}], :end=>"end"}
@transform_output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new("x")] , [Ast::IntegerExpression.new(5)] )
@parser = @parser.function_definition
end
def test_class_function
@string_input = <<HERE
def String.length(x)
@length
end
HERE
@parse_output = {:receiver=>{:module_name=>"String"}, :function_name=>{:name=>"length"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:instance_variable=>{:name=>"length"}}], :end=>"end"}
@transform_output = Ast::FunctionExpression.new(:length, [Ast::NameExpression.new("x")] , [Ast::VariableExpression.new(:length)] ,Ast::ModuleName.new("String") )
@parser = @parser.function_definition
end
def test_function_ops
@string_input = <<HERE
def foo(x)
abba = 5
2 + 5
end
HERE
@parse_output = {:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}
@transform_output = Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )
@parser = @parser.function_definition
end
def test_function_if
@string_input = <<HERE
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
HERE
@parse_output = {:function_name=>{:name=>"ofthen"}, :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"}
@transform_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 )
@parser = @parser.function_definition
end
def test_function_return
@string_input = <<HERE
def retvar(n)
i = 5
return i
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :parameter_list=>[{:parameter=>{:name=>"n"}}], :expressions=>[{:l=>{:name=>"i"}, :o=>"= ", :r=>{:integer=>"5"}}, {:return=>"return", :return_expression=>{:name=>"i"}}], :end=>"end"}
@transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:i),Ast::IntegerExpression.new(5)),Ast::ReturnExpression.new(Ast::NameExpression.new(:i) )] ,nil )
@parser = @parser.function_definition
end
def test_function_return_if
@string_input = <<HERE
def retvar(n)
if( n > 5)
return 10
else
return 20
end
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :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"}
@transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new("n")] , [Ast::IfExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new("n"),Ast::IntegerExpression.new(5)), [Ast::ReturnExpression.new(Ast::IntegerExpression.new(10) )],[Ast::ReturnExpression.new(Ast::IntegerExpression.new(20) )] )] )
@parser = @parser.function_definition
end
def test_function_return_while
@string_input = <<HERE
def retvar(n)
while( n > 5) do
n = n + 1
return n
end
end
HERE
@parse_output = {:function_name=>{:name=>"retvar"}, :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"}
@transform_output = Ast::FunctionExpression.new(:retvar, [Ast::NameExpression.new(:n)] , [Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(5)), [Ast::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 )
@parser = @parser.function_definition
end
def test_function_while
@string_input = <<HERE
def fibonaccit(n)
a = 0
while (n) do
some = 43
other = some * 4
end
end
HERE
@parse_output = {:function_name=>{:name=>"fibonaccit"}, :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"}
@transform_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 )
@parser = @parser.function_definition
end
def test_function_big_while
@string_input = <<HERE
def fibonaccit(n)
a = 0
b = 1
while( n > 1 ) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
end
HERE
@parse_output = {:function_name=>{:name=>"fibonaccit"}, :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"}
@transform_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 )
@parser = @parser.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
@string_input = <<HERE
module Simple
5
end
HERE
@parse_output = {:module_name=>"Simple", :module_expressions=>[{:integer=>"5"}], :end=>"end"}
@transform_output = Ast::ModuleExpression.new(:Simple ,[Ast::IntegerExpression.new(5)] )
@parser = @parser.module_definition
end
def test_module_ops
@string_input = <<HERE
module Opers
def foo(x)
abba = 5
2 + 5
end
end
HERE
@parse_output = {:module_name=>"Opers", :module_expressions=>[{:function_name=>{:name=>"foo"}, :parameter_list=>[{:parameter=>{:name=>"x"}}], :expressions=>[{:l=>{:name=>"abba"}, :o=>"= ", :r=>{:integer=>"5"}}, {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"5"}}], :end=>"end"}], :end=>"end"}
@transform_output = Ast::ModuleExpression.new(:Opers ,[Ast::FunctionExpression.new(:foo, [Ast::NameExpression.new(:x)] , [Ast::AssignmentExpression.new(Ast::NameExpression.new(:abba),Ast::IntegerExpression.new(5)),Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(5))] ,nil )] )
@parser = @parser.module_definition
end
def test_module_assign_instance
@string_input = <<HERE
module Opers
@abba = 5
end
HERE
@parse_output = {:module_name=>"Opers", :module_expressions=>[{:l=>{:instance_variable=>{:name=>"abba"}}, :o=>"= ", :r=>{:integer=>"5"}}], :end=>"end"}
@transform_output = Ast::ModuleExpression.new(:Opers ,[Ast::AssignmentExpression.new(Ast::VariableExpression.new(:abba),Ast::IntegerExpression.new(5))] )
@parser = @parser.module_definition
end
def test_module_if
@string_input = <<HERE
module Foo
def ofthen(n)
if(0)
isit = 42
else
maybenot = 667
end
end
end
HERE
@parse_output = {:module_name=>"Foo", :module_expressions=>[{:function_name=>{:name=>"ofthen"}, :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"}
@transform_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 )] )
@parser = @parser.module_definition
end
def test_module_function
@string_input = <<HERE
module Soho
ofthen(3+4 , var)
def ofthen(n,m)
44
end
end
HERE
@parse_output = {:module_name=>"Soho", :module_expressions=>[{:call_site=>{:name=>"ofthen"}, :argument_list=>[{:argument=>{:l=>{:integer=>"3"}, :o=>"+", :r=>{:integer=>"4"}}}, {:argument=>{:name=>"var"}}]}, {:function_name=>{:name=>"ofthen"}, :parameter_list=>[{:parameter=>{:name=>"n"}}, {:parameter=>{:name=>"m"}}], :expressions=>[{:integer=>"44"}], :end=>"end"}], :end=>"end"}
@transform_output = Ast::ModuleExpression.new(:Soho ,[Ast::CallSiteExpression.new(:ofthen, [Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)),Ast::NameExpression.new("var")] ), Ast::FunctionExpression.new(:ofthen, [Ast::NameExpression.new("n"),Ast::NameExpression.new("m")] , [Ast::IntegerExpression.new(44)] )] )
@parser = @parser.module_definition
end
def test_module_class
@string_input = <<HERE
module Foo
class Bar
funcall(3+4 , var)
end
end
HERE
@parse_output = {:module_name=>"Foo", :module_expressions=>[{:module_name=>"Bar", :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"}
@transform_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))] )] )
@parser = @parser.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
@string_input = "5 #{op} 3"
@parse_output = {:l=>{:integer=>"5"}, :o=>"#{op} ", :r=>{:integer=>"3"}}
@transform_output = Ast::OperatorExpression.new(op, Ast::IntegerExpression.new(5),Ast::IntegerExpression.new(3))
@parser = @parser.operator_expression
end
def test_simple_multiply
simple_op "*"
end
def test_simple_devide
simple_op "/"
end
def test_simple_plus
simple_op "+"
end
def test_simple_minus
simple_op "-"
end
def test_simple_greater
simple_op ">"
end
def test_simple_smaller
simple_op "<"
end
def test_op_variable
@string_input = "a + 35"
@parse_output = {:l=>{:name=>"a"}, :o=>"+ ", :r=>{:integer=>"35"}}
@transform_output = Ast::OperatorExpression.new("+", Ast::NameExpression.new(:a),Ast::IntegerExpression.new(35))
@parser = @parser.operator_expression
end
def test_op_two_variable
@string_input = "a - b"
@parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:name=>"b"}}
@transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::NameExpression.new("b"))
@parser = @parser.operator_expression
end
def test_op_instance_variable
@string_input = "@a - 5"
@parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"- ", :r=>{:integer=>"5"}}
@transform_output = Ast::OperatorExpression.new("-", Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))
@parser = @parser.operator_expression
end
def test_op_variable_string
@string_input = 'a - "st"'
@parse_output = {:l=>{:name=>"a"}, :o=>"- ", :r=>{:string=>[{:char=>"s"}, {:char=>"t"}]}}
@transform_output = Ast::OperatorExpression.new("-", Ast::NameExpression.new(:a),Ast::StringExpression.new("st"))
@parser = @parser.operator_expression
end
def test_two_same_ops
@string_input = '2 + 3 + 4'
@parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}
@transform_output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))
@parser = @parser.operator_expression
end
def test_two_different_ops
@string_input = '2 + 3 * 4'
@parse_output = {:l=>{:integer=>"2"}, :o=>"+ ", :r=>{:l=>{:integer=>"3"}, :o=>"* ", :r=>{:integer=>"4"}}}
@transform_output = Ast::OperatorExpression.new("+", Ast::IntegerExpression.new(2),Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(3),Ast::IntegerExpression.new(4)))
@parser = @parser.operator_expression
end
def test_two_different_ops_order
@string_input = '2 * 3 + 4'
@parse_output = {:l=>{:l=>{:integer=>"2"}, :o=>"* ", :r=>{:integer=>"3"}}, :o=>"+ ", :r=>{:integer=>"4"}}
@transform_output = Ast::OperatorExpression.new("+", Ast::OperatorExpression.new("*", Ast::IntegerExpression.new(2),Ast::IntegerExpression.new(3)),Ast::IntegerExpression.new(4))
@parser = @parser.operator_expression
end
def test_assignment
@string_input = "a = 5"
@parse_output = {:l=>{:name=>"a"}, :o=>"= ", :r=>{:integer=>"5"}}
@transform_output = Ast::AssignmentExpression.new(Ast::NameExpression.new(:a),Ast::IntegerExpression.new(5))
@parser = @parser.operator_expression
end
def test_assignment_instance
@string_input = "@a = 5"
@parse_output = {:l=>{:instance_variable=>{:name=>"a"}}, :o=>"= ", :r=>{:integer=>"5"}}
@transform_output = Ast::AssignmentExpression.new(Ast::VariableExpression.new(:a),Ast::IntegerExpression.new(5))
@parser = @parser.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
@string_input = 'return 42'
@parse_output = {:return=>"return", :return_expression=>{:integer=>"42"}}
@transform_output = Ast::ReturnExpression.new(Ast::IntegerExpression.new(42) )
@parser = @parser.simple_return
end
def test_return_variable
@string_input = 'return foo'
@parse_output = {:return=>"return", :return_expression=>{:name=>"foo"}}
@transform_output = Ast::ReturnExpression.new(Ast::NameExpression.new("foo") )
@parser = @parser.simple_return
end
def test_return_string
@string_input = 'return "hello"'
@parse_output = {:return=>"return", :return_expression=>{:string=>[{:char=>"h"}, {:char=>"e"}, {:char=>"l"}, {:char=>"l"}, {:char=>"o"}]}}
@transform_output = Ast::ReturnExpression.new(Ast::StringExpression.new("hello") )
@parser = @parser.simple_return
end
def test_return_true
@string_input = 'return true'
@parse_output = {:return=>"return", :return_expression=>{:true=>"true"}}
@transform_output = Ast::ReturnExpression.new(Ast::TrueExpression.new() )
@parser = @parser.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
@string_input = <<HERE
while(1) do
tmp = a
puts(b)
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}], :end=>"end"}}
@transform_output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::AssignmentExpression.new(Ast::NameExpression.new(:tmp),Ast::NameExpression.new(:a)), Ast::CallSiteExpression.new(:puts, [Ast::NameExpression.new(:b)] ,Ast::NameExpression.new(:self))] )
@parser = @parser.while_do
end
def pest_while_reverse
@string_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"}}
@transform_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))] )
@parser = @parser.while_do
end
def test_while_method
@string_input = <<HERE
while(1) do
tmp = String.new()
tmp.puts(i)
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:integer=>"1"}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:receiver=>{:module_name=>"String"}, :call_site=>{:name=>"new"}, :argument_list=>[]}}, {:receiver=>{:name=>"tmp"}, :call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"i"}}]}], :end=>"end"}}
@transform_output = Ast::WhileExpression.new(Ast::IntegerExpression.new(1), [Ast::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))] )
@parser = @parser.while_do
end
def test_big_while
@string_input = <<HERE
while( n > 1) do
tmp = a
a = b
b = tmp + b
puts(b)
n = n - 1
end
HERE
@string_input.chop!
@parse_output = {:while=>"while", :while_cond=>{:l=>{:name=>"n"}, :o=>"> ", :r=>{:integer=>"1"}}, :do=>"do", :body=>{:expressions=>[{:l=>{:name=>"tmp"}, :o=>"= ", :r=>{:name=>"a"}}, {:l=>{:name=>"a"}, :o=>"= ", :r=>{:name=>"b"}}, {:l=>{:name=>"b"}, :o=>"= ", :r=>{:l=>{:name=>"tmp"}, :o=>"+ ", :r=>{:name=>"b"}}}, {:call_site=>{:name=>"puts"}, :argument_list=>[{:argument=>{:name=>"b"}}]}, {:l=>{:name=>"n"}, :o=>"= ", :r=>{:l=>{:name=>"n"}, :o=>"- ", :r=>{:integer=>"1"}}}], :end=>"end"}}
@transform_output = Ast::WhileExpression.new(Ast::OperatorExpression.new(">", Ast::NameExpression.new(:n),Ast::IntegerExpression.new(1)), [Ast::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)))] )
@parser = @parser.while_do
end
end

36
to_code.rb Normal file
View File

@ -0,0 +1,36 @@
require 'rubygems'
require 'bundler'
Bundler.setup(:default, :development)
require 'soml-parser'
require "parslet/convenience"
require "ast/sexp"
require "pp"
class Converter
include AST::Sexp
SEPERATOR = "-- -- --"
def to_ast
file = ARGV[0]
inn = File.new(file).read.split(SEPERATOR).first
begin
syntax = Parser::Salama.new.parse(inn)
rescue
root = file.split("/").last.split(".").first
parser = Parser::Salama.new.send root.to_sym
syntax = parser.parse_with_debug(inn )
end
result = Parser::Transform.new.apply(syntax)
out_file = File.new(file, "w")
out_file.puts inn
out_file.puts SEPERATOR
out_file.puts result.inspect
out_file.close
end
end
Converter.new.to_ast