///|
typealias @pc.Parser
///|
priv struct OriginalParser[Repr] {
litP : Lazy[Parser[Repr]]
plusP : Lazy[Parser[Repr]]
wholeP : Lazy[Parser[Repr]]
}
///|
priv struct ExtendedParser[Repr] {
litP : Lazy[Parser[Repr]]
plusP : Lazy[Parser[Repr]]
varP : Lazy[Parser[Repr]]
wholeP : Lazy[Parser[Repr]]
}
///|
let intP : @pc.Parser[Int] = @pc.foldl(
@pc.digit,
@pc.pure(0),
@pc.pure((acc, x) => acc * 10 + (Char::to_int(x) - '0'.to_int())),
)
///|
let letterP : Parser[Char] = @pc.alphabetic
///|
let stringP : Parser[String] = {
let buffer = StringBuilder::new()
letterP
.many_each(fn(ch) { buffer.write_char(ch) })
.map(fn(_) {
let res = buffer.to_string()
buffer.reset()
res
})
}
///|
let charP = @pc.any
///|
let spaces : @pc.Parser[Char] = @pc.spaces
///|
priv trait AST {
lit(Int) -> Self
plus(Self, Self) -> Self
}
///|
priv trait Var {
var_(String) -> Self
}
///|
priv struct MyString(String)
///|
impl Show for MyString with output(self, logger) {
self.inner().output(logger)
}
///|
impl AST for MyString with lit(self) {
self.to_string()
}
///|
impl AST for MyString with plus(lhs, rhs) {
"(\{lhs.inner()} + \{rhs.inner()})"
}
///|
impl Var for MyString with var_(self) {
self
}
///|
fn[Repr : AST] originalParser() -> LazyBuilder[OriginalParser[Repr]] {
fn(self) {
Lazy::from_fun(fn() {
let litP = Lazy::from_val(intP.map(Repr::lit))
let plusP = Lazy::from_fun(fn() {
Parser::Parser(fn(input) {
let plusP = self.force().wholeP.map(fn(wholeP) {
@pc.between(
@pc.foldl1(
wholeP,
@pc.char('+').discard_left(@pc.pure(Repr::plus)),
),
open=@pc.char('('),
close=@pc.char(')'),
)
})
plusP.force()(input)
})
})
let wholeP = Lazy::from_fun(fn() {
Parser::Parser(fn(input) {
let { litP, plusP, .. } = self.force()
let wholeP : Lazy[Parser[Repr]] = litP.bind(fn(litP) {
plusP.map(fn(plusP) { plusP | litP })
})
wholeP.force()(input)
})
})
{ litP, plusP, wholeP }
})
}
}
///|
fn[Repr : AST + Var] extendedParser() -> LazyBuilder[ExtendedParser[Repr]] {
fn f(self : OriginalParser[Repr]) -> ExtendedParser[Repr] {
let { litP, plusP, wholeP } = self
let varP = stringP.map(Var::var_)
let wholeP = Lazy::new(fn() { varP | wholeP.force() })
let varP = Lazy::from_val(varP)
{ varP, litP, plusP, wholeP }
}
fn g(self : ExtendedParser[Repr]) {
let { varP, litP, plusP, wholeP } = self
{ litP, plusP, wholeP }
}
let originalParser : LazyBuilder[OriginalParser[Repr]] = originalParser()
originalParser.inherit_(f, g)
}
///|
test "OriginalParser" {
let parser : LazyBuilder[OriginalParser[MyString]] = originalParser()
let { litP, plusP, wholeP } = parser.run_force()
let litP = litP.force()
let plusP = plusP.force()
let wholeP = wholeP.force()
inspect(
litP.run(@pc.Input::new("123")),
content=(
#|"123"
),
)
inspect(
plusP.run(@pc.Input::new("(1+2)")),
content=(
#|"(1 + 2)"
),
)
inspect(
wholeP.run(@pc.Input::new("(1+2)")),
content=(
#|"(1 + 2)"
),
)
}
///|
test "ExtendedParser" {
let parser : LazyBuilder[ExtendedParser[MyString]] = extendedParser()
let parser = parser.run_force()
let { varP, litP, plusP, wholeP } = parser
let litP = litP.force()
let plusP = plusP.force()
let wholeP = wholeP.force()
let varP = varP.force()
inspect(
wholeP.run(@pc.Input::new("(1+a)")),
content=(
#|"(1 + a)"
),
)
inspect(
varP.run(@pc.Input::new("abc")),
content=(
#|"abc"
),
)
inspect(
wholeP.run(@pc.Input::new("(1+(1+2))")),
content=(
#|"(1 + (1 + 2))"
),
)
}