aurum 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/Rakefile +29 -0
  2. data/examples/dangling_else/grammar.rb +23 -0
  3. data/examples/expression/grammar.rb +28 -0
  4. data/examples/smalltalk/grammar.rb +151 -0
  5. data/examples/smalltalk/interpreter.rb +70 -0
  6. data/examples/yacc/grammar.rb +72 -0
  7. data/lib/aurum.rb +1 -9
  8. data/lib/aurum/engine.rb +39 -175
  9. data/lib/aurum/engine/parsing_facility.rb +107 -0
  10. data/lib/aurum/engine/tokenization_facility.rb +86 -0
  11. data/lib/aurum/grammar.rb +52 -219
  12. data/lib/aurum/grammar/automata.rb +194 -0
  13. data/lib/aurum/grammar/builder/augmented_grammar.rb +83 -0
  14. data/lib/aurum/grammar/builder/dot_logger.rb +66 -0
  15. data/lib/aurum/grammar/builder/lexical_table_builder.rb +55 -0
  16. data/lib/aurum/grammar/builder/parsing_table_builder.rb +238 -0
  17. data/lib/aurum/grammar/builder/set_of_items.rb +190 -0
  18. data/lib/aurum/grammar/compiled_tables.rb +20 -0
  19. data/lib/aurum/grammar/dsl/lexical_definition.rb +94 -0
  20. data/lib/aurum/grammar/dsl/syntax_definition.rb +79 -0
  21. data/lib/aurum/grammar/lexical_rules.rb +224 -0
  22. data/lib/aurum/grammar/metalang/grammar.rb +47 -0
  23. data/lib/aurum/grammar/syntax_rules.rb +95 -0
  24. data/spec/builder/dsl_definition/aurum_grammar_spec.rb +33 -0
  25. data/spec/engine/lexer_spec.rb +59 -0
  26. data/spec/engine/parser_spec.rb +90 -0
  27. data/spec/examples/dangling_else_example.rb +30 -0
  28. data/spec/examples/expression_example.rb +48 -0
  29. data/spec/examples/smalltalk_example.rb +50 -0
  30. data/spec/examples/yacc_spec.rb +30 -0
  31. data/spec/grammar/builder/lexical_table/automata_spec.rb +55 -0
  32. data/spec/grammar/builder/lexical_table/builder_spec.rb +78 -0
  33. data/spec/grammar/builder/lexical_table/character_set_spec.rb +100 -0
  34. data/spec/grammar/builder/lexical_table/pattern_spec.rb +11 -0
  35. data/spec/grammar/builder/lexical_table/regular_expression.rb +40 -0
  36. data/spec/grammar/builder/parsing_table/augmented_grammar_spec.rb +36 -0
  37. data/spec/grammar/builder/parsing_table/builder_spec.rb +152 -0
  38. data/spec/grammar/builder/parsing_table/digraph_traverser_spec.rb +42 -0
  39. data/spec/grammar/builder/parsing_table/item_spec.rb +51 -0
  40. data/spec/grammar/builder/parsing_table/sources_spec.rb +66 -0
  41. data/spec/grammar/builder/parsing_table/state_spec.rb +82 -0
  42. data/spec/grammar/dsl/character_classes_builder_spec.rb +50 -0
  43. data/spec/grammar/dsl/lexical_rules_builder_spec.rb +181 -0
  44. data/spec/grammar/dsl/precedence_builder_spec.rb +64 -0
  45. data/spec/grammar/dsl/productions_builder_spec.rb +78 -0
  46. data/spec/grammar/metalang/metalang_spec.rb +0 -0
  47. data/spec/grammar/precedence_spec.rb +42 -0
  48. data/spec/grammar/syntax_rules_spec.rb +31 -0
  49. data/spec/parser_matcher.rb +69 -0
  50. data/spec/pattern_matcher.rb +123 -0
  51. data/spec/spec_helper.rb +133 -0
  52. metadata +70 -36
  53. data/example/expression/expression.rb +0 -35
  54. data/example/expression/lisp.rb +0 -26
  55. data/lib/aurum/lexical_table_generator.rb +0 -429
  56. data/lib/aurum/parsing_table_generator.rb +0 -464
  57. data/test/engine/lexer_test.rb +0 -59
  58. data/test/engine/semantic_attributes_test.rb +0 -15
  59. data/test/grammar_definition/character_class_definition_test.rb +0 -28
  60. data/test/grammar_definition/grammar_definition_test.rb +0 -55
  61. data/test/grammar_definition/lexical_definition_test.rb +0 -56
  62. data/test/grammar_definition/operator_precedence_definition_test.rb +0 -35
  63. data/test/grammar_definition/production_definition_test.rb +0 -60
  64. data/test/lexical_table_generator/automata_test.rb +0 -74
  65. data/test/lexical_table_generator/character_set_test.rb +0 -73
  66. data/test/lexical_table_generator/interval_test.rb +0 -36
  67. data/test/lexical_table_generator/pattern_test.rb +0 -115
  68. data/test/lexical_table_generator/subset_determinizer_test.rb +0 -19
  69. data/test/lexical_table_generator/table_generator_test.rb +0 -126
  70. data/test/parsing_table_generator/augmented_grammar_test.rb +0 -45
  71. data/test/parsing_table_generator/lalr_n_computation_test.rb +0 -92
  72. data/test/parsing_table_generator/lr_0_automata_test.rb +0 -94
  73. data/test/parsing_table_generator/lr_item_test.rb +0 -27
  74. data/test/parsing_table_generator/parsing_table_state_test.rb +0 -39
  75. data/test/parsing_table_generator/precedence_table_test.rb +0 -28
  76. data/test/parsing_table_generator/production_test.rb +0 -9
  77. data/test/test_helper.rb +0 -103
