summaryrefslogtreecommitdiffstats
path: root/parser.sml
diff options
context:
space:
mode:
authorRose Hogenson <rhogenson@posteo.net>2022-09-11 23:11:30 -0700
committerRose Hogenson <rhogenson@posteo.net>2022-09-11 23:11:30 -0700
commit4763deb1df6e409f79623f58d2ceb4e022585e6a (patch)
treec374769cdc509480011ffd01cd40cd33723f633d /parser.sml
parent86991830c05279583910758551a9c3974437623e (diff)
downloadsml-4763deb1df6e409f79623f58d2ceb4e022585e6a.tar.zst
Don't break the parser abstraction for recursion.
Parsers are values. Of course, one can always make recursion from scratch even if the language doesn't allow recursive values.
Diffstat (limited to 'parser.sml')
-rw-r--r--parser.sml81
1 files changed, 44 insertions, 37 deletions
diff --git a/parser.sml b/parser.sml
index af7ec76..930431f 100644
--- a/parser.sml
+++ b/parser.sml
@@ -312,41 +312,48 @@ struct
| op1 :: ops => Syntax.EIdent <$> foldl (op <|>) op1 ops
end)
- (* These need to be declared as functions so they can be mutually recursive.
- Of course, functions are values. *)
- fun atom (st : state) : Syntax.expr parserResponse =
- (Syntax.EInt <$> integer
- <|> Syntax.EStr <$> stringConstant
- <|> Syntax.EIdent <$> identifier
- <|> (symbol "(" >>
- bind (sepBy1 expr (symbol ",")) (fn exprs =>
- symbol ")" >>
- const
- (case exprs of
- [x] => x
- | _ => Syntax.ETuple exprs)))) st
- and expr0 (st : state) : Syntax.expr parserResponse =
- bind atom (fn e0 =>
- foldl (fn (x, acc) => Syntax.EApp (acc, x)) e0 <$> many atom) st
- and expr (st : state) : Syntax.expr parserResponse =
- foldl
- (fn (i, exprLower) =>
- let
- fun exprLeft expr1 =
- bind (leftOp i) (fn opEx =>
- bind exprLower (fn expr2 =>
- let val app = Syntax.EApp (opEx, Syntax.ETuple [expr1, expr2])
- in exprLeft app <|> const app
- end))
- fun exprRight expr1 =
- bind (rightOp i) (fn opEx =>
- bind exprLower (fn expr2 =>
- bind (exprRight expr2 <|> const expr2) (fn rest =>
- const (Syntax.EApp (opEx, Syntax.ETuple [expr1, rest])))))
- in
- bind exprLower (fn expr1 =>
- exprLeft expr1 <|> exprRight expr1 <|> const expr1)
- end)
- expr0
- (List.tabulate (10, fn i => 9 - i)) st
+ (* Values cannot be recursive. So we take the recursive call as a parameter,
+ and wire it together with the Y combinator. *)
+ fun expr' (expr : Syntax.expr parser) : Syntax.expr parser =
+ let
+ val atom =
+ Syntax.EInt <$> integer
+ <|> Syntax.EStr <$> stringConstant
+ <|> Syntax.EIdent <$> identifier
+ <|> (symbol "(" >>
+ bind (sepBy1 expr (symbol ",")) (fn exprs =>
+ symbol ")" >>
+ const
+ (case exprs of
+ [x] => x
+ | _ => Syntax.ETuple exprs)))
+ val expr0 =
+ bind atom (fn e0 =>
+ foldl (fn (x, acc) => Syntax.EApp (acc, x)) e0 <$> many atom)
+ in
+ foldl
+ (fn (i, exprLower) =>
+ let
+ fun exprLeft expr1 =
+ bind (leftOp i) (fn opEx =>
+ bind exprLower (fn expr2 =>
+ let val app = Syntax.EApp (opEx, Syntax.ETuple [expr1, expr2])
+ in exprLeft app <|> const app
+ end))
+ fun exprRight expr1 =
+ bind (rightOp i) (fn opEx =>
+ bind exprLower (fn expr2 =>
+ bind (exprRight expr2 <|> const expr2) (fn rest =>
+ const (Syntax.EApp (opEx, Syntax.ETuple [expr1, rest])))))
+ in
+ bind exprLower (fn expr1 =>
+ exprLeft expr1 <|> exprRight expr1 <|> const expr1)
+ end)
+ expr0
+ (List.tabulate (10, fn i => 9 - i))
+ end
+
+ fun Y (f : ('a -> 'b) -> 'a -> 'b) : 'a -> 'b = f (fn x => Y f x)
+
+ val expr = Y expr'
end