~hauleth/BARE-Erlang

9945f6d8843daba50877799572d2273943f40a00 — Łukasz Niemier 1 year, 8 months ago 36cbce0 ft/compiler
fix: relax name and type checks
3 files changed, 75 insertions(+), 45 deletions(-)

M src/bare_parse.yrl
M src/bare_scan.xrl
M src/barec.erl
M src/bare_parse.yrl => src/bare_parse.yrl +17 -18
@@ 1,11 1,13 @@
%% @hidden

Terminals
  ktype kenum eol
  '{' '}' ':' '(' ')' '|' '=' '<' '>' '[' ']'
  typename name entry number
  map optional data_fixed.
  name number
  map optional data.

Nonterminals
    defs usertype type field fields primtype union union_type enum enum_fields
    defs usertype type field fields union union_type enum enum_fields
    enum_field maybe_eol.

Rootsymbol defs.


@@ 14,15 16,16 @@ defs -> '$empty' : [].
defs -> usertype : ['$1'].
defs -> usertype eol defs : ['$1' | '$3'].

usertype -> ktype typename type : {'$def', value_of('$2'), '$3'}.
usertype -> kenum typename enum : {'$def', value_of('$2'), '$3'}.
usertype -> ktype name type : {'$def', value_of('$2'), '$3'}.
usertype -> kenum name enum : {'$def', value_of('$2'), '$3'}.

type -> typename : {'$call', value_of('$1')}.
type -> name : maybe_primtype('$1').
type -> '[' number ']' type : {array, '$4', value_of('$2')}.
type -> '[' ']' type : {array, '$3'}.
type -> map '[' primtype ']' type : {map, '$3', '$5'}.
type -> map '[' type ']' type : {map, '$3', '$5'}.
type -> optional '<' type '>' : {optional, '$1'}.
type -> primtype : '$1'.
type -> data : data.
type -> data '<' number '>' : {data, value_of('$3')}.
type -> '{' maybe_eol fields '}'  : {struct, '$3'}.
type -> '(' union ')' : {union, '$2'}.



@@ 32,9 35,6 @@ union -> union_type '|' union : ['$1' | '$3'].
union_type -> type : '$1'.
union_type -> type '=' number : ['$1'|value_of('$3')].

primtype -> data_fixed : value_of('$1').
primtype -> name : primtype('$1').

field -> name ':' type : {value_of('$1'), '$3'}.

fields -> field : ['$1'].


@@ 47,8 47,8 @@ enum_fields -> enum_field : ['$1'].
enum_fields -> enum_field eol : ['$1'].
enum_fields -> enum_field eol enum_fields : ['$1' | '$3'].

enum_field -> entry : value_of('$1').
enum_field -> entry '=' number : [value_of('$1') | value_of('$3')].
enum_field -> name : value_of('$1').
enum_field -> name '=' number : [value_of('$1') | value_of('$3')].

maybe_eol -> '$empty'.
maybe_eol -> eol.


@@ 57,7 57,7 @@ Erlang code.

value_of(Token) -> element(3, Token).

primtype({name, _, Name})
maybe_primtype({name, _, Name})
  when Name =:= uint;
       Name =:= int;
       Name =:= u8; Name =:= u16; Name =:= u32; Name =:= u64;


@@ 65,8 65,7 @@ primtype({name, _, Name})
       Name =:= f32; Name =:= f64;
       Name =:= string;
       Name =:= bool;
       Name =:= void;
       Name =:= data ->
       Name =:= void ->
    Name;
primtype({_, Line, _}) ->
    return_error(Line, "Invalid type").
maybe_primtype({name, _, Name}) ->
    {'$call', Name}.

M src/bare_scan.xrl => src/bare_scan.xrl +5 -14
@@ 1,10 1,11 @@
%% @hidden

Definitions.

DIGIT = [0-9]
NZDIG = [1-9]
UPPER = [A-Z]
LOWER = [a-z]

ALPHA = [A-Za-z]
ALNUM = [A-Za-z0-9_]

WS = [\s\t\r]


@@ 23,9 24,7 @@ enum : {token, {kenum, TokenLine}}.
% Types
map : {token, {map, TokenLine}}.
optional : {token, {optional, TokenLine}}.
data<{NZDIG}{DIGIT}*> :
  S = string:slice(TokenChars, 6, TokenLen - 6),
  {token, {data_fixed, TokenLine, {data, list_to_integer(S)}}}.
