Skip to content

Commit

Permalink
+ Parslet::Parser is now also a parslet atom
Browse files Browse the repository at this point in the history
This allows reuse of grammars in other grammars as if they were simple
grammar atoms
  • Loading branch information
kschiess committed Feb 21, 2011
1 parent 8d37204 commit 1080d75
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 43 deletions.
9 changes: 9 additions & 0 deletions HISTORY.txt
@@ -1,3 +1,12 @@
= 1.2.0 / ???

+ Parslet::Parser is now also a grammar atom, it can be composed freely with
other atoms. (str('f') >> MiniLispParser.new >> str('b'))

+ No strings, only slices are returned as part of the parser result.
Parslet::Slice is almost a string class, but one that remembers the
source offset. This has also bought us a slight speedup.

= 1.1.1 / 4Feb2011

! FIX: Line counting was broken by performance optimisations.
Expand Down
28 changes: 0 additions & 28 deletions lib/parslet.rb
Expand Up @@ -68,34 +68,6 @@ class ParseFailed < StandardError
end

module ClassMethods
# Define the parsers #root function. This is the place where you start
# parsing; if you have a rule for 'file' that describes what should be
# in a file, this would be your root declaration:
#
# class Parser
# root :file
# rule(:file) { ... }
# end
#
# #root declares a 'parse' function that works just like the parse
# function that you can call on a simple parslet, taking a string as input
# and producing parse output.
#
# In a way, #root is a shorthand for:
#
# def parse(str)
# your_parser_root.parse(str)
# end
#
def root(name)
define_method(:root) do
self.send(name)
end
define_method(:parse) do |str|
root.parse(str)
end
end

# Define an entity for the parser. This generates a method of the same
# name that can be used as part of other patterns. Those methods can be
# freely mixed in your parser class with real ruby methods.
Expand Down
2 changes: 1 addition & 1 deletion lib/parslet/atoms/visitor.rb
Expand Up @@ -5,7 +5,7 @@
module Parslet::Atoms
class Base
def accept(visitor)
raise NotImplementedError, "No visit method on #{self.class.name}."
raise NotImplementedError, "No #accept method on #{self.class.name}."
end
end

Expand Down
37 changes: 36 additions & 1 deletion lib/parslet/parser.rb
Expand Up @@ -12,6 +12,41 @@
# pp MyParser.new.parse('bbbb') # => Parslet::Atoms::ParseFailed:
# # Don't know what to do with bbbb at line 1 char 1.
#
class Parslet::Parser
class Parslet::Parser < Parslet::Atoms::Base
include Parslet

class <<self # class methods
# Define the parsers #root function. This is the place where you start
# parsing; if you have a rule for 'file' that describes what should be
# in a file, this would be your root declaration:
#
# class Parser
# root :file
# rule(:file) { ... }
# end
#
# #root declares a 'parse' function that works just like the parse
# function that you can call on a simple parslet, taking a string as input
# and producing parse output.
#
# In a way, #root is a shorthand for:
#
# def parse(str)
# your_parser_root.parse(str)
# end
#
def root(name)
define_method(:root) do
self.send(name)
end
end
end

def try(source, context) # :nodoc:
root.try(source, context)
end

def to_s_inner(prec) # :nodoc:
root.to_s(prec)
end
end
2 changes: 1 addition & 1 deletion parslet.gemspec
Expand Up @@ -2,7 +2,7 @@

Gem::Specification.new do |s|
s.name = 'parslet'
s.version = '1.1.1'
s.version = '1.2.0'

s.required_rubygems_version = Gem::Requirement.new('>= 0') if s.respond_to? :required_rubygems_version=
s.authors = ['Kaspar Schiess']
Expand Down
19 changes: 19 additions & 0 deletions spec/parslet/parser_spec.rb
@@ -1,12 +1,31 @@
require 'spec_helper'

describe Parslet::Parser do
include Parslet
class FooParser < Parslet::Parser
rule(:foo) { str('foo') }
root(:foo)
end

describe "<- .root" do
parser = Class.new(Parslet::Parser)
parser.root :root_parslet

it "should have defined a 'root' method, returning the root" do
parser_instance = parser.new
flexmock(parser_instance).should_receive(:root_parslet => :answer)

parser_instance.root.should == :answer
end
end
it "should parse 'foo'" do
FooParser.new.parse('foo').should == 'foo'
end
context "composition" do
let(:parser) { FooParser.new }
it "should allow concatenation" do
composite = parser >> str('bar')
composite.should parse('foobar')
end
end
end
12 changes: 0 additions & 12 deletions spec/parslet/parslet_spec.rb
Expand Up @@ -12,18 +12,6 @@
end
end
end
describe "<- .root" do
let(:root_parslet) { flexmock() }
root :root_parslet

it "should have defined a 'parse' method in the current context" do
root_parslet.should_receive(:parse).with('snaf').once
parse('snaf')
end
it "should have defined a 'root' method, returning the root" do
root.should == root_parslet
end
end
describe "<- .rule" do
# Rules define methods. This can be easily tested by defining them right
# here.
Expand Down

0 comments on commit 1080d75

Please sign in to comment.