Last active
May 19, 2022 14:29
-
-
Save naartjie/87beed5f4cbc0c7aba2d4360ae1c9429 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open System | |
open System.Text.RegularExpressions | |
type Expr = | |
| Int of int | |
| Symbol of string | |
| Exprs of Expr list | |
(* convert a string into a list of tokens (include parentheses, remove whitespace) *) | |
let tokenize (str: string) = | |
(* split on parentheses (capture them), spaces and newliness (but remove those) *) | |
Regex.Split(str, "(\(|\))| +|\n+") | |
|> Array.filter (fun x -> x <> "") | |
|> Array.toList | |
(* parse a list of tokens into an AST *) | |
let parse (tokens: string list) = | |
let parseToken (token: string) : Expr = | |
match Int32.TryParse token with | |
| true, i -> Int i | |
| false, _ -> Symbol token | |
let rec aux (tokens: string list) (depth: int) = | |
match tokens with | |
| [] when depth > 0 -> failwith ("balance your parentheses, missing some `)`") | |
| [] -> [], [] | |
| "(" :: xs -> | |
let parsed, remaining = aux xs (depth + 1) | |
let r', r'' = aux remaining depth | |
Exprs(parsed) :: r', r'' | |
| ")" :: xs -> | |
if depth <= 0 then | |
failwith ("balance your parentheses, too many `)`") | |
[], xs | |
| x :: xs -> | |
let parsed, remaining = aux xs depth | |
parseToken x :: parsed, remaining | |
let parsed, remaining = aux tokens 0 | |
assert (remaining.IsEmpty) | |
parsed | |
(* allows for more than one top-level expression *) | |
let lastExpression = | |
""" | |
hello | |
() | |
(1) | |
(2 3) | |
(first (list 1 (+ 2 3) 9)) | |
""" | |
|> tokenize | |
|> parse | |
|> Seq.last | |
let expected = | |
Exprs [ Symbol "first" | |
Exprs [ Symbol "list" | |
Int 1 | |
Exprs [ Symbol "+"; Int 2; Int 3 ] | |
Int 9 ] ] | |
if lastExpression <> expected then | |
failwith | |
$""" | |
actual: | |
{lastExpression}" | |
expected: | |
{expected} | |
""" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment