diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/parcom.cr | 63 |
1 files changed, 51 insertions, 12 deletions
diff --git a/src/parcom.cr b/src/parcom.cr index 8835778..ef1aa2a 100644 --- a/src/parcom.cr +++ b/src/parcom.cr @@ -4,17 +4,56 @@ module Parcom class ParserException < Exception end + struct TokenStream(T) + getter tokens + + def self.from_string(s : String) : TokenStream(Char) + TokenStream.new(s.chars) + end + + def initialize(ts : Iterable(T)) + if ts.responds_to?(:to_a) + @tokens = ts.to_a + else + @tokens = [] of T + ts.each { |t| @tokens << t } + end + end + + def [](index : Int) : T + @tokens[index] + end + + def [](start : Int, count : Int) : TokenStream(T) + TokenStream.new(@tokens[start, count]) + end + + def [](range : Range) : TokenStream(T) + TokenStream.new(@tokens[range]) + end + + def []?(*args) + self.[](*args) + rescue IndexError + nil + end + + def empty? : Bool + @tokens.empty? + end + end + struct Result(T, V) getter tokens, value - def initialize(@tokens : Array(T), @value : V) + def initialize(@tokens : TokenStream(T), @value : V) end end abstract class Parser(T, V) - abstract def parse(tokens : Array(T)) : Result(T, V) + abstract def parse(tokens : TokenStream(T)) : Result(T, V) - def parse?(tokens : Array(T)) : Result(T, V)? + def parse?(tokens : TokenStream(T)) : Result(T, V)? self.parse(tokens) rescue return nil @@ -29,7 +68,7 @@ module Parcom end # TODO: Find a way to annotate this method's type - def map(f) + def map(f : V -> U) : Map(T, V, U) forall U Map.new(self, f) end end @@ -41,7 +80,7 @@ module Parcom end class AnyToken(T) < Parser(T, T) - def parse(tokens : Array(T)) : Result(T, T) + def parse(tokens : TokenStream(T)) : Result(T, T) if tokens.empty? raise ParserException.new("AnyToken: input was empty") else @@ -51,7 +90,7 @@ module Parcom end class Eof(T) < Parser(T, Nil) - def parse(tokens : Array(T)) : Result(T, Nil) + def parse(tokens : TokenStream(T)) : Result(T, Nil) if tokens.empty? Result.new(tokens, nil) else @@ -64,7 +103,7 @@ module Parcom def initialize(@p : Parser(T, V)) end - def parse(tokens : Array(T)) : Result(T, V) + def parse(tokens : TokenStream(T)) : Result(T, V) result = @p.parse(tokens) Result.new(tokens, result.value) end @@ -74,7 +113,7 @@ module Parcom def initialize(@p : Parser(T, V), @f : V -> Bool) end - def parse(tokens : Array(T)) : Result(T, V) + def parse(tokens : TokenStream(T)) : Result(T, V) result = @p.parse(tokens) unless @f.call(result.value) @@ -89,7 +128,7 @@ module Parcom def initialize(@f : T -> Bool) end - def parse(tokens : Array(T)) : Result(T, T) + def parse(tokens : TokenStream(T)) : Result(T, T) AnyToken(T).new.assert(@f).parse(tokens) end end @@ -98,7 +137,7 @@ module Parcom def initialize(@expected : T) end - def parse(tokens : Array(T)) : Result(T, T) + def parse(tokens : TokenStream(T)) : Result(T, T) Satisfy(T).new(->(x : T) { x == @expected }).parse(tokens) end end @@ -107,7 +146,7 @@ module Parcom def initialize(@p1 : Parser(T, V), @p2 : Parser(T, V)) end - def parse(tokens : Array(T)) : Result(T, V) + def parse(tokens : TokenStream(T)) : Result(T, V) @p1.parse(tokens) rescue ParserException @p2.parse(tokens) @@ -118,7 +157,7 @@ module Parcom def initialize(@p : Parser(T, V), @f : V -> U) end - def parse(tokens : Array(T)) : Result(T, U) + def parse(tokens : TokenStream(T)) : Result(T, U) result = @p.parse(tokens) Result.new(result.tokens, @f.call(result.value)) end |
