Current section
Files
Jump to
Current section
Files
src/gecko.erl
-module(gecko).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gecko.gleam").
-export([gen_naked/2, gen_rule/2, next_opt/2, next/2]).
-export_type([naked/0, token/1, lexer/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.
-type naked() :: {rule, binary()} | naked.
-type token(DRG) :: {token, naked(), fun((binary()) -> DRG), binary()}.
-type lexer(DRH) :: {lexer,
list(fun((binary(), binary(), fun((binary()) -> DRH)) -> gleam@option:option({binary(),
token(DRH)}))),
DRH}.
-file("src/gecko.gleam", 52).
?DOC(
" Creates a token function that matches a literal string.\n"
" \n"
" ## Example\n"
" \n"
" ```gleam\n"
" let lparen = gen_naked(\"(\", fn(_) { OParen })\n"
" ```\n"
" \n"
" ## Parameters\n"
" \n"
" - `s`: The literal string to match\n"
" - `constructor`: Function that takes matched text and returns a token\n"
" \n"
" ## Returns\n"
" \n"
" A `TokenFn` that matches the literal string at the start of input.\n"
).
-spec gen_naked(binary(), fun((binary()) -> DRL)) -> fun((binary(), binary(), fun((binary()) -> DRL)) -> gleam@option:option({binary(),
token(DRL)})).
gen_naked(S, Constructor) ->
fun(Input, _, _) ->
S_len = string:length(S),
Input_len = string:length(Input),
case (S_len =< Input_len) andalso gleam_stdlib:string_starts_with(
Input,
S
) of
true ->
{some,
{gleam@string:drop_start(Input, S_len),
{token, naked, Constructor, S}}};
false ->
none
end
end.
-file("src/gecko.gleam", 86).
?DOC(
" Creates a token function that matches a regex pattern.\n"
" \n"
" Uses the `gleam_regexp` library for regex matching.\n"
" Supports standard regex syntax as provided by the library.\n"
" \n"
" ## Example\n"
" \n"
" ```gleam\n"
" let identifier = gen_rule(\"[a-zA-Z][a-zA-Z0-9_]*\", Ident)\n"
" let number = gen_rule(\"[1-9][0-9]*\", fn(s) { Number(parse_int(s)) })\n"
" ```\n"
" \n"
" ## Parameters\n"
" \n"
" - `regex`: A regex pattern string\n"
" - `constructor`: Function that takes matched text and returns a token\n"
" \n"
" ## Returns\n"
" \n"
" A `TokenFn` that matches the regex pattern at the start of input.\n"
).
-spec gen_rule(binary(), fun((binary()) -> DRN)) -> fun((binary(), binary(), fun((binary()) -> DRN)) -> gleam@option:option({binary(),
token(DRN)})).
gen_rule(Regex, Constructor) ->
fun(Input, _, _) ->
case gleam@regexp:compile(Regex, {options, false, false}) of
{ok, Compiled} ->
case gleam@regexp:scan(Compiled, Input) of
[Match | _] ->
case gleam_stdlib:string_starts_with(
Input,
erlang:element(2, Match)
) of
true ->
Matched_text = erlang:element(2, Match),
Remaining = gleam@string:drop_start(
Input,
string:length(Matched_text)
),
{some,
{Remaining,
{token,
{rule, Regex},
Constructor,
Matched_text}}};
false ->
none
end;
_ ->
none
end;
{error, _} ->
none
end
end.
-file("src/gecko.gleam", 156).
-spec try_toks(
list(fun((binary(), binary(), fun((binary()) -> DRU)) -> gleam@option:option({binary(),
token(DRU)}))),
binary(),
DRU
) -> gleam@option:option({binary(), DRU}).
try_toks(Toks, Source, Eof) ->
case Toks of
[] ->
none;
[F | Rest] ->
case F(Source, <<""/utf8>>, fun(_) -> Eof end) of
{some, {Remaining, {token, _, Constructor, Word}}} ->
Token = Constructor(Word),
{some, {Remaining, Token}};
none ->
try_toks(Rest, Source, Eof)
end
end.
-file("src/gecko.gleam", 136).
?DOC(
" Attempt to read the next token from the start of `source`.\n"
" - If `source` is empty, returns `Some(#(source, eof))`.\n"
" - Otherwise, tries each token function in order and returns the first match.\n"
" - If no token matches the current input, returns `None`.\n"
).
-spec next_opt(lexer(DRP), binary()) -> gleam@option:option({binary(), DRP}).
next_opt(Lexer, Source) ->
{lexer, Toks, Eof} = Lexer,
Trimmed = gleam@string:trim_start(Source),
case gleam@string:is_empty(Trimmed) of
true ->
{some, {Trimmed, Eof}};
false ->
try_toks(Toks, Trimmed, Eof)
end.
-file("src/gecko.gleam", 149).
?DOC(
" Attempt to read the next token from the start of `source`.\n"
" - If `source` is empty, returns `#(\"\", eof)`.\n"
" - Otherwise, tries each token function in order and returns the first match.\n"
" - If no token matches the caurrent input, returns `#(\"\", eof)`.\n"
).
-spec next(lexer(DRS), binary()) -> {binary(), DRS}.
next(Lexer, Source) ->
case next_opt(Lexer, Source) of
{some, {Source@1, Tk}} ->
{Source@1, Tk};
none ->
{<<""/utf8>>, erlang:element(3, Lexer)}
end.