Skip to content

Commit

Permalink
feat: Add format_runtime_error
Browse files Browse the repository at this point in the history
  • Loading branch information
Olian04 committed Jun 19, 2024
1 parent 5b29219 commit 3fc324f
Show file tree
Hide file tree
Showing 12 changed files with 181 additions and 118 deletions.
9 changes: 7 additions & 2 deletions src/handles/error.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ pub type TokenizerError {
}

pub type RuntimeError {
UnexpectedTypeError(path: List(String), got: String, expected: List(String))
UnknownPropertyError(key: List(String))
UnexpectedTypeError(
index: Int,
path: List(String),
got: String,
expected: List(String),
)
UnknownPropertyError(index: Int, path: List(String))
}
27 changes: 26 additions & 1 deletion src/handles/format.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn resolve_position(
}
}

pub fn transform_error(template: String, offset: Int, message: String) {
fn transform_error(template: String, offset: Int, message: String) {
case resolve_position(template, offset, Position(0, 0, 0)) {
Position(_, row, col) ->
Ok(
Expand Down Expand Up @@ -74,3 +74,28 @@ pub fn format_tokenizer_error(
transform_error(template, index, "Tag is of unknown block kind")
}
}

pub fn format_runtime_error(
error: error.RuntimeError,
template: String,
) -> Result(String, Nil) {
case error {
error.UnexpectedTypeError(index, path, got, expected) ->
transform_error(
template,
index,
"Unexpected type of property "
<> string.join(path, ".")
<> ", extepced "
<> string.join(expected, " or ")
<> " but found found "
<> got,
)
error.UnknownPropertyError(index, path) ->
transform_error(
template,
index,
"Unable to resolve property " <> string.join(path, "."),
)
}
}
79 changes: 51 additions & 28 deletions src/handles/internal/ctx_utils.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,31 @@ pub fn drill_ctx(
ctx.Dict(arr) -> {
case list.find(arr, fn(it) { it.key == key }) {
Ok(ctx.Prop(_, value)) -> drill_ctx(rest, value)
Error(_) -> Error(error.UnknownPropertyError([]))
Error(_) -> Error(error.UnknownPropertyError(0, []))
}
}
ctx.List(_) -> Error(error.UnexpectedTypeError([], "List", ["Dict"]))
ctx.Str(_) -> Error(error.UnexpectedTypeError([], "Str", ["Dict"]))
ctx.Int(_) -> Error(error.UnexpectedTypeError([], "Int", ["Dict"]))
ctx.Float(_) -> Error(error.UnexpectedTypeError([], "Float", ["Dict"]))
ctx.Bool(_) -> Error(error.UnexpectedTypeError([], "Bool", ["Dict"]))
ctx.List(_) -> Error(error.UnexpectedTypeError(0, [], "List", ["Dict"]))
ctx.Str(_) -> Error(error.UnexpectedTypeError(0, [], "Str", ["Dict"]))
ctx.Int(_) -> Error(error.UnexpectedTypeError(0, [], "Int", ["Dict"]))
ctx.Float(_) ->
Error(error.UnexpectedTypeError(0, [], "Float", ["Dict"]))
ctx.Bool(_) -> Error(error.UnexpectedTypeError(0, [], "Bool", ["Dict"]))
}
}
}

pub fn get_property(
index: Int,
path: List(String),
root_ctx: ctx.Value,
) -> Result(String, error.RuntimeError) {
drill_ctx(path, root_ctx)
|> result.map_error(fn(err) {
case err {
error.UnexpectedTypeError(_, got, expected) ->
error.UnexpectedTypeError(path, got, expected)
error.UnknownPropertyError(_) -> error.UnknownPropertyError(path)
error.UnexpectedTypeError(_, _, got, expected) ->
error.UnexpectedTypeError(index, path, got, expected)
error.UnknownPropertyError(_, _) ->
error.UnknownPropertyError(index, path)
}
})
|> result.try(fn(it) {
Expand All @@ -46,59 +49,79 @@ pub fn get_property(
ctx.Int(value) -> value |> int.to_string |> Ok
ctx.Float(value) -> value |> float.to_string |> Ok
ctx.List(_) ->
Error(error.UnexpectedTypeError(path, "List", ["Str", "Int", "Float"]))
Error(
error.UnexpectedTypeError(index, path, "List", ["Str", "Int", "Float"]),
)
ctx.Dict(_) ->
Error(error.UnexpectedTypeError(path, "Dict", ["Str", "Int", "Float"]))
Error(
error.UnexpectedTypeError(index, path, "Dict", ["Str", "Int", "Float"]),
)
ctx.Bool(_) ->
Error(error.UnexpectedTypeError(path, "Bool", ["Str", "Int", "Float"]))
Error(
error.UnexpectedTypeError(index, path, "Bool", ["Str", "Int", "Float"]),
)
}
})
}

pub fn get_list(
index: Int,
path: List(String),
root_ctx: ctx.Value,
) -> Result(List(ctx.Value), error.RuntimeError) {
drill_ctx(path, root_ctx)
|> result.map_error(fn(err) {
case err {
error.UnexpectedTypeError(_, got, expected) ->
error.UnexpectedTypeError(path, got, expected)
error.UnknownPropertyError(_) -> error.UnknownPropertyError(path)
error.UnexpectedTypeError(_, _, got, expected) ->
error.UnexpectedTypeError(index, path, got, expected)
error.UnknownPropertyError(_, _) ->
error.UnknownPropertyError(index, path)
}
})
|> result.try(fn(it) {
case it {
ctx.List(value) -> value |> Ok
ctx.Bool(_) -> Error(error.UnexpectedTypeError(path, "Bool", ["List"]))
ctx.Str(_) -> Error(error.UnexpectedTypeError(path, "Str", ["List"]))
ctx.Int(_) -> Error(error.UnexpectedTypeError(path, "Int", ["List"]))
ctx.Float(_) -> Error(error.UnexpectedTypeError(path, "Float", ["List"]))
ctx.Dict(_) -> Error(error.UnexpectedTypeError(path, "Dict", ["List"]))
ctx.Bool(_) ->
Error(error.UnexpectedTypeError(index, path, "Bool", ["List"]))
ctx.Str(_) ->
Error(error.UnexpectedTypeError(index, path, "Str", ["List"]))
ctx.Int(_) ->
Error(error.UnexpectedTypeError(index, path, "Int", ["List"]))
ctx.Float(_) ->
Error(error.UnexpectedTypeError(index, path, "Float", ["List"]))
ctx.Dict(_) ->
Error(error.UnexpectedTypeError(index, path, "Dict", ["List"]))
}
})
}

pub fn get_bool(
index: Int,
path: List(String),
root_ctx: ctx.Value,
) -> Result(Bool, error.RuntimeError) {
drill_ctx(path, root_ctx)
|> result.map_error(fn(err) {
case err {
error.UnexpectedTypeError(_, got, expected) ->
error.UnexpectedTypeError(path, got, expected)
error.UnknownPropertyError(_) -> error.UnknownPropertyError(path)
error.UnexpectedTypeError(_, _, got, expected) ->
error.UnexpectedTypeError(index, path, got, expected)
error.UnknownPropertyError(_, _) ->
error.UnknownPropertyError(index, path)
}
})
|> result.try(fn(it) {
case it {
ctx.Bool(value) -> value |> Ok
ctx.List(_) -> Error(error.UnexpectedTypeError(path, "List", ["Bool"]))
ctx.Str(_) -> Error(error.UnexpectedTypeError(path, "Str", ["Bool"]))
ctx.Int(_) -> Error(error.UnexpectedTypeError(path, "Int", ["Bool"]))
ctx.Float(_) -> Error(error.UnexpectedTypeError(path, "Float", ["Bool"]))
ctx.Dict(_) -> Error(error.UnexpectedTypeError(path, "Dict", ["Bool"]))
ctx.List(_) ->
Error(error.UnexpectedTypeError(index, path, "List", ["Bool"]))
ctx.Str(_) ->
Error(error.UnexpectedTypeError(index, path, "Str", ["Bool"]))
ctx.Int(_) ->
Error(error.UnexpectedTypeError(index, path, "Int", ["Bool"]))
ctx.Float(_) ->
Error(error.UnexpectedTypeError(index, path, "Float", ["Bool"]))
ctx.Dict(_) ->
Error(error.UnexpectedTypeError(index, path, "Dict", ["Bool"]))
}
})
}
16 changes: 8 additions & 8 deletions src/handles/internal/engine.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ pub fn run(
[] -> builder |> string_builder.to_string |> Ok
[node, ..rest] ->
case node {
parser.Constant(value) -> Ok(value)
parser.Property(path) -> ctx_utils.get_property(path, ctx)
parser.IfBlock(path, children) ->
ctx_utils.get_bool(path, ctx)
parser.Constant(_, value) -> Ok(value)
parser.Property(index, path) -> ctx_utils.get_property(index, path, ctx)
parser.IfBlock(index, path, children) ->
ctx_utils.get_bool(index, path, ctx)
|> result.try(run_if(_, children, ctx))
parser.UnlessBlock(path, children) ->
ctx_utils.get_bool(path, ctx)
parser.UnlessBlock(index, path, children) ->
ctx_utils.get_bool(index, path, ctx)
|> result.map(bool.negate)
|> result.try(run_if(_, children, ctx))
parser.EachBlock(path, children) ->
ctx_utils.get_list(path, ctx)
parser.EachBlock(index, path, children) ->
ctx_utils.get_list(index, path, ctx)
|> result.try(run_each(_, children, string_builder.new()))
}
|> result.try(fn(it) {
Expand Down
34 changes: 18 additions & 16 deletions src/handles/internal/parser.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -2,44 +2,46 @@ import gleam/list
import handles/internal/tokenizer

pub type AST {
Constant(value: String)
Property(path: List(String))
IfBlock(path: List(String), children: List(AST))
UnlessBlock(path: List(String), children: List(AST))
EachBlock(path: List(String), children: List(AST))
Constant(index: Int, value: String)
Property(index: Int, path: List(String))
IfBlock(index: Int, path: List(String), children: List(AST))
UnlessBlock(index: Int, path: List(String), children: List(AST))
EachBlock(index: Int, path: List(String), children: List(AST))
}

pub fn run(tokens: List(tokenizer.Token), ast: List(AST)) -> List(AST) {
case tokens {
[] -> list.reverse(ast)
[head, ..tail] -> {
case head {
tokenizer.Constant(value) -> run(tail, [Constant(value), ..ast])
tokenizer.Property(path) -> run(tail, [Property(path), ..ast])
tokenizer.IfBlockStart(path) -> {
tokenizer.Constant(index, value) ->
run(tail, [Constant(index, value), ..ast])
tokenizer.Property(index, path) ->
run(tail, [Property(index, path), ..ast])
tokenizer.IfBlockStart(index, path) -> {
let children = run(tail, [])
run(list.drop(tail, list.length(children) + 1), [
IfBlock(path, children),
IfBlock(index, path, children),
..ast
])
}
tokenizer.UnlessBlockStart(path) -> {
tokenizer.UnlessBlockStart(index, path) -> {
let children = run(tail, [])
run(list.drop(tail, list.length(children) + 1), [
UnlessBlock(path, children),
UnlessBlock(index, path, children),
..ast
])
}
tokenizer.EachBlockStart(path) -> {
tokenizer.EachBlockStart(index, path) -> {
let children = run(tail, [])
run(list.drop(tail, list.length(children) + 1), [
EachBlock(path, children),
EachBlock(index, path, children),
..ast
])
}
tokenizer.IfBlockEnd -> list.reverse(ast)
tokenizer.UnlessBlockEnd -> list.reverse(ast)
tokenizer.EachBlockEnd -> list.reverse(ast)
tokenizer.IfBlockEnd(_) -> list.reverse(ast)
tokenizer.UnlessBlockEnd(_) -> list.reverse(ast)
tokenizer.EachBlockEnd(_) -> list.reverse(ast)
}
}
}
Expand Down
39 changes: 21 additions & 18 deletions src/handles/internal/tokenizer.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import gleam/string
import handles/error

pub type Token {
Constant(value: String)
Property(path: List(String))
IfBlockStart(path: List(String))
IfBlockEnd
UnlessBlockStart(path: List(String))
UnlessBlockEnd
EachBlockStart(path: List(String))
EachBlockEnd
Constant(index: Int, value: String)
Property(index: Int, path: List(String))
IfBlockStart(index: Int, path: List(String))
IfBlockEnd(index: Int)
UnlessBlockStart(index: Int, path: List(String))
UnlessBlockEnd(index: Int)
EachBlockStart(index: Int, path: List(String))
EachBlockEnd(index: Int)
}

pub fn run(
Expand All @@ -21,7 +21,8 @@ pub fn run(
case input {
"{{/if" <> rest ->
case rest |> string.split_once("}}") {
Ok(#("", rest)) -> run(rest, index + 7, [IfBlockEnd, ..tokens])
Ok(#("", rest)) ->
run(rest, index + 7, [IfBlockEnd(index + 2), ..tokens])
_ -> Error(error.UnexpectedBlockArgument(index + 2))
}
"{{#if" <> rest ->
Expand All @@ -31,7 +32,7 @@ pub fn run(
[""] -> Error(error.MissingBlockArgument(index + 2))
path ->
run(rest, index + 7 + string.length(arg), [
IfBlockStart(path),
IfBlockStart(index + 2, path),
..tokens
])
}
Expand All @@ -40,7 +41,8 @@ pub fn run(

"{{/unless" <> rest ->
case rest |> string.split_once("}}") {
Ok(#("", rest)) -> run(rest, index + 11, [UnlessBlockEnd, ..tokens])
Ok(#("", rest)) ->
run(rest, index + 11, [UnlessBlockEnd(index + 2), ..tokens])
_ -> Error(error.UnexpectedBlockArgument(index + 2))
}
"{{#unless" <> rest ->
Expand All @@ -50,7 +52,7 @@ pub fn run(
[""] -> Error(error.MissingBlockArgument(index + 2))
path ->
run(rest, index + 11 + string.length(arg), [
UnlessBlockStart(path),
UnlessBlockStart(index + 2, path),
..tokens
])
}
Expand All @@ -59,7 +61,8 @@ pub fn run(

"{{/each" <> rest ->
case rest |> string.split_once("}}") {
Ok(#("", rest)) -> run(rest, index + 9, [EachBlockEnd, ..tokens])
Ok(#("", rest)) ->
run(rest, index + 9, [EachBlockEnd(index + 2), ..tokens])
_ -> Error(error.UnexpectedBlockArgument(index + 2))
}
"{{#each" <> rest ->
Expand All @@ -69,7 +72,7 @@ pub fn run(
[""] -> Error(error.MissingBlockArgument(index + 2))
path ->
run(rest, index + 9 + string.length(arg), [
EachBlockStart(path),
EachBlockStart(index + 2, path),
..tokens
])
}
Expand All @@ -87,12 +90,12 @@ pub fn run(
[""] -> Error(error.MissingPropertyPath(index + 2))
["", ""] ->
run(rest, index + 4 + string.length(body), [
Property([]),
Property(index + 2, []),
..tokens
])
path ->
run(rest, index + 4 + string.length(body), [
Property(path),
Property(index + 2, path),
..tokens
])
}
Expand All @@ -103,13 +106,13 @@ pub fn run(
case input |> string.split_once("{{") {
Ok(#(str, rest)) ->
run("{{" <> rest, index + string.length(str), [
Constant(str),
Constant(index, str),
..tokens
])
_ ->
case input {
"" -> Ok(list.reverse(tokens))
str -> Ok(list.reverse([Constant(str), ..tokens]))
str -> Ok(list.reverse([Constant(index, str), ..tokens]))
}
}
}
Expand Down
Loading

0 comments on commit 3fc324f

Please sign in to comment.