wip restructuring
This commit is contained in:
@@ -0,0 +1,273 @@
|
||||
% @doc experiment centering around the file syntax node using ntree approach
|
||||
-module(gsc_test_file).
|
||||
|
||||
-export([
|
||||
main/0
|
||||
]).
|
||||
|
||||
-include("$gsc_include/gsc.hrl").
|
||||
|
||||
|
||||
-record(ct,
|
||||
{payable = none :: none | false | {true, tk()},
|
||||
main = none :: none | false | {true, tk()},
|
||||
contract = none :: none | tk(),
|
||||
con = none :: none | tk(),
|
||||
impls = none :: none | [tk()],
|
||||
eq = none :: none | tk()}).
|
||||
|
||||
-type meta() :: #ct{}.
|
||||
|
||||
-record(decl_type,
|
||||
{type = none :: none | tk(),
|
||||
id = none :: none | tk(),
|
||||
params = none :: none | [tk()],
|
||||
eq = none :: none | tk()}).
|
||||
|
||||
-type decl_meta() :: #decl_type{}.
|
||||
|
||||
|
||||
-type ast_meta() :: file
|
||||
| meta()
|
||||
| decl_meta()
|
||||
| nyi
|
||||
| {nyi, any()}
|
||||
.
|
||||
|
||||
|
||||
-type target()
|
||||
:: ct
|
||||
| iface
|
||||
| ns
|
||||
| pragma
|
||||
| include
|
||||
| using
|
||||
.
|
||||
|
||||
-type s2t_target()
|
||||
:: file
|
||||
| top_decl
|
||||
| target()
|
||||
| nyi
|
||||
| {nyi, any()}
|
||||
.
|
||||
|
||||
-type s2f_target()
|
||||
:: {block_of, s2t_target()}
|
||||
.
|
||||
|
||||
|
||||
-type ast() :: ntree(ast_meta(), tk()).
|
||||
-type asf() :: nforest(ast_meta(), tk()).
|
||||
|
||||
main() ->
|
||||
HelloN = "hello.aes",
|
||||
HelloP = ts_utils:ct_file_abspath(HelloN),
|
||||
{ok, HelloS} = file:read_file(HelloP),
|
||||
S0 = gsc:unsafe_signal_from_file(HelloP),
|
||||
T1 = s2t(file, S0),
|
||||
io:format("hello.aes:~n", []),
|
||||
io:format("```~n", []),
|
||||
io:format("~ts", [HelloS]),
|
||||
io:format("```~n~n", []),
|
||||
io:format("AST: ~tp~n", [T1]),
|
||||
ok.
|
||||
|
||||
% // Hello World Contract
|
||||
% // Copyright (c) 2025 QPQ AG
|
||||
%
|
||||
% contract Hello =
|
||||
% type state = unit
|
||||
% entrypoint init(): state =
|
||||
% ()
|
||||
%
|
||||
% entrypoint hello(): string =
|
||||
% "hello, world"
|
||||
|
||||
-spec s2t(ParseTarget, Signal) -> AST when
|
||||
ParseTarget :: file,
|
||||
Signal :: [tk()],
|
||||
AST :: ast().
|
||||
|
||||
% File ::= Block(TopDecl)
|
||||
s2t(file, Signal) ->
|
||||
case Signal of
|
||||
[] -> error(empty_file);
|
||||
_ -> {ns, file, s2f({block_of, top_decl}, Signal)}
|
||||
end;
|
||||
% TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
% | ['payable'] 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
||||
% | 'namespace' Con '=' Block(Decl)
|
||||
% | '@compiler' PragmaOp Version
|
||||
% | 'include' String
|
||||
% | Using
|
||||
s2t(top_decl, Signal) ->
|
||||
NewTarget =
|
||||
case gsc_tokens:strings(3, Signal) of
|
||||
["payable", "contract", "interface"] -> iface;
|
||||
["contract", "interface" | _] -> iface;
|
||||
["payable", "main", "contract"] -> ct;
|
||||
["payable", "contract" | _] -> ct;
|
||||
["contract" | _] -> ct;
|
||||
["namespace" | _] -> namespace;
|
||||
["@compiler" | _] -> pragma;
|
||||
["include" | _] -> include;
|
||||
["using" | _] -> using
|
||||
end,
|
||||
s2t(NewTarget, Signal);
|
||||
% ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
s2t(ct, S0) ->
|
||||
{slurp, CtMeta, S1} = s2s_slurp_meta(#ct{}, S0),
|
||||
{ns, CtMeta, s2f({block_of, decl}, S1)};
|
||||
% Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
% | 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
% | 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
% | 'let' Id [':' Type] '=' Expr
|
||||
% | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
% | Using
|
||||
s2t(decl, S0) ->
|
||||
NewTarget =
|
||||
case gsc_tokens:strings(3, S0) of
|
||||
["type" | _] -> decl_type;
|
||||
["record" | _] -> decl_record;
|
||||
["datatype" | _] -> decl_datatype;
|
||||
["let" | _] -> decl_let;
|
||||
Pfx3 ->
|
||||
IsEp = lists:member("entrypoint", Pfx3),
|
||||
IsFn = lists:member("function", Pfx3),
|
||||
if
|
||||
IsEp -> decl_entrypoint;
|
||||
IsFn -> decl_function;
|
||||
true -> error({bad_decl, S0})
|
||||
end
|
||||
end,
|
||||
s2t(NewTarget, S0);
|
||||
% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
s2t(decl_type, S0) ->
|
||||
{slurp, Meta, S1} = s2s_slurp_meta(#decl_type{}, S0),
|
||||
{ns, Meta, s2t(type, S1)};
|
||||
s2t(nyi, Signal) ->
|
||||
{ns, nyi, Signal};
|
||||
s2t(NYI = {nyi, _}, Signal) ->
|
||||
{ns, NYI, Signal};
|
||||
s2t(NYI, Signal) ->
|
||||
{ns, {nyi, NYI}, Signal}.
|
||||
|
||||
|
||||
|
||||
-spec s2f(ForestTarget, Signal) -> Forest when
|
||||
ForestTarget :: s2f_target(),
|
||||
Signal :: [tk()],
|
||||
Forest :: asf().
|
||||
|
||||
s2f({block_of, TreeTarget}, S0) ->
|
||||
{gulp, Items} = gsc_signal:gulp_block_items(S0),
|
||||
[s2t(TreeTarget, I) || I <- Items].
|
||||
|
||||
|
||||
-spec s2s_slurp_meta(InitMeta, Signal) -> Result when
|
||||
InitMeta :: Meta,
|
||||
Signal :: [tk()],
|
||||
Result :: {slurp, Meta, NewSignal},
|
||||
Meta :: ast_meta(),
|
||||
NewSignal :: Signal.
|
||||
|
||||
s2s_slurp_meta(M = #ct{}, S) ->
|
||||
s2s_sm_ct(M, S);
|
||||
s2s_slurp_meta(M = #decl_type{}, S) ->
|
||||
s2s_sm_decl_type(M, S);
|
||||
s2s_slurp_meta(M, S) ->
|
||||
error({s2s_slurp_meta, M, S}).
|
||||
|
||||
|
||||
s2s_sm_ct(Ct = #ct{payable = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "payable"} = T0 | S1] ->
|
||||
s2s_sm_ct(Ct#ct{payable = {true, T0}}, S1);
|
||||
_ ->
|
||||
s2s_sm_ct(Ct#ct{payable = false}, S0)
|
||||
end;
|
||||
s2s_sm_ct(Ct = #ct{main = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "main"} = T0 | S1] ->
|
||||
s2s_sm_ct(Ct#ct{main = {true, T0}}, S1);
|
||||
_ ->
|
||||
s2s_sm_ct(Ct#ct{main = false}, S0)
|
||||
end;
|
||||
s2s_sm_ct(Ct = #ct{contract = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "contract"} = T0 | S1] ->
|
||||
s2s_sm_ct(Ct#ct{contract = T0}, S1);
|
||||
_ ->
|
||||
error({no_kwd_contract, Ct, S0})
|
||||
end;
|
||||
s2s_sm_ct(Ct = #ct{con = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{shape = con} = T0 | S1] ->
|
||||
s2s_sm_ct(Ct#ct{con = T0}, S1);
|
||||
_ ->
|
||||
error({no_contract_name, Ct, S0})
|
||||
end;
|
||||
s2s_sm_ct(Ct = #ct{impls = none}, S0) ->
|
||||
case gsc_tokens:strings(1, S0) of
|
||||
[":"] ->
|
||||
{slurp, Impls, S1} = s2f_slurp_impls(S0),
|
||||
s2s_sm_ct(Ct#ct{impls = Impls}, S1);
|
||||
_ ->
|
||||
s2s_sm_ct(Ct#ct{impls = []}, S0)
|
||||
end;
|
||||
s2s_sm_ct(Ct = #ct{eq = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "="} = T0 | S1] ->
|
||||
s2s_sm_ct(Ct#ct{eq = T0}, S1);
|
||||
_ ->
|
||||
error({no_equal_sign, Ct, S0})
|
||||
end;
|
||||
s2s_sm_ct(Ct, S0) ->
|
||||
{slurp, Ct, S0}.
|
||||
|
||||
s2f_slurp_impls([#tk{str = ":"}, #tk{shape = con} = I0 | S0]) ->
|
||||
s2f_slurp_impls([I0], S0).
|
||||
|
||||
s2f_slurp_impls(Stk, [#tk{str = ","}, #tk{shape = con} = I0 | S0]) ->
|
||||
s2f_slurp_impls([I0 | Stk], S0);
|
||||
s2f_slurp_impls(Stk, S0) ->
|
||||
{slurp, lists:reverse(Stk), S0}.
|
||||
|
||||
|
||||
%-record(decl_type,
|
||||
% {type = none :: none | tk(),
|
||||
% id = none :: none | tk(),
|
||||
% params = none :: none | [tk()],
|
||||
% eq = none :: none | tk()}).
|
||||
|
||||
s2s_sm_decl_type(M = #decl_type{type = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "type"} = T0 | S1] ->
|
||||
s2s_sm_decl_type(M#decl_type{type = T0}, S1);
|
||||
_ ->
|
||||
error({no_kwd_type, S0})
|
||||
end;
|
||||
s2s_sm_decl_type(M = #decl_type{id = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{shape = id} = T0 | S1] ->
|
||||
s2s_sm_decl_type(M#decl_type{id = T0}, S1);
|
||||
_ ->
|
||||
error({no_type_id, S0})
|
||||
end;
|
||||
s2s_sm_decl_type(M = #decl_type{params = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "("} = T0 | _] ->
|
||||
error({fixme, parens_bad});
|
||||
_ ->
|
||||
s2s_sm_decl_type(M#decl_type{params = []}, S0)
|
||||
end;
|
||||
s2s_sm_decl_type(M = #decl_type{eq = none}, S0) ->
|
||||
case S0 of
|
||||
[#tk{str = "="} = T0 | S1] ->
|
||||
s2s_sm_decl_type(M#decl_type{eq = T0}, S1);
|
||||
_ ->
|
||||
error({no_equal_sign, S0})
|
||||
end;
|
||||
s2s_sm_decl_type(M, S0) ->
|
||||
{slurp, M, S0}.
|
||||
Reference in New Issue
Block a user