Skip to content
This repository has been archived by the owner on Jan 4, 2025. It is now read-only.

Commit

Permalink
labels kinda working
Browse files Browse the repository at this point in the history
  • Loading branch information
bcpeinhardt committed Aug 31, 2024
1 parent 5b33dd2 commit b037ff6
Show file tree
Hide file tree
Showing 10 changed files with 720 additions and 249 deletions.
815 changes: 577 additions & 238 deletions priv/static/squared_away.mjs

Large diffs are not rendered by default.

14 changes: 13 additions & 1 deletion src/squared_away/lang.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ pub fn scan_grid(
input: dict.Dict(String, String),
) -> dict.Dict(String, Result(List(token.Token), error.CompileError)) {
use acc, key, src <- dict.fold(input, dict.new())
let maybe_scanned = scanner.scan(src) |> result.map_error(error.ScanError)
let maybe_scanned =
scanner.scan(src)
|> result.map_error(error.ScanError)
|> result.map(list.map(_, fn(t) {
case t {
token.LabelDef(txt, "") ->
token.LabelDef(
txt,
key |> util.cell_to_the_right |> option.unwrap(or: ""),
)
_ -> t
}
}))
dict.insert(acc, key, maybe_scanned)
}
43 changes: 42 additions & 1 deletion src/squared_away/lang/interpreter.gleam
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import gleam/dict
import gleam/float
import gleam/int
import gleam/list.{Continue, Stop}
import gleam/option.{None, Some}
import gleam/result
import squared_away/lang/error
import squared_away/lang/interpreter/runtime_error
import squared_away/lang/interpreter/value
import squared_away/lang/parser/expr
import squared_away/lang/typechecker/typed_expr
Expand All @@ -13,8 +16,46 @@ pub fn interpret(
) -> Result(value.Value, error.CompileError) {
case expr {
typed_expr.Empty(_) -> Ok(value.Empty)
typed_expr.LabelDef(_, _, _) -> Ok(value.Empty)
typed_expr.Group(_, expr) -> interpret(env, expr)
typed_expr.Label(_, txt) -> Ok(value.Text(txt))
typed_expr.Label(_, txt) -> {
let key =
env
|> dict.to_list
|> list.fold_until(None, fn(acc, i) {
case i {
#(_, Ok(typed_expr.LabelDef(ty, label_txt, cell_ref)))
if label_txt == txt
-> {
Stop(Some(cell_ref))
}
_ -> Continue(None)
}
})

case key {
None ->
Error(
error.RuntimeError(runtime_error.RuntimeError(
"Label doesn't point to anything",
)),
)
Some(key) -> {
case dict.get(env, key) {
Error(Nil) ->
Error(
error.RuntimeError(runtime_error.RuntimeError(
"Label doesn't point to anything",
)),
)
Ok(Error(e)) -> Error(e)
Ok(Ok(te)) -> {
interpret(env, te)
}
}
}
}
}
typed_expr.BooleanLiteral(_, b) -> Ok(value.Boolean(b))
typed_expr.IntegerLiteral(_, n) -> Ok(value.Integer(n))
typed_expr.FloatLiteral(_, f) -> Ok(value.FloatingPointNumber(f))
Expand Down
1 change: 1 addition & 0 deletions src/squared_away/lang/parser.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ fn do_parse(
) -> Result(#(expr.Expr, List(token.Token)), parse_error.ParseError) {
case tokens {
[] -> Ok(#(expr.Empty, []))
[token.LabelDef(str, key), ..rest] -> Ok(#(expr.LabelDef(str, key), rest))
// Let's do the single token patterns first
[token.Label(str), ..rest] -> {
case try_parse_binary_ops(rest) {
Expand Down
1 change: 1 addition & 0 deletions src/squared_away/lang/parser/expr.gleam
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub type Expr {
Empty
FloatLiteral(f: Float)
LabelDef(txt: String, cell_ref: String)
Label(txt: String)
IntegerLiteral(n: Int)
CellReference(key: String)
Expand Down
61 changes: 55 additions & 6 deletions src/squared_away/lang/scanner.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub fn scan(src: String) -> Result(List(token.Token), scan_error.ScanError) {
case string.trim(src) {
"" -> Ok([])
"=" <> rest -> do_scan(rest |> string.trim_left, [])
_ -> Ok([token.Label(src)])
_ -> Ok([token.LabelDef(src, "")])
}
}

Expand Down Expand Up @@ -61,11 +61,60 @@ fn do_scan(
}

Error(_) -> {
use #(cell_ref, rest) <- result.try(
parse_cell_ref(src, "")
|> result.replace_error(scan_error.ScanError),
)
do_scan(string.trim_left(rest), [token.CellReference(cell_ref), ..acc])
case parse_cell_ref(src, "") {
Ok(#(cell_ref, rest)) ->
do_scan(string.trim_left(rest), [
token.CellReference(cell_ref),
..acc
])
_ -> {
case parse_identifier(src, "") {
Error(Nil) -> Error(scan_error.ScanError)
Ok(#(ident, rest)) ->
do_scan(string.trim_left(rest), [token.Label(ident), ..acc])
}
}
}
}
}
}
}
}

fn parse_identifier(src: String, acc: String) -> Result(#(String, String), Nil) {
case src {
"A" as l <> rest
| "B" as l <> rest
| "C" as l <> rest
| "D" as l <> rest
| "E" as l <> rest
| "F" as l <> rest
| "G" as l <> rest
| "H" as l <> rest
| "I" as l <> rest
| "J" as l <> rest
| "K" as l <> rest
| "L" as l <> rest
| "M" as l <> rest
| "N" as l <> rest
| "O" as l <> rest
| "P" as l <> rest
| "Q" as l <> rest
| "R" as l <> rest
| "S" as l <> rest
| "T" as l <> rest
| "U" as l <> rest
| "V" as l <> rest
| "W" as l <> rest
| "X" as l <> rest
| "Y" as l <> rest
| "Z" as l <> rest -> parse_identifier(rest, acc <> l)
_ -> {
case acc {
// Meaning we called this on something that didnt start with a capital letter
"" -> Error(Nil)
_ -> {
Ok(#(acc, src))
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/squared_away/lang/scanner/token.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ pub type Token {
CellReference(key: String)
/// Anything not starting with an = in a cell is a string literal
Label(String)
LabelDef(txt: String, cell_ref: String)
}
30 changes: 28 additions & 2 deletions src/squared_away/lang/typechecker.gleam
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gleam/dict
import gleam/list
import gleam/list.{Continue, Stop}
import gleam/option.{type Option, None, Some}
import gleam/result
import gleam/string
import squared_away/lang/error
Expand All @@ -15,10 +16,35 @@ pub fn typecheck(
) -> Result(typed_expr.TypedExpr, error.CompileError) {
case expr {
expr.Empty -> Ok(typed_expr.Empty(type_: typ.TNil))
expr.LabelDef(txt, key) ->
Ok(typed_expr.LabelDef(type_: typ.TNil, txt:, key:))

// We will typecheck the label when we typecheck the grid as a whole. For now it's a
// "Nil" type
expr.Label(txt) -> Ok(typed_expr.Label(type_: typ.TNil, txt:))
expr.Label(txt) -> {
let key =
env
|> dict.to_list
|> list.fold_until(None, fn(acc, i) {
case i {
#(_, Ok(expr.LabelDef(label_txt, cell_ref))) if label_txt == txt -> {
Stop(Some(cell_ref))
}
_ -> Continue(None)
}
})

case key {
None -> Ok(typed_expr.Label(typ.TNil, txt))
Some(key) -> {
let assert Ok(x) = dict.get(env, key)
case x {
Error(e) -> Error(e)
Ok(expr) -> typecheck(env, expr)
}
}
}
}
expr.BooleanLiteral(b) ->
Ok(typed_expr.BooleanLiteral(type_: typ.TBool, b:))
expr.FloatLiteral(f) -> Ok(typed_expr.FloatLiteral(type_: typ.TFloat, f:))
Expand Down
1 change: 1 addition & 0 deletions src/squared_away/lang/typechecker/typed_expr.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub type TypedExpr {
Empty(type_: typ.Typ)
FloatLiteral(type_: typ.Typ, f: Float)
Label(type_: typ.Typ, txt: String)
LabelDef(type_: typ.Typ, txt: String, key: String)
IntegerLiteral(type_: typ.Typ, n: Int)
CellReference(type_: typ.Typ, key: String)
BooleanLiteral(type_: typ.Typ, b: Bool)
Expand Down
2 changes: 1 addition & 1 deletion test/squared_away_test.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn scanner_test() {
token.Plus,
token.IntegerLiteral(786),
]),
#("+-*/=", [token.Label("+-*/=")]),
#("+-*/=", [token.LabelDef("+-*/=", "")]),
]

use tc <- list.each(test_cases)
Expand Down

0 comments on commit b037ff6

Please sign in to comment.