Skip to content

Instantly share code, notes, and snippets.

View gosukiwi's full-sized avatar

Federico Ramirez gosukiwi

View GitHub Profile
Start := "ab" A
| "aba"
A := "a"
Foo := Foo "ab"
| "ab"
def my_rule
if my_rule # infinite loop here
do something
else
do something else
end
end
Assign := Identifier EQUALS Number
Identifier := WORD
Number := NUMBER
Assign := Identifier EQUALS Number
:= WORD EQUALS NUMBER
:= foo EQUALS NUMBER # foo is a valid workd token, we can replace it
:= foo = NUMBER # = is a valid equals token
:= foo = 1 # 1 is a valid number token
[PARAGRAPH]
|
v
+-------[SENTENCES]-----------+
| | |
v v v
[TEXT="hello "] [BOLD="world"] [TEXT="."]
Parser.new.parse("__Foo__ and *bar*.\n\nAnother paragraph.")
=> #<BodyNode:0x007fc774abe008
    @consumed=14,
    @paragraphs=
    [#<ParagraphNode:0x007fc774eb25d8
      @consumed=12,
      @sentences=
        [#<Node:0x007fc774ea8150 @consumed=5, @type="BOLD", @value="Foo">,
        #<Node:0x007fc774ac5f60 @consumed=1, @type="TEXT", @value=" and ">,
        #<Node:0x007fc774ac6758 @consumed=3, @type="EMPHASIS", @value="bar">,
class Parser
def parse(tokens)
body = body_parser.match(tokens)
raise "Syntax error: #{tokens[body.consumed]}" unless tokens.count == body.consumed
body
end
private
def body_parser
class BodyParser < BaseParser
include MatchesStar
def match(tokens)
nodes, consumed = match_star tokens, with: paragraph_parser
return Node.null if nodes.empty?
BodyNode.new(paragraphs: nodes, consumed: consumed)
end
end
class SentencesAndNewlineParser < BaseParser
include MatchesStar
def match(tokens)
nodes, consumed = match_star tokens, with: sentence_parser
return Node.null if nodes.empty?
return Node.null unless tokens.peek_at(consumed, 'NEWLINE', 'NEWLINE')
consumed += 2 # consume newlines
ParagraphNode.new(sentences: nodes, consumed: consumed)