-module(glisp@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([parse/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC("// Parses a list of tokens into an abstract syntax tree expression.\n"). -file("src/glisp/parser.gleam", 32). -spec is_digit(binary()) -> boolean(). is_digit(Token) -> gleam@result:is_ok(gleam_stdlib:parse_int(Token)). -file("src/glisp/parser.gleam", 36). -spec as_int_or(binary(), integer()) -> integer(). as_int_or(Token, Ex) -> gleam@result:unwrap(gleam_stdlib:parse_int(Token), Ex). -file("src/glisp/parser.gleam", 56). -spec flip(list(glisp@ast:expr())) -> list(glisp@ast:expr()). flip(Arr) -> lists:reverse(Arr). -file("src/glisp/parser.gleam", 60). -spec parse_list(list(glisp@ast:expr()), list(binary())) -> {ok, {glisp@ast:expr(), list(binary())}} | {error, binary()}. parse_list(Acc, Tokens) -> case Tokens of [] -> {error, <<"Unclosed list"/utf8>>}; [Head | Rest] -> case Head of <<")"/utf8>> -> {ok, {{list, flip(Acc)}, Rest}}; <<"("/utf8>> -> case parse_list([], Rest) of {ok, {Inner_expr, Remaining}} -> parse_list([Inner_expr | Acc], Remaining); {error, Msg} -> {error, Msg} end; _ -> case parse_tokens([Head]) of {ok, {Item, _}} -> parse_list([Item | Acc], Rest); {error, Msg@1} -> {error, Msg@1} end end end. -file("src/glisp/parser.gleam", 40). -spec parse_tokens(list(binary())) -> {ok, {glisp@ast:expr(), list(binary())}} | {error, binary()}. parse_tokens(Tokens) -> case Tokens of [] -> {error, <<"Unexpected EOF"/utf8>>}; [Head | Rest] -> case Head of <<"("/utf8>> -> parse_list([], Rest); <<")"/utf8>> -> {error, <<"Unexpected ')'"/utf8>>}; _ -> case is_digit(Head) of true -> {ok, {{number, as_int_or(Head, 0)}, Rest}}; false -> {ok, {{atom, Head}, Rest}} end end end. -file("src/glisp/parser.gleam", 24). ?DOC( " This function takes a list of string tokens and attempts to parse them\n" " into a structured expression according to a simple Lisp-like syntax.\n" " It can recognize atoms, numbers, and nested lists.\n" "\n" " ## Examples\n" "\n" " ```\n" " parse([\"(\", \"hello\", \"world\", \")\"])\n" " // -> Ok(List([Atom(\"hello\"), Atom(\"world\")]))\n" "\n" " parse([\"42\"])\n" " // -> Ok(Number(42))\n" "\n" " parse([\"missing_paren\", \"(\"])\n" " // -> Error(\"Unclosed list\")\n" " ```\n" ). -spec parse(list(binary())) -> {ok, glisp@ast:expr()} | {error, binary()}. parse(Tokens) -> case parse_tokens(Tokens) of {ok, {Expr, []}} -> {ok, Expr}; {ok, {_, _}} -> {error, <<"Unexpected tokens after valid expression"/utf8>>}; {error, Msg} -> {error, Msg} end.