%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*- %%%------------------------------------------------------------------- %%% @copyright (C) 2019, aeternity Anstalt %%% @doc %%% Handling FATE code. %%% @end %%% ###REPLACEWITHNOTE### %%%------------------------------------------------------------------- Definitions. DIGIT = [0-9] HEXDIGIT = [0-9a-fA-F] LOWER = [a-z_] UPPER = [A-Z] BASE58 = [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz] BASE64 = [A-Za-z0-9+/=] INT = {DIGIT}+ HEX = 0x{HEXDIGIT}+ OBJECT = @[a-z][a-z]_{BASE58}+ BYTES = #{BASE64}+ WS = [\000-\s] ID = {LOWER}[a-zA-Z0-9_]* STRING = "[^"]*" BITS = (\!)?\<[\s01]*\> Rules. arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}. var{INT} : {token, {var, TokenLine, parse_var(TokenChars)}}. a : {token, {stack, TokenLine}}. true : {token, {boolean, TokenLine, true}}. false : {token, {boolean, TokenLine, false}}. %% ###REPLACEWITHOPTOKENS### FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}. {BYTES} : {token, {bytes, TokenLine, parse_hash(TokenChars)}}. {OBJECT} : {token, {object, TokenLine, parse_object(TokenChars)}}. {ID} : {token, {id, TokenLine, TokenChars}}. {HEX} : {token, {int, TokenLine, parse_hex(TokenChars)}}. {INT} : {token, {int, TokenLine, parse_int(TokenChars)}}. -{INT} : {token, {int, TokenLine, parse_int(TokenChars)}}. %% Due to the definition of STRING the tokens start and end with a quote ". {STRING} : {token, {string, TokenLine, unicode:characters_to_binary( lists:sublist(TokenChars, 2, length(TokenChars) - 2))}}. {BITS} : {token, {bits, TokenLine, bits(TokenChars)}}. %% Symbols \-\> : {token, {to, TokenLine}}. \: : {token, {to, TokenLine}}. \=\> : {token, {arrow, TokenLine}}. \(\| : {token, {start_variant, TokenLine}}. \|\) : {token, {end_variant, TokenLine}}. , : {token, {',', TokenLine}}. \( : {token, {'(', TokenLine}}. \) : {token, {')', TokenLine}}. \[ : {token, {'[', TokenLine}}. \] : {token, {']', TokenLine}}. \{ : {token, {'{', TokenLine}}. \} : {token, {'}', TokenLine}}. \| : {token, {'|', TokenLine}}. \' : {token, {typerep, TokenLine}}. ;;.* : {token, {comment, TokenLine, drop_prefix($;, TokenChars)}}. \. : skip_token. %% Whitespace ignore {WS} : skip_token. %% Comments (TODO: nested comments) . : {error, "Unexpected token: " ++ TokenChars}. Erlang code. -export([scan/1]). -dialyzer({nowarn_function, yyrev/2}). -ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]). -include_lib("aebytecode/include/aeb_fate_opcodes.hrl"). parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16). parse_int(Chars) -> list_to_integer(Chars). parse_arg("arg" ++ N) -> list_to_integer(N). parse_var("var" ++ N) -> list_to_integer(N). parse_hash("#" ++ Chars) -> base64:decode(Chars). parse_object([_|Chars]) -> case aeser_api_encoder:decode(unicode:characters_to_binary(Chars)) of {account_pubkey, Bin} -> {address, Bin}; {contract_pubkey, Bin} -> {contract, Bin}; {oracle_pubkey, Bin} -> {oracle, Bin}; {oracle_query_id, Bin} -> {oracle_query, Bin}; {channel, Bin} -> {channel, Bin}; {signature, Bin} -> {signature, Bin} end. scan(S) -> string(S). drop_prefix(C, [C|Rest]) -> drop_prefix(C, Rest); drop_prefix(_, Tail) -> Tail. bits([$!, $< | Rest]) -> bits(Rest, -1); bits([$< | Rest]) -> bits(Rest, 0). bits([$> |_Rest], Acc) -> Acc; bits([$0 | Rest], Acc) -> bits(Rest, Acc bsl 1); bits([$1 | Rest], Acc) -> bits(Rest, (Acc bsl 1) bor 1); bits([$ | Rest], Acc) -> bits(Rest, Acc).