rockit 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BUGS +13 -0
- data/LICENSE +280 -0
- data/README +172 -0
- data/TODO +53 -0
- data/VERSION +1 -0
- data/lib/packrat/grammar.rb +537 -0
- data/lib/rockit/prettyprint/box.rb +60 -0
- data/lib/rockit/prettyprint/renderer.rb +41 -0
- data/lib/rockit/prettyprint/text_renderer.rb +47 -0
- data/lib/rockit/tree/base.rb +223 -0
- data/lib/rockit/tree/enter_leave_visitor.rb +12 -0
- data/lib/rockit/tree/graphviz.rb +69 -0
- data/lib/rockit/tree/visitor.rb +12 -0
- data/lib/util/array_alternatives.rb +20 -0
- data/lib/util/enter_leave_visitor.rb +69 -0
- data/lib/util/graphviz_dot.rb +182 -0
- data/lib/util/string_location.rb +42 -0
- data/lib/util/visitor.rb +49 -0
- data/lib/util/visitor_combinators.rb +14 -0
- data/rakefile +200 -0
- data/tests/acceptance/packrat/minibasic/atest_minibasic.rb +45 -0
- data/tests/acceptance/packrat/minibasic/minibasic.rb +137 -0
- data/tests/acceptance/rockit/dparser/atest_any_operator.rb +33 -0
- data/tests/acceptance/rockit/dparser/atest_arithmetic_grammar.rb +30 -0
- data/tests/acceptance/rockit/dparser/atest_list_operator.rb +57 -0
- data/tests/acceptance/rockit/dparser/atest_mult_operator.rb +60 -0
- data/tests/acceptance/rockit/dparser/atest_operator_grammar.rb +61 -0
- data/tests/acceptance/rockit/dparser/atest_plus_operator.rb +55 -0
- data/tests/acceptance/rockit/dparser/atest_samples_calculator.rb +14 -0
- data/tests/acceptance/rockit/dparser/atest_samples_minibasic.rb +20 -0
- data/tests/acceptance/rockit/dparser/atest_samples_multifunccalculator.rb +36 -0
- data/tests/acceptance/rockit/dparser/atest_simple_grammar.rb +34 -0
- data/tests/acceptance/rockit/dparser/atest_speculative_code_action.rb +128 -0
- data/tests/acceptance/rockit/dparser/calc_tests_common.rb +103 -0
- data/tests/unit/packrat/test_interpreting_parser.rb +296 -0
- data/tests/unit/parse/utest_ebnf_grammar.rb +50 -0
- data/tests/unit/parse/utest_expand_grammar.rb +23 -0
- data/tests/unit/parse/utest_grammar.rb +160 -0
- data/tests/unit/rockit/assembler/llvm/utest_instructions.rb +41 -0
- data/tests/unit/rockit/assembler/llvm/utest_module.rb +19 -0
- data/tests/unit/rockit/prettyprint/utest_box.rb +44 -0
- data/tests/unit/rockit/tree/utest_tree_base.rb +301 -0
- data/tests/unit/rockit/tree/utest_tree_enter_leave_visitor.rb +69 -0
- data/tests/unit/rockit/tree/utest_tree_visitor.rb +63 -0
- data/tests/unit/rockit/utest_grammar.rb +145 -0
- data/tests/unit/rockit/utest_grammar_symbol.rb +11 -0
- data/tests/unit/rockit/utest_maybe_operator.rb +12 -0
- data/tests/unit/rockit/utest_regexp_terminal.rb +45 -0
- data/tests/unit/rockit/utest_repetition_operators.rb +35 -0
- data/tests/unit/rockit/utest_rule.rb +23 -0
- data/tests/unit/rockit/utest_string_terminal.rb +40 -0
- data/tests/unit/util/utest_array_alternatives.rb +23 -0
- data/tests/unit/util/utest_enter_leave_visitor.rb +89 -0
- data/tests/unit/util/utest_string_location.rb +42 -0
- data/tests/unit/util/utest_visitor.rb +92 -0
- data/tests/unit/util/utest_visitor_combinators.rb +64 -0
- metadata +112 -0
data/rakefile
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/packagetask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
#require 'rubygems'
|
7
|
+
|
8
|
+
#require 'rbconfig'
|
9
|
+
#require 'find'
|
10
|
+
#require 'ftools'
|
11
|
+
#require 'fileutils'
|
12
|
+
#include Config
|
13
|
+
|
14
|
+
PROJECT = "rockit"
|
15
|
+
|
16
|
+
VERSION_FILE = "VERSION"
|
17
|
+
MANIFEST_FILE = "Manifest"
|
18
|
+
README_FILE = "README"
|
19
|
+
TODO_FILE = "TODO"
|
20
|
+
RAKE_FILE = "rakefile"
|
21
|
+
CHANGELOG = "Changelog"
|
22
|
+
|
23
|
+
|
24
|
+
task :default => :ptest
|
25
|
+
|
26
|
+
|
27
|
+
#############################################################################
|
28
|
+
# Version related
|
29
|
+
#############################################################################
|
30
|
+
|
31
|
+
# Read the version from the version file
|
32
|
+
def Version()
|
33
|
+
File.open(VERSION_FILE) {|fh| fh.read.strip}
|
34
|
+
end
|
35
|
+
|
36
|
+
# Update the version num on disc
|
37
|
+
def update_version
|
38
|
+
v = Version().split(".").map {|vp| vp.to_i}
|
39
|
+
new_v = yield(v)
|
40
|
+
File.open(VERSION_FILE, "w") {|fh| fh.write(new_v)}
|
41
|
+
puts Version()
|
42
|
+
end
|
43
|
+
|
44
|
+
def inc_tiny; update_version {|v| "#{v[0]}.#{v[1]}.#{v[2]+1}\n"}; end
|
45
|
+
def inc_minor; update_version {|v| "#{v[0]}.#{v[1]+1}.0\n"}; end
|
46
|
+
def inc_major; update_version {|v| "#{v[0]+1}.0.0\n"}; end
|
47
|
+
|
48
|
+
task :version do
|
49
|
+
puts Version()
|
50
|
+
end
|
51
|
+
task :inc_tiny do
|
52
|
+
inc_tiny()
|
53
|
+
end
|
54
|
+
task :inc_minor do
|
55
|
+
inc_minor()
|
56
|
+
end
|
57
|
+
task :inc_major do
|
58
|
+
inc_major()
|
59
|
+
end
|
60
|
+
|
61
|
+
#############################################################################
|
62
|
+
# Test related
|
63
|
+
#############################################################################
|
64
|
+
|
65
|
+
PackratTestFiles = FileList["tests/unit/packrat/test*.rb"]
|
66
|
+
PackratAcceptanceTestFiles = FileList["tests/acceptance/packrat/**/atest*.rb"]
|
67
|
+
|
68
|
+
task :setup_for_test do
|
69
|
+
$: << "lib"
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_files(list)
|
73
|
+
list.each {|f| puts "Loading #{f}"; require f}
|
74
|
+
end
|
75
|
+
|
76
|
+
task :ptest => [:setup_for_test] do
|
77
|
+
load_files PackratTestFiles
|
78
|
+
end
|
79
|
+
|
80
|
+
task :patest => [:setup_for_test] do
|
81
|
+
load_files PackratAcceptanceTestFiles
|
82
|
+
end
|
83
|
+
|
84
|
+
task :unit_tests => [:setup_for_test] do
|
85
|
+
load_files FileList["tests/unit/**/test*.rb"]
|
86
|
+
end
|
87
|
+
|
88
|
+
task :acceptance_tests do
|
89
|
+
load_files FileList["tests/acceptance/**/test*.rb"]
|
90
|
+
end
|
91
|
+
|
92
|
+
task :utest => :unit_tests
|
93
|
+
task :ut => :unit_tests
|
94
|
+
task :atest => :acceptance_tests
|
95
|
+
task :at => :acceptance_tests
|
96
|
+
|
97
|
+
#############################################################################
|
98
|
+
# Gem and package related
|
99
|
+
#############################################################################
|
100
|
+
|
101
|
+
BaseFileToIncludeGlobs = [
|
102
|
+
"README", "TODO", "BUGS", "LICENSE", "VERSION",
|
103
|
+
"rakefile", "Manifest",
|
104
|
+
"lib/packrat/**/*",
|
105
|
+
"lib/rockit/prettyprint/**/*",
|
106
|
+
"lib/rockit/tree/**/*",
|
107
|
+
"lib/util/**/*",
|
108
|
+
]
|
109
|
+
|
110
|
+
TestFilesToIncludeGlobs = [
|
111
|
+
"tests/acceptance/**/*",
|
112
|
+
"tests/unit/**/*",
|
113
|
+
]
|
114
|
+
|
115
|
+
PkgFileGlobs = BaseFileToIncludeGlobs + TestFilesToIncludeGlobs
|
116
|
+
|
117
|
+
GemSpec = Gem::Specification.new do |s|
|
118
|
+
s.name = PROJECT
|
119
|
+
s.version = Version()
|
120
|
+
s.platform = Gem::Platform::RUBY
|
121
|
+
s.summary = "Rockit is the Ruby Object-oriented Compiler construction toolKIT"
|
122
|
+
s.author = "Robert Feldt"
|
123
|
+
s.email = "Robert.Feldt@gmail.com"
|
124
|
+
s.homepage = "http://www.pronovomundo.com/projects/ruby/rockit"
|
125
|
+
|
126
|
+
s.description = <<EOS
|
127
|
+
Rockit is a potent parser generator and gives you AST's (Abstract Syntax Tree's) which you can pattern match and pretty-print. Rockit does not distinghuish between lexing and parsing so the generated parsers are scanner-/lexer-less. The vision is to extend Rockit with more advanced compiler-related abilities including back-ends and code generation. However, currently the focus is on parsing and AST-related tasks such as transformation.
|
128
|
+
EOS
|
129
|
+
|
130
|
+
s.require_path = "lib"
|
131
|
+
s.requirements << "none"
|
132
|
+
|
133
|
+
s.has_rdoc = false
|
134
|
+
# Dependency on rake?
|
135
|
+
|
136
|
+
s.files = []
|
137
|
+
PkgFileGlobs.each do |globpat|
|
138
|
+
fs = Dir.glob(globpat).delete_if {|i| i.include?(".svn")}
|
139
|
+
s.files += fs
|
140
|
+
end
|
141
|
+
|
142
|
+
s.extensions = []
|
143
|
+
end
|
144
|
+
|
145
|
+
Rake::GemPackageTask.new(GemSpec) do |pkg|
|
146
|
+
pkg.need_zip = true
|
147
|
+
pkg.need_tar = true
|
148
|
+
end
|
149
|
+
|
150
|
+
# Reformat the 'svn log' output to become the Changelog file. We assume
|
151
|
+
# log entries are single lines with each log event starting with an asterisk
|
152
|
+
# "*" and use those as split markers. We also insert newlines before the
|
153
|
+
# svn log event separators "-----------------------...---".
|
154
|
+
def reformat_svn_log_to_changelog(svnLogAsString)
|
155
|
+
s = svnLogAsString.split(/, \*/).join(",\n\n* ")
|
156
|
+
s.split(/^------/).join("\n------")
|
157
|
+
end
|
158
|
+
|
159
|
+
task :changelog do
|
160
|
+
# We must run 'svn up' first to make sure the log is recent
|
161
|
+
system "svn up"
|
162
|
+
File.open("Changelog", "w") do |fh|
|
163
|
+
fh.write reformat_svn_log_to_changelog(`svn log`)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
#############################################################################
|
168
|
+
# Rubyforge related
|
169
|
+
#############################################################################
|
170
|
+
|
171
|
+
# Create a package (a name for a top-level "item" which can then have multiple
|
172
|
+
# releases where each release can have multiple files)
|
173
|
+
def create_package(packageName = "rockit")
|
174
|
+
system "rubyforge create_package #{PROJECT} #{packageName}"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Release a <file> with a given <release_name> in the given <package>.
|
178
|
+
def release_file(file, release_name, package = PROJECT)
|
179
|
+
group_id = PROJECT
|
180
|
+
system "rubyforge add_release #{group_id} #{package} #{release_name} #{file}"
|
181
|
+
end
|
182
|
+
|
183
|
+
# Delete a package (and all its files)
|
184
|
+
def delete_package(packageName)
|
185
|
+
system "rubyforge create_package rockit #{ARGV.last}"
|
186
|
+
end
|
187
|
+
|
188
|
+
# We use a temporary package name for now, should be PROJECT later...
|
189
|
+
PACKAGE_NAME = "1799" # if of the test package in rockit group
|
190
|
+
|
191
|
+
desc "Create package and release to rubyforge"
|
192
|
+
task :rubyforge_release => [:package] do
|
193
|
+
system "rubyforge login"
|
194
|
+
release_name = "#{PROJECT}-#{Version()}"
|
195
|
+
files_to_release = FileList["pkg/#{release_name}.*"]
|
196
|
+
files_to_release.each do |file|
|
197
|
+
puts "Releasing #{file} to Rubyforge"
|
198
|
+
release_file(file, release_name, PACKAGE_NAME)
|
199
|
+
end
|
200
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), "minibasic")
|
4
|
+
|
5
|
+
class ATestMiniBasic < Test::Unit::TestCase
|
6
|
+
def assert_parse(exp, str)
|
7
|
+
res = MiniBasic::Parser.parse_string(str)
|
8
|
+
assert_equal(exp, res)
|
9
|
+
end
|
10
|
+
|
11
|
+
def assert_stmt(expStmt, str)
|
12
|
+
assert_parse([expStmt], str)
|
13
|
+
end
|
14
|
+
|
15
|
+
include MiniBasic::Grammar::ASTs
|
16
|
+
|
17
|
+
def test_01
|
18
|
+
assert_stmt(PrintLn["PRINTLN"], "PRINTLN")
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_02
|
22
|
+
assert_stmt(Read["READ", :A], "READ A")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_03
|
26
|
+
assert_stmt(Print["PRINT", :BC], "PRINT BC")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_04
|
30
|
+
assert_stmt(Assign[:D, ":=", 1], "D := 1")
|
31
|
+
assert_stmt(Assign[:D, ":=", 1], "D :=1")
|
32
|
+
assert_stmt(Assign[:D, ":=", 1], "D:=1")
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_05
|
36
|
+
assert_stmt(For["FOR", :A, ":=", 1, "TO", 3,
|
37
|
+
[Assign[:S, ":=", OpExpr[:S, "+", :A]],
|
38
|
+
Print["PRINT", :S],
|
39
|
+
],
|
40
|
+
"NEXT"], "FOR A := 1 TO 3 S:= S + A PRINT S NEXT")
|
41
|
+
end
|
42
|
+
|
43
|
+
def atest_06
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
#############################################################################
|
2
|
+
# Grammar and interpreter for a mini version of Basic.
|
3
|
+
# Author: Robert Feldt
|
4
|
+
#
|
5
|
+
# The grammar is based on the minibasic example in SableCC.
|
6
|
+
#
|
7
|
+
# Here's the copyright notice from the original file SableCC file:
|
8
|
+
#
|
9
|
+
# Copyright (C) 1997, 1998, 1999 J-Meg inc. All rights reserved.
|
10
|
+
#
|
11
|
+
# This file is free software; you can redistribute it and/or modify it
|
12
|
+
# under the terms of the GNU Lesser General Public License as published
|
13
|
+
# by the Free Software Foundation; either version 2.1 of the License, or
|
14
|
+
# (at your option) any later version.
|
15
|
+
#
|
16
|
+
# This file is distributed in the hope that it will be useful, but WITHOUT
|
17
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
19
|
+
# License for more details.
|
20
|
+
#
|
21
|
+
# You should have received a copy of the GNU Lesser General Public
|
22
|
+
# License along with this file (in the file "COPYING-LESSER"); if not,
|
23
|
+
# write to the Free Software Foundation, Inc., 59 Temple Place,
|
24
|
+
# Suite 330, Boston, MA 02111-1307 USA
|
25
|
+
#
|
26
|
+
# If you have any question, send an electronic message to
|
27
|
+
# Etienne M. Gagnon, M.Sc. (egagnon@j-meg.com), or write to:
|
28
|
+
#
|
29
|
+
# J-Meg inc.
|
30
|
+
# 11348 Brunet
|
31
|
+
# Montreal-Nord (Quebec)
|
32
|
+
# H1G 5G1 Canada
|
33
|
+
#############################################################################
|
34
|
+
require 'packrat/grammar'
|
35
|
+
|
36
|
+
module MiniBasic
|
37
|
+
class Interpreter
|
38
|
+
def initialize
|
39
|
+
# For variables and their values. Default value is 0.
|
40
|
+
@vars = Hash.new(0)
|
41
|
+
end
|
42
|
+
|
43
|
+
def eval(sexpr)
|
44
|
+
case sexpr.first
|
45
|
+
when :Statements
|
46
|
+
sexpr.statements.each {|stmt| mb_eval(stmt)}
|
47
|
+
when "If"
|
48
|
+
if mb_eval(sexpr.condition) # What is true and false in basic?
|
49
|
+
mb_eval(sexpr.statements)
|
50
|
+
elsif sexpr.optelse
|
51
|
+
mb_eval(sexpr.optelse[2])
|
52
|
+
end
|
53
|
+
when "For"
|
54
|
+
for i in (mb_eval(sexpr.from)..mb_eval(sexpr.to))
|
55
|
+
$vars[sexpr.ident.id] = i
|
56
|
+
mb_eval(sexpr.statements)
|
57
|
+
end
|
58
|
+
when "Read"
|
59
|
+
print "? "; STDOUT.flush
|
60
|
+
$vars[sexpr.ident.id] = STDIN.gets.to_i # Error catching?!
|
61
|
+
when "Print"
|
62
|
+
print mb_eval(sexpr.message); STDOUT.flush
|
63
|
+
when "PrintLn"
|
64
|
+
print "\n"; STDOUT.flush
|
65
|
+
when "Assignment"
|
66
|
+
$vars[sexpr.ident.id] = mb_eval(sexpr.expression)
|
67
|
+
when "Condition"
|
68
|
+
map = {">" => :>, "<" => :<, "=" => :==}
|
69
|
+
mb_eval(sexpr.left).send(map[sexpr.op], mb_eval(sexpr.right))
|
70
|
+
when "BinExpr"
|
71
|
+
map = {"+"=>:+, "-"=>:-, "*"=>:*, "/"=>"/".intern, "MOD"=>"%".intern }
|
72
|
+
mb_eval(sexpr.left).send(map[sexpr.op], mb_eval(sexpr.right))
|
73
|
+
when "String"
|
74
|
+
sexpr.value[1..-2] # Skip leading and trailing double quotes
|
75
|
+
when "Identifier"
|
76
|
+
$vars[sexpr.id]
|
77
|
+
when "Number"
|
78
|
+
sexpr.lexeme.to_i
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
Grammar = Packrat::Grammar.new do
|
84
|
+
start_symbol :Program
|
85
|
+
|
86
|
+
# Spacing (S) and Forced Spacing (FS)
|
87
|
+
S = hidden(/\s*/)
|
88
|
+
FS = hidden(/\s\s*/)
|
89
|
+
|
90
|
+
prod :Program, [S, :Statements, eos(), lift(0)]
|
91
|
+
|
92
|
+
prod :Statements, [plus(:Statement), lift(0)]
|
93
|
+
|
94
|
+
rule :Statement, [
|
95
|
+
['IF', FS, :Condition, FS, 'THEN', FS,
|
96
|
+
:Statements, FS,
|
97
|
+
maybe(:OptElse), S,
|
98
|
+
'ENDIF', S, ast(:If)],
|
99
|
+
|
100
|
+
['FOR', FS, :Identifier, S, ':=', S, :Expr, FS, 'TO', FS, :Expr, S,
|
101
|
+
:Statements, S,
|
102
|
+
'NEXT', S, ast(:For)],
|
103
|
+
|
104
|
+
['READ', FS, :Identifier, S, ast(:Read)],
|
105
|
+
|
106
|
+
['PRINTLN', S, ast(:PrintLn)],
|
107
|
+
|
108
|
+
['PRINT', FS, any(:Expr, :String), S, ast(:Print)],
|
109
|
+
|
110
|
+
[:Identifier, S, ':=', S, :Expr, S, ast(:Assign)],
|
111
|
+
]
|
112
|
+
|
113
|
+
prod :OptElse, ['ELSE', FS, :Statements, lift(1)]
|
114
|
+
|
115
|
+
prod :Condition, [:Expr, S, any('<', '>', '='), S, :Expr, ast(:Cond)]
|
116
|
+
|
117
|
+
# This is crude! No precedence levels or handling of associativity.
|
118
|
+
rule :Expr, [
|
119
|
+
[:BaseExpr, S, any('+', '-', '*', '/', 'MOD'), S, :BaseExpr,
|
120
|
+
ast(:OpExpr)
|
121
|
+
],
|
122
|
+
[:BaseExpr, lift(0)],
|
123
|
+
]
|
124
|
+
|
125
|
+
rule :BaseExpr, [
|
126
|
+
[:Number, lift(0)],
|
127
|
+
[:Identifier, lift(0)],
|
128
|
+
['(', S, :Expr, S, ')', lift(2)],
|
129
|
+
]
|
130
|
+
|
131
|
+
prod :String, [/"[^"]*"/, lift(0)]
|
132
|
+
prod :Identifier, [/[A-Z]([A-Z0-9])*/, lift(0) {|r| r.intern}]
|
133
|
+
prod :Number, [/[0-9]+/, lift(0) {|r| r.to_i}]
|
134
|
+
end
|
135
|
+
|
136
|
+
Parser = Grammar.interpreting_parser
|
137
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestAnyOperator < Test::Unit::TestCase
|
5
|
+
AnyTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :S, [["a", any("b", "c"), any(:D, :E), ast(:S, 0, 1, 2)]]
|
7
|
+
("d".."e").map {|s| term(s.upcase.intern, s)}
|
8
|
+
end
|
9
|
+
|
10
|
+
Parser = AnyTestGrammar.new_parser
|
11
|
+
|
12
|
+
def test_01
|
13
|
+
ast = Parser.parse "abd"
|
14
|
+
assert_equal("a", ast[0])
|
15
|
+
assert_equal("b", ast[1])
|
16
|
+
assert_equal("d", ast[2])
|
17
|
+
|
18
|
+
ast = Parser.parse "abe"
|
19
|
+
assert_equal("a", ast[0])
|
20
|
+
assert_equal("b", ast[1])
|
21
|
+
assert_equal("e", ast[2])
|
22
|
+
|
23
|
+
ast = Parser.parse "acd"
|
24
|
+
assert_equal("a", ast[0])
|
25
|
+
assert_equal("c", ast[1])
|
26
|
+
assert_equal("d", ast[2])
|
27
|
+
|
28
|
+
ast = Parser.parse "ace"
|
29
|
+
assert_equal("a", ast[0])
|
30
|
+
assert_equal("c", ast[1])
|
31
|
+
assert_equal("e", ast[2])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestArithmeticGrammar < Test::Unit::TestCase
|
5
|
+
ArithmeticTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :Expr, [
|
7
|
+
[:Digit, "+", :Digit, ast(:Add, 0, 2)],
|
8
|
+
[:Digit, "*", :Digit, ast(:Mult, 0, 2)],
|
9
|
+
]
|
10
|
+
term :Digit, /[0-9]+/
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_03_use_parser
|
14
|
+
parser = ArithmeticTestGrammar.new_parser
|
15
|
+
|
16
|
+
ast = parser.parse "12+34"
|
17
|
+
assert_equal("Add", ast.name)
|
18
|
+
assert_kind_of(parser.astclass_of_name(:Add), ast)
|
19
|
+
assert_equal(2, ast.num_children)
|
20
|
+
assert_equal("12", ast[0])
|
21
|
+
assert_equal("34", ast[1])
|
22
|
+
|
23
|
+
ast = parser.parse "567*980"
|
24
|
+
assert_equal("Mult", ast.name)
|
25
|
+
assert_kind_of(parser.astclass_of_name(:Mult), ast)
|
26
|
+
assert_equal(2, ast.num_children)
|
27
|
+
assert_equal("567", ast[0])
|
28
|
+
assert_equal("980", ast[1])
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestListOperator < Test::Unit::TestCase
|
5
|
+
ListTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :S, [list(:Number, ",")], value(0)
|
7
|
+
term :Number, [/[0-9]+/]
|
8
|
+
end
|
9
|
+
|
10
|
+
Parser = ListTestGrammar.new_parser
|
11
|
+
|
12
|
+
def test_01_two_value_list
|
13
|
+
ary = Parser.parse("1, 2")
|
14
|
+
assert_equal(["1", "2"], ary)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_02_multi_value_list
|
18
|
+
ary = Parser.parse("1, 2, 34, 567,890")
|
19
|
+
assert_equal(["1", "2", "34", "567", "890"], ary)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_03_single_value_list
|
23
|
+
ary = Parser.parse("9731")
|
24
|
+
assert_equal(["9731"], ary)
|
25
|
+
end
|
26
|
+
|
27
|
+
ListAndAstTestGrammar = Rockit::DParser::Grammar.new do
|
28
|
+
start :S, [list(:Digit)], ast(:S, 0)
|
29
|
+
term :Digit, [/[0-9]+/]
|
30
|
+
end
|
31
|
+
|
32
|
+
AstParser = ListAndAstTestGrammar.new_parser
|
33
|
+
|
34
|
+
def test_04_multiple_occurences_and_ast
|
35
|
+
ast = AstParser.parse("7,5,6,9")
|
36
|
+
assert_equal("S", ast.name)
|
37
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
38
|
+
assert_equal(1, ast.num_children)
|
39
|
+
assert_equal(["7", "5", "6", "9"], ast[0])
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_05_single_occurence_and_ast
|
43
|
+
ast = AstParser.parse("745")
|
44
|
+
assert_equal("S", ast.name)
|
45
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
46
|
+
assert_equal(1, ast.num_children)
|
47
|
+
assert_equal(["745"], ast[0])
|
48
|
+
end
|
49
|
+
|
50
|
+
def atest_06_no_occurence_and_ast
|
51
|
+
ast = AstParser.parse("")
|
52
|
+
assert_equal("S", ast.name)
|
53
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
54
|
+
assert_equal(1, ast.num_children)
|
55
|
+
assert_equal([], ast[0])
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestMultOperator < Test::Unit::TestCase
|
5
|
+
MultTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :S, [mult(:Digit)], value(0)
|
7
|
+
term :Digit, [/[0-9]/]
|
8
|
+
end
|
9
|
+
|
10
|
+
Parser = MultTestGrammar.new_parser
|
11
|
+
|
12
|
+
def test_01_multiple_occurences
|
13
|
+
(2..20).each do |i|
|
14
|
+
digit = rand(10).to_s
|
15
|
+
ary = Parser.parse(digit * i)
|
16
|
+
assert_equal((1..i).map {digit}, ary)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_02_single_occurence
|
21
|
+
ary = Parser.parse("7")
|
22
|
+
assert_equal(["7"], ary)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_03_no_occurence
|
26
|
+
ary = Parser.parse("")
|
27
|
+
assert_equal([], ary)
|
28
|
+
end
|
29
|
+
|
30
|
+
MultAndAstTestGrammar = Rockit::DParser::Grammar.new do
|
31
|
+
start :S, [mult(:Digit)], ast(:S, 0)
|
32
|
+
term :Digit, [/[0-9]/]
|
33
|
+
end
|
34
|
+
|
35
|
+
AstParser = MultAndAstTestGrammar.new_parser
|
36
|
+
|
37
|
+
def test_04_multiple_occurences_and_ast
|
38
|
+
ast = AstParser.parse("7 5 6 9")
|
39
|
+
assert_equal("S", ast.name)
|
40
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
41
|
+
assert_equal(1, ast.num_children)
|
42
|
+
assert_equal(["7", "5", "6", "9"], ast[0])
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_05_single_occurence_and_ast
|
46
|
+
ast = AstParser.parse("7")
|
47
|
+
assert_equal("S", ast.name)
|
48
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
49
|
+
assert_equal(1, ast.num_children)
|
50
|
+
assert_equal(["7"], ast[0])
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_06_no_occurence_and_ast
|
54
|
+
ast = AstParser.parse("")
|
55
|
+
assert_equal("S", ast.name)
|
56
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
57
|
+
assert_equal(1, ast.num_children)
|
58
|
+
assert_equal([], ast[0])
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestOperatorGrammar < Test::Unit::TestCase
|
5
|
+
MaybeTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :M, [[:A, maybe(:Digit)]], ast(:M, 0, 1)
|
7
|
+
term :A, ["a"]
|
8
|
+
term :Digit, [/[0-9]+/]
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_01_use_maybe_parser
|
12
|
+
parser = MaybeTestGrammar.new_parser
|
13
|
+
|
14
|
+
ast = parser.parse "a1"
|
15
|
+
assert_equal("M", ast.name)
|
16
|
+
assert_kind_of(parser.astclass_of_name(:M), ast)
|
17
|
+
assert_equal(2, ast.num_children)
|
18
|
+
assert_equal("a", ast[0])
|
19
|
+
assert_equal("1", ast[1])
|
20
|
+
|
21
|
+
ast = parser.parse "a"
|
22
|
+
assert_equal("M", ast.name)
|
23
|
+
assert_kind_of(parser.astclass_of_name(:M), ast)
|
24
|
+
assert_equal(2, ast.num_children)
|
25
|
+
assert_equal("a", ast[0])
|
26
|
+
assert_equal(nil, ast[1])
|
27
|
+
end
|
28
|
+
|
29
|
+
OperatorTestGrammar = Rockit::DParser::Grammar.new do
|
30
|
+
start :Str, [[:A, plus(:B), plus(:A), mult(:C), maybe(:D)]],
|
31
|
+
ast(:Str, 0, 1, 3, 4)
|
32
|
+
term :A, ["a"]
|
33
|
+
term :B, ["b"]
|
34
|
+
term :C, ["c"]
|
35
|
+
term :D, ["d"]
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_02_use_parser
|
39
|
+
parser = OperatorTestGrammar.new_parser
|
40
|
+
ast = parser.parse "abbbac"
|
41
|
+
assert_equal("Str", ast.name)
|
42
|
+
assert_kind_of(parser.astclass_of_name(:Str), ast)
|
43
|
+
assert_equal(4, ast.num_children)
|
44
|
+
assert_equal("a", ast[0])
|
45
|
+
assert_equal(["b", "b", "b"], ast[1])
|
46
|
+
assert_equal(["c"], ast[2])
|
47
|
+
assert_equal(nil, ast[3])
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_03_use_parser
|
51
|
+
parser = OperatorTestGrammar.new_parser
|
52
|
+
ast = parser.parse "a b a c c d"
|
53
|
+
assert_equal("Str", ast.name)
|
54
|
+
assert_kind_of(parser.astclass_of_name(:Str), ast)
|
55
|
+
assert_equal(4, ast.num_children)
|
56
|
+
assert_equal("a", ast[0])
|
57
|
+
assert_equal(["b"], ast[1])
|
58
|
+
assert_equal(["c", "c"], ast[2])
|
59
|
+
assert_equal("d", ast[3])
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
|
4
|
+
class ATestPlusOperator < Test::Unit::TestCase
|
5
|
+
PlusTestGrammar = Rockit::DParser::Grammar.new do
|
6
|
+
start :S, [plus(:A)], value(0)
|
7
|
+
term :A, ["a"]
|
8
|
+
end
|
9
|
+
|
10
|
+
Parser = PlusTestGrammar.new_parser
|
11
|
+
|
12
|
+
|
13
|
+
def test_01_multiple_occurences
|
14
|
+
(2..20).each do |i|
|
15
|
+
ary = Parser.parse("a" * i)
|
16
|
+
assert_equal((1..i).map {"a"}, ary)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_02_single_occurence
|
21
|
+
ary = Parser.parse("a")
|
22
|
+
assert_equal(["a"], ary)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_03_no_occurence
|
26
|
+
assert_raises(RuntimeError) {Parser.parse("b")}
|
27
|
+
end
|
28
|
+
|
29
|
+
PlusAndAstTestGrammar = Rockit::DParser::Grammar.new do
|
30
|
+
start :S, [plus(:Digit)], ast(:S, 0)
|
31
|
+
term :Digit, [/[0-9]/]
|
32
|
+
end
|
33
|
+
|
34
|
+
AstParser = PlusAndAstTestGrammar.new_parser
|
35
|
+
|
36
|
+
def test_04_multiple_occurences_and_ast
|
37
|
+
ast = AstParser.parse("7 5 6 9")
|
38
|
+
assert_equal("S", ast.name)
|
39
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
40
|
+
assert_equal(1, ast.num_children)
|
41
|
+
assert_equal(["7", "5", "6", "9"], ast[0])
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_05_single_occurence_and_ast
|
45
|
+
ast = AstParser.parse("7")
|
46
|
+
assert_equal("S", ast.name)
|
47
|
+
assert_kind_of(AstParser.astclass_of_name(:S), ast)
|
48
|
+
assert_equal(1, ast.num_children)
|
49
|
+
assert_equal(["7"], ast[0])
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_06_no_occurence_and_ast
|
53
|
+
assert_raises(RuntimeError) {AstParser.parse("b")}
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'rockit/dparser'
|
3
|
+
require 'calculator/calculator'
|
4
|
+
|
5
|
+
require File.join(File.dirname(__FILE__), "calc_tests_common")
|
6
|
+
|
7
|
+
class ATestSamplesCalculator < Test::Unit::TestCase
|
8
|
+
include CalcTestsCommon
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@grammar = Samples::CalculatorGrammar
|
12
|
+
@calculator = Samples::Calculator.new
|
13
|
+
end
|
14
|
+
end
|