Skip to content

Commit

Permalink
Merge pull request #81 from flavorjones/flavorjones-master-frozen-str…
Browse files Browse the repository at this point in the history
…ing-literal

support Ruby 2.4's frozen string literals (on master)
  • Loading branch information
flavorjones committed Nov 22, 2017
2 parents 8e40d4c + 3f8e7f3 commit c92678b
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 31 deletions.
5 changes: 3 additions & 2 deletions bin/racc
Expand Up @@ -165,9 +165,10 @@ def main
profiler.report
rescue Racc::CompileError, Errno::ENOENT, Errno::EPERM => err
raise if $DEBUG
lineno = err.message.slice!(/\A\d+:/).to_s
message = err.message.dup # string may be frozen literal
lineno = message.slice!(/\A\d+:/).to_s
location = lineno.empty? ? bright("#{input}:") : bright("#{input}:#{lineno}")
$stderr.puts "#{red('Error: ')}#{location} #{err.message.strip}"
$stderr.puts "#{red('Error: ')}#{location} #{message.strip}"
exit 1
end
end
Expand Down
18 changes: 9 additions & 9 deletions lib/racc/color.rb
Expand Up @@ -23,43 +23,43 @@ def self.without_color
def bright(text)
return text unless Color.enabled?
text = text.gsub(/\e\[.*?m[^\e]*\e\[0m/, "\e[0m\\0\e[1m")
"\e[1m#{text}\e[0m"
String.new "\e[1m#{text}\e[0m"
end

def red(text)
return text unless Color.enabled?
"\e[31m#{text}\e[0m"
String.new "\e[31m#{text}\e[0m"
end

def green(text)
return text unless Color.enabled?
"\e[32m#{text}\e[0m"
String.new "\e[32m#{text}\e[0m"
end

def violet(text)
return text unless Color.enabled?
"\e[1;35m#{text}\e[0m"
String.new "\e[1;35m#{text}\e[0m"
end

# Syntax highlighting for various types of symbols...
def nonterminal(text)
return text unless Color.enabled?
"\e[1;34m#{text}\e[0m" # blue
String.new "\e[1;34m#{text}\e[0m" # blue
end

def terminal(text)
return text unless Color.enabled?
"\e[1;36m\e[4m#{text}\e[0m" # cyan, with underline
String.new "\e[1;36m\e[4m#{text}\e[0m" # cyan, with underline
end

def string(text)
return text unless Color.enabled?
"\e[1;33m#{text}\e[0m" # bright yellow
String.new "\e[1;33m#{text}\e[0m" # bright yellow
end

def explicit_prec(text)
return text unless Color.enabled?
"\e[1;31m#{text}\e[0m" # bright reddish orange
String.new "\e[1;31m#{text}\e[0m" # bright reddish orange
end
end
end
end
16 changes: 8 additions & 8 deletions lib/racc/grammar.rb
Expand Up @@ -298,7 +298,7 @@ def check_terminals
locations = undeclared.flat_map(&:locate).map(&:rule).uniq
raise CompileError, "terminal#{'s' unless undeclared.one?} " \
"#{Racc.to_sentence(undeclared)} #{undeclared.one? ? 'was' : 'were'} " \
"not declared in a 'token' block:\n" <<
"not declared in a 'token' block:\n" +
Source::SparseLines.render(locations.map(&:source))
end

Expand All @@ -308,15 +308,15 @@ def check_terminals
raise CompileError, "token#{'s' unless wrongly_declared.one?} " \
"#{Racc.to_sentence(wrongly_declared)} were declared in a 'token'" \
" block, but #{wrongly_declared.one? ? 'it also has' : 'they also have'}" \
" derivation rules:\n" << Source::SparseLines.render(bad_rules.map(&:source))
" derivation rules:\n" + Source::SparseLines.render(bad_rules.map(&:source))
end
end

bad_strings = @symbols.select { |s| s.string_symbol? && s.nonterminal? }
unless bad_strings.empty?
bad_rules = bad_strings.flat_map(&:heads).map(&:rule)
raise CompileError, 'you may not create derivation rules for a ' \
"string literal:\n" << Source::SparseLines.render(bad_rules.map(&:source))
"string literal:\n" + Source::SparseLines.render(bad_rules.map(&:source))
end

bad_prec = @symbols.select { |s| s.assoc && s.nonterminal? }
Expand All @@ -325,7 +325,7 @@ def check_terminals
raise CompileError, "token#{'s' unless bad_prec.one?} " \
"#{Racc.to_sentence(bad_prec)} appeared in a prechigh/preclow " \
"block, but #{bad_prec.one? ? 'it is not a' : 'they are not'} " \
"terminal#{'s' unless bad_prec.one?}:\n" <<
"terminal#{'s' unless bad_prec.one?}:\n" +
Source::SparseLines.render(bad_rules.map(&:source))
end

Expand All @@ -335,7 +335,7 @@ def check_terminals
unless bad_prec.empty?
raise CompileError, "The following rule#{'s' unless bad_prec.one?} " \
"use#{'s' if bad_prec.one?} nonterminals for explicit precedence, " \
"which is not allowed:\n" <<
"which is not allowed:\n" +
Source::SparseLines.render(bad_prec.map(&:source))
end
end
Expand All @@ -344,13 +344,13 @@ def check_rules
@rules.group_by(&:target).each_value do |same_lhs|
same_lhs.group_by { |r| r.symbols.reject(&:hidden?) }.each_value do |same_rhs|
next unless same_rhs.size > 1
raise CompileError, "The following rules are duplicates:\n" <<
raise CompileError, "The following rules are duplicates:\n" +
Source::SparseLines.render(same_rhs.map(&:source))
end
end

unless @error.heads.empty?
raise CompileError, "You cannot create rules for the error symbol:\n" <<
raise CompileError, "You cannot create rules for the error symbol:\n" +
Source::SparseLines.render(@error.heads.map { |ptr| ptr.rule.source} )
end
end
Expand Down Expand Up @@ -568,7 +568,7 @@ def following
end

def to_s
result = "#{@rule.target} : "
result = String.new "#{@rule.target} : "
if @index > 0
result << "#{preceding.reject(&:hidden?).map(&:to_s).join(' ')} ."
else
Expand Down
2 changes: 1 addition & 1 deletion lib/racc/source.rb
Expand Up @@ -31,7 +31,7 @@ def spiffy
highlights.sort_by!(&:from)

raw = text
cooked = ''
cooked = String.new
offset = 0

highlights.each do |hilite|
Expand Down
2 changes: 1 addition & 1 deletion lib/racc/state_transition_table.rb
Expand Up @@ -202,7 +202,7 @@ def add_entry(all, array, chkval, ptr_array)
end

def mkmapexp(arr)
map = ''
map = String.new
maxdup = RE_DUP_MAX

arr.chunk(&:nil?).each do |is_nil, items|
Expand Down
16 changes: 8 additions & 8 deletions lib/racc/warning.rb
Expand Up @@ -53,7 +53,7 @@ def initialize(type, title, details = nil)
end

def to_s
msg = violet('Warning: ') << bright(title)
msg = violet('Warning: ') + bright(title)
msg << "\n" << details if details
msg
end
Expand Down Expand Up @@ -104,7 +104,7 @@ def title
def details
"Its derivation rule#{'s all' unless @sym.heads.one?} contain" \
"#{'s' if @sym.heads.one?} #{'an ' if @sym.heads.one?}infinite loop" \
"#{'s' unless @sym.heads.one?}:\n" <<
"#{'s' unless @sym.heads.one?}:\n" +
@sym.heads.map { |ptr| ptr.rule.to_s }.join("\n")
end

Expand Down Expand Up @@ -175,7 +175,7 @@ def details

"When the next token is #{connective}#{Racc.to_sentence(tokens, 'or')}" \
", it is overridden by #{rules.one? ? 'this' : 'these'} " \
"higher-precedence rule#{'s' unless rules.one?}:\n" <<
"higher-precedence rule#{'s' unless rules.one?}:\n" +
Source::SparseLines.render(rules.map(&:source))
end.join("\n\n")
end
Expand All @@ -196,15 +196,15 @@ def initialize(conflict, grammar, verbose)
end

def title
"Shift/reduce conflict on #{@sym}," <<
"Shift/reduce conflict on #{@sym}," +
(@path.reject(&:hidden?).empty? ?
' at the beginning of the parse.' :
' after the following input:')
end

def details
if @path.reject(&:hidden?).empty?
result = ''
result = String.new
else
result = @path.reject(&:hidden?).map(&:to_s).join(' ') << "\n"
end
Expand Down Expand Up @@ -253,15 +253,15 @@ def initialize(conflict, grammar, verbose)
end

def title
"Reduce/reduce conflict on #{@sym}," <<
"Reduce/reduce conflict on #{@sym}," +
(@path.reject(&:hidden?).empty? ?
' at the beginning of the parse.' :
' after the following input:')
end

def details
if @path.reject(&:hidden?).empty?
result = ''
result = String.new
else
result = @path.reject(&:hidden?).map(&:to_s).join(' ') << "\n"
end
Expand Down Expand Up @@ -300,4 +300,4 @@ def type
end
end
end
end
end
10 changes: 10 additions & 0 deletions test/run_tests.sh
@@ -1,4 +1,14 @@
#!/usr/bin/env bash

set -eux

test_frozen_strings=$(ruby -e 'puts (RUBY_ENGINE == "ruby" && RUBY_VERSION > "2.4")')

if [[ $test_frozen_strings == "true" ]] ; then
echo "NOTE: enabling frozen string literals"
rvm install rubygems 2.6.12 --force # because of an issue in rubygems 2.7 with ruby 2.5 and frozen string literals
export RUBYOPT="--enable-frozen-string-literal --debug=frozen-string-literal"
fi

bundle exec rake test
bundle exec rake test_pure
4 changes: 2 additions & 2 deletions test/test_scanner.rb
Expand Up @@ -9,11 +9,11 @@ class TestScanner < TestCase
define_method("test_scan_#{File.basename(testfile)}".to_sym) do
original = File.read(testfile)
# wrap the Ruby source code in an action block
wrapped = "class Test\nrule\na : '*' {" << original << "\n}"
wrapped = "class Test\nrule\na : '*' {" + original + "\n}"
file = Source::Buffer.new(testfile, wrapped)
scanner = Racc::GrammarFileScanner.new(file)

rebuilt = ''
rebuilt = String.new
scanner.yylex do |token|
break if token.nil?
rebuilt << token[1][0].text if token[0] == :ACTION
Expand Down

0 comments on commit c92678b

Please sign in to comment.