diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-16 20:36:03 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-16 20:36:03 +1300 |
| commit | b274828831fec26cd8b3089ffef14cb96ce2de2f (patch) | |
| tree | ff5927b85a59b4d85c9e4aa269a475a7a37a54a0 /src/__OLD_parcom.cr | |
| parent | 77c370d27be174e0b036b33d1469e84e67a7153a (diff) | |
Second rewrite attempt, this one should work, monkaS
Diffstat (limited to 'src/__OLD_parcom.cr')
| -rw-r--r-- | src/__OLD_parcom.cr | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/__OLD_parcom.cr b/src/__OLD_parcom.cr new file mode 100644 index 0000000..ddb2e50 --- /dev/null +++ b/src/__OLD_parcom.cr @@ -0,0 +1,84 @@ +require "./parcom/*" + +module Parcom + VERSION = "0.1.0" + + # A ParserFail exception should be raised by `Parser#parse` when + # a parse attempt is unsuccessful. + # Raising this exception in the `#parse` method of a Parser "Foo" + # usually follows this pattern to allow for error tracing: + # + # ``` + # class Foo(T, V) < Parser(T, V) + # def parse(tokens : Tokens(T)) : Result(T, V) + # helper.parse(tokens) + # rescue ex : ParserFail + # raise ParserFail.new("Foo: #{ex.message}") + # end + # ``` + class ParserFail < Exception + end + + # `Tokens` is an `Array` wrapper struct to store the input + # stream of one or more `Parser` objects. + # A `Tokens` can be created from any `Iterable`, along with + # `String` objects using a special constructor. + struct Tokens(T) + getter tokens + + # Constructs a `Tokens(Char)` from a `String`. + def self.from_string(s : String) : Tokens(Char) + Tokens.new(s.chars) + end + + # Constructs a `Tokens` from an `Iterable`. + 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 + + # Exposes `Array#[](Int)`. + def [](index : Int) : T + @tokens[index] + end + + # Exposes `Array#[](Int, Int)`, but wraps the returned array in a new `Tokens`. + def [](start : Int, count : Int) : Tokens(T) + Tokens.new(@tokens[start, count]) + end + + # Exposes `Array#[](Range)`, but wraps the returned array in a new `Tokens`. + def [](range : Range) : Tokens(T) + Tokens.new(@tokens[range]) + end + + # Like `#[]`, but returns `nil` instead of raising an `IndexError`. + def []?(*args) + self.[](*args) + rescue IndexError + nil + end + + # Exposes `Array#empty?`. + def empty? : Bool + @tokens.empty? + end + end + + # A `Result` stores a `Tokens` object and a parsed value, + # and is effectively used to store the state of a parser chain. + # This is used instead of a `Tuple` or `NamedTuple` because: + # 1. This is more idiomatic than a `Tuple`. + # 2. Crystal does not support generic named tuples. + struct Result(T, V) + getter tokens, value + + def initialize(@tokens : Tokens(T), @value : V) + end + end +end + |
