Skip to content

Commit

Permalink
Renamed concatenated_list to sequence, and separated_list to delimite…
Browse files Browse the repository at this point in the history
…d_sequence
  • Loading branch information
glv committed Mar 14, 2010
1 parent 78aa36d commit 523ea93
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 65 deletions.
5 changes: 0 additions & 5 deletions README.md
Expand Up @@ -104,11 +104,6 @@ this design before committing to it for the long term.
(and debug) the algorithm.
* Reusable example groups for lexers and lexer tokens.
* Refactor scoping.
* Pull most of the grammar definition methods out of the JS
parser and put them where they can be reused (and write tests
for them).
* Separate grammar definition (including symbol table management)
from actual parsing.
* Investigate separating parsing from tree building.
* Figure out a good way to unit-test prefix, infix, and stmt methods.
* Address all the TODO and ??? comments
Expand Down
20 changes: 10 additions & 10 deletions lib/radish/parser.rb
Expand Up @@ -56,25 +56,25 @@ def expression(rbp=0)
extend_with_infixes(rbp, start_expression)
end

def concatenated_list(terminator)
def sequence(boundary)
result = []
until looking_at?(terminator)
until looking_at?(boundary)
result << yield
end
advance_if_looking_at! terminator
advance_if_looking_at! boundary
result
end

def separated_list(separator, terminator, options={})
def delimited_sequence(delimiter, boundary, options={})
result = []
unless looking_at?(terminator)
unless looking_at?(boundary)
loop do
result << yield
advance_if_looking_at separator or break
break if options[:allow_extra] && looking_at?(terminator)
advance_if_looking_at delimiter or break
break if options[:allow_extra] && looking_at?(boundary)
end
end
advance_if_looking_at! terminator
advance_if_looking_at! boundary
result
end

Expand Down Expand Up @@ -136,8 +136,8 @@ def expression_statement(terminator=nil)
end
end

