{Record file}
Where
Let (file text)
(run text
(bind1 (recursive_parser `expr)
Func expr. (recursive_parser `package_block.expr)))
Where
Define (recursive_parser mode)
Match mode
| `expr
Let (dispatch_on_symbol text)
Let parse_expr (recursive_parser `expr)
In
Cond
| (STRING.equal text "~")
(lift1 parse_expr
Func expr. `app.{`prim."negate" [expr]})
| (STRING.equal text "!")
(lift1 parse_expr
Func expr. `if.{expr `false `true})
| (STRING.equal text "(")
(parse_applications parse_expr)
| (STRING.equal text "{")
(if_match "Record"
(lift1 (parse_record_inits parse_expr)
Func labels_and_inits.
`record.(LIST.unzip labels_and_inits))
(lift1 (parse_sequence parse_expr "}")
Func exprs. `tuple.exprs))
| (STRING.equal text "[")
(lift1 (parse_sequence parse_expr "]")
Func exprs. `list.exprs)
| (STRING.equal text "`")
(bind1 parse_id
Func label.
(if_match "."
(lift1 parse_expr
Func expr. `labeled.{label expr})
(pure `labeled.{label `tuple.[]})))
| (STRING.equal text "True")
(pure `true)
| (STRING.equal text "False")
(pure `false)
| (STRING.equal text "And")
(lift2 parse_expr parse_expr
Func test then. `and.{test then})
| (STRING.equal text "Or")
(lift2 parse_expr parse_expr
Func test else. `or.{test else})
| (STRING.equal text "If")
(lift3 parse_expr parse_expr parse_expr
Func test then else. `if.{test then else})
| (STRING.equal text "Cond")
Let parse_cond_clause
(sequence2 (match "|")
(lift2 parse_expr (recursive_parser `block_body)
Func test body. {test body}))
In
(lift1 (parse_sequence parse_cond_clause ";")
Func clauses. `cond.clauses)
| (STRING.equal text "Switch")
Let parse_switch_clause
(sequence2 (match "|")
(lift2 parse_switch_pattern (recursive_parser `block_body)
Func pat body. {pat body}))
In
(lift2 parse_expr (parse_sequence parse_switch_clause ";")
Func expr clauses. `switch.{expr clauses})
| (STRING.equal text "Match")
Let parse_match_clause
(sequence2 (match "|")
(lift2 parse_match_pattern (recursive_parser `block_body)
Func pat body. {pat body}))
In
(lift2 parse_expr (parse_sequence parse_match_clause ";")
Func expr clauses. `match.{expr clauses})
| (STRING.equal text "Func")
(bind1 (parse_patterns ".")
Func pats.
(lift1 (recursive_parser `block_body)
Func expr. `func.{`nothing pats expr}))
| (STRING.equal text "Prim")
(lift1 parse_id
Func name. `prim.name)
| (STRING.equal text "Package")
(bind1 pop
Func token.
Match token
| `str.s (pure `package.(strip_quotes s))
| _ (fail "Malformed Package expression.")
;)
| (STRING.equal text "Block")
(recursive_parser `block_body)
| (STRING.equal text "For")
(bind2 parse_expr
(if_match "Let" (pure parse_let_binder)
(if_match "Do" (pure parse_do_binder)
(if_match "Define" (pure parse_define_binder)
(sequence2 pop (fail "Expected binder.")))))
Func expr parser.
(lift1 (parser (recursive_parser `block_body))
Func binder.
`block.{[binder] expr}))
| (STRING.equal text "Iterate")
(bind1 (sequence2 (match "{") (parse_patterns "}"))
Func pats.
Let vars (simplify_patterns pats)
In
(lift2
(sequence2 (match "From")
(sequence2 (match "{")
(parse_sequence parse_expr "}")))
(recursive_parser `block_body)
Func inits expr. `iterate.{vars inits expr}))
| (STRING.equal text "Continue")
(lift1 (sequence2 (match "{") (parse_sequence parse_expr "}"))
Func exprs. `continue.exprs)
| (STRING.equal text "Begin")
(lift1 (parse_sequence parse_expr "End")
Func stmts.
Let binders
(LIST.reduce stmts []
Func binders stmt. (`do.stmt :: binders))
In
Match binders
| `nil `tuple.[]
| `cons._ `block.{binders `tuple.[]}
;)
| (STRING.equal text "When")
(lift2 parse_expr (parse_sequence parse_expr "End")
Func test stmts.
Let binders
(LIST.reduce stmts []
Func binders stmt. (`do.stmt :: binders))
In
Let then
Match binders
| `nil `tuple.[]
| `cons._ `block.{binders `tuple.[]}
;
In
`if.{test then `tuple.[]})
| True (fail "Unexpected token while parsing expression.")
;
In
(bind1 pop
Func token.
Match token
| `num.n (pure `num.n)
| `str.s (pure `str.s)
| `id.name
(lift1 parse_chain
Func chain.
Match chain
| `nil `var.name
| `cons._ `chain.{`var.name chain}
;)
| `sym.text (dispatch_on_symbol text)
| `eof (fail "Unexpected end of file.")
;)
| `block_body
Let (continue binders)
(bind1 pop
Func token.
Match token
| `sym.s
Cond
| (STRING.equal s "In")
(lift1 (recursive_parser `block_body)
Func expr. `block.{binders expr})
| True (fail "Unexpected token while parsing binders.")
;
| `eof (fail "Unexpected end of file.")
| _ (fail "Unexpected token while parsing binders.")
;)
In
(bind1 peek
Func token.
Match token
| `sym.s
Let has_binder
Cond
| (STRING.equal s "Let") True
| (STRING.equal s "Do") True
| (STRING.equal s "Define") True
| True False
;
In
If has_binder
(recursive_parser `binder_group.{[] continue})
(recursive_parser `expr)
| _ (recursive_parser `expr)
;)
| `package_block.expr
(bind1 pop
Func token.
Match token
| `eof (pure expr)
| `sym.s
Cond
| (STRING.equal s "Where")
Let (continue binders)
(recursive_parser
`package_block.`block.{binders expr})
In
(recursive_parser `binder_group.{[] continue})
| True (fail "Unexpected token while parsing package.")
;
| _ (fail "Unexpected token while parsing package.")
;)
| `binder_group.{binders continue}
(bind1 peek
Func token.
Match token
| `sym.s
Let maybe_parser
Cond
| (STRING.equal s "Let") `just.parse_let_binder
| (STRING.equal s "Define") `just.parse_define_binder
| (STRING.equal s "Do") `just.parse_do_binder
| True `nothing
;
In
Match maybe_parser
| `just.parser
(bind1 (sequence2 pop (parser (recursive_parser `block_body)))
Func binder.
Let binders (binder :: binders)
In
(recursive_parser `binder_group.{binders continue}))
| `nothing (continue binders)
;
| _ (continue binders)
;)
;
Where
Let (parse_applications parse_expr)
Let (parse_left_apply expr)
(lift1 (parse_sequence parse_expr ")")
Func exprs.
Match exprs
| `nil expr
| `cons._ `app.{expr exprs}
;)
Define (parse_right_apply expr)
(if_match ")"
(pure expr)
(lift1 (bind1 parse_expr parse_right_apply)
Func expr_right.
`app.{expr [expr_right]}))
Define (parse_left_general expr_left op expr_right)
Let expr_left `app.{`prim.op [expr_left expr_right]}
In
(bind1 maybe_parse_binary_op
Func maybe_op.
Match maybe_op
| `nothing
(if_match ")"
(pure expr_left)
(sequence2 pop
(fail "Expected binary operator or close paren.")))
| `just.op'
If (STRING.equal op op')
(bind1 parse_expr
Func expr_right.
(parse_left_general expr_left op expr_right))
(fail "Mismatched operator.")
;)
Define (parse_right_general expr_left op expr_right)
(bind1 maybe_parse_binary_op
Func maybe_op.
Match maybe_op
| `nothing
(if_match ")"
(pure `app.{`prim.op [expr_left expr_right]})
(sequence2 pop
(fail "Expected binary operator or close paren.")))
| `just.op'
If (STRING.equal op op')
(lift1
Block
Let expr_left expr_right
In
(bind1 parse_expr
Func expr_right.
(parse_right_general expr_left op expr_right))
Func expr_right.
`app.{`prim.op [expr_left expr_right]})
(fail "Mismatched operator.")
;)
In
(bind2 (if_match "Right" (pure `right) (pure `left)) parse_expr
Func assoc expr.
(bind1 maybe_parse_binary_op
Func maybe_op.
Match maybe_op
| `nothing
Match assoc
| `left (parse_left_apply expr)
| `right (parse_right_apply expr)
;
| `just.op
(bind1 parse_expr
Func expr_right.
Match assoc
| `left (parse_left_general expr op expr_right)
| `right (parse_right_general expr op expr_right)
;)
;))
Let parse_chain
Define (chain_parser _)
(if_match "."
Block
Let (parse_access token)
Match token
| `id.name
(lift1 (chain_parser {})
Func chain. (`id.name :: chain))
| `num.n
(lift1 (chain_parser {})
Func chain. (`num.n :: chain))
| `eof (fail "Unexpected end of file.")
| _ (fail "Unexpected token while parsing access chain.")
;
In
(bind1 pop parse_access)
(pure []))
In
(chain_parser {})
Let parse_switch_pattern
(bind1 pop
Func token.
Match token
| `sym.s
Cond
| (STRING.equal s "_")
(pure `default.`nothing)
| (STRING.equal s "~")
(bind1 pop
Func token.
Match token
| `num.n (pure `value.~n)
| _ (fail "Malformed Switch pattern.")
;)
| True (fail "Malformed Switch pattern.")
;
| `num.n (pure `value.n)
| `id.name (pure `default.`just.name)
| `eof (fail "Unexpected end of file.")
| _ (fail "Malformed Switch pattern.")
;)
Let parse_match_pattern
Let parse_vars
(if_match "{"
(lift1 (parse_patterns "}")
Func pats. `tuple.(simplify_patterns pats))
(if_match "_" (pure `ignore)
(lift1 parse_id
Func name. `var.name)))
In
(bind1 pop
Func token.
Match token
| `sym.s
Cond
| (STRING.equal s "_") (pure `default)
| (STRING.equal s "`")
(lift2 parse_id (if_match "." parse_vars (pure `tuple.[]))
Func label vars. `labeled.{label vars})
| True (fail "Malformed Match pattern.")
;
| `eof (fail "Unexpected end of file.")
| _ (fail "Malformed Match pattern.")
;)
Where
Let maybe_parse_binary_op
Define (gather_symbols _)
(bind1 peek
Func token.
Match token
| `sym.s
Let maybe_symbol
Cond
| (STRING.equal s "+") `just.s
| (STRING.equal s "-") `just.s
| (STRING.equal s "*") `just.s
| (STRING.equal s ":") `just.s
| (STRING.equal s "<") `just.s
| (STRING.equal s ">") `just.s
| (STRING.equal s "=") `just.s
| True `nothing
;
In
Match maybe_symbol
| `just.symbol
(sequence2 pop
(lift1 (gather_symbols {})
Func symbols. (symbol :: symbols)))
| `nothing (pure [])
;
| _ (pure [])
;)
In
(lift1 (gather_symbols {})
Func symbols.
Match symbols
| `nil `nothing
| `cons._
Let op (STRING.concat symbols)
In
Cond
| (STRING.equal op "+") `just."add"
| (STRING.equal op "-") `just."subtract"
| (STRING.equal op "*") `just."multiply"
| (STRING.equal op "<") `just."less"
| (STRING.equal op ">") `just."greater"
| (STRING.equal op "=") `just."equal"
| (STRING.equal op "<=") `just."less_or_equal"
| (STRING.equal op ">=") `just."greater_or_equal"
| (STRING.equal op "::") `just."cons"
| True `nothing
;
;)
Let (parse_let_binder parse_block_body)
(bind1 peek
Func token.
Match token
| `sym.s
Cond
| (STRING.equal s "{")
(lift2 (sequence2 pop (parse_patterns "}"))
parse_block_body
Func pats expr.
Let pats (simplify_patterns pats)
In
`let.{`tuple.pats expr})
| (STRING.equal s "(")
(lift3 (sequence2 pop parse_id)
(parse_patterns ")")
parse_block_body
Func name pats expr.
`let.{`var.name `func.{`nothing pats expr}})
;
| `eof (fail "Unexpected end of file.")
| _
(lift2 parse_id parse_block_body
Func name expr. `let.{`var.name expr})
;)
Let (parse_do_binder parse_block_body)
(lift1 parse_block_body
Func expr. `do.expr)
Let (parse_define_binder parse_block_body)
(lift3 (sequence2 (match "(") parse_id)
(parse_patterns ")")
parse_block_body
Func name pats expr.
`let.{`var.name `func.{`just.name pats expr}})
Where
Let (parse_record_inits parse_expr)
(parse_sequence (parse_record_init parse_expr) "}")
Let (parse_patterns terminator)
(parse_sequence (parse_pattern {}) terminator)
Where
Let (parse_record_init parse_expr)
(bind1 parse_id
Func name.
(if_match ":"
(lift1 parse_expr
Func expr. {name expr})
(pure {name `var.name})))
Define (parse_pattern _)
(bind1 pop
Func token.
Match token
| `id.name (pure `var.name)
| `sym.s
Cond
| (STRING.equal s "{")
(lift1 (parse_sequence (parse_pattern {}) "}")
Func pats. `tuple.(simplify_patterns pats))
| (STRING.equal s "_") (pure `ignore)
| True (fail "Invalid pattern.")
;
| `eof (fail "Unexpected end of file.")
| _ (fail "Expected token while parsing patterns.")
;)
Where
Define (parse_sequence parser terminator)
(if_match terminator
(pure [])
(bind1 parser
Func item.
(lift1 (parse_sequence parser terminator)
Func items. (item :: items))))
Where
Let (simplify_patterns pats)
(LIST.map pats
Func pat. Match pat | `ignore "_" | `var.name name ;)
Let parse_id
(bind1 pop
Func token.
Match token
| `id.name (pure name)
| `sym.s (fail (STRING.append "Expected identifier, got " s))
| `eof (fail "Unexpected end of file.")
| _ (fail "Unexpected token.")
;)
Let (match s1)
(bind1 pop
Func token.
Match token
| `sym.s2
If (STRING.equal s1 s2)
(pure {})
(fail (STRING.concat ["Expected \"" s1 "\"."]))
| `eof (fail "Unexpected end of file.")
| _ (fail (STRING.concat ["Expected \"" s1 "\"."]))
;)
Let (check_for_match s1)
(lift1 peek
Func token.
Match token
| `sym.s2 (STRING.equal s1 s2)
| _ False
;)
Let (if_match s1 then else)
(bind1 peek
Func token.
Match token
| `sym.s2 If (STRING.equal s1 s2) (sequence2 pop then) else
| _ else
;)
Where
Let (pop text i)
Let i (SCAN.whitespace text i)
In
Let {i token} (SCAN.token text i)
In
`succeed.{token i}
Let (peek text i)
Let j (SCAN.whitespace text i)
In
Let {_ token} (SCAN.token text j)
In
`succeed.{token i}
Where
Let (run text parser)
Match (parser text 0)
| `succeed.{expr _}
`succeed.expr
| `fail.{message i}
`fail.{message i}
;
Let (fail message)
Func text i.
`fail.{message i}
Let (pure x)
Func text i. `succeed.{x i}
Let (bind1 m1 f)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{x1 i}
Let m2 (f x1)
In
(m2 text i)
| `fail._ r1
;
Let (bind2 m1 m2 f)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{x1 i}
Let r2 (m2 text i)
In
Match r2
| `succeed.{x2 i}
Let m3 (f x1 x2)
In
(m3 text i)
| `fail._ r2
;
| `fail._ r1
;
Let (lift1 m1 f)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{x1 i}
`succeed.{(f x1) i}
| `fail._ r1
;
Let (lift2 m1 m2 f)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{x1 i}
Let r2 (m2 text i)
In
Match r2
| `succeed.{x2 i}
`succeed.{(f x1 x2) i}
| `fail._ r2
;
| `fail._ r1
;
Let (lift3 m1 m2 m3 f)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{x1 i}
Let r2 (m2 text i)
In
Match r2
| `succeed.{x2 i}
Let r3 (m3 text i)
In
Match r3
| `succeed.{x3 i}
`succeed.{(f x1 x2 x3) i}
| `fail._ r3
;
| `fail._ r2
;
| `fail._ r1
;
Let (sequence2 m1 m2)
Func text i.
Let r1 (m1 text i)
In
Match r1
| `succeed.{_ i} (m2 text i)
| `fail._ r1
;
Where
Let (strip_quotes s)
(STRING.clip s 1 ((STRING.length s) - 1))
Where
Let LIST Package "list"
Let OS Package "os"
Let SCAN Package "scan"
Let STDIO Package "stdio"
Let STRING Package "string"