Skip to content

Commit

Permalink
chore: Parser should be Lexer, and Compiler should be Parser... -_-
Browse files Browse the repository at this point in the history
  • Loading branch information
Olian04 committed Jun 14, 2024
1 parent a12fdb6 commit 4b1c431
Show file tree
Hide file tree
Showing 14 changed files with 427 additions and 399 deletions.
17 changes: 8 additions & 9 deletions src/handles.gleam
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
import gleam/dynamic
import gleam/result
import handles/compiler
import handles/engine
import handles/lexer
import handles/parser

pub type TemplateError {
ParseError(error: parser.ParseError)
CompileError(error: List(compiler.CompileError))
LexError(error: lexer.LexError)
ParseError(error: List(parser.ParseError))
}

pub type Template {
Template(ast: List(compiler.AST))
Template(ast: List(parser.AST))
}

pub fn prepare(template: String) -> Result(Template, TemplateError) {
use tokens <- result.try(
result.map_error(parser.parse(template), fn(err) { ParseError(err) }),
result.map_error(lexer.run(template), fn(err) { LexError(err) }),
)
use ast <- result.try(
result.map_error(
compiler.compile(tokens, ["if", "unless", "each"]),
fn(err) { CompileError(err) },
),
result.map_error(parser.run(tokens, ["if", "unless", "each"]), fn(err) {
ParseError(err)
}),
)
Ok(Template(ast))
}
Expand Down
108 changes: 0 additions & 108 deletions src/handles/compiler.gleam

This file was deleted.

14 changes: 7 additions & 7 deletions src/handles/engine.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import gleam/io
import gleam/list
import gleam/result
import gleam/string_builder
import handles/compiler
import handles/parser

