aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-16 20:36:03 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-16 20:36:03 +1300
commitb274828831fec26cd8b3089ffef14cb96ce2de2f (patch)
treeff5927b85a59b4d85c9e4aa269a475a7a37a54a0 /src
parent77c370d27be174e0b036b33d1469e84e67a7153a (diff)
Second rewrite attempt, this one should work, monkaS
Diffstat (limited to 'src')
-rw-r--r--src/__OLD_parcom.cr84
-rw-r--r--src/__OLD_parcom/alt.cr (renamed from src/parcom/alt.cr)0
-rw-r--r--src/__OLD_parcom/any_token.cr (renamed from src/parcom/any_token.cr)0
-rw-r--r--src/__OLD_parcom/assert.cr (renamed from src/parcom/assert.cr)0
-rw-r--r--src/__OLD_parcom/at_least.cr (renamed from src/parcom/at_least.cr)0
-rw-r--r--src/__OLD_parcom/at_most.cr (renamed from src/parcom/at_most.cr)0
-rw-r--r--src/__OLD_parcom/between.cr (renamed from src/parcom/between.cr)0
-rw-r--r--src/__OLD_parcom/eof.cr (renamed from src/parcom/eof.cr)0
-rw-r--r--src/__OLD_parcom/exactly.cr (renamed from src/parcom/exactly.cr)0
-rw-r--r--src/__OLD_parcom/first_of.cr (renamed from src/parcom/first_of.cr)0
-rw-r--r--src/__OLD_parcom/flunk.cr (renamed from src/parcom/flunk.cr)0
-rw-r--r--src/__OLD_parcom/left.cr (renamed from src/parcom/left.cr)0
-rw-r--r--src/__OLD_parcom/many.cr (renamed from src/parcom/many.cr)0
-rw-r--r--src/__OLD_parcom/map.cr (renamed from src/parcom/map.cr)0
-rw-r--r--src/__OLD_parcom/optional.cr (renamed from src/parcom/optional.cr)0
-rw-r--r--src/__OLD_parcom/parser.cr (renamed from src/parcom/parser.cr)0
-rw-r--r--src/__OLD_parcom/peek.cr (renamed from src/parcom/peek.cr)0
-rw-r--r--src/__OLD_parcom/phrase.cr (renamed from src/parcom/phrase.cr)0
-rw-r--r--src/__OLD_parcom/plus.cr (renamed from src/parcom/plus.cr)0
-rw-r--r--src/__OLD_parcom/recover.cr (renamed from src/parcom/recover.cr)0
-rw-r--r--src/__OLD_parcom/right.cr (renamed from src/parcom/right.cr)0
-rw-r--r--src/__OLD_parcom/satisfy.cr (renamed from src/parcom/satisfy.cr)0
-rw-r--r--src/__OLD_parcom/sep_by.cr (renamed from src/parcom/sep_by.cr)0
-rw-r--r--src/__OLD_parcom/sequence.cr (renamed from src/parcom/sequence.cr)0
-rw-r--r--src/__OLD_parcom/some.cr (renamed from src/parcom/some.cr)0
-rw-r--r--src/__OLD_parcom/token.cr (renamed from src/parcom/token.cr)0
-rw-r--r--src/__OLD_parcom/token_seq.cr (renamed from src/parcom/token_seq.cr)0
-rw-r--r--src/parcom.cr56
-rw-r--r--src/parcom/basic.cr10
29 files changed, 137 insertions, 13 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
+
diff --git a/src/parcom/alt.cr b/src/__OLD_parcom/alt.cr
index dedd41d..dedd41d 100644
--- a/src/parcom/alt.cr
+++ b/src/__OLD_parcom/alt.cr
diff --git a/src/parcom/any_token.cr b/src/__OLD_parcom/any_token.cr
index 1f65bfc..1f65bfc 100644
--- a/src/parcom/any_token.cr
+++ b/src/__OLD_parcom/any_token.cr
diff --git a/src/parcom/assert.cr b/src/__OLD_parcom/assert.cr
index 5a3e621..5a3e621 100644
--- a/src/parcom/assert.cr
+++ b/src/__OLD_parcom/assert.cr
diff --git a/src/parcom/at_least.cr b/src/__OLD_parcom/at_least.cr
index 2fb8dcf..2fb8dcf 100644
--- a/src/parcom/at_least.cr
+++ b/src/__OLD_parcom/at_least.cr
diff --git a/src/parcom/at_most.cr b/src/__OLD_parcom/at_most.cr
index b70164f..b70164f 100644
--- a/src/parcom/at_most.cr
+++ b/src/__OLD_parcom/at_most.cr
diff --git a/src/parcom/between.cr b/src/__OLD_parcom/between.cr
index 05519e4..05519e4 100644
--- a/src/parcom/between.cr
+++ b/src/__OLD_parcom/between.cr
diff --git a/src/parcom/eof.cr b/src/__OLD_parcom/eof.cr
index 650da56..650da56 100644
--- a/src/parcom/eof.cr
+++ b/src/__OLD_parcom/eof.cr
diff --git a/src/parcom/exactly.cr b/src/__OLD_parcom/exactly.cr
index a34fd0d..a34fd0d 100644
--- a/src/parcom/exactly.cr
+++ b/src/__OLD_parcom/exactly.cr
diff --git a/src/parcom/first_of.cr b/src/__OLD_parcom/first_of.cr
index c4077eb..c4077eb 100644
--- a/src/parcom/first_of.cr
+++ b/src/__OLD_parcom/first_of.cr
diff --git a/src/parcom/flunk.cr b/src/__OLD_parcom/flunk.cr
index 00a0bd6..00a0bd6 100644
--- a/src/parcom/flunk.cr
+++ b/src/__OLD_parcom/flunk.cr
diff --git a/src/parcom/left.cr b/src/__OLD_parcom/left.cr
index 201f497..201f497 100644
--- a/src/parcom/left.cr
+++ b/src/__OLD_parcom/left.cr
diff --git a/src/parcom/many.cr b/src/__OLD_parcom/many.cr
index a734c63..a734c63 100644
--- a/src/parcom/many.cr
+++ b/src/__OLD_parcom/many.cr
diff --git a/src/parcom/map.cr b/src/__OLD_parcom/map.cr
index 34961b5..34961b5 100644
--- a/src/parcom/map.cr
+++ b/src/__OLD_parcom/map.cr
diff --git a/src/parcom/optional.cr b/src/__OLD_parcom/optional.cr
index b368d4e..b368d4e 100644
--- a/src/parcom/optional.cr
+++ b/src/__OLD_parcom/optional.cr
diff --git a/src/parcom/parser.cr b/src/__OLD_parcom/parser.cr
index ca350df..ca350df 100644
--- a/src/parcom/parser.cr
+++ b/src/__OLD_parcom/parser.cr
diff --git a/src/parcom/peek.cr b/src/__OLD_parcom/peek.cr
index 2b6f657..2b6f657 100644
--- a/src/parcom/peek.cr
+++ b/src/__OLD_parcom/peek.cr
diff --git a/src/parcom/phrase.cr b/src/__OLD_parcom/phrase.cr
index 1996fd4..1996fd4 100644
--- a/src/parcom/phrase.cr
+++ b/src/__OLD_parcom/phrase.cr
diff --git a/src/parcom/plus.cr b/src/__OLD_parcom/plus.cr
index 53c9b4f..53c9b4f 100644
--- a/src/parcom/plus.cr
+++ b/src/__OLD_parcom/plus.cr
diff --git a/src/parcom/recover.cr b/src/__OLD_parcom/recover.cr
index 378f8d6..378f8d6 100644
--- a/src/parcom/recover.cr
+++ b/src/__OLD_parcom/recover.cr
diff --git a/src/parcom/right.cr b/src/__OLD_parcom/right.cr
index a0489b1..a0489b1 100644
--- a/src/parcom/right.cr
+++ b/src/__OLD_parcom/right.cr
diff --git a/src/parcom/satisfy.cr b/src/__OLD_parcom/satisfy.cr
index 9734635..9734635 100644
--- a/src/parcom/satisfy.cr
+++ b/src/__OLD_parcom/satisfy.cr
diff --git a/src/parcom/sep_by.cr b/src/__OLD_parcom/sep_by.cr
index fa19027..fa19027 100644
--- a/src/parcom/sep_by.cr
+++ b/src/__OLD_parcom/sep_by.cr
diff --git a/src/parcom/sequence.cr b/src/__OLD_parcom/sequence.cr
index 6a05cde..6a05cde 100644
--- a/src/parcom/sequence.cr
+++ b/src/__OLD_parcom/sequence.cr
diff --git a/src/parcom/some.cr b/src/__OLD_parcom/some.cr
index a2e3563..a2e3563 100644
--- a/src/parcom/some.cr
+++ b/src/__OLD_parcom/some.cr
diff --git a/src/parcom/token.cr b/src/__OLD_parcom/token.cr
index b4e1fef..b4e1fef 100644
--- a/src/parcom/token.cr
+++ b/src/__OLD_parcom/token.cr
diff --git a/src/parcom/token_seq.cr b/src/__OLD_parcom/token_seq.cr
index 45900f9..45900f9 100644
--- a/src/parcom/token_seq.cr
+++ b/src/__OLD_parcom/token_seq.cr
diff --git a/src/parcom.cr b/src/parcom.cr
index ddb2e50..d12b011 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -5,17 +5,6 @@ module Parcom
# 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
@@ -74,10 +63,51 @@ module Parcom
# 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)
+ struct Result(T, U)
getter tokens, value
- def initialize(@tokens : Tokens(T), @value : V)
+ def initialize(@tokens : Tokens(T), @value : U)
+ end
+ end
+
+ class Parser(T, U)
+ getter name
+
+ def initialize(@name : String, @f : Tokens(T) -> Result(T, U))
+ end
+
+ def initialize(@name : String, &block : Tokens(T) -> Result(T, U))
+ @f = block
+ end
+
+ def named(name : String) : self
+ @name = name
+ self
+ end
+
+ def parse(tokens : Tokens(T)) : Result(T, U)
+ @f.call(tokens)
+ end
+
+ def parse(tokens : Tokens(T)) : Result(T, U)?
+ parse(tokens)
+ rescue
+ nil
+ end
+
+ def assert(f : U -> Bool) : Parser(T, U)
+ p = self
+ Parser.new("#{p.name} assertion") do |tokens|
+ result = p.parse(tokens)
+ unless f.call(r.value)
+ raise ParserFail.new("Assertion failed for value #{r.value}")
+ end
+ result
+ end
+ end
+
+ def assert(&block : U -> Bool) : Parser(T, U)
+ assert(block)
end
end
end
diff --git a/src/parcom/basic.cr b/src/parcom/basic.cr
new file mode 100644
index 0000000..6594555
--- /dev/null
+++ b/src/parcom/basic.cr
@@ -0,0 +1,10 @@
+require "../parcom.cr"
+
+module Parcom
+ module Basic
+ def pure(value : U) : Parser(T, U) forall T, U
+ Parser.new("Pure #{value}") { |tokens| Result.new(tokens, value) }
+ end
+ end
+end
+