aurum 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +29 -0
- data/examples/dangling_else/grammar.rb +23 -0
- data/examples/expression/grammar.rb +28 -0
- data/examples/smalltalk/grammar.rb +151 -0
- data/examples/smalltalk/interpreter.rb +70 -0
- data/examples/yacc/grammar.rb +72 -0
- data/lib/aurum.rb +1 -9
- data/lib/aurum/engine.rb +39 -175
- data/lib/aurum/engine/parsing_facility.rb +107 -0
- data/lib/aurum/engine/tokenization_facility.rb +86 -0
- data/lib/aurum/grammar.rb +52 -219
- data/lib/aurum/grammar/automata.rb +194 -0
- data/lib/aurum/grammar/builder/augmented_grammar.rb +83 -0
- data/lib/aurum/grammar/builder/dot_logger.rb +66 -0
- data/lib/aurum/grammar/builder/lexical_table_builder.rb +55 -0
- data/lib/aurum/grammar/builder/parsing_table_builder.rb +238 -0
- data/lib/aurum/grammar/builder/set_of_items.rb +190 -0
- data/lib/aurum/grammar/compiled_tables.rb +20 -0
- data/lib/aurum/grammar/dsl/lexical_definition.rb +94 -0
- data/lib/aurum/grammar/dsl/syntax_definition.rb +79 -0
- data/lib/aurum/grammar/lexical_rules.rb +224 -0
- data/lib/aurum/grammar/metalang/grammar.rb +47 -0
- data/lib/aurum/grammar/syntax_rules.rb +95 -0
- data/spec/builder/dsl_definition/aurum_grammar_spec.rb +33 -0
- data/spec/engine/lexer_spec.rb +59 -0
- data/spec/engine/parser_spec.rb +90 -0
- data/spec/examples/dangling_else_example.rb +30 -0
- data/spec/examples/expression_example.rb +48 -0
- data/spec/examples/smalltalk_example.rb +50 -0
- data/spec/examples/yacc_spec.rb +30 -0
- data/spec/grammar/builder/lexical_table/automata_spec.rb +55 -0
- data/spec/grammar/builder/lexical_table/builder_spec.rb +78 -0
- data/spec/grammar/builder/lexical_table/character_set_spec.rb +100 -0
- data/spec/grammar/builder/lexical_table/pattern_spec.rb +11 -0
- data/spec/grammar/builder/lexical_table/regular_expression.rb +40 -0
- data/spec/grammar/builder/parsing_table/augmented_grammar_spec.rb +36 -0
- data/spec/grammar/builder/parsing_table/builder_spec.rb +152 -0
- data/spec/grammar/builder/parsing_table/digraph_traverser_spec.rb +42 -0
- data/spec/grammar/builder/parsing_table/item_spec.rb +51 -0
- data/spec/grammar/builder/parsing_table/sources_spec.rb +66 -0
- data/spec/grammar/builder/parsing_table/state_spec.rb +82 -0
- data/spec/grammar/dsl/character_classes_builder_spec.rb +50 -0
- data/spec/grammar/dsl/lexical_rules_builder_spec.rb +181 -0
- data/spec/grammar/dsl/precedence_builder_spec.rb +64 -0
- data/spec/grammar/dsl/productions_builder_spec.rb +78 -0
- data/spec/grammar/metalang/metalang_spec.rb +0 -0
- data/spec/grammar/precedence_spec.rb +42 -0
- data/spec/grammar/syntax_rules_spec.rb +31 -0
- data/spec/parser_matcher.rb +69 -0
- data/spec/pattern_matcher.rb +123 -0
- data/spec/spec_helper.rb +133 -0
- metadata +70 -36
- data/example/expression/expression.rb +0 -35
- data/example/expression/lisp.rb +0 -26
- data/lib/aurum/lexical_table_generator.rb +0 -429
- data/lib/aurum/parsing_table_generator.rb +0 -464
- data/test/engine/lexer_test.rb +0 -59
- data/test/engine/semantic_attributes_test.rb +0 -15
- data/test/grammar_definition/character_class_definition_test.rb +0 -28
- data/test/grammar_definition/grammar_definition_test.rb +0 -55
- data/test/grammar_definition/lexical_definition_test.rb +0 -56
- data/test/grammar_definition/operator_precedence_definition_test.rb +0 -35
- data/test/grammar_definition/production_definition_test.rb +0 -60
- data/test/lexical_table_generator/automata_test.rb +0 -74
- data/test/lexical_table_generator/character_set_test.rb +0 -73
- data/test/lexical_table_generator/interval_test.rb +0 -36
- data/test/lexical_table_generator/pattern_test.rb +0 -115
- data/test/lexical_table_generator/subset_determinizer_test.rb +0 -19
- data/test/lexical_table_generator/table_generator_test.rb +0 -126
- data/test/parsing_table_generator/augmented_grammar_test.rb +0 -45
- data/test/parsing_table_generator/lalr_n_computation_test.rb +0 -92
- data/test/parsing_table_generator/lr_0_automata_test.rb +0 -94
- data/test/parsing_table_generator/lr_item_test.rb +0 -27
- data/test/parsing_table_generator/parsing_table_state_test.rb +0 -39
- data/test/parsing_table_generator/precedence_table_test.rb +0 -28
- data/test/parsing_table_generator/production_test.rb +0 -9
- data/test/test_helper.rb +0 -103
@@ -0,0 +1,47 @@
|
|
1
|
+
module Aurum
|
2
|
+
module MetaLanguage
|
3
|
+
class Grammar < Aurum::Grammar
|
4
|
+
tokens do
|
5
|
+
ignore enum(" \r\n").one_or_more
|
6
|
+
_nonterminal 'nonterminal'
|
7
|
+
_terminal 'terminal'
|
8
|
+
_literal 'literal'
|
9
|
+
end
|
10
|
+
|
11
|
+
syntax_rules do
|
12
|
+
bnf bnf, rules
|
13
|
+
bnf _
|
14
|
+
|
15
|
+
rules rule
|
16
|
+
rules rules, '|', symbol_list
|
17
|
+
|
18
|
+
rule _nonterminal, '->', symbol_list
|
19
|
+
|
20
|
+
symbol_list _
|
21
|
+
symbol_list symbol_list, symbol
|
22
|
+
|
23
|
+
symbol _nonterminal
|
24
|
+
symbol _terminal
|
25
|
+
symbol _literal
|
26
|
+
|
27
|
+
=begin
|
28
|
+
syntax_rules syntax_rules, syntax_rule {syntax_rules.s_exp = syntax_rules1.s_exp + syntax_rule.s_exp}
|
29
|
+
syntax_rules _ {syntax_rules.s_exp = []}
|
30
|
+
|
31
|
+
# syntax_rule _nonterminal, '->', symbols {syntax_rule.s_exp = [:production, [:nonterminal, _nonterminal.value], symbols.s_exp]}
|
32
|
+
syntax_rule _nonterminal, '->', handles {syntax_rule.s_exp = [:production, [:nonterminal, _nonterminal.value], handles.s_exp]}
|
33
|
+
|
34
|
+
handles handle, '|', handles
|
35
|
+
handles _
|
36
|
+
|
37
|
+
handle handle, symbol {handle.s_exp = handle1.s_exp << symbol.s_exp}
|
38
|
+
handle _ {handle.s_exp = []}
|
39
|
+
|
40
|
+
symbol _nonterminal {symbol.s_exp = [:nonterminal, _nonterminal.value]}
|
41
|
+
symbol _terminal {symbol.s_exp = [:terminal, _terminal.value]}
|
42
|
+
symbol _literal {symbol.s_exp = [:literal, _literal.value]}
|
43
|
+
=end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
module Aurum
|
2
|
+
class Grammar
|
3
|
+
class SyntaxRules < Struct.new(:precedences, :productions)
|
4
|
+
attr_reader :literals
|
5
|
+
def initialize
|
6
|
+
@precedences, @productions, @terminals, @literals = {}, {}, {}, [].to_set
|
7
|
+
@precedences_update = true
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_syntax_rule production
|
11
|
+
@precedences_update = true
|
12
|
+
nonterminal = production.nonterminal
|
13
|
+
production.symbols.each {|s| @terminals[s.name] = s if s.is_terminal && !s.precedence}
|
14
|
+
@productions[nonterminal] = [] unless @productions.has_key?(nonterminal)
|
15
|
+
return false if @productions[nonterminal].include?(production)
|
16
|
+
@productions[nonterminal] << production
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_literal literal
|
21
|
+
@literals << literal
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_operator_precedence operator, precedence
|
25
|
+
@precedences_update = true
|
26
|
+
@precedences[operator] = precedence
|
27
|
+
end
|
28
|
+
|
29
|
+
def productions nonterminal
|
30
|
+
@productions[nonterminal]
|
31
|
+
end
|
32
|
+
|
33
|
+
def operator_precedence symbol_name
|
34
|
+
@precedences[symbol_name]
|
35
|
+
end
|
36
|
+
|
37
|
+
def assign_operator_precedence_to_symbols
|
38
|
+
return unless @precedences_update
|
39
|
+
@precedences_update = false
|
40
|
+
for name, precedence in @precedences
|
41
|
+
symbol = @terminals[name]
|
42
|
+
symbol.precedence = precedence if symbol
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Precedence < Struct.new(:associativity, :level)
|
47
|
+
include Comparable
|
48
|
+
Highest, Lowest = Precedence.new(:non_associative, 65535), Precedence.new(:non_associative, -65535)
|
49
|
+
def <=> other
|
50
|
+
return level <=> other.level unless level == other.level
|
51
|
+
return 1 if associativity == :left_associative
|
52
|
+
return -1 if associativity == :right_associative
|
53
|
+
#TODO non_associative
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Symbol < Struct.new(:name, :is_terminal)
|
58
|
+
attr_accessor :precedence, :action
|
59
|
+
def inspect
|
60
|
+
name.split('$literal_').last
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Production < Struct.new(:nonterminal, :symbols)
|
65
|
+
attr_accessor :name
|
66
|
+
|
67
|
+
def precedence
|
68
|
+
terminals = symbols.find_all {|symbol| symbol.is_terminal && symbol.precedence}
|
69
|
+
terminals.size == 1 ? terminals.first.precedence : Precedence::Highest
|
70
|
+
end
|
71
|
+
|
72
|
+
def inspect
|
73
|
+
"#{nonterminal.inspect} -> #{symbols.map {|symbol| symbol.inspect}.join(' ')}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def Grammar.terminal name
|
79
|
+
SyntaxRules::Symbol.new(name, true)
|
80
|
+
end
|
81
|
+
|
82
|
+
def Grammar.nonterminal name
|
83
|
+
SyntaxRules::Symbol.new(name, false)
|
84
|
+
end
|
85
|
+
|
86
|
+
def Grammar.precedence associative, level
|
87
|
+
SyntaxRules::Precedence.new(associative, level)
|
88
|
+
end
|
89
|
+
|
90
|
+
def Grammar.production nonterminal, symbols
|
91
|
+
SyntaxRules::Production.new(nonterminal, symbols)
|
92
|
+
end
|
93
|
+
EOF, Epsilon = Grammar.terminal('$eof'), Grammar.terminal('$epsilon')
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
helper_lib = "#{File.dirname(__FILE__)}/../../"
|
2
|
+
$:.unshift helper_lib unless $:.include? helper_lib
|
3
|
+
#require 'spec_helper'
|
4
|
+
#require File.join(File.dirname(__FILE__), '../../engine/parser_matcher')
|
5
|
+
=begin
|
6
|
+
class TestGrammar < Aurum::Grammar
|
7
|
+
end
|
8
|
+
class GrammarA < Aurum::Grammar
|
9
|
+
productions do
|
10
|
+
expression factor, '+', factor
|
11
|
+
factor _id
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe Aurum::Grammar, 'including other grammar' do
|
16
|
+
def be_parsed_as(nonterminal, value=nil)
|
17
|
+
ParserMatcher::BeParsedAs.new(TestGrammar.parsing_table(nonterminal), nonterminal, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should throw an error if included object is not a grammar' do
|
21
|
+
lambda {TestGrammar.include_grammar String}.should raise_error(RuntimeError, 'String is not a grammar!')
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should include grammar into TestGrammar' do
|
25
|
+
TestGrammar.include_grammar GrammarA
|
26
|
+
[:_id, '+', :_id].should be_parsed_as('expression')
|
27
|
+
end
|
28
|
+
it 'should change symbol names and include grammar into TestGrammar' do
|
29
|
+
TestGrammar.include_grammar GrammarA, :syntax => {:expression => :exp}
|
30
|
+
[:_id, '+', :_id].should be_parsed_as('exp')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
=end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe Aurum::Engine::BasicTokenizationCapability do
|
7
|
+
before :all do
|
8
|
+
Lexer = Aurum::Lexer.new(GrammarForLexerTesting)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should return recognized symbol' do
|
12
|
+
lexer = Lexer.new('1234')
|
13
|
+
lexer.next_symbol.to_a.should == ['_numeric', '1234']
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should shift to lexical state' do
|
17
|
+
lexer = Lexer.new('state_a_begin1234')
|
18
|
+
lexer.next_symbol.to_a.should == ['_numeric', 'state_a_begin1234']
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return recognized symbol and shift to lexical state' do
|
22
|
+
lexer = Lexer.new('state_b_begin1234')
|
23
|
+
lexer.next_symbol.to_a.should == ['_state_b_begin', 'state_b_begin']
|
24
|
+
lexer.next_symbol.to_a.should == ['_numeric', '1234']
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should ignore ignored pattern' do
|
28
|
+
lexer = Lexer.new('ignore1234')
|
29
|
+
lexer.next_symbol.to_a.should == ['_numeric', '1234']
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should not match pattern greedily' do
|
33
|
+
lexer = Lexer.new('state_b_begi1234')
|
34
|
+
lexer.next_symbol.to_a.should == ['_state_b_beg', 'state_b_beg']
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return EOF if reach the end of input' do
|
38
|
+
lexer = Lexer.new('ignore')
|
39
|
+
lexer.next_symbol.to_a.should == ['$eof', '']
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should return UNKNOWN if can not recognize token' do
|
43
|
+
lexer = Lexer.new('state_b_')
|
44
|
+
lexer.next_symbol.to_a.should == ['$unknown', 'state_b_']
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should return pushbacked symbol' do
|
48
|
+
lexer = Lexer.new('state_b_')
|
49
|
+
lexer.pushback('pushback')
|
50
|
+
lexer.next_symbol.should == 'pushback'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should return current column' do
|
54
|
+
lexer = Lexer.new('1234')
|
55
|
+
lexer.column.should == 0
|
56
|
+
lexer.next_symbol
|
57
|
+
lexer.column.should == 4
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
|
6
|
+
describe Aurum::Engine::BasicParsingCapability, ' LR(0) : simple LR(0) grammar' do
|
7
|
+
include ParserMatcher
|
8
|
+
before :all do
|
9
|
+
@grammar = SimpleLR0Grammar
|
10
|
+
end
|
11
|
+
it {[:_id].should be_parsed_as('term')}
|
12
|
+
it {[:_id, '+', :_id].should be_parsed_as('expression')}
|
13
|
+
it {[:_it].should_not be_parsed_as('term')}
|
14
|
+
it {[:_id, '+', :_it].should_not be_parsed_as('expression')}
|
15
|
+
it 'should not look for eof' do
|
16
|
+
[:_id, '+', :_id].should be_parsed_as('term')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Aurum::Engine::BasicParsingCapability, ' LALR(1) : Grammar 4.19 in Dragon book' do
|
21
|
+
include ParserMatcher
|
22
|
+
before :all do
|
23
|
+
@grammar = Grammar419InDragonBook
|
24
|
+
end
|
25
|
+
it {[:_id].should be_parsed_as('factor')}
|
26
|
+
it {['(', :_id, ')'].should be_parsed_as('factor')}
|
27
|
+
it {['(', :_id, '*', :_id, ')'].should be_parsed_as('factor')}
|
28
|
+
it {['(', :_id, '+', :_id, ')'].should be_parsed_as('factor')}
|
29
|
+
it {[:_id, '*', :_id].should be_parsed_as('term')}
|
30
|
+
it {[:_id, '*', '(', :_id, '*', :_id, ')'].should be_parsed_as('term')}
|
31
|
+
it {[:_id, '*', '(', :_id, '+', :_id, ')'].should be_parsed_as('term')}
|
32
|
+
it {[:_id, '+', :_id].should be_parsed_as('expression')}
|
33
|
+
it {[:_id, '*', :_id].should be_parsed_as('expression')}
|
34
|
+
it {[:_id, '+', :_id, '*', :_id].should be_parsed_as('expression')}
|
35
|
+
it {[:_id, '+', :_id, '+', :_id].should be_parsed_as('expression')}
|
36
|
+
it {[:_id, '+', '(', :_id, '*', :_id, ')'].should be_parsed_as('expression')}
|
37
|
+
it {[:_id, '+', '(', :_id, '+', :_id, ')'].should be_parsed_as('expression')}
|
38
|
+
it {[:_id, '+', :_id].should_not be_parsed_as('term')}
|
39
|
+
end
|
40
|
+
|
41
|
+
describe Aurum::Engine::BasicParsingCapability, ' LALR(1) : Expression Grammar with operator precedences' do
|
42
|
+
include ParserMatcher
|
43
|
+
before :all do
|
44
|
+
@grammar = ExpressionGrammarWithOperatorPrecedence
|
45
|
+
end
|
46
|
+
it {[:_id, '+', :_id].should be_parsed_as('expression')}
|
47
|
+
it {[:_id, '*', :_id].should be_parsed_as('expression')}
|
48
|
+
it {[:_id, '+', :_id, '*', :_id].should be_parsed_as('expression')}
|
49
|
+
it {[:_id, '+', :_id, '+', :_id].should be_parsed_as('expression')}
|
50
|
+
it {[:_id, '+', '(', :_id, '*', :_id, ')'].should be_parsed_as('expression')}
|
51
|
+
it {[:_id, '+', '(', :_id, '+', :_id, ')'].should be_parsed_as('expression')}
|
52
|
+
end
|
53
|
+
|
54
|
+
describe Aurum::Engine::SemanticActionExecutable, ' LALR(2) : BNF grammar in Philippe Charles\' thesis' do
|
55
|
+
include ParserMatcher
|
56
|
+
before :all do
|
57
|
+
@grammar = BnfGrammarWithActions
|
58
|
+
end
|
59
|
+
it {[:_s, '->', :_s, :_s, :_s].should be_parsed_as('bnf', :s_exp => [[:rule, :_s, [:_s, :_s, :_s]]])}
|
60
|
+
it {[:_s, '->', :_s, :_s, '->', :_s].should be_parsed_as('bnf', :s_exp => [[:rule, :_s, [:_s]], [:rule, :_s, [:_s]]])}
|
61
|
+
it {[:_s, '->', :_s, '->', :_s].should be_parsed_as('bnf', :s_exp => [[:rule, :_s, []], [:rule, :_s, [:_s]]])}
|
62
|
+
it {[:_s, '->', :_s, '->'].should be_parsed_as('bnf', :s_exp => [[:rule, :_s, []], [:rule, :_s, []]])}
|
63
|
+
end
|
64
|
+
|
65
|
+
describe Aurum::Engine::BasicParsingCapability, ' LALR(4) : simple LALR(4) grammar' do
|
66
|
+
include ParserMatcher
|
67
|
+
before :all do
|
68
|
+
@grammar = LALR4Grammar
|
69
|
+
end
|
70
|
+
it {[:_x, :_w, :_x, :_x, :_x, :_x, :_y].should be_parsed_as('s')}
|
71
|
+
it {[:_w, :_x, :_x, :_x, :_y, :_z].should be_parsed_as('s')}
|
72
|
+
it {[:_w, :_x, :_x, :_x, :_x, :_z].should be_parsed_as('s')}
|
73
|
+
end
|
74
|
+
|
75
|
+
describe Aurum::Engine::SemanticActionExecutable::SemanticContext do
|
76
|
+
it 'lexer should be accessible in semantic context' do
|
77
|
+
@context = Aurum::Engine::SemanticActionExecutable::SemanticContext.new('lexer', {}, {})
|
78
|
+
(@context.instance_eval {@lexer}).should == 'lexer'
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should access symbols by name' do
|
82
|
+
@context = Aurum::Engine::SemanticActionExecutable::SemanticContext.new('lexer', {'symbolA' => 1}, {})
|
83
|
+
@context.symbolA.should == 1
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should access symbols by alias name' do
|
87
|
+
@context = Aurum::Engine::SemanticActionExecutable::SemanticContext.new('lexer', {'symbolA' => 1}, {'symbolB' => 'symbolA'})
|
88
|
+
@context.symbolB.should == 1
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'dangling_else/grammar'
|
6
|
+
|
7
|
+
describe 'Dangling Else' do
|
8
|
+
before :all do
|
9
|
+
DanglingElseLexer = Aurum::Lexer.new(Aurum::Examples::DanglingElse)
|
10
|
+
DanglingElseParser = Aurum::Parser.new(Aurum::Examples::DanglingElse, :statement)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'else should be matched to closest if' do
|
14
|
+
parse(<<-EOF).should == [:if, [:expr], [:if, [:expr], [:other], [:other]], nil]
|
15
|
+
if ( expr )
|
16
|
+
if (expr)
|
17
|
+
other
|
18
|
+
else
|
19
|
+
other
|
20
|
+
EOF
|
21
|
+
end
|
22
|
+
|
23
|
+
def scanner source
|
24
|
+
DanglingElseLexer.new(source)
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse source
|
28
|
+
DanglingElseParser.new.parse(DanglingElseLexer.new(source)).s_exp
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
helper_dir = File.join(File.dirname(__FILE__), '..')
|
2
|
+
$:.unshift(helper_dir) unless $:.include?(helper_dir)
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'expression/grammar'
|
6
|
+
|
7
|
+
describe 'Expression Grammar' do
|
8
|
+
before :all do
|
9
|
+
ExpressionLexer = Aurum::Lexer.new(Aurum::Examples::ExpressionGrammar)
|
10
|
+
ExpressionParser = Aurum::Parser.new(Aurum::Examples::ExpressionGrammar, :expression)
|
11
|
+
end
|
12
|
+
|
13
|
+
it '1 + 1 should == 2' do
|
14
|
+
parse('1 + 1').should == 2
|
15
|
+
end
|
16
|
+
|
17
|
+
it '2 * 3 should == 6' do
|
18
|
+
parse('2 * 3').should == 6
|
19
|
+
end
|
20
|
+
|
21
|
+
it '2 + 2 * 3 should == 8' do
|
22
|
+
parse('2 + 2 * 3').should == 8
|
23
|
+
end
|
24
|
+
|
25
|
+
it '(2 + 2) * 3 should == 12' do
|
26
|
+
parse('(2 + 2) * 3').should == 12
|
27
|
+
end
|
28
|
+
|
29
|
+
it '3 * (2 + 2) should == 12' do
|
30
|
+
parse('3 * (2 + 2)').should == 12
|
31
|
+
end
|
32
|
+
|
33
|
+
it '2 * (2 + 2) * 3 should == 24' do
|
34
|
+
parse('2 * (2 + 2) * 3').should == 24
|
35
|
+
end
|
36
|
+
|
37
|
+
it '-2 * -4 should == 8' do
|
38
|
+
parse('-2 * -4').should == 8
|
39
|
+
end
|
40
|
+
|
41
|
+
it '-2 - - 4 should == 2' do
|
42
|
+
parse('-2 - - 4').should == 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse source
|
46
|
+
ExpressionParser.new.parse(ExpressionLexer.new(source)).value
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
=begin
|
2
|
+
helper_dir = "#{File.dirname(__FILE__)}/../"
|
3
|
+
$:.unshift helper_dir unless $:.include?(helper_dir)
|
4
|
+
require 'spec_helper'
|
5
|
+
require 'smalltalk/grammar'
|
6
|
+
|
7
|
+
describe 'Little Smalltalk' do
|
8
|
+
before :all do
|
9
|
+
@logger = Aurum::Builder::GraphvizLogger.new
|
10
|
+
@parsing_table = Smalltalk::Grammar.parsing_table :program, @logger
|
11
|
+
@lexical_table = Smalltalk::Grammar.lexical_table @logger
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'keyword message sending should be parsed correctly' do
|
15
|
+
parse(<<-EOF).should == [:program, [], [[:keyword, [:var, "Transcript"], [["show:", [:var, "helloMessage"]]]]]]
|
16
|
+
Transcript show: helloMessage.
|
17
|
+
EOF
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'binary message sending should be parsed correctly' do
|
21
|
+
parse(<<-EOF).should == [:program, [], [[:binary, [:var, "a"], [["+", [:var, "b"]]]]]]
|
22
|
+
a + b.
|
23
|
+
EOF
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'unary message sending should be parsed correctly' do
|
27
|
+
parse(<<-EOF).should == [:program, [], [[:unary, [:var, "car"], ["go"]]]]
|
28
|
+
car go.
|
29
|
+
EOF
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'unary message sending should have higher precedence then keyword message sending' do
|
33
|
+
parse(<<-EOF).should == [:program, [], [[:keyword, [:var, "Rectangle"], [["width:", [:unary, [:var, "aRect"], ["weight"]]], ["height:", [:unary, [:var, "aRect"], ["height"]]]]]]]
|
34
|
+
Rectangle width:aRect weight height:aRect height.
|
35
|
+
EOF
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'binary message sending should have higher precedence then keyword message sending' do
|
39
|
+
parse(<<-EOF).should == [:program, [], [[:keyword, [:var, "Rectangle"], [["width:", [:binary, [:var, "width"], [["+", [:var, "delta"]]]]], ["height:", [:binary, [:var, "height"], [["+", [:var, "delta"]]]]]]]]]
|
40
|
+
Rectangle width:width + delta height:height + delta.
|
41
|
+
EOF
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse source
|
45
|
+
lexer = Aurum::Engine::Lexer.new(@lexical_table, source)
|
46
|
+
parser = Aurum::Engine::Parser.new(@parsing_table)
|
47
|
+
parser.parse(lexer).s_exp
|
48
|
+
end
|
49
|
+
end
|
50
|
+
=end
|