pub type RuntimeError {
UnexpectedTypeError(path: List(String), got: String, expected: List(String))
Expand Down Expand Up @@ -106,7 +106,7 @@ pub fn get_as_list(

fn eval_if(
condition: Bool,
children: List(compiler.AST),
children: List(parser.AST),
ctx: dynamic.Dynamic,
) -> Result(String, RuntimeError) {
case condition {
Expand All @@ -117,7 +117,7 @@ fn eval_if(

fn eval_each(
ctx_list: List(dynamic.Dynamic),
children: List(compiler.AST),
children: List(parser.AST),
) -> Result(String, RuntimeError) {
{
use acc, ctx <- list.fold(ctx_list, Ok(string_builder.new()))
Expand All @@ -129,18 +129,18 @@ fn eval_each(
}

pub fn run(
ast: List(compiler.AST),
ast: List(parser.AST),
ctx: dynamic.Dynamic,
) -> Result(String, RuntimeError) {
{
use acc, it <- list.fold(ast, Ok(string_builder.new()))
use acc <- result.try(acc)
case it {
compiler.Constant(value) -> Ok(string_builder.append(acc, value))
compiler.Property(path) ->
parser.Constant(value) -> Ok(string_builder.append(acc, value))
parser.Property(path) ->
get_as_string(ctx, path)
|> result.map(string_builder.append(acc, _))
compiler.Block(kind, path, children) ->
parser.Block(kind, path, children) ->
case kind {
"if" ->
get_as_bool(ctx, path)
Expand Down
21 changes: 9 additions & 12 deletions src/handles/format.gleam
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import gleam/int
import gleam/list
import gleam/string
import handles/parser
import handles/lexer

type Position {
Position(index: Int, row: Int, col: Int)
Expand Down Expand Up @@ -39,9 +39,9 @@ fn resolve_position(
}
}

pub fn format_parse_error(error: parser.ParseError, template: String) -> String {
pub fn format_parse_error(error: lexer.LexError, template: String) -> String {
case error {
parser.UnexpectedEof(index) ->
lexer.UnexpectedEof(index) ->
case resolve_position(template, index, Position(0, 0, 0)) {
Position(_, row, col) ->
string.concat([
Expand All @@ -54,7 +54,7 @@ pub fn format_parse_error(error: parser.ParseError, template: String) -> String
])
OutOfBounds -> panic as "Unable to resolve error position in template"
}
parser.UnexpectedToken(index, char) ->
lexer.UnexpectedToken(index, char) ->
case resolve_position(template, index, Position(0, 0, 0)) {
Position(_, row, col) ->
string.concat([
Expand All @@ -68,20 +68,17 @@ pub fn format_parse_error(error: parser.ParseError, template: String) -> String
])
OutOfBounds -> panic as "Unable to resolve error position in template"
}
parser.SyntaxError(errors) ->
lexer.SyntaxError(errors) ->
errors
|> list.fold("", fn(acc, err) {
string.concat([acc, "\n", format_syntax_error(err, template)])
})
}
}

pub fn format_syntax_error(
error: parser.SyntaxError,
template: String,
) -> String {
pub fn format_syntax_error(error: lexer.SyntaxError, template: String) -> String {
case error {
parser.EmptyExpression(start, _) ->
lexer.EmptyExpression(start, _) ->
case resolve_position(template, start, Position(0, 0, 0)) {
Position(_, row, col) ->
string.concat([
Expand All @@ -94,7 +91,7 @@ pub fn format_syntax_error(
])
OutOfBounds -> panic as "Unable to resolve error position in template"
}
parser.MissingBlockKind(start, _) ->
lexer.MissingBlockKind(start, _) ->
case resolve_position(template, start, Position(0, 0, 0)) {
Position(_, row, col) ->
string.concat([
Expand All @@ -107,7 +104,7 @@ pub fn format_syntax_error(
])
OutOfBounds -> panic as "Unable to resolve error position in template"
}
parser.UnexpectedBlockArgument(start, _) ->
lexer.UnexpectedBlockArgument(start, _) ->
case resolve_position(template, start, Position(0, 0, 0)) {
Position(_, row, col) ->
string.concat([
Expand Down
122 changes: 122 additions & 0 deletions src/handles/lexer.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import gleam/result
import gleam/string

pub type Token {
Constant(start: Int, end: Int, value: String)
Property(start: Int, end: Int, path: List(String))
BlockStart(start: Int, end: Int, kind: String, path: List(String))
BlockEnd(start: Int, end: Int, kind: String)
}

pub type LexError {
UnexpectedToken(index: Int, str: String)
UnexpectedEof(index: Int)
SyntaxError(errors: List(SyntaxError))
}

pub type SyntaxError {
EmptyExpression(start: Int, end: Int)
MissingBlockKind(start: Int, end: Int)
UnexpectedBlockArgument(start: Int, end: Int)
}

type ParserState {
Static(start: Int, end: Int, str: String)
Tag(start: Int, end: Int, str: String)
TagStart(start: Int)
TagEnd(start: Int)
}

fn step(
state: ParserState,
acc: List(Result(Token, SyntaxError)),
input: String,
) -> Result(List(Result(Token, SyntaxError)), LexError) {
case state {
Static(start, end, str) ->
case string.first(input) {
Ok("{") ->
step(
TagStart(end + 1),
[Ok(Constant(start, end, str)), ..acc],
string.drop_left(input, 1),
)
Ok(char) ->
step(
Static(start, end + 1, string.append(str, char)),
acc,
string.drop_left(input, 1),
)
Error(_) -> Ok([Ok(Constant(start, end, str)), ..acc])
}
Tag(start, end, value) ->
case string.first(input) {
Ok("}") ->
step(
TagEnd(end + 1),
[
{
let val = string.trim(value)
case string.first(val) {
Ok("#") ->
case string.split_once(string.drop_left(val, 1), " ") {
Ok(#(kind, body)) ->
Ok(BlockStart(start, end, kind, string.split(body, ".")))
Error(_) -> Error(MissingBlockKind(start, end))
}
Ok("/") ->
case string.split_once(string.drop_left(val, 1), " ") {
Ok(#(_, _)) -> Error(UnexpectedBlockArgument(start, end))
Error(_) ->
Ok(BlockEnd(start, end, string.drop_left(val, 1)))
}
Ok(_) -> Ok(Property(start, end, string.split(value, ".")))
Error(_) -> Error(EmptyExpression(start, end))
}
},
..acc
],
string.drop_left(input, 1),
)
Ok(char) ->
step(
Tag(start, end + 1, string.append(value, char)),
acc,
string.drop_left(input, 1),
)
Error(_) -> Error(UnexpectedEof(end))
}
TagStart(start) ->
case string.first(input) {
Ok("{") ->
step(Tag(start + 1, start + 1, ""), acc, string.drop_left(input, 1))
Ok(char) -> Error(UnexpectedToken(start, char))
Error(_) -> Error(UnexpectedEof(start))
}
TagEnd(start) ->
case string.first(input) {
Ok("}") ->
step(
Static(start + 1, start + 1, ""),
acc,
string.drop_left(input, 1),
)
Ok(char) -> Error(UnexpectedToken(start, char))
Error(_) -> Error(UnexpectedEof(start))
}
}
}

pub fn run(template: String) -> Result(List(Token), LexError) {
case step(Static(0, 0, ""), [], template) {
Ok(tokens) ->
case
tokens
|> result.partition
{
#(ok, []) -> Ok(ok)
#(_, err) -> Error(SyntaxError(err))
}
Error(err) -> Error(err)
}
}
Loading

0 comments on commit 4b1c431

Please sign in to comment.