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.
Files changed (57) hide show
  1. data/BUGS +13 -0
  2. data/LICENSE +280 -0
  3. data/README +172 -0
  4. data/TODO +53 -0
  5. data/VERSION +1 -0
  6. data/lib/packrat/grammar.rb +537 -0
  7. data/lib/rockit/prettyprint/box.rb +60 -0
  8. data/lib/rockit/prettyprint/renderer.rb +41 -0
  9. data/lib/rockit/prettyprint/text_renderer.rb +47 -0
  10. data/lib/rockit/tree/base.rb +223 -0
  11. data/lib/rockit/tree/enter_leave_visitor.rb +12 -0
  12. data/lib/rockit/tree/graphviz.rb +69 -0
  13. data/lib/rockit/tree/visitor.rb +12 -0
  14. data/lib/util/array_alternatives.rb +20 -0
  15. data/lib/util/enter_leave_visitor.rb +69 -0
  16. data/lib/util/graphviz_dot.rb +182 -0
  17. data/lib/util/string_location.rb +42 -0
  18. data/lib/util/visitor.rb +49 -0
  19. data/lib/util/visitor_combinators.rb +14 -0
  20. data/rakefile +200 -0
  21. data/tests/acceptance/packrat/minibasic/atest_minibasic.rb +45 -0
  22. data/tests/acceptance/packrat/minibasic/minibasic.rb +137 -0
  23. data/tests/acceptance/rockit/dparser/atest_any_operator.rb +33 -0
  24. data/tests/acceptance/rockit/dparser/atest_arithmetic_grammar.rb +30 -0
  25. data/tests/acceptance/rockit/dparser/atest_list_operator.rb +57 -0
  26. data/tests/acceptance/rockit/dparser/atest_mult_operator.rb +60 -0
  27. data/tests/acceptance/rockit/dparser/atest_operator_grammar.rb +61 -0
  28. data/tests/acceptance/rockit/dparser/atest_plus_operator.rb +55 -0
  29. data/tests/acceptance/rockit/dparser/atest_samples_calculator.rb +14 -0
  30. data/tests/acceptance/rockit/dparser/atest_samples_minibasic.rb +20 -0
  31. data/tests/acceptance/rockit/dparser/atest_samples_multifunccalculator.rb +36 -0
  32. data/tests/acceptance/rockit/dparser/atest_simple_grammar.rb +34 -0
  33. data/tests/acceptance/rockit/dparser/atest_speculative_code_action.rb +128 -0
  34. data/tests/acceptance/rockit/dparser/calc_tests_common.rb +103 -0
  35. data/tests/unit/packrat/test_interpreting_parser.rb +296 -0
  36. data/tests/unit/parse/utest_ebnf_grammar.rb +50 -0
  37. data/tests/unit/parse/utest_expand_grammar.rb +23 -0
  38. data/tests/unit/parse/utest_grammar.rb +160 -0
  39. data/tests/unit/rockit/assembler/llvm/utest_instructions.rb +41 -0
  40. data/tests/unit/rockit/assembler/llvm/utest_module.rb +19 -0
  41. data/tests/unit/rockit/prettyprint/utest_box.rb +44 -0
  42. data/tests/unit/rockit/tree/utest_tree_base.rb +301 -0
  43. data/tests/unit/rockit/tree/utest_tree_enter_leave_visitor.rb +69 -0
  44. data/tests/unit/rockit/tree/utest_tree_visitor.rb +63 -0
  45. data/tests/unit/rockit/utest_grammar.rb +145 -0
  46. data/tests/unit/rockit/utest_grammar_symbol.rb +11 -0
  47. data/tests/unit/rockit/utest_maybe_operator.rb +12 -0
  48. data/tests/unit/rockit/utest_regexp_terminal.rb +45 -0
  49. data/tests/unit/rockit/utest_repetition_operators.rb +35 -0
  50. data/tests/unit/rockit/utest_rule.rb +23 -0
  51. data/tests/unit/rockit/utest_string_terminal.rb +40 -0
  52. data/tests/unit/util/utest_array_alternatives.rb +23 -0
  53. data/tests/unit/util/utest_enter_leave_visitor.rb +89 -0
  54. data/tests/unit/util/utest_string_location.rb +42 -0
  55. data/tests/unit/util/utest_visitor.rb +92 -0
  56. data/tests/unit/util/utest_visitor_combinators.rb +64 -0
  57. 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