146 lines
4.1 KiB
Erlang
146 lines
4.1 KiB
Erlang
% This is a header file that contains gsc's record types
|
|
%
|
|
% This is in order to
|
|
% 1. share records across modules; and,
|
|
% 2. allow external modules to just use the gsc records
|
|
|
|
-type tk_shape()
|
|
:: bcom % /* ... */
|
|
| lcom % //
|
|
| ws % whitespace
|
|
% literals
|
|
| char % 'a'
|
|
| string % "foo"
|
|
| int10 % 69_420
|
|
| int16 % 0xDEAD_BEEF
|
|
| bytes % #DEAD_BEEF
|
|
| ak % ak_ABC
|
|
| ct % ct_ABC
|
|
| sg % sg_ABC
|
|
% kwds/variables/etc
|
|
| id % foo, foo_bar, foo_bar'baz' _'foo'
|
|
| con % Foo, Foo_Bar, FooBar
|
|
| qid % Foo.Bar.baz
|
|
| qcon % Foo.Bar.Baz
|
|
| tvar % 'foo, 'foo_bar, '_'foo'_'bar'''
|
|
% kwds ops and punct are all collapsed by
|
|
% so_scan:scan down to eg {'contract', {420, 69}}
|
|
% where {420, 69} is the source location
|
|
% these are three different parsers
|
|
| kwd % contract, interface, payable, etc
|
|
| op % "=!<>+-*/:&|?~@^"
|
|
| punct % ".." | oneof(",.;()[]{}")
|
|
% kwds and punct are kind of the same thing
|
|
% but i'll keep them separate now for my own sanity. ok
|
|
% i guess op or symbol or whatever is fine.
|
|
%
|
|
% not going to overthink. if having them separate
|
|
% becomes an issue it's easy enough to collapse. harder
|
|
% to separate afterward if collapsing is wrong.
|
|
.
|
|
|
|
|
|
-type tk_pos() :: {Line :: pos_integer(), Col :: pos_integer()}.
|
|
|
|
-record(tk,
|
|
{shape :: tk_shape(),
|
|
pos :: tk_pos(),
|
|
str :: string()}).
|
|
|
|
-type tk() :: #tk{}.
|
|
|
|
|
|
% tokens are in essence the "chunk boundaries" of
|
|
% the file
|
|
%
|
|
% because we have semantic whitespace, we have to be
|
|
% careful about block declarations, because we don't
|
|
% have an explicit open/close block token. blocks can
|
|
% be closed in one of two ways:
|
|
%
|
|
% 1. a new block at a previous indent level:
|
|
% switch(foo)
|
|
% // block starts here
|
|
% Bar => bar()
|
|
% Baz => baz()
|
|
% quux() // ends because indent level
|
|
% 2. it's part of some type of list:
|
|
%
|
|
% [switch(foo)
|
|
% // block starts here
|
|
% Bar => bar()
|
|
% Baz => baz(), // ends here
|
|
% switch(bizz)
|
|
% // block starts here
|
|
% Bar => bar()
|
|
% Baz => baz()]
|
|
%
|
|
% in order to avoid speculatively inserting virtual
|
|
% close tokens, at least on first write-out, we're
|
|
% going to disambiguate list notions right away
|
|
|
|
% token groups
|
|
% lists = (_, _, _)
|
|
% | [_, _, _]
|
|
% | {_, _, _}
|
|
%-record(gsc_ast1_block,
|
|
% {indent = none :: none | pos_integer(),
|
|
% decls = none :: [gsc_ast1_decl()]}).
|
|
%
|
|
%-type gsc_ast() ::
|
|
%
|
|
%-type gsc_list_group() :: {'(', [tk()], ')'}
|
|
% | {'[', [tk()], ']'}
|
|
% | {'{', [tk()], '}'}
|
|
% | {proof,
|
|
% .
|
|
|
|
|
|
|
|
% @doc
|
|
% this one is very specific so it deserves its own
|
|
% record type: unterminated block comments at the end
|
|
% of files. these are ok in legacy sophia, so we have to
|
|
% specifically account for this error
|
|
-record(gsc_err_bcom_unterminated,
|
|
{prev_tokens :: [tk()],
|
|
break_pos :: tk_pos(),
|
|
rest :: string()}).
|
|
|
|
-record(gsc_err_no_tokmatch,
|
|
{prev_tokens :: [tk()],
|
|
break_pos :: tk_pos(),
|
|
rest :: string()}).
|
|
|
|
|
|
-record(gsc_err_delims,
|
|
{past :: [tk()],
|
|
open_stack :: [tk()],
|
|
bad_close :: tk(),
|
|
future :: [tk()]}).
|
|
% FIXME
|
|
-record(gsc_err_nyi, {}).
|
|
-record(gsc_err_empty_file, {}).
|
|
|
|
%-record(src_parse_error,
|
|
% {atom = none :: none | atom(),
|
|
% string =
|
|
|
|
%j-record(gsc_err_gulp_ct,
|
|
%j {gulped ::
|
|
|
|
% @doc
|
|
% generic placeholder error for now
|
|
-record(gsc_err,
|
|
{atom :: atom(),
|
|
str = none :: none | iolist(),
|
|
extra = none :: none | any()}).
|
|
|
|
% @doc all errors GSC can return conveniently listed in
|
|
% one place
|
|
-type gsc_err() :: #gsc_err_bcom_unterminated{}
|
|
| #gsc_err_no_tokmatch{}
|
|
| #gsc_err_nyi{}
|
|
| #gsc_err_empty_file{}
|
|
| #gsc_err{}.
|