Skip to content

Commit e473345

Browse files
authored
Merge pull request #290 from ydah/fix-182
Reject symbols prefixed with colon
2 parents bf9d9a7 + e9fe862 commit e473345

2 files changed

Lines changed: 66 additions & 1 deletion

File tree

lib/racc/grammarfileparser.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ def initialize(str, filename = '-')
405405
@filename = filename
406406
@lineno = -1
407407
@line_head = true
408+
@allow_colon2 = false
408409
@in_rule_blk = false
409410
@in_conv_blk = false
410411
@in_block = nil
@@ -437,11 +438,17 @@ def yylex(&block)
437438
def yylex0
438439
begin
439440
until @line.empty?
440-
@line.sub!(/\A\s+/, '')
441+
@allow_colon2 = false if @line.sub!(/\A\s+/, '')
441442
if /\A\#/ =~ @line
442443
break
443444
elsif /\A\/\*/ =~ @line
444445
skip_comment
446+
elsif @allow_colon2 && @line.start_with?(':')
447+
@allow_colon2 = false
448+
read(1)
449+
yield [':', ':']
450+
elsif @line.start_with?(':') && (s = reads(/\A:(?!:)[a-zA-Z_]\w*/))
451+
scan_error! "terminal and nonterminal symbols cannot start with ':', but got #{s}"
445452
elsif s = reads(/\A[a-zA-Z_]\w*/)
446453
yield [atom_symbol(s), s.intern]
447454
elsif s = reads(/\A\d+/)
@@ -457,6 +464,7 @@ def yylex0
457464
if ch == '|'
458465
@line_head = false
459466
end
467+
@allow_colon2 = ch == ':' && @line.start_with?(':')
460468
yield [ch, ch]
461469
end
462470
else

test/test_grammar_file_parser.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,62 @@ def test_parse
1111
parser = Racc::GrammarFileParser.new(debug_flags)
1212
parser.parse(File.read(file), File.basename(file))
1313
end
14+
15+
def test_allow_double_colon_in_class_name
16+
parser = Racc::GrammarFileParser.new
17+
18+
result = parser.parse(<<~RACC, 'namespace.y')
19+
class Foo::Bar
20+
rule
21+
target : TERM
22+
end
23+
RACC
24+
25+
assert_equal 'Foo::Bar', result.params.classname
26+
end
27+
28+
def test_reject_colon_prefixed_symbol_in_rule_body
29+
parser = Racc::GrammarFileParser.new
30+
error = assert_raise(CompileError) do
31+
parser.parse(<<~RACC, 'colon_prefixed_symbol.y')
32+
class Parse
33+
rule
34+
target : :TERM1
35+
end
36+
RACC
37+
end
38+
39+
assert_equal "3: terminal and nonterminal symbols cannot start with ':', but got :TERM1", error.message
40+
end
41+
42+
def test_reject_colon_prefixed_symbol_in_rule_alternative
43+
parser = Racc::GrammarFileParser.new
44+
error = assert_raise(CompileError) do
45+
parser.parse(<<~RACC, 'colon_prefixed_symbol.y')
46+
class Parse
47+
rule
48+
target : TERM1
49+
| :TERM2
50+
end
51+
RACC
52+
end
53+
54+
assert_equal "4: terminal and nonterminal symbols cannot start with ':', but got :TERM2", error.message
55+
end
56+
57+
def test_reject_colon_prefixed_symbol_after_rhs_symbol
58+
parser = Racc::GrammarFileParser.new
59+
error = assert_raise(CompileError) do
60+
parser.parse(<<~RACC, 'colon_prefixed_symbol.y')
61+
class Parse
62+
rule
63+
target : TERM1
64+
| term :TERM2
65+
end
66+
RACC
67+
end
68+
69+
assert_equal "4: terminal and nonterminal symbols cannot start with ':', but got :TERM2", error.message
70+
end
1471
end
1572
end

0 commit comments

Comments
 (0)