def statements(terminator)
concatenated_list(terminator) do
def statements(boundary)
sequence(boundary) do
statement
end
end
Expand Down
2 changes: 1 addition & 1 deletion radish.gemspec
Expand Up @@ -9,7 +9,7 @@ Gem::Specification.new do |s|

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Glenn Vanderburg"]
s.date = %q{2010-03-13}
s.date = %q{2010-03-14}
s.description = %q{A library for building parsers using top-down operator precedence}
s.email = %q{glv@vanderburg.org}
s.extra_rdoc_files = [
Expand Down
10 changes: 5 additions & 5 deletions samples/simplified_javascript/javascript_parser.rb
Expand Up @@ -79,11 +79,11 @@ def module_for_token(token)
end

prefix :'[' do
[:array] + separated_list(:',', :']') { expression(0) }
[:array] + delimited_sequence(:',', :']') { expression(0) }
end

prefix :'{' do
keyvals = separated_list(:',', :'}') do
keyvals = delimited_sequence(:',', :'}') do
key = take_token
raise key, "Bad property name" unless [:string, :number, :name].include?(key.type)
advance_if_looking_at! :':'
Expand All @@ -105,7 +105,7 @@ def module_for_token(token)
new_scope

advance_if_looking_at! :'('
args = separated_list(:',', :')') do
args = delimited_sequence(:',', :')') do
raise next_token, "Expected a parameter name" unless looking_at? :name
param = take_token
scope.define(param)
Expand Down Expand Up @@ -169,7 +169,7 @@ def module_for_token(token)
infix :'(', 80 do |left|
# TODO: raise a ParseError here, rather than a StandardError
raise "Expected a function" unless CALLABLE_TYPES.include?(left.first)
[:call, left, separated_list(:',', :')'){ expression(0) }]
[:call, left, delimited_sequence(:',', :')'){ expression(0) }]
end

# -------------------------------------------------------------- statements
Expand All @@ -181,7 +181,7 @@ def module_for_token(token)
end

stmt :var do
decls = separated_list(:',', :';') do
decls = delimited_sequence(:',', :';') do
raise next_token, "Expected a new variable name" unless looking_at?(:name)
varname = take_token
scope.define varname
Expand Down
88 changes: 44 additions & 44 deletions spec/radish/parser_spec.rb
Expand Up @@ -82,87 +82,87 @@ class MockGrammar < Radish::Grammar; end
end
end

describe "#concatenated_list" do
it "returns an empty array if the next token is the terminator" do
mock(subject).looking_at?(:term){true}
describe "#sequence" do
it "returns an empty array if the next token is the boundary" do
mock(subject).looking_at?(:boundary){true}
stub(subject).advance_if_looking_at!
subject.concatenated_list(:term).should == []
subject.sequence(:boundary).should == []
end

it "yields until the next token is the terminator" do
it "yields until the next token is the boundary" do
mock(subject) do |expect|
expect.looking_at?(:term){false}.times(2).ordered
expect.looking_at?(:term){true}.ordered
expect.looking_at?(:boundary){false}.times(2).ordered
expect.looking_at?(:boundary){true}.ordered
end
stub(subject).advance_if_looking_at!
subject.concatenated_list(:term){}
subject.sequence(:boundary){}
end

it "returns the results of the yields" do
mock(subject) do |expect|
expect.looking_at?(:term){false}.times(2).ordered
expect.looking_at?(:term){true}.ordered
expect.looking_at?(:boundary){false}.times(2).ordered
expect.looking_at?(:boundary){true}.ordered
end
stub(subject).advance_if_looking_at!
yield_vals = [:foo, :bar]
subject.concatenated_list(:term){yield_vals.pop}.should == [:bar, :foo]
subject.sequence(:boundary){yield_vals.pop}.should == [:bar, :foo]
end

it "advances over the terminator before returning" do
it "advances over the boundary before returning" do
mock(subject) do |expect|
expect.looking_at?(:term){true}
expect.advance_if_looking_at!(:term){true}
expect.looking_at?(:boundary){true}
expect.advance_if_looking_at!(:boundary){true}
end
subject.concatenated_list(:term)
subject.sequence(:boundary)
end
end

describe "#separated_list" do
it "returns an empty array if the next token is the terminator" do
mock(subject).looking_at?(:term){true}
describe "#delimited_sequence" do
it "returns an empty array if the next token is the boundary" do
mock(subject).looking_at?(:boundary){true}
stub(subject).advance_if_looking_at!
subject.separated_list(:sep, :term).should == []
subject.delimited_sequence(:delimiter, :boundary).should == []
end

it "yields until the next token is not the separator if :allow_extra is false" do
it "yields until the next token is not the delimiter if :allow_extra is false" do
mock(subject) do |expect|
expect.looking_at?(:term){false}.ordered
expect.advance_if_looking_at(:sep){true}.times(2).ordered
expect.advance_if_looking_at(:sep){false}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.advance_if_looking_at(:delimiter){true}.times(2).ordered
expect.advance_if_looking_at(:delimiter){false}.ordered
end
stub(subject).advance_if_looking_at!
subject.separated_list(:sep, :term){}
subject.delimited_sequence(:delimiter, :boundary){}
end

it "yields and skips the separator until looking at terminator if :allow_extra" do
it "yields and skips the delimiter until looking at boundary if :allow_extra" do
mock(subject) do |expect|
expect.looking_at?(:term){false}.ordered
expect.advance_if_looking_at(:sep){true}.ordered
expect.looking_at?(:term){false}.ordered
expect.advance_if_looking_at(:sep){true}.ordered
expect.looking_at?(:term){true}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.advance_if_looking_at(:delimiter){true}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.advance_if_looking_at(:delimiter){true}.ordered
expect.looking_at?(:boundary){true}.ordered
end
stub(subject).advance_if_looking_at!
subject.separated_list(:sep, :term, :allow_extra => true){}
subject.delimited_sequence(:delimiter, :boundary, :allow_extra => true){}
end

it "returns the results of the yields" do
mock(subject) do |expect|
expect.looking_at?(:term){false}.ordered
expect.advance_if_looking_at(:sep){true}.ordered
expect.advance_if_looking_at(:sep){false}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.advance_if_looking_at(:delimiter){true}.ordered
expect.advance_if_looking_at(:delimiter){false}.ordered
end
stub(subject).advance_if_looking_at!
yield_vals = [:foo, :bar]
subject.separated_list(:sep, :term){yield_vals.pop}.should == [:bar, :foo]
subject.delimited_sequence(:delimiter, :boundary){yield_vals.pop}.should == [:bar, :foo]
end

it "advances over the terminator before returning" do
it "advances over the boundary before returning" do
mock(subject) do |expect|
expect.looking_at?(:term){true}
expect.advance_if_looking_at!(:term){true}
expect.looking_at?(:boundary){true}
expect.advance_if_looking_at!(:boundary){true}
end
subject.separated_list(:sep, :term)
subject.delimited_sequence(:delimiter, :boundary)
end

end
Expand Down Expand Up @@ -387,17 +387,17 @@ class MockGrammar < Radish::Grammar; end
end

describe "#statements" do
it "parses a list statements, up to a terminator" do
it "parses a sequence of statements, up to a boundary" do
yield_vals = [:stmt1, :stmt2]
mock(subject) do |expect|
expect.looking_at?(:term){false}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.statement{yield_vals.shift}.ordered
expect.looking_at?(:term){false}.ordered
expect.looking_at?(:boundary){false}.ordered
expect.statement{yield_vals.shift}.ordered
expect.looking_at?(:term){true}.ordered
expect.looking_at?(:boundary){true}.ordered
end
stub(subject).advance_if_looking_at!
subject.statements(:term).should == [:stmt1, :stmt2]
subject.statements(:boundary).should == [:stmt1, :stmt2]
end
end

Expand Down

0 comments on commit 523ea93

Please sign in to comment.