more mass renaming
This commit is contained in:
@@ -0,0 +1,693 @@
|
||||
% @doc
|
||||
% type for a GSC AST
|
||||
%
|
||||
% based on so_syntax.erl
|
||||
%
|
||||
% this is the second layer in the parsing pipeline after tokens. From
|
||||
% so_syntax:
|
||||
%
|
||||
% ## Declarations
|
||||
%
|
||||
% A Sophia file consists of a sequence of *declarations* in a layout block.
|
||||
%
|
||||
% ```c
|
||||
% File ::= Block(TopDecl)
|
||||
%
|
||||
% TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
% | 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
||||
% | 'namespace' Con '=' Block(Decl)
|
||||
% | '@compiler' PragmaOp Version
|
||||
% | 'include' String
|
||||
% | Using
|
||||
%
|
||||
% Implement ::= ':' Sep1(Con, ',')
|
||||
%
|
||||
% Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
% | 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
% | 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
% | 'let' Id [':' Type] '=' Expr
|
||||
% | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
% | Using
|
||||
%
|
||||
% FunDecl ::= Id ':' Type // Type signature
|
||||
% | Id Args [':' Type] '=' Block(Stmt) // Definition
|
||||
% | Id Args [':' Type] Block(GuardedDef) // Guarded definitions
|
||||
%
|
||||
% GuardedDef ::= '|' Sep1(Expr, ',') '=' Block(Stmt)
|
||||
%
|
||||
% Using ::= 'using' Con ['as' Con] [UsingParts]
|
||||
% UsingParts ::= 'for' '[' Sep1(Id, ',') ']'
|
||||
% | 'hiding' '[' Sep1(Id, ',') ']'
|
||||
%
|
||||
% PragmaOp ::= '<' | '=<' | '==' | '>=' | '>'
|
||||
% Version ::= Sep1(Int, '.')
|
||||
%
|
||||
% EModifier ::= 'payable' | 'stateful'
|
||||
% FModifier ::= 'stateful' | 'private'
|
||||
%
|
||||
% Args ::= '(' Sep(Pattern, ',') ')'
|
||||
%
|
||||
% Type ::= Domain '=>' Type // Function type
|
||||
% | Type '(' Sep(Type, ',') ')' // Type application
|
||||
% | '(' Type ')' // Parens
|
||||
% | 'unit' | Sep(Type, '*') // Tuples
|
||||
% | Id | QId | TVar
|
||||
%
|
||||
% Domain ::= Type // Single argument
|
||||
% | '(' Sep(Type, ',') ')' // Multiple arguments
|
||||
% ```
|
||||
-module(gsc_ast).
|
||||
|
||||
%-compile([export_all,nowarn_export_all]).
|
||||
%
|
||||
%%-export_type([
|
||||
%%]).
|
||||
%%
|
||||
%%-export([
|
||||
%% slurp/2
|
||||
%%]).
|
||||
%
|
||||
%-export([
|
||||
% gulp_file/1
|
||||
%]).
|
||||
%
|
||||
%-include("$gsc_include/gsc.hrl").
|
||||
%
|
||||
%%%-----------------------------
|
||||
%%% TYPES: gsc_ast
|
||||
%%%-----------------------------
|
||||
%
|
||||
%
|
||||
%% % placeholders
|
||||
%-type ast_() :: any().
|
||||
%-record(ast_nyi, {tokens = none :: [tk()]}).
|
||||
%-type ast_nyi() :: #ast_nyi{}.
|
||||
%
|
||||
%
|
||||
%% product type: foo * bar * baz
|
||||
%%
|
||||
%% stupid weird implication from bad syntax foresight trying to be
|
||||
%% fancy and overload what parens do is products must always have at
|
||||
%% least two operands; probably this is because `(foo)` is always the
|
||||
%% same as `foo`
|
||||
%%
|
||||
%% - 0-tuple -> `unit`
|
||||
%% - 1-tuple -> type itself
|
||||
%% - 2+ -> here
|
||||
%-record(ast_te_pi,
|
||||
% {types = none :: none | [ast_te_()]}).
|
||||
%
|
||||
%-type ast_type_expr()
|
||||
% :: #ast_te_fn{} % function (string, string) => string
|
||||
% | #ast_te_ap{} % application map(string, int)
|
||||
% | #ast_te_pi{} % product foo * bar * baz
|
||||
% | #ast_te_tk{} % token string int 'a Foo.Bar.baz
|
||||
% | ast_nyi().
|
||||
%-type ast_te() :: ast_type_expr().
|
||||
%
|
||||
%
|
||||
%% ta = type alias
|
||||
%% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%-record(ast_ta,
|
||||
% {alias = none :: none | tk(),
|
||||
% tvars = none :: none | [tk()],
|
||||
% points_to = none :: none | ast_type_expr()}).
|
||||
%
|
||||
%% Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% | 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
%% | 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
%% | 'let' Id [':' Type] '=' Expr
|
||||
%% | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
%% | Using
|
||||
%-type decl() :: #ast_ta{}
|
||||
% | #ast_nyi{}.
|
||||
%
|
||||
%% ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
%-record(ast_ct,
|
||||
% {payable = none :: none | boolean(),
|
||||
% main = none :: none | boolean(),
|
||||
% name = none :: none | tk(),
|
||||
% impls = none :: none | [tk()],
|
||||
% decls = none :: none | [decl()]}).
|
||||
%
|
||||
%-record(ast_td_iface,{}).
|
||||
%-record(ast_td_ns,{}).
|
||||
%-record(ast_td_compiler,{}).
|
||||
%-record(ast_td_include,{}).
|
||||
%-record(ast_using,{}).
|
||||
%
|
||||
%% @doc
|
||||
%% TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
%% | 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
||||
%% | 'namespace' Con '=' Block(Decl)
|
||||
%% | '@compiler' PragmaOp Version
|
||||
%% | 'include' String
|
||||
%% | Using
|
||||
%-type top_decl() :: #ast_ct{}
|
||||
% | #ast_td_iface{}
|
||||
% | #ast_td_ns{}
|
||||
% | #ast_td_compiler{}
|
||||
% | #ast_td_include{}
|
||||
% | #ast_using{}
|
||||
% .
|
||||
%
|
||||
%-record(ast_file,
|
||||
% {top_decls :: [top_decl()]}).
|
||||
%-type ast_file() :: #ast_file{}.
|
||||
%
|
||||
%
|
||||
%-type parse_error_() :: any().
|
||||
%-record(parse_error,
|
||||
% {pos = none :: none | tk_pos(),
|
||||
% msg = "" :: string(),
|
||||
% subs = [] :: [parse_error_()],
|
||||
% extra = none :: any()}).
|
||||
%-type parse_error() :: parse_error().
|
||||
%
|
||||
%
|
||||
%-type ast()
|
||||
% :: #ast_ct{}
|
||||
% | #ast_file{}
|
||||
% | #ast_nyi{}
|
||||
% | #ast_ta{}
|
||||
% | #ast_td_compiler{}
|
||||
% | #ast_td_iface{}
|
||||
% | #ast_td_include{}
|
||||
% | #ast_td_ns{}
|
||||
% | #ast_te_ap{} % application map(string, int)
|
||||
% | #ast_te_fn{} % function (string, string) => string
|
||||
% | #ast_te_pi{} % product foo * bar * baz
|
||||
% | #ast_te_tk{} % token string int 'a Foo.Bar.baz
|
||||
% | #ast_using{}.
|
||||
%
|
||||
%
|
||||
%
|
||||
%
|
||||
%
|
||||
%%%-----------------------------
|
||||
%%% FUNCTIONS
|
||||
%%%-----------------------------
|
||||
%
|
||||
%-spec gulp_file(Tokens) -> Perhaps
|
||||
% when Tokens :: [tk()],
|
||||
% Perhaps :: {gulp, #ast_file{}}
|
||||
% | {error, #parse_error{}}.
|
||||
%
|
||||
%gulp_file([]) ->
|
||||
% {error, empty_file};
|
||||
%gulp_file(Tokens) ->
|
||||
% case gs_tokens:take_block(Tokens) of
|
||||
% {Tokens, []} ->
|
||||
% gulp_block(fun gulp_top_decl/1, Tokens);
|
||||
% %gulp_file2([], [], Tokens);
|
||||
% {A, B} ->
|
||||
% StartPos = gs_tokens:start_pos(A),
|
||||
% ErrPos = gs_tokens:start_pos(B),
|
||||
% Msg = efmt("gulp_file: block starting at ~p ends at ~p instead of EOF",
|
||||
% [StartPos, ErrPos]),
|
||||
% {error, #parse_error{pos = ErrPos, msg = Msg}}
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%
|
||||
%%gulp_file2(AccOks, AccErrs, Tokens = [_ | _]) ->
|
||||
%% % ItemTokens will be nonempty
|
||||
%% {ItemTokens, NewTokens} = gs_tokens:take_block_item(Tokens),
|
||||
%% case gulp_top_decl(ItemTokens) of
|
||||
%% {gulp, Ok} -> gulp_file2([Ok | AccOks], AccErrs, NewTokens);
|
||||
%% Err -> gulp_file2(AccOks, [Err | AccErrs], NewTokens)
|
||||
%% end;
|
||||
%%gulp_file2(AccOks, [], []) ->
|
||||
%% TopDecls = lists:reverse(AccOks),
|
||||
%% {gulp, #ast_file{top_decls = TopDecls}};
|
||||
%%gulp_file2(_, AccErrs, []) ->
|
||||
%% Errs = [#parse_error{pos = Pos} | _]
|
||||
%% = lists:reverse(AccErrs),
|
||||
%% {error, #parse_error{pos = Pos, subs = Errs}}.
|
||||
%
|
||||
%-spec gulp_block(GulpItem, Tokens) -> GulpedItems
|
||||
% when GulpItem :: fun((ItemTokens) -> GulpedItem),
|
||||
% Tokens :: [tk()],
|
||||
% ItemTokens :: Tokens,
|
||||
% GulpedItem :: {gulp, Item} | {error, Reason},
|
||||
% GulpedItems :: {gulp, Items} | {error, Reason},
|
||||
% Items :: [Item],
|
||||
% Item :: ast(),
|
||||
% Reason :: any().
|
||||
%% @doc
|
||||
%% this almost is the familiar `traverse' idiom from Haskell
|
||||
%%
|
||||
%% ghci> :t traverse
|
||||
%% traverse
|
||||
%% :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
|
||||
%% ghci> :t mapM
|
||||
%% mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
|
||||
%%
|
||||
%% (or `mapM' if youre being sloppy)
|
||||
%%
|
||||
%% however in our case our function is actually of
|
||||
%% signature
|
||||
%%
|
||||
%% :: (t a -> f b)
|
||||
%%
|
||||
%% so this is more sophisticated
|
||||
%% @end
|
||||
%
|
||||
%gulp_block(GulpItem, Tokens) ->
|
||||
% gulp_block(GulpItem, [], [], Tokens).
|
||||
%
|
||||
%gulp_block(GulpItem, AccOks, AccErrs, Tokens = [_ | _]) ->
|
||||
% % ItemTokens will be nonempty
|
||||
% {ItemTokens, NewTokens} = gs_tokens:take_block_item(Tokens),
|
||||
% case GulpItem(ItemTokens) of
|
||||
% {gulp, Ok} -> gulp_block(GulpItem, [Ok | AccOks], AccErrs, NewTokens);
|
||||
% Err -> gulp_block(GulpItem, AccOks, [Err | AccErrs], NewTokens)
|
||||
% end;
|
||||
%gulp_block(_, AccOks, [], []) ->
|
||||
% Items = lists:reverse(AccOks),
|
||||
% {gulp, Items};
|
||||
%gulp_block(_, _, AccErrs, []) ->
|
||||
% {error, #parse_error{subs = lists:reverse(AccErrs)}}.
|
||||
%
|
||||
%
|
||||
%
|
||||
%-spec gulp_top_decl(DeclTokens) -> Result
|
||||
% when DeclTokens :: [tk()],
|
||||
% Result :: {gulp, ast()} | {error, any()}.
|
||||
%
|
||||
%% @doc
|
||||
%% TopDecl ::= ['payable'] ['main'] 'contract' Con [Implement] '=' Block(Decl)
|
||||
%% | 'contract' 'interface' Con [Implement] '=' Block(Decl)
|
||||
%% | 'namespace' Con '=' Block(Decl)
|
||||
%% | '@compiler' PragmaOp Version
|
||||
%% | 'include' String
|
||||
%% | Using
|
||||
%% @end
|
||||
%gulp_top_decl(DeclTokens) ->
|
||||
% case gs_tokens:strings(3, DeclTokens) of
|
||||
% ["payable", "contract", "interface"] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% ["contract", "interface" | _] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% ["payable", "main", "contract"] ->
|
||||
% gulp_ct2(#ast_ct{payable = true, main = true},
|
||||
% drop(3, DeclTokens));
|
||||
% ["main", "contract" | _] ->
|
||||
% gulp_ct2(#ast_ct{payable = false, main = true},
|
||||
% drop(2, DeclTokens));
|
||||
% ["payable", "contract" | _] ->
|
||||
% gulp_ct2(#ast_ct{payable = true, main = false},
|
||||
% drop(2, DeclTokens));
|
||||
% ["contract" | _] ->
|
||||
% gulp_ct2(#ast_ct{payable = false, main = false},
|
||||
% drop(1, DeclTokens));
|
||||
% ["namespace" | _] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% ["@", "compiler" | _] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% ["include" | _] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% ["using" | _ ] ->
|
||||
% gulp_nyi(DeclTokens);
|
||||
% _ ->
|
||||
% % decl tokens will always be nonempty
|
||||
% [H = #tk{pos = ErrPos} | _] = DeclTokens,
|
||||
% EMsg = efmt("gulp_top_decl: bad token: ~p; "
|
||||
% "expecting one of: [payable, main, contract, namespace, @compiler, include, using]",
|
||||
% [H]),
|
||||
% {error, #parse_error{pos = ErrPos,
|
||||
% msg = EMsg}}
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%gulp_ct2(Ast, Tokens = [#tk{pos = Pos} | _]) ->
|
||||
% % need to pass through pos for error messages on premature end of
|
||||
% % input... for now it's a fixme thing
|
||||
% gulp_ct3(Ast, Tokens, Pos).
|
||||
%
|
||||
%
|
||||
%% payable main contract X : Y, Z, W = <block>
|
||||
%% ^
|
||||
%gulp_ct3(Ast = #ast_ct{name = none}, Tokens, Pos) ->
|
||||
% NewPos = Pos, %% fixme
|
||||
% case Tokens of
|
||||
% [Name = #tk{type = con} | NewTokens] ->
|
||||
% NewAst = Ast#ast_ct{name = Name},
|
||||
% gulp_ct3(NewAst, NewTokens, NewPos);
|
||||
% [Name | _] ->
|
||||
% {error, {fixme, {bad_contract_name, Name}}};
|
||||
% [] ->
|
||||
% {error, {fixme, no_contract_name}}
|
||||
% end;
|
||||
%% contract X = <block>
|
||||
%% contract X : Y, Z, W = <block>
|
||||
%% ^
|
||||
%gulp_ct3(Ast = #ast_ct{impls = none}, Tokens, Pos) ->
|
||||
% NewPos = Pos, %% fixme
|
||||
% case slurp_ct_impls(Tokens) of
|
||||
% {slurp, Impls, NewTokens} ->
|
||||
% NewAst = Ast#ast_ct{impls = Impls},
|
||||
% gulp_ct3(NewAst, NewTokens, NewPos);
|
||||
% Error ->
|
||||
% Error
|
||||
% end;
|
||||
%% contract X = <block>
|
||||
%% contract X : Y, Z, W = <block>
|
||||
%% ^
|
||||
%gulp_ct3(Ast = #ast_ct{decls = none},
|
||||
% [#tk{string = "="} | Tokens],
|
||||
% _Pos) ->
|
||||
% case gulp_block(fun gulp_decl/1, Tokens) of
|
||||
% {gulp, Decls} ->
|
||||
% Result = Ast#ast_ct{decls = Decls},
|
||||
% {gulp, Result};
|
||||
% Error ->
|
||||
% Error
|
||||
% end;
|
||||
%gulp_ct3(Ast, Tokens, Pos) ->
|
||||
% {error, {fixme, {nyi, gulp_ct3, [Ast, Tokens, Pos]}}}.
|
||||
%
|
||||
%
|
||||
%
|
||||
%-spec slurp_ct_impls(Tokens) -> Slurped
|
||||
% when Tokens :: [tk()],
|
||||
% Slurped :: {slurp, Impls, NewTokens}
|
||||
% | {error, Reason},
|
||||
% Impls :: Tokens,
|
||||
% NewTokens :: Tokens,
|
||||
% Reason :: any().
|
||||
%% @doc ": X, Y, Z = ..." ~> {slurp, [X, Y, Z], "= ..."}
|
||||
%
|
||||
%% FIXME: this should be a restructured a tiny bit for better error
|
||||
%% handling
|
||||
%slurp_ct_impls([_ = #tk{string = ":"},
|
||||
% Con = #tk{type = con}
|
||||
% | NewTokens]) ->
|
||||
% slurp_ct_impls2([Con], NewTokens);
|
||||
%slurp_ct_impls(NewTokens = [#tk{string = "="} | _]) ->
|
||||
% {slurp, [], NewTokens};
|
||||
%slurp_ct_impls([BadToken | _]) ->
|
||||
% Msg = efmt("slurp_ct_impls: expecting (: Con | =), got ~p", [BadToken]),
|
||||
% {error, {fixme, Msg}};
|
||||
%slurp_ct_impls([]) ->
|
||||
% {error, {fixme, "expecting : or =, got end-of-input"}}.
|
||||
%
|
||||
%
|
||||
%slurp_ct_impls2(Stk, [_ = #tk{string = ","},
|
||||
% Con = #tk{type = con}
|
||||
% | NewTokens]) ->
|
||||
% slurp_ct_impls2([Con | Stk], NewTokens);
|
||||
%slurp_ct_impls2(Stk, NewTokens = [#tk{string = "="} | _]) ->
|
||||
% {slurp, lists:reverse(Stk), NewTokens};
|
||||
%slurp_ct_impls2(Stk, BadTokens) ->
|
||||
% {error, {fixme, nyi, slurp_ct_impls2, [Stk, BadTokens]}}.
|
||||
%
|
||||
%
|
||||
%% Decl ::= 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% | 'record' Id ['(' TVar* ')'] '=' RecordType
|
||||
%% | 'datatype' Id ['(' TVar* ')'] '=' DataType
|
||||
%% | 'let' Id [':' Type] '=' Expr
|
||||
%% | (EModifier* 'entrypoint' | FModifier* 'function') Block(FunDecl)
|
||||
%% | Using
|
||||
%gulp_decl(Tokens) ->
|
||||
% case gs_tokens:strings(1, Tokens) of
|
||||
% ["type"] -> gulp_type_alias(Tokens);
|
||||
% _ -> gulp_nyi(Tokens)
|
||||
% end.
|
||||
%
|
||||
%% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%gulp_type_alias(Tokens) ->
|
||||
% gulp_ta(#ast_ta{}, Tokens).
|
||||
%
|
||||
%
|
||||
%% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% ^
|
||||
%gulp_ta(Ast = #ast_ta{alias = none},
|
||||
% _ = [#tk{string = "type"}, Alias = #tk{type = id}
|
||||
% | NewTokens]) ->
|
||||
% NewAst = Ast#ast_ta{alias = Alias},
|
||||
% gulp_ta(NewAst, NewTokens);
|
||||
%% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% ^
|
||||
%gulp_ta(Ast = #ast_ta{tvars = none},
|
||||
% Tokens) ->
|
||||
% case slurp_ta_tvars(Tokens) of
|
||||
% {slurp, TVars, NewTokens} ->
|
||||
% NewAst = Ast#ast_ta{tvars = TVars},
|
||||
% gulp_ta(NewAst, NewTokens);
|
||||
% Error -> Error
|
||||
% end;
|
||||
%% 'type' Id ['(' TVar* ')'] '=' TypeAlias
|
||||
%% ^
|
||||
%gulp_ta(Ast = #ast_ta{points_to = none},
|
||||
% _ = [#tk{string = "="} | NewTokens]) ->
|
||||
% case gulp_type_expr(NewTokens) of
|
||||
% {gulp, TypeExpr} ->
|
||||
% Result = Ast#ast_ta{points_to = TypeExpr},
|
||||
% {gulp, Result};
|
||||
% Error -> Error
|
||||
% end;
|
||||
%gulp_ta(A, B) ->
|
||||
% {error, {fixme, gulp_ta, A, B, ?MODULE, ?LINE}}.
|
||||
%
|
||||
%
|
||||
%% type foo(bar, baz) = quux
|
||||
%% ^
|
||||
%%
|
||||
%% "(bar, baz) = ..." ~> {slurp, [bar, baz], "= ..."}
|
||||
%slurp_ta_tvars(Tks = [#tk{string = "="} | _]) ->
|
||||
% {slurp, [], Tks};
|
||||
%slurp_ta_tvars([#tk{string = "("},
|
||||
% #tk{string = ")"}
|
||||
% | NewTokens]) ->
|
||||
% {slurp, [], NewTokens};
|
||||
%slurp_ta_tvars([_ = #tk{string = "("},
|
||||
% TVar = #tk{type = tvar}
|
||||
% | NewTokens]) ->
|
||||
% slurp_tavars([TVar], NewTokens).
|
||||
%
|
||||
%
|
||||
%slurp_tavars(Stk,
|
||||
% [_ = #tk{string = ","},
|
||||
% TVar = #tk{type = tvar}
|
||||
% | NewTks]) ->
|
||||
% slurp_tavars([TVar | Stk], NewTks);
|
||||
%slurp_tavars(Stk,
|
||||
% [#tk{string = ")"}
|
||||
% | NewTks]) ->
|
||||
% {slurp, lists:reverse(Stk), NewTks}.
|
||||
%
|
||||
%
|
||||
%gulp_type_expr(Tokens) ->
|
||||
% case slurp_type_expr(Tokens) of
|
||||
% {slurp, T, []} -> {gulp, T};
|
||||
% {slurp, _, E} -> {error, {fixme, trailing, E}};
|
||||
% Error -> Error
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%% Type ::= Domain '=>' Type // Function type
|
||||
%% | Type '(' Sep(Type, ',') ')' // Type application
|
||||
%% | '(' Type ')' // Parens
|
||||
%% | 'unit'
|
||||
%% | Sep(Type, '*') // Tuples
|
||||
%% | Id
|
||||
%% | QId
|
||||
%% | TVar
|
||||
%%
|
||||
%% Domain ::= Type // Single argument
|
||||
%% | '(' Sep(Type, ',') ')' // Multiple arguments
|
||||
%
|
||||
%% terminals:
|
||||
%% TkType = id | qid | tvar
|
||||
%% PList = PList0 | PList1 | PList2
|
||||
%% ProdType = Type [* Type]+
|
||||
%% LamType = Type [=> Type]+
|
||||
%%
|
||||
%% PList0 = ()
|
||||
%% PList1 = (Type)
|
||||
%% PList2 = (Type [, Type]+)
|
||||
%%
|
||||
%% Ah ok:
|
||||
%%
|
||||
%% Type1 = TkType | PList(Type)
|
||||
%%
|
||||
%% Type = Type1 % string, (string), (string, string)
|
||||
%% | Type1 => Type % function
|
||||
%% | Type1 PList(Type) % application
|
||||
%% | Type1 * Type % product
|
||||
%
|
||||
%
|
||||
%% each type either starts with an id/qid/tvar token or an open paren
|
||||
%%
|
||||
%% we're going to eliminate open paren cases first:
|
||||
%%
|
||||
%% legal cases:
|
||||
%%
|
||||
%% 1. Function types can have arbitrary #args:
|
||||
%%
|
||||
%% () => ... // legal
|
||||
%% (_) => ... // legal
|
||||
%% (_, _) => ... // legal
|
||||
%%
|
||||
%% 2. Otherwise it must be a plist of ONLY one type
|
||||
%%
|
||||
%% () // illegal, should be "unit"
|
||||
%% (X) // legal, equiv to X
|
||||
%% (X, Y) // illegal, should be X * Y
|
||||
%%
|
||||
%slurp_type_expr(Tks = [#tk{pos = Pos} | _]) ->
|
||||
% case slurp_type1(Tks) of
|
||||
% % plist cases
|
||||
% % function types _ => _
|
||||
% {slurp, {plist, PList}, NewTks} ->
|
||||
% case {PList, NewTks} of
|
||||
% % ANY plist (including (), (foo)) followed by => is fine
|
||||
% % () => _
|
||||
% % (_) => _
|
||||
% % (_, _) => _
|
||||
% {DomainType, [#tk{string = "=>"} | After]} ->
|
||||
% case slurp_type_expr(After) of
|
||||
% {slurp, CodomainType, NewTks} ->
|
||||
% TypeExpr = #ast_te_fn{dom = DomainType,
|
||||
% codom = CodomainType},
|
||||
% {slurp, TypeExpr, NewTks};
|
||||
% Error = {error, _} ->
|
||||
% Error
|
||||
% end;
|
||||
% % WMA not a function type, so only plists with 1 type are
|
||||
% % allowed
|
||||
% {[One], After} ->
|
||||
% slurp_type_expr2(One, After);
|
||||
% % plists of 0 or 2+ not allowed
|
||||
% {[], _} ->
|
||||
% Msg = "() is called unit",
|
||||
% {error, {fixme, ?MODULE, ?LINE, illegal_type, Pos, Msg}};
|
||||
% {_, _} ->
|
||||
% Msg = "(_, _, ...) must be followed by =>; "
|
||||
% "the type for tuples (A, B) is A * B",
|
||||
% {error, {fixme, ?MODULE, ?LINE, illegal_type, Pos, Msg}}
|
||||
% end;
|
||||
% % first token is id|qid|tvar: foo, Foo.bar, 'foo
|
||||
% {slurp, {token, Tk}, NewTks} ->
|
||||
% case NewTks of
|
||||
% % foo => bar is fine, normalized to (foo) => bar
|
||||
% [#tk{string = "=>"} | After] ->
|
||||
% case slurp_type_expr(After) of
|
||||
% {slurp, Codom, NewAfter} ->
|
||||
% ArgType = #ast_te_tk{token = ArgTypeTk},
|
||||
% Dom = [ArgType],
|
||||
% Result = #ast_te_fn{dom = Dom, codom = Codom},
|
||||
% {slurp, Result, NewAfter};
|
||||
% Error = {error, _} ->
|
||||
% Error
|
||||
% end;
|
||||
% {_, _} ->
|
||||
% One = #ast_te_tk{token = Tk},
|
||||
% slurp_type_expr2(One, After)
|
||||
% end;
|
||||
% Error = {error, _} ->
|
||||
% Error
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%% parsed the first type, now need to see if this is an application
|
||||
%% or a product or if we're done
|
||||
%slurp_type_expr2(FirstType, After) ->
|
||||
% % fixme: just going to ignore products and applications for now
|
||||
% {slurp, FirstType, After}.
|
||||
% %case strings(1, After) of
|
||||
% % ["("] -> error(nyi);
|
||||
% % ["*"] -> error(nyi);
|
||||
% %case After of
|
||||
% % [#tk{string = "("} | _] ->
|
||||
% % case slurp_type1_II(After) of
|
||||
% % {slurp, {plist, ArgTypes}, NewAfter} ->
|
||||
% % {slurp, #ast_te_ap{fn = FirstType
|
||||
%
|
||||
%
|
||||
%
|
||||
%
|
||||
%% Type1 = {plist, Types} () (foo) (foo, bar)
|
||||
%% | {token, #tk{}} foo Bar.baz 'quux
|
||||
%slurp_type1(Tks) ->
|
||||
% case gs_tokens:slurp_plist(Tks) of
|
||||
% % head token is NOT open paren -> must be id/qid/tvar
|
||||
% {slurp, [], [Tk | NewTks]} ->
|
||||
% TkType = Tk#tk.type,
|
||||
% case TkType of
|
||||
% id -> {slurp, {token, Tk}, NewTks};
|
||||
% qid -> {slurp, {token, Tk}, NewTks};
|
||||
% tvar -> {slurp, {token, Tk}, NewTks};
|
||||
% _ -> {error, {fixme, illegal_type, Tk, ?MODULE, ?LINE}}
|
||||
% end;
|
||||
% % head token is an open paren, need to recursively consume
|
||||
% % the inner types
|
||||
% {slurp, PListTokens, After} ->
|
||||
% case gulp_ptype1(PListTokens) of
|
||||
% {gulp, Types} -> {slurp, {plist, Types}, After};
|
||||
% Error = {error, _} -> Error
|
||||
% end;
|
||||
% Error = {error, _} -> Error
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%%slurp_type_expr_plist(Tks) ->
|
||||
%% case gs_tokens:slurp_plist(Tks) of
|
||||
%% % head token is NOT open paren -> must be id/qid/tvar
|
||||
%% {slurp, [], [Tk | NewTks]} ->
|
||||
%% TkType = Tk#tk.type,
|
||||
%% case TkType of
|
||||
%% id -> {slurp, {token, Tk}, NewTks};
|
||||
%% qid -> {slurp, {token, Tk}, NewTks};
|
||||
%% tvar -> {slurp, {token, Tk}, NewTks};
|
||||
%% _ -> {error, {fixme, illegal_type, Tk}}
|
||||
%% end;
|
||||
%% % head token is an open paren, need to recursively consume
|
||||
%% % the inner types
|
||||
%% {slurp, PListTokens, After} ->
|
||||
%% case gulp_ptype1(PListTokens) of
|
||||
%% {gulp, Types} -> {slurp, {plist, Types}, After};
|
||||
%% Error = {error, _} -> Error
|
||||
%% end;
|
||||
%% Error = {error, _} -> Error
|
||||
%% end.
|
||||
%
|
||||
%gulp_ptype1([#tk{string = "("}, #tk{string = ")"}]) ->
|
||||
% {gulp, []};
|
||||
%gulp_ptype1([#tk{string = "("} | Tail]) ->
|
||||
% gulp_ptype1_II([], Tail).
|
||||
%
|
||||
%gulp_ptype1_II(Stk, Tks) ->
|
||||
% case slurp_type_expr(Tks) of
|
||||
% {slurp, NewType, [#tk{string = ")"}]} ->
|
||||
% {gulp, lists:reverse([NewType | Stk])};
|
||||
% {slurp, NewType, [#tk{string = ","} | NewTks]} ->
|
||||
% gulp_ptype1_II([NewType | Stk], NewTks);
|
||||
% Error = {error, _} ->
|
||||
% Error
|
||||
% end.
|
||||
%
|
||||
%
|
||||
%%gulp_te_tk([Tk = #tk{type = TkType}])
|
||||
%% when id =:= TkType;
|
||||
%% qid =:= TkType;
|
||||
%% tvar =:= TkType ->
|
||||
%% {gulp, #ast_te_tk{token = Tk}};
|
||||
%%gulp_te_tk(Tks) ->
|
||||
%% {error, {fixme, nyi, gulp_te_tks, Tks}}.
|
||||
%
|
||||
%
|
||||
%gulp_nyi(Tokens) ->
|
||||
% {gulp, #ast_nyi{tokens = Tokens}}.
|
||||
%
|
||||
%
|
||||
%drop(N, [_ | Xs]) when is_integer(N), N >= 1 ->
|
||||
% drop(N-1, Xs);
|
||||
%drop(_, []) ->
|
||||
% [];
|
||||
%drop(0, X) ->
|
||||
% X.
|
||||
%
|
||||
%efmt(Fmt, Args) ->
|
||||
% unicode:characters_to_list(io_lib:format(Fmt, Args)).
|
||||
Reference in New Issue
Block a user