data : {token, {data, TokenLine}}.

% Operators ===================================================================



@@ 43,16 42,8 @@ data<{NZDIG}{DIGIT}*> :
[<>] : operator(TokenChars, TokenLine).
[\[\]] : operator(TokenChars, TokenLine).

% Enum values
{UPPER}[A-Z0-9_]* :
  {token, {entry, TokenLine, list_to_atom(TokenChars)}}.

% User-defined typename
{UPPER}{ALNUM}* :
  {token, {typename, TokenLine, list_to_atom(TokenChars)}}.

% Names
{LOWER}{ALNUM}* :
{ALPHA}{ALNUM}* :
  {token, {name, TokenLine, list_to_atom(TokenChars)}}.

{DIGIT}+ :

M src/barec.erl => src/barec.erl +53 -13
@@ 2,30 2,70 @@

-import(erl_syntax, [atom/1, tuple/1, application/2, integer/1, list/1, cons/2, clause/2, function/2]).

-export([forms/2,
         string/2,
-export([string/2, string/3,
         file/1, file/2]).

forms(Name, Source) when is_atom(Name) ->
    S = unicode:characters_to_list(Source),
    {ok, Tokens, _} = bare_scan:string(S),
    {ok, AST} = bare_parse:parse(Tokens),
-define(bool_opt(Opt, Name), (Opt =:= Name orelse Opt =:= {Name, true})).

    build(Name, AST).
%% @equiv string(Name, Source, [])
string(Name, Source) -> string(Name, Source, []).

string(Name, Source) ->
%% @doc Compile given string into module `Name'.
%%
%% @end
string(Name, Source, Opts0) ->
    {Opts1, CompileOpts} = proplists:split(Opts0, [forms, binary, load, file]),
    Opts = lists:flatten(Opts1),
    Load = proplists:get_bool(load, Opts),
    Forms = forms(Name, Source),
    compile:forms(Forms).

    case expected_output(Opts) of
        forms -> Forms;
        {file, Path} ->
            Formatted = erl_prettypr:format(Forms, [{encoding, utf8}]),
            Binary  = unicode:characters_to_binary(Formatted, utf8),
            file:write_file(Path, Binary, [binary, write]);
        binary ->
            FormList = [erl_syntax:revert(F) || F <- erl_syntax:form_list_elements(Forms)],
            case compile:noenv_forms(FormList, [binary | CompileOpts]) of
                {ok, Name, Code} = Ret when Load ->
                    erlang:load_module(Name, Code),
                    Ret;
                {ok, Name, Code, _Warnings} = Ret when Load ->
                    erlang:load_module(Name, Code),
                    Ret;
                Ret ->
                    Ret
            end
    end.

expected_output([]) ->
    binary;
expected_output([Opt | _]) when ?bool_opt(Opt, forms) ->
    forms;
expected_output([Opt | _]) when ?bool_opt(Opt, binary) ->
    binary;
expected_output([{file, Path} | _]) ->
    {file, Path};
expected_output([_ | Rest]) ->
    expected_output(Rest).

file(Path) -> file(Path, []).
file(Path, _Opts) ->
file(Path, Opts) ->
    case file:read_file(Path) of
        {ok, Binary} ->
            Name = to_atom(filename:basename(Path)),
            string(Name, Binary);
            string(Name, Binary, Opts);
        Error -> Error
    end.

forms(Name, Source) when is_atom(Name) ->
    S = unicode:characters_to_list(Source),
    {ok, Tokens, _} = bare_scan:string(S),
    {ok, AST} = bare_parse:parse(Tokens),

    build(Name, AST).

to_atom(Input) -> binary_to_atom(unicode:characters_to_binary(Input), utf8).

build(Name, AST) ->


@@ 40,8 80,8 @@ comment(Node) ->
                                               [{offset, "Z"},
                                                {time_designator, $\s}]),
    C = erl_syntax:comment([" This is generated file, do not edit manually.",
                            " Generated at " ++ DateTime ++ " by BARE compiler",
                            " https://hex.pm/packages/bare by Łukasz Niemier"]),
                        " Generated at " ++ DateTime ++ " by BARE compiler",
                        " https://hex.pm/packages/bare by Łukasz Niemier"]),
    erl_syntax:add_precomments([C], Node).

arity(F) ->