Permalink
Browse files

+ start of a documentation love project

  • Loading branch information...
1 parent c9f6758 commit 2da5063c8b420cfdca3ebbd99f5f7dd7d7a5d5c3 @kschiess committed May 16, 2012
Showing with 126 additions and 69 deletions.
  1. +32 −20 README
  2. +56 −49 lib/parslet.rb
  3. +38 −0 readme.rb
View
@@ -18,26 +18,38 @@ SYNOPSIS
require 'parslet'
include Parslet
- # Constructs a parser using a Parser Expression Grammar like DSL:
- parser = str('"') >>
- (
- str('\\') >> any |
- str('"').absnt? >> any
- ).repeat.as(:string) >>
- str('"')
-
- # Parse the string and capture parts of the interpretation (:string above)
- tree = parser.parse('"This is a \\"String\\" in which you can escape stuff"')
-
- tree # => {:string=>"This is a \\\"String\\\" in which you can escape stuff"}
-
- # Here's how you can grab results from that tree:
-
- transform = Parslet::Transform.new do
- rule(:string => simple(:x)) {
- puts "String contents: #{x}" }
+ # parslet parses strings
+ str('foo').
+ parse('foo') # => "foo"@0
+
+ # it matches character sets
+ match['abc'].parse('a') # => "a"@0
+ match['abc'].parse('b') # => "b"@0
+ match['abc'].parse('c') # => "c"@0
+
+ # and it annotates its output
+ str('foo').as(:important_bit).
+ parse('foo') # => {:important_bit=>"foo"@0}
+
+ # you can construct parsers with just a few lines
+ quote = str('"')
+ simple_string = quote >> (quote.absent? >> any).repeat >> quote
+
+ simple_string.
+ parse('"Simple Simple Simple"') # => "\"Simple Simple Simple\""@0
+
+ # or by making a fuss about it
+ class Smalltalk < Parslet::Parser
+ root :smalltalk
+
+ rule(:smalltalk) { statements }
+ rule(:statements) {
+ # insert smalltalk parser here (outside of the scope of this readme)
+ }
end
- transform.apply(tree)
+
+ # and then
+ Smalltalk.new.parse('smalltalk')
COMPATIBILITY
@@ -53,6 +65,6 @@ ruby-1.8.7-p334 for better results.
STATUS
-At version 1.3.0 - See HISTORY.txt for changes.
+At version 1.4.0 - See HISTORY.txt for changes.
(c) 2010 Kaspar Schiess
View
@@ -22,7 +22,7 @@
# * Parsing the input string; this yields an intermediary tree, see
# Parslet.any, Parslet.match, Parslet.str, Parslet::ClassMethods#rule and
# Parslet::ClassMethods#root.
-# * Transformation of the tree into something useful to you, see
+# * Transformat ion of the tree into something useful to you, see
# Parslet::Transform, Parslet.simple, Parslet.sequence and Parslet.subtree.
#
# The first stage is traditionally intermingled with the second stage; output
@@ -34,41 +34,40 @@
#
# == Further reading
#
-# All parslet atoms are subclasses of Parslet::Atoms::Base. You might want to
-# look at all of those: Parslet::Atoms::Re, Parslet::Atoms::Str,
-# Parslet::Atoms::Repetition, Parslet::Atoms::Sequence,
-# Parslet::Atoms::Alternative.
+# All parslet atoms are subclasses of {Parslet::Atoms::Base}. You might want to
+# look at all of those: {Parslet::Atoms::Re}, {Parslet::Atoms::Str},
+# {Parslet::Atoms::Repetition}, {Parslet::Atoms::Sequence},
+# {Parslet::Atoms::Alternative}.
#
# == When things go wrong
#
-# A parse that fails will raise Parslet::ParseFailed. A detailed explanation
-# of what went wrong can be obtained from the parslet involved or the root of
-# the parser instance.
+# A parse that fails will raise {Parslet::ParseFailed}. This exception contains
+# all the details of what went wrong, including a detailed error trace that
+# can be printed out as an ascii tree. ({Parslet::Cause})
#
module Parslet
+ # Extends classes that include Parslet with the module
+ # {Parslet::ClassMethods}.
+ #
def self.included(base) # :nodoc:
base.extend(ClassMethods)
end
- # Raised when the parse failed to match or to consume all its input. It
- # contains the message that should be presented to the user. If you want to
- # display more error explanation, you can print the #error_tree that is
- # stored in the parslet. This is a graphical representation of what went
- # wrong.
- #
- # Example:
- #
+ # Raised when the parse failed to match. It contains the message that should
+ # be presented to the user. More details can be extracted from the
+ # exceptions #cause member: It contains an instance of {Parslet::Cause} that
+ # stores all the details of your failed parse in a tree structure.
+ #
# begin
# parslet.parse(str)
# rescue Parslet::ParseFailed => failure
- # puts parslet.error_tree
+ # puts failure.cause.ascii_tree
# end
#
- # Alternatively, you can just require 'parslet/convenience' and call
- # the method #parse_with_debug instead of #parse. This method will never
- # raise and print error trees to stdout.
+ # Alternatively, you can just require 'parslet/convenience' and call the
+ # method #parse_with_debug instead of #parse. This method will never raise
+ # and print error trees to stdout.
#
- # Example:
# require 'parslet/convenience'
# parslet.parse_with_debug(str)
#
@@ -77,7 +76,11 @@ def initialize(message, cause=nil)
super(message)
@cause = cause
end
- attr_reader :cause
+
+ # Why the parse failed.
+ #
+ # @return [Parslet::Cause]
+ attr_reader :cause
end
# Raised when the parse operation didn't consume all of its input. In this
@@ -92,14 +95,12 @@ module ClassMethods
# 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.
- #
- # Example:
- #
+ #
# class MyParser
# include Parslet
#
- # rule :bar { str('bar') }
- # rule :twobar do
+ # rule(:bar) { str('bar') }
+ # rule(:twobar) do
# bar >> bar
# end
#
@@ -123,7 +124,8 @@ def rule(name, &definition)
# Allows for delayed construction of #match. See also Parslet.match.
#
- class DelayedMatchConstructor # :nodoc:
+ # @api private
+ class DelayedMatchConstructor
def [](str)
Atoms::Re.new("[" + str + "]")
end
@@ -132,8 +134,6 @@ def [](str)
# Returns an atom matching a character class. All regular expressions can be
# used, as long as they match only a single character at a time.
#
- # Example:
- #
# match('[ab]') # will match either 'a' or 'b'
# match('[\n\s]') # will match newlines and spaces
#
@@ -142,19 +142,24 @@ def [](str)
# match['a-z'] # synonymous to match('[a-z]')
# match['\n'] # synonymous to match('[\n]')
#
+ # @overload match(str)
+ # @param str [String] character class to match (regexp syntax)
+ # @return [Parslet::Atoms::Re] a parslet atom
+ #
def match(str=nil)
return DelayedMatchConstructor.new unless str
return Atoms::Re.new(str)
end
module_function :match
- # Returns an atom matching the +str+ given.
- #
- # Example:
+ # Returns an atom matching the +str+ given:
#
# str('class') # will match 'class'
#
+ # @param str [String] string to match verbatim
+ # @return [Parslet::Atoms::Str] a parslet atom
+ #
def str(str)
Atoms::Str.new(str)
end
@@ -163,10 +168,10 @@ def str(str)
# Returns an atom matching any character. It acts like the '.' (dot)
# character in regular expressions.
#
- # Example:
- #
# any.parse('a') # => 'a'
#
+ # @return [Parslet::Atoms::Re] a parslet atom
+ #
def any
Atoms::Re.new('.')
end
@@ -175,39 +180,43 @@ def any
# A special kind of atom that allows embedding whole treetop expressions
# into parslet construction.
#
- # Example:
+ # # the same as str('a') >> str('b').maybe
+ # exp(%Q("a" "b"?))
#
- # exp(%Q("a" "b"?)) # => returns the same as str('a') >> str('b').maybe
+ # @param str [String] a treetop expression
+ # @return [Parslet::Atoms::Base] the corresponding parslet parser
#
- def exp(str) # :nodoc:
+ def exp(str)
Parslet::Expression.new(str).to_parslet
end
module_function :exp
- # Returns a placeholder for a tree transformation that will only match a
- # sequence of elements. The +symbol+ you specify will be the key for the
+ # Returns a placeholder for a tree transformation that will only match a
+ # sequence of elements. The +symbol+ you specify will be the key for the
# matched sequence in the returned dictionary.
#
- # Example:
- #
# # This would match a body element that contains several declarations.
# { :body => sequence(:declarations) }
#
- # The above example would match :body => ['a', 'b'], but not :body => 'a'.
+ # The above example would match <code>:body => ['a', 'b']</code>, but not
+ # <code>:body => 'a'</code>.
+ #
+ # see {Parslet::Transform}
#
def sequence(symbol)
Pattern::SequenceBind.new(symbol)
end
module_function :sequence
- # Returns a placeholder for a tree transformation that will only match
- # simple elements. This matches everything that #sequence doesn't match.
- #
- # Example:
+ # Returns a placeholder for a tree transformation that will only match
+ # simple elements. This matches everything that <code>#sequence</code>
+ # doesn't match.
#
# # Matches a single header.
# { :header => simple(:header) }
#
+ # see {Parslet::Transform}
+ #
def simple(symbol)
Pattern::SimpleBind.new(symbol)
end
@@ -216,8 +225,6 @@ def simple(symbol)
# Returns a placeholder for tree transformation patterns that will match
# any kind of subtree.
#
- # Example:
- #
# { :expression => subtree(:exp) }
#
def subtree(symbol)
View
@@ -0,0 +1,38 @@
+require 'parslet'
+include Parslet
+
+# parslet parses strings
+str('foo').
+ parse('foo') # => "foo"@0
+
+# it matches character sets
+match['abc'].parse('a') # => "a"@0
+match['abc'].parse('b') # => "b"@0
+match['abc'].parse('c') # => "c"@0
+
+# and it annotates its output
+str('foo').as(:important_bit).
+ parse('foo') # => {:important_bit=>"foo"@0}
+
+# you can construct parsers with just a few lines
+quote = str('"')
+simple_string = quote >> (quote.absent? >> any).repeat >> quote
+
+simple_string.
+ parse('"Simple Simple Simple"') # => "\"Simple Simple Simple\""@0
+
+# or by making a fuss about it
+class Smalltalk < Parslet::Parser
+ root :smalltalk
+
+ rule(:smalltalk) { statements }
+ rule(:statements) {
+ # insert smalltalk parser here (outside of the scope of this readme)
+ }
+end
+
+# and then
+Smalltalk.new.parse('smalltalk')
+
+# be sure to read our 'Get started' tutorial at
+# http://kschiess.github.com/parslet/get-started.html

0 comments on commit 2da5063

Please sign in to comment.