@@ 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}.
@@ 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}+ :
@@ 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) ->