aboutsummaryrefslogtreecommitdiff
path: root/src/parcom.cr
diff options
context:
space:
mode:
Diffstat (limited to 'src/parcom.cr')
-rw-r--r--src/parcom.cr63
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