rockit 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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