@@ -1,36 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
-
4
- class IntervalTest < Test::Unit::TestCase
5
- def test_should_include_character_in_interval
6
- interval = Aurum::CharacterSet::Interval.new ?a, ?c
7
- assert interval.include?('b')
8
- assert !interval.include?('d')
9
- end
10
-
11
- def test_should_use_lowest_as_first_and_highest_as_end
12
- interval_a = Aurum::CharacterSet::Interval.new ?a, ?c
13
- interval_b = Aurum::CharacterSet::Interval.new ?b, ?d
14
- assert interval_a.merge!(interval_b)
15
- assert_equal Aurum::CharacterSet::Interval.new(?a, ?d), interval_a
16
- end
17
-
18
- def test_should_cat_two_intervals
19
- interval_a = Aurum::CharacterSet::Interval.new ?a, ?c
20
- interval_b = Aurum::CharacterSet::Interval.new ?d, ?f
21
- assert interval_a.merge!(interval_b)
22
- assert_equal Aurum::CharacterSet::Interval.new(?a, ?f), interval_a
23
- end
24
-
25
- def test_should_return_nil_if_two_intervls_do_not_have_any_char_in_common
26
- interval_a = Aurum::CharacterSet::Interval.new ?a, ?c
27
- interval_b = Aurum::CharacterSet::Interval.new ?e, ?f
28
- assert !interval_a.merge!(interval_b)
29
- end
30
-
31
- def test_should_def_interval_for_single_char
32
- interval = Aurum::CharacterSet::Interval.new ?a
33
- assert interval.include?('a')
34
- assert !interval.include?('b')
35
- end
36
- end
@@ -1,115 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
-
4
- class PatternTest < Test::Unit::TestCase
5
- Epsilon = Aurum::Epsilon
6
-
7
- def test_should_match_single_string
8
- pattern = Aurum::Pattern.from_string 'a'
9
- assert match?('a', pattern)
10
- assert !match?('b', pattern)
11
- end
12
-
13
- def test_should_match_string_literal
14
- pattern = Aurum::Pattern.from_string 'abc'
15
- assert match?('abc', pattern)
16
- assert !match?('abcabc', pattern)
17
- assert !match?('bcd', pattern)
18
- end
19
-
20
- def test_should_match_character_set
21
- char_set = Aurum::CharacterSet::Interval.new(?A, ?Z).to_char_set
22
- pattern = Aurum::Pattern.from_char_set char_set
23
- ('A'..'Z').each {|x| assert match?(x, pattern)}
24
- end
25
-
26
- def test_should_match_string_literal_zero_or_more_times
27
- pattern = Aurum::Pattern.from_string('abc').kleene
28
- assert match?('', pattern)
29
- assert match?('abc' * 10, pattern)
30
- assert !match?('ab', pattern)
31
- end
32
-
33
- def test_should_match_string_literal_one_or_more_times
34
- pattern = Aurum::Pattern.from_string('abc').iterate
35
- assert match?('abc', pattern)
36
- assert match?('abc' * 10, pattern)
37
- assert !match?('', pattern)
38
- end
39
-
40
- def test_should_match_string_literal_zero_or_one_time
41
- pattern = Aurum::Pattern.from_string('abc').opt
42
- assert match?('', pattern)
43
- assert match?('abc', pattern)
44
- assert !match?('abc' * 2, pattern)
45
- end
46
-
47
- def test_should_match_concate_string
48
- first = Aurum::Pattern.from_string 'first'
49
- second = Aurum::Pattern.from_string 'second'
50
- pattern = Aurum::Pattern.concat(first, second)
51
- assert match?('firstsecond', pattern)
52
- assert !match?('first', pattern)
53
- assert !match?('second', pattern)
54
- end
55
-
56
- def test_should_match_pattern_a_or_pattern_b
57
- pattern_a = Aurum::Pattern.from_string 'patterna'
58
- pattern_b = Aurum::Pattern.from_string 'patternb'
59
- pattern = pattern_a | pattern_b
60
- ['patterna', 'patternb'].each {|x| assert match?(x, pattern)}
61
- end
62
-
63
- def test_should_match_pattern_n_times
64
- pattern = Aurum::Pattern.from_string 'pattern'
65
- assert match?('pattern' * 5, pattern[5])
66
- assert match?('pattern' * 10, pattern[10])
67
- end
68
-
69
- def test_should_match_pattern_n_to_m_times
70
- pattern = Aurum::Pattern.from_string('pattern')[5, 7]
71
- (5..7).each {|x| assert match?('pattern' * x, pattern)}
72
- assert !match?('pattern' * 4, pattern)
73
- assert !match?('pattern' * 8, pattern)
74
- end
75
-
76
- def test_should_match_everything_but_the_strings_matched_by_pattern
77
- pattern = Aurum::Pattern.from_string 'pattern'
78
- negative_pattern = pattern.negate
79
- assert !match?('pattern', negative_pattern)
80
- assert match?('anything', negative_pattern)
81
- end
82
-
83
- def test_should_match_everything_upto_first_occurrence_of_a_text_matched_by_pattern
84
- pattern = ~ Aurum::Pattern.from_string('*/')
85
- assert match?('comments */', pattern)
86
- assert !match?('everything', pattern)
87
- end
88
-
89
- def test_should_match_every_char_in_enum_literal
90
- pattern = Aurum::Pattern.from_enum('*/')
91
- assert match?('*', pattern)
92
- assert match?('/', pattern)
93
- end
94
-
95
- def match? expected_string, pattern
96
- states = closure pattern.automata.table, [0]
97
- expected_string.each_byte {|char| states = move(pattern.automata.table, states, char)}
98
- states.include?(pattern.accept)
99
- end
100
-
101
- def move automata, states, char
102
- result = []
103
- states.each {|state| automata[state].each {|tran| result.concat(closure(automata, [tran.destination])) if tran.symbols.include? char} }
104
- result.uniq;
105
- end
106
-
107
- def closure automata, states
108
- closure, unvisited = Set.new(states.dup), states.dup
109
- filter = lambda {|x| x.symbols == Epsilon && !closure.include?(x.destination)}
110
- while !unvisited.empty? do
111
- automata[unvisited.pop].grep_each(filter){|tran| [closure, unvisited].each {|x| x << tran.destination}}
112
- end
113
- closure.to_a
114
- end
115
- end
@@ -1,19 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
- require 'set'
4
-
5
- class SubsetDeterminizerTest < Test::Unit::TestCase
6
- def test_should_create_equivalentDFA()
7
- a, b, abb = Aurum::Pattern.from_string('a'), Aurum::Pattern.from_string('b'), Aurum::Pattern.from_string('abb')
8
- pattern = Aurum::Pattern.concat((a | b).kleene, abb)
9
- automata, accepts = pattern.automata.determinize [pattern.accept]
10
- final = move automata.table, 'aaabbbaaabb'
11
- assert accepts.include?(final)
12
- end
13
-
14
- def move table, source
15
- state = 0
16
- source.each_byte {|char| state = (table[state].find {|tran| tran.symbols.include? char}).destination}
17
- state
18
- end
19
- end
@@ -1,126 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
-
4
- Aurum::LexicalTableGenerator.class_eval do
5
- attr_reader :accept_states, :partitions, :lexical_automata
6
-
7
- public :construct_automata, :make_initial_partitions, :refine_partitions
8
-
9
- def table
10
- @lexical_automata.table
11
- end
12
- end
13
-
14
- class LexicalTableGeneratorTest < Test::Unit::TestCase
15
- def test_should_construct_sub_automata_for_lexical_states
16
- specification = {:initial => {PATTERN_A => 'recognize'},
17
- :state_a => {PATTERN_B => 'recognize'}}
18
-
19
- generator = Aurum::LexicalTableGenerator.new specification
20
- generator.construct_automata
21
- @table, @accepts, @lexical_states = generator.table, generator.accept_states, generator.lexical_states
22
-
23
- assert recognize?(:initial, 'pattern_a')
24
- assert !recognize?(:initial, 'pattern_b')
25
- assert !recognize?(:state_a, 'pattern_a')
26
- assert recognize?(:state_a, 'pattern_b')
27
- end
28
-
29
- def test_should_add_common_patterns_to_all_lexical_states
30
- specification = {:initial => {PATTERN_A => 'recognize'},
31
- :state_a => {PATTERN_B => 'recognize'},
32
- :all => {PATTERN_C => 'recognize'}}
33
-
34
- generator = Aurum::LexicalTableGenerator.new specification
35
- generator.construct_automata
36
- @table, @accepts, @lexical_states = generator.table, generator.accept_states, generator.lexical_states
37
-
38
- assert recognize?(:initial, 'pattern_c')
39
- assert recognize?(:state_a, 'pattern_b')
40
- assert !recognize?(:all, 'pattern_b')
41
- end
42
-
43
- def test_initial_partiations_should_be_start_accepts_and_non_accepts
44
- specification = {:initial => {PATTERN_A => 'recognize'},
45
- :state_a => {PATTERN_B => 'recognize'}}
46
-
47
- generator = Aurum::LexicalTableGenerator.new specification
48
- generator.construct_automata
49
- generator.make_initial_partitions
50
- partitions = generator.partitions
51
-
52
- assert_equal 3, partitions.size
53
- assert partitions.include?([0])
54
- assert partitions.include?(generator.accept_states.keys)
55
- assert partitions.include?(generator.lexical_automata.all_states - generator.accept_states.keys - [0])
56
- end
57
-
58
- def test_should_not_split_accept_states_if_has_same_action
59
- specification = {:initial => {PATTERN_A => 'recognize', PATTERN_B => 'recognize'}}
60
- generator = Aurum::LexicalTableGenerator.new specification
61
- generator.construct_automata
62
- generator.make_initial_partitions
63
-
64
- assert generator.partitions.include?(generator.accept_states.keys)
65
- end
66
-
67
- def test_should_split_accept_states_if_has_different_actions
68
- specification = {:initial => {PATTERN_A => 'recognizeA', PATTERN_B => 'recognizeB'}}
69
- generator = Aurum::LexicalTableGenerator.new specification
70
- generator.construct_automata
71
- generator.make_initial_partitions
72
-
73
- assert !generator.partitions.include?(generator.accept_states.keys)
74
- end
75
-
76
- def test_should_partition_size_should_equal_to_state_size_if_min_dfa_given
77
- specification = {:initial => {PATTERN_A => 'recognize'}}
78
- generator = Aurum::LexicalTableGenerator.new specification
79
- generator.construct_automata
80
- generator.make_initial_partitions
81
- generator.refine_partitions
82
- assert_equal generator.table.size, generator.partitions.size
83
- end
84
-
85
- def test_should_partition_size_should_less_than_state_size
86
- specification = {:initial => {ABABB => 'recognize'}}
87
- generator = Aurum::LexicalTableGenerator.new specification
88
- generator.construct_automata
89
- generator.make_initial_partitions
90
- generator.refine_partitions
91
- assert generator.table.size > generator.partitions.size
92
- end
93
-
94
- def test_should_return_original_automata_if_min_dfa_given
95
- specification = {:initial => {PATTERN_A => 'recognize'}}
96
- generator = Aurum::LexicalTableGenerator.new specification
97
- lexical_table, accepts = generator.lexical_table
98
- assert generator.table.eql?(lexical_table)
99
- end
100
-
101
- def test_should_recognize_same_lexeme
102
- specification = {:initial => {ABABB => 'recognize'},
103
- :state_a => {PATTERN_B => 'recognize'},
104
- :all => {PATTERN_C => 'recognize'}}
105
-
106
- generator = Aurum::LexicalTableGenerator.new specification
107
- @table, @accepts = generator.lexical_table
108
- @lexical_states = generator.lexical_states
109
-
110
- assert recognize?(:initial, 'aabaabaabb')
111
- assert !recognize?(:initial, 'patterna')
112
- assert recognize?(:state_a, 'pattern_b')
113
- assert !recognize?(:all, 'pattern_b')
114
- end
115
-
116
- def recognize? lexical_state, source
117
- begin
118
- lexical_state = - @lexical_states.index(lexical_state) - 1
119
- state = (@table[0].find {|tran| tran.symbols.include?(lexical_state)}).destination
120
- source.each_byte {|char| state = (@table[state].find {|tran| tran.symbols.include? char}).destination}
121
- @accepts.keys.include?(state)
122
- rescue
123
- false
124
- end
125
- end
126
- end
@@ -1,45 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
- require 'set'
4
-
5
- Aurum::ParsingTableGenerator.class_eval do
6
- attr_reader :nullables, :first_sets
7
- end
8
-
9
- class AugmentedGrammarTest < Test::Unit::TestCase
10
- def test_should_find_all_used_symbols
11
- generator = parser_generator E=>[production(E, T)], T=>[production(T, F)], F=>[production(F, ID)]
12
- generator.start_from E
13
- assert_equal [E, T, F, ID], generator.symbols
14
- generator.start_from T
15
- assert_equal [T, F, ID], generator.symbols
16
- end
17
-
18
- def test_should_find_all_used_productions
19
- generator = parser_generator E=>[production(E, T)], T=>[production(T, F)], F=>[production(F, ID)]
20
- generator.start_from E
21
- assert_equal [production(START, E), production(E, T), production(T, F), production(F, ID)].to_set, generator.productions.to_set
22
- generator.start_from T
23
- assert_equal [production(START, T), production(T, F), production(F, ID)].to_set, generator.productions.to_set
24
- end
25
-
26
- def test_should_compute_nullable_nonterminals
27
- generator = parser_generator E=>[production(E, T)], T=>[production(T)], F=>[production(F, T, ID)]
28
- generator.start_from E
29
- assert_equal [T, E, START].to_set, generator.nullables.to_set
30
- generator.start_from F
31
- assert_equal [T].to_set, generator.nullables.to_set
32
- end
33
-
34
- def test_first_set_should_contain_terminals_left_depends_on_nt_dirctly
35
- generator = parser_generator E=>[production(E, T, ID), production(E, T, T, T, terminal('other'))], T=>[production(T)]
36
- generator.start_from E
37
- assert_equal [ID, terminal('other')].to_set, generator.first_sets[E].to_set
38
- end
39
-
40
- def test_should_contain_fist_set_of_nt_which_left_depends_on_nt_dirctly
41
- generator = parser_generator E=>[production(E, T, ID), production(E, T, T, T, terminal('other'))], T=>[production(T)], F=>[production(F, T, E)]
42
- generator.start_from F
43
- assert_equal generator.first_sets[F].to_set, generator.first_sets[E].to_set
44
- end
45
- end
@@ -1,92 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
-
4
- Aurum::ParsingTableGenerator.class_eval do
5
- attr_reader :states
6
- public :construct_LR0_automata, :compute_LALR_1_lookahead, :compute_LALR_n_lookahead, :default_action
7
- end
8
- class LALRLookaheadComputationTest < Test::Unit::TestCase
9
-
10
- def test_should_compute_reduce_action_for_inconsistent_states
11
- generator = parser_generator EXPRESSION_GRAMMAR_LALR1
12
- generator.start_from E
13
- generator.construct_LR0_automata
14
- states = generator.states.find_all {|x| x.inconsistent?}
15
- generator.compute_LALR_1_lookahead
16
- assert_equal [reduce(0)].to_set, states[0][terminal('$eof')]
17
- assert_equal [reduce(2)].to_set, states[1][terminal('+')]
18
- assert_equal [reduce(2)].to_set, states[1][terminal(')')]
19
- assert_equal [reduce(1)].to_set, states[2][terminal('+')]
20
- assert_equal [reduce(1)].to_set, states[2][terminal(')')]
21
- end
22
-
23
- def test_should_replace_conficted_state_actions_with_lookahead_action
24
- generator = parser_generator BNF_GRAMMAR_LALR2
25
- generator.start_from BNF
26
- generator.construct_LR0_automata
27
- generator.compute_LALR_1_lookahead
28
- conflicted_state = (generator.states.find_all {|x| x.conflict? })[0]
29
- generator.compute_LALR_n_lookahead
30
- assert_equal [lookahead_shift(generator.states.length - 1)].to_set, conflicted_state[terminal('s')]
31
- assert !conflicted_state.conflict?
32
- end
33
-
34
- def test_should_add_reduce_action_to_lookahead_state
35
- generator = parser_generator BNF_GRAMMAR_LALR2
36
- generator.start_from BNF
37
- generator.construct_LR0_automata
38
- generator.compute_LALR_1_lookahead
39
- generator.compute_LALR_n_lookahead
40
- states = generator.states
41
- assert_equal [read_reduce(6)].to_set, states[-1][terminal('s')]
42
- assert_equal [read_reduce(6)].to_set, states[-1][terminal('$eof')]
43
- assert_equal [reduce(4)].to_set, states[-1][terminal('->')]
44
- end
45
-
46
- def test_should_return_default_reduce_if_no_action_for_given_symbol
47
- generator = parser_generator BNF_GRAMMAR_LALR2
48
- generator.start_from BNF
49
- generator.construct_LR0_automata
50
- generator.compute_LALR_1_lookahead
51
- generator.compute_LALR_n_lookahead
52
- default_actions = generator.states.map {|x| generator.default_action x}
53
- assert_equal [reduce(2), reduce(1), nil, reduce(5), reduce(4), reduce(4)], default_actions
54
- end
55
-
56
- def test_should_return_lookahead_level
57
- generator = parser_generator SIMPLE_GRAMMAR_LR0
58
- table, level = generator.start_from(E).parsing_table
59
- assert_equal 0, level
60
- generator = parser_generator EXPRESSION_GRAMMAR_LALR1
61
- table, level = generator.start_from(E).parsing_table
62
- assert_equal 1, level
63
- generator = parser_generator IF_GRAMMAR_LALR2
64
- table, level = generator.start_from(STATEMENT).parsing_table
65
- assert_equal 2, level
66
- generator = parser_generator BNF_GRAMMAR_LALR2
67
- table, level = generator.start_from(BNF).parsing_table
68
- assert_equal 2, level
69
- end
70
-
71
- def test_should_raise_error_if_grammar_not_lalr_n
72
- begin
73
- parser_generator(NOT_LALR_GRAMMAR).start_from(E).parsing_table
74
- assert false
75
- rescue RuntimeError => error
76
- assert_equal 'not LALR(n)', error.message
77
- end
78
- end
79
-
80
- def test_should_resolve_conflicts_for_expression
81
- op_a, op_b = terminal('+'), terminal('*')
82
- generator = parser_generator EXPRESSION_GRAMMAR, [[op_b], [op_a]]
83
- generator.start_from E
84
- generator.construct_LR0_automata
85
- generator.compute_LALR_1_lookahead
86
- state = generator.states.last
87
- assert_equal 1, state[terminal('+')].size
88
- assert state[terminal('+')].to_a.first.kind_of?(Aurum::ReduceAction)
89
- assert_equal 1, state[terminal('*')].size
90
- assert state[terminal('*')].to_a.first.kind_of?(Aurum::ShiftAction)
91
- end
92
- end
@@ -1,94 +0,0 @@
1
- $:.unshift(File.dirname(__FILE__) + '/../')
2
- require 'test_helper'
3
-
4
- Aurum::ParsingTableGenerator.class_eval do
5
- attr_reader :states
6
- public :closure, :goto, :read_set, :construct_LR0_automata
7
- end
8
-
9
- class LR0AutomataTest < Test::Unit::TestCase
10
- def test_closure_should_contain_items_themselves
11
- generator = parser_generator E=>[production(E, ID)]
12
- assert_equal [LR_item(0, E, ID)], generator.closure([LR_item(0, E, ID)])
13
- end
14
-
15
- def test_closure_should_contain_all_right_most_lr_items_of_dot_symbol
16
- generator = parser_generator E=>[production(E, T)], T=>[production(T, ID), production(T, terminal('other'))]
17
- generator.start_from E
18
- closure = generator.closure [LR_item(0, E, T)]
19
- [LR_item(0, T, ID), LR_item(0, T, terminal('other'))].each {|x| assert closure.include?(x)}
20
- end
21
-
22
- def test_should_return_goto_items_if_expected_symbol_given
23
- generator = parser_generator E=>[production(E, T)], T=>[production(T, ID), production(T, terminal('other'))]
24
- generator.start_from E
25
- assert_equal [LR_item(1, E, T)], generator.goto([LR_item(0, E, T)], T)
26
- end
27
-
28
- def test_goto_items_should_be_closured_if_expected_symbol_given
29
- generator = parser_generator E=>[production(E, T, T)], T=>[production(T, ID), production(T, terminal('other'))]
30
- generator.start_from E
31
- goto = generator.goto [LR_item(0, E, T, T)], T
32
- [LR_item(0, T, ID), LR_item(0, T, terminal('other'))].each {|x| assert goto.include?(x)}
33
- end
34
-
35
- def test_should_use_LR0_items_of_collection_as_state
36
- generator = parser_generator SIMPLE_GRAMMAR_LR0
37
- generator.start_from E
38
- generator.construct_LR0_automata
39
- states = generator.states
40
- assert 3, states.length
41
- assert [LR_item(0, START, E), LR_item(0, T, terminal('+'), T), LR_item(0, T, ID)], states[0]
42
- assert [LR_item(1, T, terminal('+'), T)], states[1]
43
- assert [LR_item(2, T, terminal('+'), T), LR_item(0, T, ID)], states[2]
44
- end
45
-
46
- def test_should_add_shift_action_to_states
47
- generator = parser_generator SIMPLE_GRAMMAR_LR0
48
- generator.start_from E
49
- generator.construct_LR0_automata
50
- states = generator.states
51
- assert_equal [shift(1)].to_set, states[0][T]
52
- assert_equal [shift(2)].to_set, states[1][terminal('+')]
53
- end
54
-
55
- def test_should_add_read_reduce_action_to_states
56
- generator = parser_generator SIMPLE_GRAMMAR_LR0
57
- generator.start_from E
58
- generator.construct_LR0_automata
59
- states = generator.states
60
- assert_equal [read_reduce(0)].to_set, states[0][E]
61
- assert_equal [read_reduce(2)].to_set, states[0][ID]
62
- assert_equal [read_reduce(2)].to_set, states[2][ID]
63
- assert_equal [read_reduce(1)].to_set, states[2][T]
64
- end
65
-
66
- def test_should_return_all_predsucceors
67
- generator = parser_generator EXPRESSION_GRAMMAR_LALR1
68
- generator.start_from E
69
- generator.construct_LR0_automata
70
- states = generator.states
71
- assert_equal [LR_item(0, START, E),
72
- LR_item(0, E, E, terminal('+'), T),
73
- LR_item(0, E, T),
74
- LR_item(0, T, T, terminal('*'), F),
75
- LR_item(0, T, F),
76
- LR_item(0, F, terminal('('), E, terminal(')')),
77
- LR_item(0, F, ID)], states[2].predsucceors([T])[0]
78
- assert_equal [LR_item(1, F, terminal('('), E, terminal(')')),
79
- LR_item(0, E, E, terminal('+'), T),
80
- LR_item(0, E, T),
81
- LR_item(0, T, T, terminal('*'), F),
82
- LR_item(0, T, F),
83
- LR_item(0, F, terminal('('), E, terminal(')')),
84
- LR_item(0, F, ID)], states[2].predsucceors([T])[1]
85
- end
86
-
87
- def test_should_return_read_set_for_state
88
- generator = parser_generator EXPRESSION_GRAMMAR_LALR1
89
- generator.start_from E
90
- generator.construct_LR0_automata
91
- states = generator.states
92
- assert_equal [terminal('id'), terminal('(')].to_set, generator.read_set(states[2], terminal('*')).to_set
93
- end
94
- end