-module(glsql@internal@parser). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/glsql/internal/parser.gleam"). -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(false). -file("src/glsql/internal/parser.gleam", 105). ?DOC(false). -spec skip_statement(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()). skip_statement(Tokens) -> case Tokens of [] -> []; [{positioned, semicolon, _, _} | Rest] -> Rest; [_ | Rest@1] -> skip_statement(Rest@1) end. -file("src/glsql/internal/parser.gleam", 639). ?DOC(false). -spec expect( list(glsql@internal@token:positioned()), glsql@internal@token:token(), binary() ) -> {ok, {integer(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. expect(Tokens, Want, Label) -> case Tokens of [{positioned, T, Pos, _} | Rest] when T =:= Want -> {ok, {Pos, Rest}}; [{positioned, T@1, Pos@1, _} | _] -> {error, {parse_error, <<<<<<<<"Expected `"/utf8, Label/binary>>/binary, "`, found `"/utf8>>/binary, (glsql@internal@token:to_string(T@1))/binary>>/binary, "`"/utf8>>, Pos@1, none}}; [] -> {error, {parse_error, <<<<"Unexpected end of file, expected `"/utf8, Label/binary>>/binary, "`"/utf8>>, 0, none}} end. -file("src/glsql/internal/parser.gleam", 598). ?DOC(false). -spec identifier(list(glsql@internal@token:positioned())) -> {ok, {binary(), integer(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. identifier(Tokens) -> case Tokens of [{positioned, {word, W}, Pos, _} | Rest] -> {ok, {W, Pos, Rest}}; [{positioned, {quoted_ident, W@1}, Pos@1, _} | Rest@1] -> {ok, {W@1, Pos@1, Rest@1}}; [{positioned, T, Pos@2, _} | _] -> {error, {parse_error, <<<<"Expected a name, found `"/utf8, (glsql@internal@token:to_string(T))/binary>>/binary, "`"/utf8>>, Pos@2, none}}; [] -> {error, {parse_error, <<"Unexpected end of file, expected a name"/utf8>>, 0, none}} end. -file("src/glsql/internal/parser.gleam", 402). ?DOC(false). -spec skip_words(list(glsql@internal@token:positioned()), list(binary())) -> list(glsql@internal@token:positioned()). skip_words(Tokens, Words) -> case Tokens of [{positioned, {word, W}, _, _} | Rest] -> case gleam@list:contains(Words, string:lowercase(W)) of true -> skip_words(Rest, Words); false -> Tokens end; _ -> Tokens end. -file("src/glsql/internal/parser.gleam", 445). ?DOC(false). -spec join(binary(), binary()) -> binary(). join(Acc, Word) -> case (Acc =:= <<""/utf8>>) orelse gleam_stdlib:string_ends_with( Acc, <<"("/utf8>> ) of true -> <>; false -> <<<>/binary, Word/binary>> end. -file("src/glsql/internal/parser.gleam", 413). ?DOC(false). -spec take_expression( list(glsql@internal@token:positioned()), binary(), integer() ) -> {binary(), list(glsql@internal@token:positioned())}. take_expression(Tokens, Acc, Depth) -> case Tokens of [] -> {gleam@string:trim(Acc), []}; [{positioned, comma, _, _} | _] when Depth =:= 0 -> {gleam@string:trim(Acc), Tokens}; [{positioned, r_paren, _, _} | _] when Depth =:= 0 -> {gleam@string:trim(Acc), Tokens}; [{positioned, {word, W}, _, _} | Rest] when Depth =:= 0 -> case gleam@list:contains( [<<"not"/utf8>>, <<"null"/utf8>>, <<"primary"/utf8>>, <<"unique"/utf8>>, <<"default"/utf8>>, <<"references"/utf8>>, <<"check"/utf8>>, <<"constraint"/utf8>>, <<"foreign"/utf8>>, <<"generated"/utf8>>, <<"collate"/utf8>>], string:lowercase(W) ) of true -> {gleam@string:trim(Acc), Tokens}; false -> take_expression(Rest, join(Acc, W), Depth) end; [{positioned, l_paren, _, _} | Rest@1] -> take_expression(Rest@1, <>, Depth + 1); [{positioned, r_paren, _, _} | Rest@2] -> take_expression(Rest@2, <>, Depth - 1); [{positioned, {word, W@1}, _, _} | Rest@3] -> take_expression(Rest@3, join(Acc, W@1), Depth); [{positioned, T, _, _} | Rest@4] -> take_expression( Rest@4, <>, Depth ) end. -file("src/glsql/internal/parser.gleam", 378). ?DOC(false). -spec take_parens(list(glsql@internal@token:positioned())) -> {binary(), list(glsql@internal@token:positioned())}. take_parens(Tokens) -> case Tokens of [{positioned, l_paren, _, _} | Rest] -> {Expr, Rest@1} = take_expression(Rest, <<""/utf8>>, 0), case Rest@1 of [{positioned, r_paren, _, _} | Rest@2] -> {Expr, Rest@2}; _ -> {Expr, Rest@1} end; _ -> take_expression(Tokens, <<""/utf8>>, 0) end. -file("src/glsql/internal/parser.gleam", 391). ?DOC(false). -spec discard_parens(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()). discard_parens(Tokens) -> case Tokens of [{positioned, l_paren, _, _} | _] -> {_, Rest} = take_parens(Tokens), Rest; _ -> Tokens end. -file("src/glsql/internal/parser.gleam", 363). ?DOC(false). -spec generated_value(list(glsql@internal@token:positioned())) -> {binary(), list(glsql@internal@token:positioned())}. generated_value(Tokens) -> Identity = case Tokens of [{positioned, {word, W}, _, _} | _] -> string:lowercase(W) =:= <<"identity"/utf8>>; _ -> false end, case {Identity, Tokens} of {true, [_ | Rest]} -> {<<"identity"/utf8>>, discard_parens(Rest)}; {_, _} -> {Expr, Rest@1} = take_parens(Tokens), {Expr, skip_words(Rest@1, [<<"stored"/utf8>>, <<"virtual"/utf8>>])} end. -file("src/glsql/internal/parser.gleam", 612). ?DOC(false). -spec keyword(list(glsql@internal@token:positioned()), binary()) -> {ok, {integer(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. keyword(Tokens, Want) -> case Tokens of [{positioned, {word, W}, Pos, _} | Rest] -> case string:lowercase(W) =:= Want of true -> {ok, {Pos, Rest}}; false -> {error, {parse_error, <<<<<<<<"Expected `"/utf8, Want/binary>>/binary, "`, found `"/utf8>>/binary, W/binary>>/binary, "`"/utf8>>, Pos, none}} end; [{positioned, T, Pos@1, _} | _] -> {error, {parse_error, <<<<<<<<"Expected `"/utf8, Want/binary>>/binary, "`, found `"/utf8>>/binary, (glsql@internal@token:to_string(T))/binary>>/binary, "`"/utf8>>, Pos@1, none}}; [] -> {error, {parse_error, <<<<"Unexpected end of file, expected `"/utf8, Want/binary>>/binary, "`"/utf8>>, 0, none}} end. -file("src/glsql/internal/parser.gleam", 338). ?DOC(false). -spec collect_names(list(glsql@internal@token:positioned()), list(binary())) -> {ok, {list(binary()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. collect_names(Tokens, Acc) -> gleam@result:'try'( identifier(Tokens), fun(_use0) -> {Name, _, Rest} = _use0, case Rest of [{positioned, comma, _, _} | Rest@1] -> collect_names(Rest@1, [Name | Acc]); [{positioned, r_paren, _, _} | Rest@2] -> {ok, {lists:reverse([Name | Acc]), Rest@2}}; [{positioned, T, Pos, _} | _] -> {error, {parse_error, <<<<"Expected `,` or `)`, found `"/utf8, (glsql@internal@token:to_string(T))/binary>>/binary, "`"/utf8>>, Pos, none}}; [] -> {error, {parse_error, <<"Unexpected end of file in column list"/utf8>>, 0, none}} end end ). -file("src/glsql/internal/parser.gleam", 329). ?DOC(false). -spec optional_column_list(list(glsql@internal@token:positioned())) -> {ok, {list(binary()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. optional_column_list(Tokens) -> case Tokens of [{positioned, l_paren, _, _} | Rest] -> collect_names(Rest, []); _ -> {ok, {[], Tokens}} end. -file("src/glsql/internal/parser.gleam", 585). ?DOC(false). -spec qualified_name(list(glsql@internal@token:positioned())) -> {ok, {gleam@option:option(binary()), binary(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. qualified_name(Tokens) -> gleam@result:'try'( identifier(Tokens), fun(_use0) -> {First, _, Rest} = _use0, case Rest of [{positioned, dot, _, _} | Rest@1] -> gleam@result:'try'( identifier(Rest@1), fun(_use0@1) -> {Second, _, Rest@2} = _use0@1, {ok, {{some, First}, Second, Rest@2}} end ); _ -> {ok, {none, First, Rest}} end end ). -file("src/glsql/internal/parser.gleam", 185). ?DOC(false). -spec parse_column_constraints( list(glsql@internal@token:positioned()), list(glsql@internal@ast:column_constraint()) ) -> {ok, {list(glsql@internal@ast:column_constraint()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_column_constraints(Tokens, Acc) -> case Tokens of [{positioned, comma, _, _} | _] -> {ok, {Acc, Tokens}}; [{positioned, r_paren, _, _} | _] -> {ok, {Acc, Tokens}}; [] -> {ok, {Acc, Tokens}}; [{positioned, {word, W}, Pos, _} | Rest] -> case string:lowercase(W) of <<"not"/utf8>> -> gleam@result:'try'( keyword(Rest, <<"null"/utf8>>), fun(_use0) -> {_, Rest@1} = _use0, parse_column_constraints( Rest@1, [{not_null, Pos} | Acc] ) end ); <<"null"/utf8>> -> parse_column_constraints(Rest, [{nullable, Pos} | Acc]); <<"primary"/utf8>> -> gleam@result:'try'( keyword(Rest, <<"key"/utf8>>), fun(_use0@1) -> {_, Rest@2} = _use0@1, parse_column_constraints( Rest@2, [{primary_key, Pos} | Acc] ) end ); <<"unique"/utf8>> -> parse_column_constraints(Rest, [{unique, Pos} | Acc]); <<"default"/utf8>> -> {Expr, Rest@3} = take_expression(Rest, <<""/utf8>>, 0), parse_column_constraints( Rest@3, [{default, Expr, Pos} | Acc] ); <<"check"/utf8>> -> {Expr@1, Rest@4} = take_expression(Rest, <<""/utf8>>, 0), parse_column_constraints( Rest@4, [{check, Expr@1, Pos} | Acc] ); <<"references"/utf8>> -> gleam@result:'try'( qualified_name(Rest), fun(_use0@2) -> {_, Tbl, Rest@5} = _use0@2, gleam@result:'try'( optional_column_list(Rest@5), fun(_use0@3) -> {Cols, Rest@6} = _use0@3, parse_column_constraints( Rest@6, [{references, Tbl, Cols, Pos} | Acc] ) end ) end ); <<"generated"/utf8>> -> Rest@7 = skip_words( Rest, [<<"always"/utf8>>, <<"by"/utf8>>, <<"default"/utf8>>] ), gleam@result:'try'( keyword(Rest@7, <<"as"/utf8>>), fun(_use0@4) -> {_, Rest@8} = _use0@4, {Expr@2, Rest@9} = generated_value(Rest@8), parse_column_constraints( Rest@9, [{default, Expr@2, Pos} | Acc] ) end ); <<"collate"/utf8>> -> gleam@result:'try'( identifier(Rest), fun(_use0@5) -> {_, _, Rest@10} = _use0@5, parse_column_constraints(Rest@10, Acc) end ); Other -> {error, {parse_error, <<<<"Unknown column constraint `"/utf8, W/binary>>/binary, "`"/utf8>>, Pos, glsql@internal@suggest:closest( Other, [<<"not"/utf8>>, <<"null"/utf8>>, <<"primary"/utf8>>, <<"unique"/utf8>>, <<"default"/utf8>>, <<"references"/utf8>>, <<"check"/utf8>>, <<"constraint"/utf8>>, <<"foreign"/utf8>>, <<"generated"/utf8>>, <<"collate"/utf8>>] )}} end; [{positioned, T, Pos@1, _} | _] -> {error, {parse_error, <<<<"Unexpected `"/utf8, (glsql@internal@token:to_string(T))/binary>>/binary, "` in column definition"/utf8>>, Pos@1, none}} end. -file("src/glsql/internal/parser.gleam", 561). ?DOC(false). -spec parse_array_dims(list(glsql@internal@token:positioned()), integer()) -> {integer(), list(glsql@internal@token:positioned())}. parse_array_dims(Tokens, Count) -> case Tokens of [{positioned, l_bracket, _, _}, {positioned, r_bracket, _, _} | Rest] -> parse_array_dims(Rest, Count + 1); _ -> {Count, Tokens} end. -file("src/glsql/internal/parser.gleam", 544). ?DOC(false). -spec collect_args(list(glsql@internal@token:positioned()), list(binary())) -> {ok, {list(binary()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. collect_args(Tokens, Acc) -> case Tokens of [{positioned, {number, N}, _, _}, {positioned, comma, _, _} | Rest] -> collect_args(Rest, [N | Acc]); [{positioned, {number, N@1}, _, _}, {positioned, r_paren, _, _} | Rest@1] -> {ok, {lists:reverse([N@1 | Acc]), Rest@1}}; [{positioned, {word, W}, _, _}, {positioned, r_paren, _, _} | Rest@2] -> {ok, {lists:reverse([W | Acc]), Rest@2}}; [{positioned, _, Pos, _} | _] -> {error, {parse_error, <<"Expected a type argument"/utf8>>, Pos, none}}; [] -> {error, {parse_error, <<"Unexpected end of file in type arguments"/utf8>>, 0, none}} end. -file("src/glsql/internal/parser.gleam", 537). ?DOC(false). -spec parse_type_args(list(glsql@internal@token:positioned())) -> {ok, {list(binary()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_type_args(Tokens) -> case Tokens of [{positioned, l_paren, _, _} | Rest] -> collect_args(Rest, []); _ -> {ok, {[], Tokens}} end. -file("src/glsql/internal/parser.gleam", 525). ?DOC(false). -spec match_words(list(binary()), list(glsql@internal@token:positioned())) -> {ok, list(glsql@internal@token:positioned())} | {error, nil}. match_words(Words, Tokens) -> case {Words, Tokens} of {[], _} -> {ok, Tokens}; {[Want | Rest_words], [{positioned, {word, W}, _, _} | Rest]} -> case string:lowercase(W) =:= Want of true -> match_words(Rest_words, Rest); false -> {error, nil} end; {_, _} -> {error, nil} end. -file("src/glsql/internal/parser.gleam", 508). ?DOC(false). -spec first_matching_name( binary(), list(list(binary())), list(glsql@internal@token:positioned()) ) -> {binary(), list(glsql@internal@token:positioned())}. first_matching_name(Name, Candidates, Tokens) -> case Candidates of [] -> {Name, Tokens}; [Words | Others] -> Wanted = gleam@list:drop(Words, 1), case match_words(Wanted, Tokens) of {ok, Rest} -> {gleam@string:join([Name | Wanted], <<" "/utf8>>), Rest}; {error, nil} -> first_matching_name(Name, Others, Tokens) end end. -file("src/glsql/internal/parser.gleam", 496). ?DOC(false). -spec extend_type_name(binary(), list(glsql@internal@token:positioned())) -> {binary(), list(glsql@internal@token:positioned())}. extend_type_name(Name, Tokens) -> Lowered = string:lowercase(Name), Candidates = gleam@list:filter( [[<<"timestamp"/utf8>>, <<"with"/utf8>>, <<"time"/utf8>>, <<"zone"/utf8>>], [<<"timestamp"/utf8>>, <<"without"/utf8>>, <<"time"/utf8>>, <<"zone"/utf8>>], [<<"time"/utf8>>, <<"with"/utf8>>, <<"time"/utf8>>, <<"zone"/utf8>>], [<<"time"/utf8>>, <<"without"/utf8>>, <<"time"/utf8>>, <<"zone"/utf8>>], [<<"character"/utf8>>, <<"varying"/utf8>>], [<<"bit"/utf8>>, <<"varying"/utf8>>], [<<"double"/utf8>>, <<"precision"/utf8>>]], fun(Words) -> case Words of [First | _] -> First =:= Lowered; [] -> false end end ), first_matching_name(Name, Candidates, Tokens). -file("src/glsql/internal/parser.gleam", 482). ?DOC(false). -spec qualified_type_name(list(glsql@internal@token:positioned())) -> {ok, {gleam@option:option(binary()), binary(), integer(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. qualified_type_name(Tokens) -> gleam@result:'try'( identifier(Tokens), fun(_use0) -> {First, Pos, Rest} = _use0, case Rest of [{positioned, dot, _, _} | Rest@1] -> gleam@result:'try'( identifier(Rest@1), fun(_use0@1) -> {Second, _, Rest@2} = _use0@1, {ok, {{some, First}, Second, Pos, Rest@2}} end ); _ -> {ok, {none, First, Pos, Rest}} end end ). -file("src/glsql/internal/parser.gleam", 464). ?DOC(false). -spec parse_type(list(glsql@internal@token:positioned())) -> {ok, {glsql@internal@ast:sql_type(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_type(Tokens) -> gleam@result:'try'( qualified_type_name(Tokens), fun(_use0) -> {_, Name, Pos, Rest} = _use0, gleam@result:'try'( parse_type_args(Rest), fun(_use0@1) -> {Args, Rest@1} = _use0@1, {Name@1, Rest@2} = extend_type_name(Name, Rest@1), gleam@result:'try'(case Args of [] -> parse_type_args(Rest@2); _ -> {ok, {Args, Rest@2}} end, fun(_use0@2) -> {Args@1, Rest@3} = _use0@2, {Dims, Rest@4} = parse_array_dims(Rest@3, 0), {ok, {{sql_type, Name@1, Args@1, Dims, Pos}, Rest@4}} end) end ) end ). -file("src/glsql/internal/parser.gleam", 170). ?DOC(false). -spec parse_column(list(glsql@internal@token:positioned())) -> {ok, {glsql@internal@ast:column(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_column(Tokens) -> gleam@result:'try'( identifier(Tokens), fun(_use0) -> {Name, Pos, Rest} = _use0, gleam@result:'try'( parse_type(Rest), fun(_use0@1) -> {Sql_type, Rest@1} = _use0@1, gleam@result:'try'( parse_column_constraints(Rest@1, []), fun(_use0@2) -> {Constraints, Rest@2} = _use0@2, {ok, {{column, Name, Sql_type, lists:reverse(Constraints), Pos}, Rest@2}} end ) end ) end ). -file("src/glsql/internal/parser.gleam", 313). ?DOC(false). -spec skip_constraint_name(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()). skip_constraint_name(Tokens) -> case Tokens of [{positioned, {word, W}, _, _} | Rest] -> case string:lowercase(W) of <<"constraint"/utf8>> -> case Rest of [{positioned, {word, _}, _, _} | Rest@1] -> Rest@1; [{positioned, {quoted_ident, _}, _, _} | Rest@2] -> Rest@2; _ -> Rest end; _ -> Tokens end; _ -> Tokens end. -file("src/glsql/internal/parser.gleam", 302). ?DOC(false). -spec continue_table_constraints( list(glsql@internal@token:positioned()), list(glsql@internal@ast:table_constraint()) ) -> {ok, {list(glsql@internal@ast:table_constraint()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. continue_table_constraints(Tokens, Acc) -> case Tokens of [{positioned, comma, _, _} | Rest] -> parse_table_constraints(Rest, Acc); _ -> {ok, {lists:reverse(Acc), Tokens}} end. -file("src/glsql/internal/parser.gleam", 249). ?DOC(false). -spec parse_table_constraints( list(glsql@internal@token:positioned()), list(glsql@internal@ast:table_constraint()) ) -> {ok, {list(glsql@internal@ast:table_constraint()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_table_constraints(Tokens, Acc) -> Tokens@1 = skip_constraint_name(Tokens), case Tokens@1 of [{positioned, {word, W}, Pos, _} | Rest] -> case string:lowercase(W) of <<"primary"/utf8>> -> gleam@result:'try'( keyword(Rest, <<"key"/utf8>>), fun(_use0) -> {_, Rest@1} = _use0, gleam@result:'try'( optional_column_list(Rest@1), fun(_use0@1) -> {Cols, Rest@2} = _use0@1, continue_table_constraints( Rest@2, [{table_primary_key, Cols, Pos} | Acc] ) end ) end ); <<"unique"/utf8>> -> gleam@result:'try'( optional_column_list(Rest), fun(_use0@2) -> {Cols@1, Rest@3} = _use0@2, continue_table_constraints( Rest@3, [{table_unique, Cols@1, Pos} | Acc] ) end ); <<"foreign"/utf8>> -> gleam@result:'try'( keyword(Rest, <<"key"/utf8>>), fun(_use0@3) -> {_, Rest@4} = _use0@3, gleam@result:'try'( optional_column_list(Rest@4), fun(_use0@4) -> {Cols@2, Rest@5} = _use0@4, gleam@result:'try'( keyword(Rest@5, <<"references"/utf8>>), fun(_use0@5) -> {_, Rest@6} = _use0@5, gleam@result:'try'( qualified_name(Rest@6), fun(_use0@6) -> {_, Tbl, Rest@7} = _use0@6, gleam@result:'try'( optional_column_list( Rest@7 ), fun(_use0@7) -> {Ref, Rest@8} = _use0@7, continue_table_constraints( Rest@8, [{table_foreign_key, Cols@2, Tbl, Ref, Pos} | Acc] ) end ) end ) end ) end ) end ); <<"check"/utf8>> -> {Expr, Rest@9} = take_expression(Rest, <<""/utf8>>, 0), continue_table_constraints( Rest@9, [{table_check, Expr, Pos} | Acc] ); Other -> {error, {parse_error, <<<<"Unknown table constraint `"/utf8, W/binary>>/binary, "`"/utf8>>, Pos, glsql@internal@suggest:closest( Other, [<<"not"/utf8>>, <<"null"/utf8>>, <<"primary"/utf8>>, <<"unique"/utf8>>, <<"default"/utf8>>, <<"references"/utf8>>, <<"check"/utf8>>, <<"constraint"/utf8>>, <<"foreign"/utf8>>, <<"generated"/utf8>>, <<"collate"/utf8>>] )}} end; [{positioned, T, Pos@1, _} | _] -> {error, {parse_error, <<<<"Expected a table constraint, found `"/utf8, (glsql@internal@token:to_string(T))/binary>>/binary, "`"/utf8>>, Pos@1, none}}; [] -> {error, {parse_error, <<"Unexpected end of file in table constraints"/utf8>>, 0, none}} end. -file("src/glsql/internal/parser.gleam", 159). ?DOC(false). -spec is_table_constraint(list(glsql@internal@token:positioned())) -> boolean(). is_table_constraint(Tokens) -> case Tokens of [{positioned, {word, W}, _, _} | _] -> case string:lowercase(W) of <<"primary"/utf8>> -> true; <<"unique"/utf8>> -> true; <<"foreign"/utf8>> -> true; <<"check"/utf8>> -> true; <<"constraint"/utf8>> -> true; _ -> false end; _ -> false end. -file("src/glsql/internal/parser.gleam", 137). ?DOC(false). -spec parse_column_list( list(glsql@internal@token:positioned()), list(glsql@internal@ast:column()) ) -> {ok, {list(glsql@internal@ast:column()), list(glsql@internal@ast:table_constraint()), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_column_list(Tokens, Acc) -> case is_table_constraint(Tokens) of true -> gleam@result:'try'( parse_table_constraints(Tokens, []), fun(_use0) -> {Constraints, Rest} = _use0, {ok, {Acc, Constraints, Rest}} end ); false -> gleam@result:'try'( parse_column(Tokens), fun(_use0@1) -> {Column, Rest@1} = _use0@1, case Rest@1 of [{positioned, comma, _, _} | Rest@2] -> parse_column_list(Rest@2, [Column | Acc]); _ -> {ok, {[Column | Acc], [], Rest@1}} end end ) end. -file("src/glsql/internal/parser.gleam", 569). ?DOC(false). -spec skip_if_not_exists(list(glsql@internal@token:positioned())) -> list(glsql@internal@token:positioned()). skip_if_not_exists(Tokens) -> case Tokens of [{positioned, {word, A}, _, _}, {positioned, {word, B}, _, _}, {positioned, {word, C}, _, _} | Rest] -> case {string:lowercase(A), string:lowercase(B), string:lowercase(C)} of {<<"if"/utf8>>, <<"not"/utf8>>, <<"exists"/utf8>>} -> Rest; {_, _, _} -> Tokens end; _ -> Tokens end. -file("src/glsql/internal/parser.gleam", 113). ?DOC(false). -spec parse_create_table(list(glsql@internal@token:positioned())) -> {ok, {glsql@internal@ast:table(), list(glsql@internal@token:positioned())}} | {error, glsql@internal@error:error()}. parse_create_table(Tokens) -> gleam@result:'try'( keyword(Tokens, <<"create"/utf8>>), fun(_use0) -> {Pos, Rest} = _use0, gleam@result:'try'( keyword(Rest, <<"table"/utf8>>), fun(_use0@1) -> {_, Rest@1} = _use0@1, Rest@2 = skip_if_not_exists(Rest@1), gleam@result:'try'( qualified_name(Rest@2), fun(_use0@2) -> {Schema, Name, Rest@3} = _use0@2, gleam@result:'try'( expect(Rest@3, l_paren, <<"("/utf8>>), fun(_use0@3) -> {_, Rest@4} = _use0@3, gleam@result:'try'( parse_column_list(Rest@4, []), fun(_use0@4) -> {Columns, Constraints, Rest@5} = _use0@4, gleam@result:'try'( expect( Rest@5, r_paren, <<")"/utf8>> ), fun(_use0@5) -> {_, Rest@6} = _use0@5, Rest@7 = skip_statement( Rest@6 ), {ok, {{table, Name, Schema, lists:reverse( Columns ), Constraints, Pos}, Rest@7}} end ) end ) end ) end ) end ) end ). -file("src/glsql/internal/parser.gleam", 39). ?DOC(false). -spec parse_statements( list(glsql@internal@token:positioned()), list(glsql@internal@ast:table()) ) -> {ok, list(glsql@internal@ast:table())} | {error, glsql@internal@error:error()}. parse_statements(Tokens, Acc) -> case Tokens of [] -> {ok, Acc}; [{positioned, semicolon, _, _} | Rest] -> parse_statements(Rest, Acc); [{positioned, {symbol, <<"\\"/utf8>>}, _, _} | Rest@1] -> parse_statements(skip_statement(Rest@1), Acc); [{positioned, {word, W}, Pos, _} | Rest@2] -> case string:lowercase(W) of <<"create"/utf8>> -> case Rest@2 of [{positioned, {word, Obj}, Obj_pos, _} | After] -> case string:lowercase(Obj) of <<"table"/utf8>> -> gleam@result:'try'( parse_create_table(Tokens), fun(_use0) -> {Table, Rest@3} = _use0, parse_statements( Rest@3, [Table | Acc] ) end ); Other -> case gleam@list:contains( [<<"index"/utf8>>, <<"unique"/utf8>>, <<"extension"/utf8>>, <<"sequence"/utf8>>, <<"view"/utf8>>, <<"schema"/utf8>>, <<"function"/utf8>>, <<"trigger"/utf8>>, <<"type"/utf8>>, <<"domain"/utf8>>, <<"materialized"/utf8>>, <<"publication"/utf8>>, <<"policy"/utf8>>, <<"aggregate"/utf8>>, <<"operator"/utf8>>, <<"role"/utf8>>, <<"database"/utf8>>], Other ) of true -> parse_statements( skip_statement(After), Acc ); false -> {error, {unknown_statement, Obj, Obj_pos, glsql@internal@suggest:closest( Other, [<<"table"/utf8>> | [<<"index"/utf8>>, <<"unique"/utf8>>, <<"extension"/utf8>>, <<"sequence"/utf8>>, <<"view"/utf8>>, <<"schema"/utf8>>, <<"function"/utf8>>, <<"trigger"/utf8>>, <<"type"/utf8>>, <<"domain"/utf8>>, <<"materialized"/utf8>>, <<"publication"/utf8>>, <<"policy"/utf8>>, <<"aggregate"/utf8>>, <<"operator"/utf8>>, <<"role"/utf8>>, <<"database"/utf8>>]] )}} end end; _ -> {error, {parse_error, <<"Unexpected end of file after `create`"/utf8>>, Pos, none}} end; Other@1 -> case gleam@list:contains( [<<"alter"/utf8>>, <<"drop"/utf8>>, <<"set"/utf8>>, <<"comment"/utf8>>, <<"grant"/utf8>>, <<"revoke"/utf8>>, <<"begin"/utf8>>, <<"commit"/utf8>>, <<"insert"/utf8>>, <<"update"/utf8>>, <<"delete"/utf8>>, <<"select"/utf8>>, <<"truncate"/utf8>>, <<"analyze"/utf8>>, <<"vacuum"/utf8>>, <<"refresh"/utf8>>, <<"reset"/utf8>>, <<"with"/utf8>>], Other@1 ) of true -> parse_statements(skip_statement(Rest@2), Acc); false -> {error, {unknown_statement, W, Pos, glsql@internal@suggest:closest( Other@1, [<<"create"/utf8>>, <<"alter"/utf8>>, <<"drop"/utf8>>, <<"set"/utf8>>, <<"comment"/utf8>>] )}} end end; [{positioned, T, Pos@1, _} | _] -> {error, {parse_error, <<<<"Expected a statement, found `"/utf8, (glsql@internal@token:to_string(T))/binary>>/binary, "`"/utf8>>, Pos@1, none}} end. -file("src/glsql/internal/parser.gleam", 34). ?DOC(false). -spec parse(list(glsql@internal@token:positioned())) -> {ok, glsql@internal@ast:schema_ast()} | {error, glsql@internal@error:error()}. parse(Tokens) -> gleam@result:'try'( parse_statements(Tokens, []), fun(Tables) -> {ok, {schema_ast, lists:reverse(Tables)}} end ).