foreverman-dhaka 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/Rakefile +64 -0
  2. data/lib/dhaka.rb +62 -0
  3. data/lib/dhaka/dot/dot.rb +29 -0
  4. data/lib/dhaka/evaluator/evaluator.rb +133 -0
  5. data/lib/dhaka/grammar/closure_hash.rb +15 -0
  6. data/lib/dhaka/grammar/grammar.rb +236 -0
  7. data/lib/dhaka/grammar/grammar_symbol.rb +27 -0
  8. data/lib/dhaka/grammar/precedence.rb +19 -0
  9. data/lib/dhaka/grammar/production.rb +36 -0
  10. data/lib/dhaka/lexer/accept_actions.rb +36 -0
  11. data/lib/dhaka/lexer/alphabet.rb +21 -0
  12. data/lib/dhaka/lexer/compiled_lexer.rb +46 -0
  13. data/lib/dhaka/lexer/dfa.rb +121 -0
  14. data/lib/dhaka/lexer/lexeme.rb +32 -0
  15. data/lib/dhaka/lexer/lexer.rb +70 -0
  16. data/lib/dhaka/lexer/lexer_run.rb +78 -0
  17. data/lib/dhaka/lexer/regex_grammar.rb +393 -0
  18. data/lib/dhaka/lexer/regex_parser.rb +2010 -0
  19. data/lib/dhaka/lexer/regex_tokenizer.rb +14 -0
  20. data/lib/dhaka/lexer/specification.rb +96 -0
  21. data/lib/dhaka/lexer/state.rb +68 -0
  22. data/lib/dhaka/lexer/state_machine.rb +37 -0
  23. data/lib/dhaka/parser/action.rb +55 -0
  24. data/lib/dhaka/parser/channel.rb +58 -0
  25. data/lib/dhaka/parser/compiled_parser.rb +51 -0
  26. data/lib/dhaka/parser/conflict.rb +54 -0
  27. data/lib/dhaka/parser/item.rb +43 -0
  28. data/lib/dhaka/parser/parse_result.rb +50 -0
  29. data/lib/dhaka/parser/parse_tree.rb +66 -0
  30. data/lib/dhaka/parser/parser.rb +165 -0
  31. data/lib/dhaka/parser/parser_methods.rb +11 -0
  32. data/lib/dhaka/parser/parser_run.rb +39 -0
  33. data/lib/dhaka/parser/parser_state.rb +74 -0
  34. data/lib/dhaka/parser/token.rb +22 -0
  35. data/lib/dhaka/runtime.rb +51 -0
  36. data/lib/dhaka/tokenizer/tokenizer.rb +190 -0
  37. data/test/all_tests.rb +5 -0
  38. data/test/arithmetic/arithmetic_evaluator.rb +64 -0
  39. data/test/arithmetic/arithmetic_evaluator_test.rb +43 -0
  40. data/test/arithmetic/arithmetic_grammar.rb +41 -0
  41. data/test/arithmetic/arithmetic_grammar_test.rb +9 -0
  42. data/test/arithmetic/arithmetic_test_methods.rb +9 -0
  43. data/test/arithmetic/arithmetic_tokenizer.rb +39 -0
  44. data/test/arithmetic/arithmetic_tokenizer_test.rb +38 -0
  45. data/test/arithmetic_precedence/arithmetic_precedence_evaluator.rb +43 -0
  46. data/test/arithmetic_precedence/arithmetic_precedence_grammar.rb +24 -0
  47. data/test/arithmetic_precedence/arithmetic_precedence_grammar_test.rb +30 -0
  48. data/test/arithmetic_precedence/arithmetic_precedence_lexer_specification.rb +23 -0
  49. data/test/arithmetic_precedence/arithmetic_precedence_parser_test.rb +33 -0
  50. data/test/brackets/bracket_grammar.rb +23 -0
  51. data/test/brackets/bracket_tokenizer.rb +22 -0
  52. data/test/brackets/brackets_test.rb +28 -0
  53. data/test/chittagong/chittagong_driver.rb +46 -0
  54. data/test/chittagong/chittagong_driver_test.rb +276 -0
  55. data/test/chittagong/chittagong_evaluator.rb +284 -0
  56. data/test/chittagong/chittagong_evaluator_test.rb +38 -0
  57. data/test/chittagong/chittagong_grammar.rb +104 -0
  58. data/test/chittagong/chittagong_lexer.rb +109 -0
  59. data/test/chittagong/chittagong_lexer_specification.rb +37 -0
  60. data/test/chittagong/chittagong_lexer_test.rb +58 -0
  61. data/test/chittagong/chittagong_parser.rb +879 -0
  62. data/test/chittagong/chittagong_parser_test.rb +55 -0
  63. data/test/chittagong/chittagong_test.rb +170 -0
  64. data/test/core/another_lalr_but_not_slr_grammar.rb +20 -0
  65. data/test/core/compiled_parser_test.rb +44 -0
  66. data/test/core/dfa_test.rb +170 -0
  67. data/test/core/evaluator_test.rb +22 -0
  68. data/test/core/grammar_test.rb +83 -0
  69. data/test/core/lalr_but_not_slr_grammar.rb +19 -0
  70. data/test/core/lexer_test.rb +139 -0
  71. data/test/core/malformed_grammar.rb +7 -0
  72. data/test/core/malformed_grammar_test.rb +8 -0
  73. data/test/core/nullable_grammar.rb +21 -0
  74. data/test/core/parse_result_test.rb +44 -0
  75. data/test/core/parser_state_test.rb +24 -0
  76. data/test/core/parser_test.rb +131 -0
  77. data/test/core/precedence_grammar.rb +17 -0
  78. data/test/core/precedence_grammar_test.rb +9 -0
  79. data/test/core/rr_conflict_grammar.rb +21 -0
  80. data/test/core/simple_grammar.rb +22 -0
  81. data/test/core/sr_conflict_grammar.rb +16 -0
  82. data/test/dhaka_test_helper.rb +18 -0
  83. data/test/fake_logger.rb +17 -0
  84. metadata +137 -0
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/arithmetic_precedence_grammar'
2
+
3
+ class ArithmeticPrecedenceEvaluator < Dhaka::Evaluator
4
+
5
+ self.grammar = ArithmeticPrecedenceGrammar
6
+
7
+ define_evaluation_rules do
8
+
9
+ for_subtraction do
10
+ evaluate(child_nodes[0]) - evaluate(child_nodes[2])
11
+ end
12
+
13
+ for_addition do
14
+ evaluate(child_nodes[0]) + evaluate(child_nodes[2])
15
+ end
16
+
17
+ for_division do
18
+ evaluate(child_nodes[0]).to_f/evaluate(child_nodes[2])
19
+ end
20
+
21
+ for_multiplication do
22
+ evaluate(child_nodes[0]) * evaluate(child_nodes[2])
23
+ end
24
+
25
+ for_literal do
26
+ child_nodes[0].token.value.to_i
27
+ end
28
+
29
+ for_parenthetized_expression do
30
+ evaluate(child_nodes[1])
31
+ end
32
+
33
+ for_negated_expression do
34
+ -evaluate(child_nodes[1])
35
+ end
36
+
37
+ for_power do
38
+ evaluate(child_nodes[0])**evaluate(child_nodes[2])
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,24 @@
1
+ class ArithmeticPrecedenceGrammar < Dhaka::Grammar
2
+
3
+ precedences do
4
+ left %w| + - |
5
+ left %w| * / |
6
+ nonassoc %w| ^ |
7
+ end
8
+
9
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
10
+ expression %w| E |
11
+ end
12
+
13
+ for_symbol('E') do
14
+ addition %w| E + E |
15
+ subtraction %w| E - E |
16
+ multiplication %w| E * E |
17
+ division %w| E / E |
18
+ power %w| E ^ E |
19
+ literal %w| n |
20
+ parenthetized_expression %w| ( E ) |
21
+ negated_expression %w| - E |, :prec => '*'
22
+ end
23
+
24
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + '/arithmetic_precedence_grammar'
3
+
4
+ class TestArithmeticPrecedenceGrammar < Test::Unit::TestCase
5
+ def setup
6
+ @addop = ArithmeticPrecedenceGrammar.symbol_for_name('+')
7
+ @subop = ArithmeticPrecedenceGrammar.symbol_for_name('-')
8
+ @mulop = ArithmeticPrecedenceGrammar.symbol_for_name('*')
9
+ @divop = ArithmeticPrecedenceGrammar.symbol_for_name('/')
10
+ @powop = ArithmeticPrecedenceGrammar.symbol_for_name('^')
11
+ end
12
+
13
+ def test_precedence_levels_and_associativity_of_terminals
14
+ assert_equal(0, @addop.precedence.precedence_level)
15
+ assert_equal(0, @subop.precedence.precedence_level)
16
+ assert_equal(1, @mulop.precedence.precedence_level)
17
+ assert_equal(1, @divop.precedence.precedence_level)
18
+ assert_equal(2, @powop.precedence.precedence_level)
19
+ assert_equal(:left, @addop.precedence.associativity)
20
+ assert_equal(:left, @subop.precedence.associativity)
21
+ assert_equal(:left, @mulop.precedence.associativity)
22
+ assert_equal(:left, @divop.precedence.associativity)
23
+ assert_equal(:nonassoc, @powop.precedence.associativity)
24
+ end
25
+ def test_precedence_of_production
26
+ assert_equal(@addop.precedence, ArithmeticPrecedenceGrammar.production_named("addition").precedence)
27
+ assert_equal(@mulop.precedence, ArithmeticPrecedenceGrammar.production_named("multiplication").precedence)
28
+ assert_equal(@mulop.precedence, ArithmeticPrecedenceGrammar.production_named("negated_expression").precedence)
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ class ArithmeticPrecedenceLexerSpecification < Dhaka::LexerSpecification
2
+
3
+ for_pattern '\s' do
4
+ # ignore whitespace
5
+ end
6
+
7
+ %w| - h l , |.each do |char|
8
+ for_pattern char do
9
+ create_token(char)
10
+ end
11
+ end
12
+
13
+ %w| ( ) + / * ^ |.each do |char|
14
+ for_pattern "\\#{char}" do
15
+ create_token(char)
16
+ end
17
+ end
18
+
19
+ for_pattern '\d+' do
20
+ create_token('n')
21
+ end
22
+
23
+ end
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/arithmetic_precedence_grammar"
3
+ require File.dirname(__FILE__) + "/arithmetic_precedence_lexer_specification"
4
+ require File.dirname(__FILE__) + "/arithmetic_precedence_evaluator"
5
+
6
+ class TestArithmeticPrecedenceParser < Test::Unit::TestCase
7
+ def test_parses_arithmetic_expressions
8
+ fake_logger = FakeLogger.new
9
+ parser = Dhaka::Parser.new(ArithmeticPrecedenceGrammar, fake_logger)
10
+ lexer = Dhaka::Lexer.new(ArithmeticPrecedenceLexerSpecification)
11
+ eval(parser.compile_to_ruby_source_as(:ArithmeticPrecedenceParser))
12
+ eval(lexer.compile_to_ruby_source_as(:ArithmeticPrecedenceLexer))
13
+
14
+ assert_equal(30, fake_logger.warnings.size)
15
+ assert_equal(0, fake_logger.errors.size)
16
+
17
+ assert_equal(-8, evaluate(parse("5 * -14/(2*7 - 7) + 2")))
18
+ assert_equal(-4, evaluate(parse("-2^2")))
19
+ assert_equal(10, evaluate(parse("2+2^3")))
20
+ assert_equal(64, evaluate(parse("(2+2)^3")))
21
+ assert_equal(128, evaluate(parse("(2+2)^3*2")))
22
+ assert(parse("(2+2)^3^2").has_error?)
23
+ end
24
+
25
+ def parse(input)
26
+ ArithmeticPrecedenceParser.parse(ArithmeticPrecedenceLexer.lex(input))
27
+ end
28
+
29
+ def evaluate(parse_tree)
30
+ ArithmeticPrecedenceEvaluator.new.evaluate(parse_tree)
31
+ end
32
+ end
33
+
@@ -0,0 +1,23 @@
1
+ class BracketGrammar < Dhaka::Grammar
2
+
3
+ for_symbol(Dhaka::START_SYMBOL_NAME) do
4
+ start %w| Package |
5
+ end
6
+
7
+ for_symbol('Package') do
8
+ soft_wrapped_package %w| ( Contents ) |
9
+ cardboard_package %w| [ Contents ] |
10
+ wooden_package %w| { Contents } |
11
+ end
12
+
13
+ for_symbol('Contents') do
14
+ bracket %w| B |
15
+ set_of_packages %w| SetOfPackages |
16
+ end
17
+
18
+ for_symbol('SetOfPackages') do
19
+ one_package %w| Package |
20
+ multiple_packages %w| SetOfPackages Package |
21
+ end
22
+
23
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + '/bracket_grammar'
2
+
3
+ class BracketTokenizer < Dhaka::Tokenizer
4
+
5
+ all_characters = %w| ( [ { B } ] ) |
6
+
7
+ for_state Dhaka::TOKENIZER_IDLE_STATE do
8
+ for_characters(all_characters) do
9
+ create_token(curr_char, nil)
10
+ advance
11
+ end
12
+ end
13
+
14
+ end
15
+
16
+ class LazyBracketTokenizer < BracketTokenizer
17
+ for_state Dhaka::TOKENIZER_IDLE_STATE do
18
+ for_default do
19
+ advance
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/bracket_grammar"
3
+ require File.dirname(__FILE__) + '/bracket_tokenizer'
4
+
5
+ class TestBracketGrammar < Test::Unit::TestCase
6
+ def test_recognizes_faulty_bracket_configuration_correctly
7
+ eval Dhaka::Parser.new(BracketGrammar).compile_to_ruby_source_as(:BracketParser)
8
+ assert correct("[{(B)[B]}(B)]")
9
+ assert correct("[[B]{(B)}(B)]")
10
+ assert correct("{(B)[B]}")
11
+ assert !correct("{B[B]}")
12
+ assert !correct("B")
13
+ assert !correct("[[B]{(B)}}(B)]")
14
+ end
15
+
16
+ def test_ignores_invalid_characters_with_default_action
17
+ tokens = BracketTokenizer.tokenize("A{(B)[B]}")
18
+ assert tokens.has_error?
19
+
20
+ tokens = LazyBracketTokenizer.tokenize("A{(B)[B]}")
21
+ assert !tokens.has_error?
22
+ end
23
+
24
+ def correct input_string
25
+ result = BracketParser.parse(BracketTokenizer.tokenize(input_string))
26
+ !result.has_error?
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + "/chittagong_lexer_specification"
2
+ require File.dirname(__FILE__) + "/chittagong_evaluator"
3
+
4
+ class ChittagongDriver
5
+
6
+ ERROR_MARKER = ">>>"
7
+
8
+ def parse_error_message unexpected_token, program
9
+ if unexpected_token.symbol_name == Dhaka::END_SYMBOL_NAME
10
+ "Unexpected end of file."
11
+ else
12
+ "Unexpected token #{unexpected_token.symbol_name}:\n#{program.dup.insert(unexpected_token.input_position, ERROR_MARKER)}"
13
+ end
14
+ end
15
+
16
+ def tokenize_error_message unexpected_char_index, program
17
+ "Unexpected character #{program[unexpected_char_index].chr}:\n#{program.dup.insert(unexpected_char_index, ERROR_MARKER)}"
18
+ end
19
+
20
+ def evaluation_error_message evaluation_result, program
21
+ "#{evaluation_result.exception}:\n#{program.dup.insert(evaluation_result.node.tokens[0].input_position, ERROR_MARKER)}"
22
+ end
23
+
24
+ # lipi:run_method
25
+ def run(program)
26
+ parse_result = ChittagongParser.parse(ChittagongLexer.lex(program))
27
+
28
+ case parse_result
29
+ when Dhaka::TokenizerErrorResult
30
+ return tokenize_error_message(parse_result.unexpected_char_index, program)
31
+ when Dhaka::ParseErrorResult
32
+ return parse_error_message(parse_result.unexpected_token, program)
33
+ end
34
+
35
+ evaluation_result = ChittagongEvaluator.new([{}], output_stream = []).
36
+ evaluate(parse_result)
37
+ if evaluation_result.exception
38
+ return (output_stream << evaluation_error_message(evaluation_result, program)).
39
+ join("\n")
40
+ end
41
+
42
+ return output_stream.join("\n")
43
+ end
44
+ # lipi:run_method
45
+
46
+ end
@@ -0,0 +1,276 @@
1
+ require File.dirname(__FILE__) + '/../dhaka_test_helper'
2
+ require File.dirname(__FILE__) + "/chittagong_grammar"
3
+ require File.dirname(__FILE__) + "/chittagong_lexer_specification"
4
+ begin
5
+ require File.dirname(__FILE__) + "/chittagong_parser"
6
+ require File.dirname(__FILE__) + "/chittagong_lexer"
7
+ rescue LoadError
8
+ puts "Please run the rake command in the root folder to generate the lexer and parser required for this test."
9
+ exit
10
+ end
11
+ require File.dirname(__FILE__) + "/chittagong_driver"
12
+
13
+ class TestChittagongDriver < Test::Unit::TestCase
14
+ def setup
15
+ @driver = ChittagongDriver.new
16
+ end
17
+
18
+ def test_return_statement_not_allowed_in_main
19
+ # Programs with problems
20
+ program = "
21
+
22
+ if 1 > 2
23
+ return 5
24
+ end
25
+
26
+ print 2
27
+ "
28
+ assert_equal(
29
+ "Unexpected token return:
30
+
31
+
32
+ if 1 > 2
33
+ >>>return 5
34
+ end
35
+
36
+ print 2
37
+ ", @driver.run(program))
38
+ end
39
+
40
+ def test_catches_unexpected_end_of_input
41
+ program = "
42
+ def"
43
+ assert_equal("Unexpected end of file.", @driver.run(program))
44
+ end
45
+
46
+ def test_catches_unexpected_characters
47
+ program = "
48
+ print 2
49
+ def #}
50
+ "
51
+ assert_equal(
52
+ "Unexpected character #:
53
+
54
+ print 2
55
+ def >>>#}
56
+ ", @driver.run(program))
57
+ end
58
+
59
+ def test_catches_undefined_variables
60
+ program = "
61
+ x = 1
62
+ y = 2
63
+ def foo(n)
64
+ return 2
65
+ end
66
+ foo(1)
67
+
68
+ if x > y
69
+ print 999
70
+ print 777
71
+ else
72
+ print 66
73
+ end
74
+
75
+ print x
76
+ print y
77
+ print 2*3+c
78
+ print 888
79
+
80
+ "
81
+
82
+ assert_equal(
83
+ "66.0
84
+ 1.0
85
+ 2.0
86
+ Undefined variable c:
87
+
88
+ x = 1
89
+ y = 2
90
+ def foo(n)
91
+ return 2
92
+ end
93
+ foo(1)
94
+
95
+ if x > y
96
+ print 999
97
+ print 777
98
+ else
99
+ print 66
100
+ end
101
+
102
+ print x
103
+ print y
104
+ print 2*3+>>>c
105
+ print 888
106
+
107
+ ", @driver.run(program))
108
+ end
109
+
110
+ def test_catches_undefined_functions
111
+ program = "
112
+
113
+ def foo(n)
114
+ bar(x)
115
+ end
116
+
117
+ foo(2)
118
+
119
+ "
120
+ assert_equal(
121
+ "Undefined function bar:
122
+
123
+
124
+ def foo(n)
125
+ >>>bar(x)
126
+ end
127
+
128
+ foo(2)
129
+
130
+ ", @driver.run(program))
131
+ end
132
+ # lipi:variable_scoping
133
+ def test_variable_scope
134
+ program = "
135
+ x = 1
136
+
137
+ def bar(n)
138
+ print 999
139
+ end
140
+
141
+ def foo(n)
142
+ bar(x)
143
+ end
144
+
145
+ foo(2)
146
+
147
+ "
148
+ assert_equal(
149
+ "Undefined variable x:
150
+
151
+ x = 1
152
+
153
+ def bar(n)
154
+ print 999
155
+ end
156
+
157
+ def foo(n)
158
+ bar(>>>x)
159
+ end
160
+
161
+ foo(2)
162
+
163
+ ", @driver.run(program))
164
+ end
165
+ # lipi:variable_scoping
166
+
167
+ def test_nested_function_calls
168
+
169
+ program = "
170
+
171
+ def foo(a)
172
+ return a + 2
173
+ end
174
+
175
+ def bar(b, c)
176
+ return b + c
177
+ end
178
+
179
+ def baz(x, y, z)
180
+ return foo(y) + bar(x, z)
181
+ end
182
+
183
+ print baz(foo(1), bar(2, 3), bar(6, 2))
184
+
185
+ "
186
+ assert_equal("18.0", @driver.run(program))
187
+ end
188
+
189
+ def test_wrong_number_of_arguments
190
+
191
+ program = "
192
+
193
+ def whatever(a, b)
194
+ return a + b
195
+ end
196
+
197
+ whatever(1, 2, 3)
198
+
199
+ "
200
+ assert_equal(
201
+ "Wrong number of arguments:
202
+
203
+
204
+ def whatever(a, b)
205
+ return a + b
206
+ end
207
+
208
+ whatever>>>(1, 2, 3)
209
+
210
+ ", @driver.run(program))
211
+
212
+ end
213
+
214
+ def test_an_empty_program
215
+ program = ""
216
+ assert_equal("Unexpected end of file.", @driver.run(program))
217
+ end
218
+
219
+ def test_associating_equality_tests_should_show_an_error
220
+ program = "
221
+ def foo()
222
+ print 999
223
+ end
224
+
225
+ foo()
226
+ print 1 == 1 == 1"
227
+
228
+ assert_equal("Unexpected token ==:
229
+
230
+ def foo()
231
+ print 999
232
+ end
233
+
234
+ foo()
235
+ print 1 == 1 >>>== 1", @driver.run(program))
236
+ end
237
+
238
+ def test_catches_bad_decimal_points
239
+ program = "
240
+ a = .234
241
+ c = 23.523
242
+ b = 20..2
243
+ "
244
+
245
+ assert_equal("Unexpected character .:
246
+
247
+ a = .234
248
+ c = 23.523
249
+ b = 20.>>>.2
250
+ ", @driver.run(program))
251
+ end
252
+ # lipi:recursive_fib
253
+ def test_recursive_fibonacci
254
+ program = "
255
+
256
+ def fib(n)
257
+ if n == 0
258
+ return 1
259
+ end
260
+ if n == 1
261
+ return 1
262
+ end
263
+ return fib(n-1) + fib(n-2)
264
+ end
265
+
266
+ x = 0
267
+ while x < 9
268
+ print fib(x)
269
+ x = x + 1
270
+ end
271
+
272
+ "
273
+ assert_equal(["1.0", "1.0", "2.0", "3.0", "5.0", "8.0", "13.0", "21.0", "34.0"].join("\n"), @driver.run(program))
274
+ end
275
+ # lipi:recursive_fib
276
+ end