Skip to content
Permalink
Browse files

Implement conjunctive grammars

  • Loading branch information...
judofyr committed Jun 6, 2019
1 parent f723705 commit 8995bbecbe6d3827c792bb1623264b8ec9216601
Showing with 88 additions and 0 deletions.
  1. +1 −0 README.adoc
  2. +17 −0 lib/glush/parser.rb
  3. +42 −0 lib/glush/patterns.rb
  4. +28 −0 test/test_parser.rb
@@ -7,6 +7,7 @@ Glush is a versatile parser toolkit based on Glushkov's construction algorithm:
- Scannerless: Works directly on characters (no lexer needed).
- Streamable, push-based API: You give it one token at a time; fail-fast supported.
- Supports matching UTF-8 characters.
- Supports conjunctive grammars.
- Flexible operator precedence.
- Usable as a parser combinator library in Ruby.
- Licensed under link:LICENSE.md[0BSD].
@@ -80,6 +80,7 @@ def <<(token)

@next_states = []
@followed_states = Set.new
@completed_conj = Hash.new { |h, k| h[k] = {} }
@final_states = []
@states.each do |state|
follow(state, token)
@@ -140,6 +141,22 @@ def follow(state, token)
end
when :success
@final_states << state
when Patterns::Conj::Finalizer
finalizer = state.terminal
conj = finalizer.id
key = [conj, state.rule_offset]
data = @completed_conj[key]

if finalizer.type == :left
data[:left] = true
data[:context] = state.context
else
data[:right] = true
end

if data[:left] && data[:right]
follow_transitions(conj, state.rule_offset, data[:context], token)
end
else
context = state.context
if state.terminal.is_a?(Patterns::Marker)
@@ -25,6 +25,10 @@ def |(other)
Alt.new(self, other)
end

def &(other)
Conj.new(self, other)
end

def plus
Plus.new(self)
end
@@ -327,6 +331,44 @@ def each_pair(&blk)
end
end

class Conj < Base
Finalizer = Struct.new(:id, :type)

def initialize(left, right)
@left = left.consume!
@right = right.consume!
end

def calculate_empty(b)
@is_empty = @left.calculate_empty(b) & @right.calculate_empty(b)
end

def static?
@left.static? && @right.static?
end

def first_set
@first_set ||= @left.first_set | @right.first_set
end

def last_set
@last_set ||= Set[self]
end

def each_pair(&blk)
@left.each_pair(&blk)
@right.each_pair(&blk)

@left.last_set.each do |lst|
yield lst, Finalizer.new(self, :left)
end

@right.last_set.each do |lst|
yield lst, Finalizer.new(self, :right)
end
end
end

class Plus < Base
def initialize(child)
@child = child.consume!
@@ -234,5 +234,33 @@ def main
[:n, 4],
]
end

describe("conj") {
let(:grammar) {
Glush::Grammar.new {
rule \
def s
(str("a").plus >> b) &
(a >> str("c").plus)
end

rule \
def a
str("a") >> a.maybe >> str("b")
end

rule \
def b
str("b") >> b.maybe >> str("c")
end

s
}
}

assert_recognize "abc"
assert_recognize "aabbcc"
refute_recognize "aabbc"
}
end

0 comments on commit 8995bbe

Please sign in to comment.
You can’t perform that action at this time.