%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, aeternity Anstalt
%%% @doc
%%%     Handling FATE code.
%%% @end
%%%
%%%   === ===  N O T E :   This file is generated do not edit. === ===
%%%
%%% Source is in aeb_fate_generate_ops.erl
%%%          and aeb_fate_asm_scan.template
%%%-------------------------------------------------------------------

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}}.

RETURN                      : {token, {mnemonic, TokenLine, 'RETURN'}}.
RETURNR                     : {token, {mnemonic, TokenLine, 'RETURNR'}}.
CALL                        : {token, {mnemonic, TokenLine, 'CALL'}}.
CALL_R                      : {token, {mnemonic, TokenLine, 'CALL_R'}}.
CALL_T                      : {token, {mnemonic, TokenLine, 'CALL_T'}}.
CALL_GR                     : {token, {mnemonic, TokenLine, 'CALL_GR'}}.
JUMP                        : {token, {mnemonic, TokenLine, 'JUMP'}}.
JUMPIF                      : {token, {mnemonic, TokenLine, 'JUMPIF'}}.
SWITCH_V2                   : {token, {mnemonic, TokenLine, 'SWITCH_V2'}}.
SWITCH_V3                   : {token, {mnemonic, TokenLine, 'SWITCH_V3'}}.
SWITCH_VN                   : {token, {mnemonic, TokenLine, 'SWITCH_VN'}}.
CALL_VALUE                  : {token, {mnemonic, TokenLine, 'CALL_VALUE'}}.
PUSH                        : {token, {mnemonic, TokenLine, 'PUSH'}}.
DUPA                        : {token, {mnemonic, TokenLine, 'DUPA'}}.
DUP                         : {token, {mnemonic, TokenLine, 'DUP'}}.
POP                         : {token, {mnemonic, TokenLine, 'POP'}}.
INCA                        : {token, {mnemonic, TokenLine, 'INCA'}}.
INC                         : {token, {mnemonic, TokenLine, 'INC'}}.
DECA                        : {token, {mnemonic, TokenLine, 'DECA'}}.
DEC                         : {token, {mnemonic, TokenLine, 'DEC'}}.
ADD                         : {token, {mnemonic, TokenLine, 'ADD'}}.
SUB                         : {token, {mnemonic, TokenLine, 'SUB'}}.
MUL                         : {token, {mnemonic, TokenLine, 'MUL'}}.
DIV                         : {token, {mnemonic, TokenLine, 'DIV'}}.
MOD                         : {token, {mnemonic, TokenLine, 'MOD'}}.
POW                         : {token, {mnemonic, TokenLine, 'POW'}}.
STORE                       : {token, {mnemonic, TokenLine, 'STORE'}}.
SHA3                        : {token, {mnemonic, TokenLine, 'SHA3'}}.
SHA256                      : {token, {mnemonic, TokenLine, 'SHA256'}}.
BLAKE2B                     : {token, {mnemonic, TokenLine, 'BLAKE2B'}}.
LT                          : {token, {mnemonic, TokenLine, 'LT'}}.
GT                          : {token, {mnemonic, TokenLine, 'GT'}}.
EQ                          : {token, {mnemonic, TokenLine, 'EQ'}}.
ELT                         : {token, {mnemonic, TokenLine, 'ELT'}}.
EGT                         : {token, {mnemonic, TokenLine, 'EGT'}}.
NEQ                         : {token, {mnemonic, TokenLine, 'NEQ'}}.
AND                         : {token, {mnemonic, TokenLine, 'AND'}}.
OR                          : {token, {mnemonic, TokenLine, 'OR'}}.
NOT                         : {token, {mnemonic, TokenLine, 'NOT'}}.
TUPLE                       : {token, {mnemonic, TokenLine, 'TUPLE'}}.
ELEMENT                     : {token, {mnemonic, TokenLine, 'ELEMENT'}}.
SETELEMENT                  : {token, {mnemonic, TokenLine, 'SETELEMENT'}}.
MAP_EMPTY                   : {token, {mnemonic, TokenLine, 'MAP_EMPTY'}}.
MAP_LOOKUP                  : {token, {mnemonic, TokenLine, 'MAP_LOOKUP'}}.
MAP_LOOKUPD                 : {token, {mnemonic, TokenLine, 'MAP_LOOKUPD'}}.
MAP_UPDATE                  : {token, {mnemonic, TokenLine, 'MAP_UPDATE'}}.
MAP_DELETE                  : {token, {mnemonic, TokenLine, 'MAP_DELETE'}}.
MAP_MEMBER                  : {token, {mnemonic, TokenLine, 'MAP_MEMBER'}}.
MAP_FROM_LIST               : {token, {mnemonic, TokenLine, 'MAP_FROM_LIST'}}.
MAP_SIZE                    : {token, {mnemonic, TokenLine, 'MAP_SIZE'}}.
MAP_TO_LIST                 : {token, {mnemonic, TokenLine, 'MAP_TO_LIST'}}.
IS_NIL                      : {token, {mnemonic, TokenLine, 'IS_NIL'}}.
CONS                        : {token, {mnemonic, TokenLine, 'CONS'}}.
HD                          : {token, {mnemonic, TokenLine, 'HD'}}.
TL                          : {token, {mnemonic, TokenLine, 'TL'}}.
LENGTH                      : {token, {mnemonic, TokenLine, 'LENGTH'}}.
NIL                         : {token, {mnemonic, TokenLine, 'NIL'}}.
APPEND                      : {token, {mnemonic, TokenLine, 'APPEND'}}.
STR_JOIN                    : {token, {mnemonic, TokenLine, 'STR_JOIN'}}.
INT_TO_STR                  : {token, {mnemonic, TokenLine, 'INT_TO_STR'}}.
ADDR_TO_STR                 : {token, {mnemonic, TokenLine, 'ADDR_TO_STR'}}.
STR_REVERSE                 : {token, {mnemonic, TokenLine, 'STR_REVERSE'}}.
STR_LENGTH                  : {token, {mnemonic, TokenLine, 'STR_LENGTH'}}.
BYTES_TO_INT                : {token, {mnemonic, TokenLine, 'BYTES_TO_INT'}}.
BYTES_TO_STR                : {token, {mnemonic, TokenLine, 'BYTES_TO_STR'}}.
BYTES_CONCAT                : {token, {mnemonic, TokenLine, 'BYTES_CONCAT'}}.
BYTES_SPLIT                 : {token, {mnemonic, TokenLine, 'BYTES_SPLIT'}}.
INT_TO_ADDR                 : {token, {mnemonic, TokenLine, 'INT_TO_ADDR'}}.
VARIANT                     : {token, {mnemonic, TokenLine, 'VARIANT'}}.
VARIANT_TEST                : {token, {mnemonic, TokenLine, 'VARIANT_TEST'}}.
VARIANT_ELEMENT             : {token, {mnemonic, TokenLine, 'VARIANT_ELEMENT'}}.
BITS_NONEA                  : {token, {mnemonic, TokenLine, 'BITS_NONEA'}}.
BITS_NONE                   : {token, {mnemonic, TokenLine, 'BITS_NONE'}}.
BITS_ALLA                   : {token, {mnemonic, TokenLine, 'BITS_ALLA'}}.
BITS_ALL                    : {token, {mnemonic, TokenLine, 'BITS_ALL'}}.
BITS_ALL_N                  : {token, {mnemonic, TokenLine, 'BITS_ALL_N'}}.
BITS_SET                    : {token, {mnemonic, TokenLine, 'BITS_SET'}}.
BITS_CLEAR                  : {token, {mnemonic, TokenLine, 'BITS_CLEAR'}}.
BITS_TEST                   : {token, {mnemonic, TokenLine, 'BITS_TEST'}}.
BITS_SUM                    : {token, {mnemonic, TokenLine, 'BITS_SUM'}}.
BITS_OR                     : {token, {mnemonic, TokenLine, 'BITS_OR'}}.
BITS_AND                    : {token, {mnemonic, TokenLine, 'BITS_AND'}}.
BITS_DIFF                   : {token, {mnemonic, TokenLine, 'BITS_DIFF'}}.
BALANCE                     : {token, {mnemonic, TokenLine, 'BALANCE'}}.
ORIGIN                      : {token, {mnemonic, TokenLine, 'ORIGIN'}}.
CALLER                      : {token, {mnemonic, TokenLine, 'CALLER'}}.
BLOCKHASH                   : {token, {mnemonic, TokenLine, 'BLOCKHASH'}}.
BENEFICIARY                 : {token, {mnemonic, TokenLine, 'BENEFICIARY'}}.
TIMESTAMP                   : {token, {mnemonic, TokenLine, 'TIMESTAMP'}}.
GENERATION                  : {token, {mnemonic, TokenLine, 'GENERATION'}}.
MICROBLOCK                  : {token, {mnemonic, TokenLine, 'MICROBLOCK'}}.
DIFFICULTY                  : {token, {mnemonic, TokenLine, 'DIFFICULTY'}}.
GASLIMIT                    : {token, {mnemonic, TokenLine, 'GASLIMIT'}}.
GAS                         : {token, {mnemonic, TokenLine, 'GAS'}}.
ADDRESS                     : {token, {mnemonic, TokenLine, 'ADDRESS'}}.
GASPRICE                    : {token, {mnemonic, TokenLine, 'GASPRICE'}}.
LOG0                        : {token, {mnemonic, TokenLine, 'LOG0'}}.
LOG1                        : {token, {mnemonic, TokenLine, 'LOG1'}}.
LOG2                        : {token, {mnemonic, TokenLine, 'LOG2'}}.
LOG3                        : {token, {mnemonic, TokenLine, 'LOG3'}}.
LOG4                        : {token, {mnemonic, TokenLine, 'LOG4'}}.
SPEND                       : {token, {mnemonic, TokenLine, 'SPEND'}}.
ORACLE_REGISTER             : {token, {mnemonic, TokenLine, 'ORACLE_REGISTER'}}.
ORACLE_QUERY                : {token, {mnemonic, TokenLine, 'ORACLE_QUERY'}}.
ORACLE_RESPOND              : {token, {mnemonic, TokenLine, 'ORACLE_RESPOND'}}.
ORACLE_EXTEND               : {token, {mnemonic, TokenLine, 'ORACLE_EXTEND'}}.
ORACLE_GET_ANSWER           : {token, {mnemonic, TokenLine, 'ORACLE_GET_ANSWER'}}.
ORACLE_GET_QUESTION         : {token, {mnemonic, TokenLine, 'ORACLE_GET_QUESTION'}}.
ORACLE_QUERY_FEE            : {token, {mnemonic, TokenLine, 'ORACLE_QUERY_FEE'}}.
AENS_RESOLVE                : {token, {mnemonic, TokenLine, 'AENS_RESOLVE'}}.
AENS_PRECLAIM               : {token, {mnemonic, TokenLine, 'AENS_PRECLAIM'}}.
AENS_CLAIM                  : {token, {mnemonic, TokenLine, 'AENS_CLAIM'}}.
AENS_UPDATE                 : {token, {mnemonic, TokenLine, 'AENS_UPDATE'}}.
AENS_TRANSFER               : {token, {mnemonic, TokenLine, 'AENS_TRANSFER'}}.
AENS_REVOKE                 : {token, {mnemonic, TokenLine, 'AENS_REVOKE'}}.
BALANCE_OTHER               : {token, {mnemonic, TokenLine, 'BALANCE_OTHER'}}.
VERIFY_SIG                  : {token, {mnemonic, TokenLine, 'VERIFY_SIG'}}.
VERIFY_SIG_SECP256K1        : {token, {mnemonic, TokenLine, 'VERIFY_SIG_SECP256K1'}}.
CONTRACT_TO_ADDRESS         : {token, {mnemonic, TokenLine, 'CONTRACT_TO_ADDRESS'}}.
AUTH_TX_HASH                : {token, {mnemonic, TokenLine, 'AUTH_TX_HASH'}}.
ORACLE_CHECK                : {token, {mnemonic, TokenLine, 'ORACLE_CHECK'}}.
ORACLE_CHECK_QUERY          : {token, {mnemonic, TokenLine, 'ORACLE_CHECK_QUERY'}}.
IS_ORACLE                   : {token, {mnemonic, TokenLine, 'IS_ORACLE'}}.
IS_CONTRACT                 : {token, {mnemonic, TokenLine, 'IS_CONTRACT'}}.
IS_PAYABLE                  : {token, {mnemonic, TokenLine, 'IS_PAYABLE'}}.
CREATOR                     : {token, {mnemonic, TokenLine, 'CREATOR'}}.
ECVERIFY_SECP256K1          : {token, {mnemonic, TokenLine, 'ECVERIFY_SECP256K1'}}.
ECRECOVER_SECP256K1         : {token, {mnemonic, TokenLine, 'ECRECOVER_SECP256K1'}}.
DEACTIVATE                  : {token, {mnemonic, TokenLine, 'DEACTIVATE'}}.
ABORT                       : {token, {mnemonic, TokenLine, 'ABORT'}}.
EXIT                        : {token, {mnemonic, TokenLine, 'EXIT'}}.
NOP                         : {token, {mnemonic, TokenLine, 'NOP'}}.


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).
