mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Add constants and string literals to funC
* Add special string literals "..."? (s,a,u,h,) * Add string literal H (256-bit hash) * Add string literal c (crc32) * Use td::hex_encode instead of homebrew function and add test * Fix error codes and use more generic address * Add support for int and slice constants * Add support for strongly typed constants * Add support for precompiled constant expressions (hard!) Co-authored-by: starlightduck <starlightduck@gmail.com>
This commit is contained in:
parent
0e955793ed
commit
0c772185ef
14 changed files with 397 additions and 26 deletions
|
@ -298,9 +298,14 @@ add_library(src_parser ${PARSER_SOURCE})
|
|||
target_include_directories(src_parser PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(src_parser PUBLIC ton_crypto)
|
||||
|
||||
add_library(ton_block ${BLOCK_SOURCE})
|
||||
target_include_directories(ton_block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/block> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_block PUBLIC ton_crypto tdutils tdactor tl_api)
|
||||
|
||||
add_executable(func func/func.cpp ${FUNC_LIB_SOURCE})
|
||||
target_include_directories(func PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||
target_link_libraries(func PUBLIC ton_crypto src_parser git)
|
||||
target_link_libraries(func PUBLIC ton_crypto src_parser git ton_block)
|
||||
if (WINGETOPT_FOUND)
|
||||
target_link_libraries_system(func wingetopt)
|
||||
endif()
|
||||
|
@ -324,11 +329,6 @@ if (WINGETOPT_FOUND)
|
|||
target_link_libraries_system(pow-miner wingetopt)
|
||||
endif()
|
||||
|
||||
add_library(ton_block ${BLOCK_SOURCE})
|
||||
target_include_directories(ton_block PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/block> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..>)
|
||||
target_link_libraries(ton_block PUBLIC ton_crypto tdutils tdactor tl_api)
|
||||
|
||||
set(TURN_OFF_LSAN cd .)
|
||||
if (TON_USE_ASAN AND NOT WIN32)
|
||||
set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0)
|
||||
|
|
|
@ -168,6 +168,11 @@ void VarDescr::set_const(td::RefInt256 value) {
|
|||
}
|
||||
}
|
||||
|
||||
void VarDescr::set_const(std::string value) {
|
||||
str_const = value;
|
||||
val = _Const;
|
||||
}
|
||||
|
||||
void VarDescr::set_const_nan() {
|
||||
set_const(td::make_refint());
|
||||
}
|
||||
|
@ -342,6 +347,11 @@ void Op::show(std::ostream& os, const std::vector<TmpVar>& vars, std::string pfx
|
|||
show_var_list(os, left, vars);
|
||||
os << " := " << int_const << std::endl;
|
||||
break;
|
||||
case _SliceConst:
|
||||
os << pfx << dis << "SCONST ";
|
||||
show_var_list(os, left, vars);
|
||||
os << " := " << str_const << std::endl;
|
||||
break;
|
||||
case _Import:
|
||||
os << pfx << dis << "IMPORT ";
|
||||
show_var_list(os, left, vars);
|
||||
|
|
|
@ -353,6 +353,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
}
|
||||
switch (cl) {
|
||||
case _IntConst:
|
||||
case _SliceConst:
|
||||
case _GlobVar:
|
||||
case _Call:
|
||||
case _CallInd:
|
||||
|
@ -540,6 +541,7 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
|
|||
bool reach;
|
||||
switch (op.cl) {
|
||||
case Op::_IntConst:
|
||||
case Op::_SliceConst:
|
||||
case Op::_GlobVar:
|
||||
case Op::_SetGlob:
|
||||
case Op::_Call:
|
||||
|
@ -707,6 +709,10 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
values.add_newval(left[0]).set_const(int_const);
|
||||
break;
|
||||
}
|
||||
case _SliceConst: {
|
||||
values.add_newval(left[0]).set_const(str_const);
|
||||
break;
|
||||
}
|
||||
case _Call: {
|
||||
prepare_args(values);
|
||||
auto func = dynamic_cast<const SymValAsmFunc*>(fun_ref->value);
|
||||
|
@ -848,6 +854,7 @@ bool Op::mark_noreturn() {
|
|||
// fallthrough
|
||||
case _Import:
|
||||
case _IntConst:
|
||||
case _SliceConst:
|
||||
case _Let:
|
||||
case _Tuple:
|
||||
case _UnTuple:
|
||||
|
|
|
@ -55,10 +55,10 @@ std::ostream& operator<<(std::ostream& os, AsmOp::SReg stack_reg) {
|
|||
}
|
||||
}
|
||||
|
||||
AsmOp AsmOp::Const(int arg, std::string push_op) {
|
||||
AsmOp AsmOp::Const(int arg, std::string push_op, td::RefInt256 origin) {
|
||||
std::ostringstream os;
|
||||
os << arg << ' ' << push_op;
|
||||
return AsmOp::Const(os.str());
|
||||
return AsmOp::Const(os.str(), origin);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::make_stk2(int a, int b, const char* str, int delta) {
|
||||
|
@ -166,27 +166,27 @@ AsmOp AsmOp::UnTuple(int a) {
|
|||
|
||||
AsmOp AsmOp::IntConst(td::RefInt256 x) {
|
||||
if (x->signed_fits_bits(8)) {
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT", x);
|
||||
}
|
||||
if (!x->is_valid()) {
|
||||
return AsmOp::Const("PUSHNAN");
|
||||
return AsmOp::Const("PUSHNAN", x);
|
||||
}
|
||||
int k = is_pos_pow2(x);
|
||||
if (k >= 0) {
|
||||
return AsmOp::Const(k, "PUSHPOW2");
|
||||
return AsmOp::Const(k, "PUSHPOW2", x);
|
||||
}
|
||||
k = is_pos_pow2(x + 1);
|
||||
if (k >= 0) {
|
||||
return AsmOp::Const(k, "PUSHPOW2DEC");
|
||||
return AsmOp::Const(k, "PUSHPOW2DEC", x);
|
||||
}
|
||||
k = is_pos_pow2(-x);
|
||||
if (k >= 0) {
|
||||
return AsmOp::Const(k, "PUSHNEGPOW2");
|
||||
return AsmOp::Const(k, "PUSHNEGPOW2", x);
|
||||
}
|
||||
if (!x->mod_pow2_short(23)) {
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINTX");
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINTX", x);
|
||||
}
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT", x);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::BoolConst(bool f) {
|
||||
|
|
|
@ -27,7 +27,7 @@ using namespace std::literals::string_literals;
|
|||
*
|
||||
*/
|
||||
|
||||
int glob_func_cnt, undef_func_cnt, glob_var_cnt;
|
||||
int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt;
|
||||
std::vector<SymDef*> glob_func, glob_vars;
|
||||
|
||||
SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) {
|
||||
|
|
|
@ -302,6 +302,15 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case _SliceConst: {
|
||||
auto p = next_var_info[left[0]];
|
||||
if (!p || p->is_unused()) {
|
||||
return true;
|
||||
}
|
||||
stack.o << AsmOp::Const("x{" + str_const + "} PUSHSLICE");
|
||||
stack.push_new_var(left[0]);
|
||||
return true;
|
||||
}
|
||||
case _GlobVar:
|
||||
if (dynamic_cast<const SymValGlobVar*>(fun_ref->value)) {
|
||||
bool used = false;
|
||||
|
|
|
@ -109,6 +109,7 @@ enum Keyword {
|
|||
_Infix,
|
||||
_Infixl,
|
||||
_Infixr,
|
||||
_Const,
|
||||
_PragmaHashtag
|
||||
};
|
||||
|
||||
|
@ -336,6 +337,8 @@ struct VarDescr {
|
|||
static constexpr int FiniteUInt = FiniteInt | _Pos;
|
||||
int val;
|
||||
td::RefInt256 int_const;
|
||||
std::string str_const;
|
||||
|
||||
VarDescr(var_idx_t _idx = -1, int _flags = 0, int _val = 0) : idx(_idx), flags(_flags), val(_val) {
|
||||
}
|
||||
bool operator<(var_idx_t other_idx) const {
|
||||
|
@ -406,6 +409,7 @@ struct VarDescr {
|
|||
}
|
||||
void set_const(long long value);
|
||||
void set_const(td::RefInt256 value);
|
||||
void set_const(std::string value);
|
||||
void set_const_nan();
|
||||
void operator+=(const VarDescr& y) {
|
||||
flags &= y.flags;
|
||||
|
@ -530,7 +534,8 @@ struct Op {
|
|||
_While,
|
||||
_Until,
|
||||
_Repeat,
|
||||
_Again
|
||||
_Again,
|
||||
_SliceConst
|
||||
};
|
||||
int cl;
|
||||
enum { _Disabled = 1, _Reachable = 2, _NoReturn = 4, _ImpureR = 8, _ImpureW = 16, _Impure = 24 };
|
||||
|
@ -543,6 +548,7 @@ struct Op {
|
|||
std::vector<var_idx_t> left, right;
|
||||
std::unique_ptr<Op> block0, block1;
|
||||
td::RefInt256 int_const;
|
||||
std::string str_const;
|
||||
Op(const SrcLocation& _where = {}, int _cl = _Undef) : cl(_cl), flags(0), fun_ref(nullptr), where(_where) {
|
||||
}
|
||||
Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left)
|
||||
|
@ -554,6 +560,9 @@ struct Op {
|
|||
Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left, td::RefInt256 _const)
|
||||
: cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(_left), int_const(_const) {
|
||||
}
|
||||
Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left, std::string _const)
|
||||
: cl(_cl), flags(0), fun_ref(nullptr), where(_where), left(_left), str_const(_const) {
|
||||
}
|
||||
Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left, const std::vector<var_idx_t>& _right,
|
||||
SymDef* _fun = nullptr)
|
||||
: cl(_cl), flags(0), fun_ref(_fun), where(_where), left(_left), right(_right) {
|
||||
|
@ -784,6 +793,30 @@ struct SymValGlobVar : sym::SymValBase {
|
|||
}
|
||||
};
|
||||
|
||||
struct SymValConst : sym::SymValBase {
|
||||
td::RefInt256 intval;
|
||||
std::string strval;
|
||||
Keyword type;
|
||||
SymValConst(int idx, td::RefInt256 value)
|
||||
: sym::SymValBase(_Const, idx), intval(value) {
|
||||
type = _Int;
|
||||
}
|
||||
SymValConst(int idx, std::string value)
|
||||
: sym::SymValBase(_Const, idx), strval(value) {
|
||||
type = _Slice;
|
||||
}
|
||||
~SymValConst() override = default;
|
||||
td::RefInt256 get_int_value() const {
|
||||
return intval;
|
||||
}
|
||||
std::string get_str_value() const {
|
||||
return strval;
|
||||
}
|
||||
Keyword get_type() const {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
extern int glob_func_cnt, undef_func_cnt, glob_var_cnt;
|
||||
extern std::vector<SymDef*> glob_func, glob_vars;
|
||||
|
||||
|
@ -820,7 +853,8 @@ struct Expr {
|
|||
_LetFirst,
|
||||
_Hole,
|
||||
_Type,
|
||||
_CondExpr
|
||||
_CondExpr,
|
||||
_SliceConst
|
||||
};
|
||||
int cls;
|
||||
int val{0};
|
||||
|
@ -828,6 +862,7 @@ struct Expr {
|
|||
int flags{0};
|
||||
SrcLocation here;
|
||||
td::RefInt256 intval;
|
||||
std::string strval;
|
||||
SymDef* sym{nullptr};
|
||||
TypeExpr* e_type{nullptr};
|
||||
std::vector<Expr*> args;
|
||||
|
@ -910,6 +945,7 @@ struct AsmOp {
|
|||
int a, b, c;
|
||||
bool gconst{false};
|
||||
std::string op;
|
||||
td::RefInt256 origin;
|
||||
struct SReg {
|
||||
int idx;
|
||||
SReg(int _idx) : idx(_idx) {
|
||||
|
@ -929,6 +965,9 @@ struct AsmOp {
|
|||
AsmOp(int _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) {
|
||||
compute_gconst();
|
||||
}
|
||||
AsmOp(int _t, int _a, int _b, std::string _op, td::RefInt256 x) : t(_t), a(_a), b(_b), op(std::move(_op)), origin(x) {
|
||||
compute_gconst();
|
||||
}
|
||||
AsmOp(int _t, int _a, int _b, int _c) : t(_t), a(_a), b(_b), c(_c) {
|
||||
}
|
||||
AsmOp(int _t, int _a, int _b, int _c, std::string _op) : t(_t), a(_a), b(_b), c(_c), op(std::move(_op)) {
|
||||
|
@ -1047,10 +1086,10 @@ struct AsmOp {
|
|||
static AsmOp make_stk3(int a, int b, int c, const char* str, int delta);
|
||||
static AsmOp IntConst(td::RefInt256 value);
|
||||
static AsmOp BoolConst(bool f);
|
||||
static AsmOp Const(std::string push_op) {
|
||||
return AsmOp(a_const, 0, 1, std::move(push_op));
|
||||
static AsmOp Const(std::string push_op, td::RefInt256 origin = {}) {
|
||||
return AsmOp(a_const, 0, 1, std::move(push_op), origin);
|
||||
}
|
||||
static AsmOp Const(int arg, std::string push_op);
|
||||
static AsmOp Const(int arg, std::string push_op, td::RefInt256 origin = {});
|
||||
static AsmOp Comment(std::string comment) {
|
||||
return AsmOp(a_none, std::string{"// "} + comment);
|
||||
}
|
||||
|
|
|
@ -362,6 +362,11 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
|||
code.close_pop_cur(args[2]->here);
|
||||
return rvect;
|
||||
}
|
||||
case _SliceConst: {
|
||||
auto rvect = new_tmp_vect(code);
|
||||
code.emplace_back(here, Op::_SliceConst, rvect, strval);
|
||||
return rvect;
|
||||
}
|
||||
default:
|
||||
std::cerr << "expression constructor is " << cls << std::endl;
|
||||
throw src::Fatal{"cannot compile expression with unknown constructor"};
|
||||
|
|
|
@ -125,8 +125,8 @@ void define_keywords() {
|
|||
.add_keyword("operator", Kw::_Operator)
|
||||
.add_keyword("infix", Kw::_Infix)
|
||||
.add_keyword("infixl", Kw::_Infixl)
|
||||
.add_keyword("infixr", Kw::_Infixr);
|
||||
|
||||
.add_keyword("infixr", Kw::_Infixr)
|
||||
.add_keyword("const", Kw::_Const);
|
||||
sym::symbols.add_keyword("#pragma", Kw::_PragmaHashtag);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include "func.h"
|
||||
#include "td/utils/crypto.h"
|
||||
#include "common/refint.h"
|
||||
#include "openssl/digest.hpp"
|
||||
#include "block/block.h"
|
||||
#include "block-parse.h"
|
||||
#include <fstream>
|
||||
|
||||
namespace sym {
|
||||
|
@ -229,6 +232,83 @@ void parse_global_var_decl(Lexer& lex) {
|
|||
lex.next();
|
||||
}
|
||||
|
||||
extern int const_cnt;
|
||||
Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false);
|
||||
|
||||
void parse_const_decl(Lexer& lex) {
|
||||
SrcLocation loc = lex.cur().loc;
|
||||
int wanted_type = Expr::_None;
|
||||
if (lex.tp() == _Int) {
|
||||
wanted_type = Expr::_Const;
|
||||
lex.next();
|
||||
} else if (lex.tp() == _Slice) {
|
||||
wanted_type = Expr::_SliceConst;
|
||||
lex.next();
|
||||
}
|
||||
if (lex.tp() != _Ident) {
|
||||
lex.expect(_Ident, "constant name");
|
||||
}
|
||||
loc = lex.cur().loc;
|
||||
SymDef* sym_def = sym::define_global_symbol(lex.cur().val, false, loc);
|
||||
if (!sym_def) {
|
||||
lex.cur().error_at("cannot define global symbol `", "`");
|
||||
}
|
||||
if (sym_def->value) {
|
||||
lex.cur().error_at("global symbol `", "` already exists");
|
||||
}
|
||||
lex.next();
|
||||
if (lex.tp() != '=') {
|
||||
lex.cur().error_at("expected = instead of ", "");
|
||||
}
|
||||
lex.next();
|
||||
CodeBlob code;
|
||||
// Handles processing and resolution of literals and consts
|
||||
auto x = parse_expr(lex, code, false); // also does lex.next() !
|
||||
if (x->flags != Expr::_IsRvalue) {
|
||||
lex.cur().error("expression is not strictly Rvalue");
|
||||
}
|
||||
if ((wanted_type == Expr::_Const) && (x->cls == Expr::_Apply))
|
||||
wanted_type = Expr::_None; // Apply is additionally checked to result in an integer
|
||||
if ((wanted_type != Expr::_None) && (x->cls != wanted_type)) {
|
||||
lex.cur().error("expression type does not match wanted type");
|
||||
}
|
||||
if (x->cls == Expr::_Const) { // Integer constant
|
||||
sym_def->value = new SymValConst{const_cnt++, x->intval};
|
||||
} else if (x->cls == Expr::_SliceConst) { // Slice constant (string)
|
||||
sym_def->value = new SymValConst{const_cnt++, x->strval};
|
||||
} else if (x->cls == Expr::_Apply) {
|
||||
code.emplace_back(loc, Op::_Import, std::vector<var_idx_t>());
|
||||
auto tmp_vars = x->pre_compile(code);
|
||||
code.emplace_back(loc, Op::_Return, std::move(tmp_vars));
|
||||
code.emplace_back(loc, Op::_Nop); // This is neccessary to prevent SIGSEGV!
|
||||
// It is REQUIRED to execute "optimizations" as in func.cpp
|
||||
code.simplify_var_types();
|
||||
code.prune_unreachable_code();
|
||||
code.split_vars(true);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
code.compute_used_code_vars();
|
||||
code.fwd_analyze();
|
||||
code.prune_unreachable_code();
|
||||
}
|
||||
code.mark_noreturn();
|
||||
AsmOpList out_list(0, &code.vars);
|
||||
code.generate_code(out_list);
|
||||
if (out_list.list_.size() != 1) {
|
||||
lex.cur().error("precompiled expression must result in single operation");
|
||||
}
|
||||
auto op = out_list.list_[0];
|
||||
if (!op.is_const()) {
|
||||
lex.cur().error("precompiled expression must result in compilation time constant");
|
||||
}
|
||||
if (op.origin.is_null() || !op.origin->is_valid()) {
|
||||
lex.cur().error("precompiled expression did not result in a valid integer constant");
|
||||
}
|
||||
sym_def->value = new SymValConst{const_cnt++, op.origin};
|
||||
} else {
|
||||
lex.cur().error("integer or slice literal or constant expected");
|
||||
}
|
||||
}
|
||||
|
||||
FormalArgList parse_formal_args(Lexer& lex) {
|
||||
FormalArgList args;
|
||||
lex.expect('(', "formal argument list");
|
||||
|
@ -246,6 +326,18 @@ FormalArgList parse_formal_args(Lexer& lex) {
|
|||
return args;
|
||||
}
|
||||
|
||||
void parse_const_decls(Lexer& lex) {
|
||||
lex.expect(_Const);
|
||||
while (true) {
|
||||
parse_const_decl(lex);
|
||||
if (lex.tp() != ',') {
|
||||
break;
|
||||
}
|
||||
lex.expect(',');
|
||||
}
|
||||
lex.expect(';');
|
||||
}
|
||||
|
||||
TypeExpr* extract_total_arg_type(const FormalArgList& arg_list) {
|
||||
if (arg_list.empty()) {
|
||||
return TypeExpr::new_unit();
|
||||
|
@ -322,8 +414,6 @@ Expr* make_func_apply(Expr* fun, Expr* x) {
|
|||
return res;
|
||||
}
|
||||
|
||||
Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false);
|
||||
|
||||
// parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _
|
||||
Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
||||
if (lex.tp() == '(' || lex.tp() == '[') {
|
||||
|
@ -388,6 +478,87 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
lex.next();
|
||||
return res;
|
||||
}
|
||||
if (t == Lexem::String) {
|
||||
std::string str = lex.cur().str;
|
||||
int str_type = lex.cur().val;
|
||||
Expr* res;
|
||||
switch (str_type) {
|
||||
case 0:
|
||||
case 's':
|
||||
case 'a':
|
||||
{
|
||||
res = new Expr{Expr::_SliceConst, lex.cur().loc};
|
||||
res->e_type = TypeExpr::new_atomic(_Slice);
|
||||
break;
|
||||
}
|
||||
case 'u':
|
||||
case 'h':
|
||||
case 'H':
|
||||
case 'c':
|
||||
{
|
||||
res = new Expr{Expr::_Const, lex.cur().loc};
|
||||
res->e_type = TypeExpr::new_atomic(_Int);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
res = new Expr{Expr::_Const, lex.cur().loc};
|
||||
res->e_type = TypeExpr::new_atomic(_Int);
|
||||
lex.cur().error("invalid string type `" + std::string(1, static_cast<char>(str_type)) + "`");
|
||||
return res;
|
||||
}
|
||||
}
|
||||
res->flags = Expr::_IsRvalue;
|
||||
switch (str_type) {
|
||||
case 0: {
|
||||
res->strval = td::hex_encode(str);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
res->strval = str;
|
||||
unsigned char buff[128];
|
||||
int bits = (int)td::bitstring::parse_bitstring_hex_literal(buff, sizeof(buff), str.data(), str.data() + str.size());
|
||||
if (bits < 0) {
|
||||
lex.cur().error_at("Invalid hex bitstring constant `", "`");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'a': { // MsgAddressInt
|
||||
block::StdAddress a;
|
||||
if (a.parse_addr(str)) {
|
||||
res->strval = block::tlb::MsgAddressInt().pack_std_address(a)->as_bitslice().to_hex();
|
||||
} else {
|
||||
lex.cur().error_at("invalid standard address `", "`");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
res->intval = td::hex_string_to_int256(td::hex_encode(str));
|
||||
if (!str.size()) {
|
||||
lex.cur().error("empty integer ascii-constant");
|
||||
}
|
||||
if (res->intval.is_null()) {
|
||||
lex.cur().error_at("too long integer ascii-constant `", "`");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'h':
|
||||
case 'H':
|
||||
{
|
||||
unsigned char hash[32];
|
||||
digest::hash_str<digest::SHA256>(hash, str.data(), str.size());
|
||||
res->intval = td::bits_to_refint(hash, (str_type == 'h') ? 32 : 256, false);
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
{
|
||||
res->intval = td::make_refint(td::crc32(td::Slice{str}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
lex.next();
|
||||
return res;
|
||||
}
|
||||
if (t == '_') {
|
||||
Expr* res = new Expr{Expr::_Hole, lex.cur().loc};
|
||||
res->val = -1;
|
||||
|
@ -429,6 +600,25 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
lex.next();
|
||||
return res;
|
||||
}
|
||||
if (sym && dynamic_cast<SymValConst*>(sym->value)) {
|
||||
auto val = dynamic_cast<SymValConst*>(sym->value);
|
||||
Expr* res = new Expr{Expr::_None, lex.cur().loc};
|
||||
res->flags = Expr::_IsRvalue;
|
||||
if (val->type == _Int) {
|
||||
res->cls = Expr::_Const;
|
||||
res->intval = val->get_int_value();
|
||||
}
|
||||
else if (val->type == _Slice) {
|
||||
res->cls = Expr::_SliceConst;
|
||||
res->strval = val->get_str_value();
|
||||
}
|
||||
else {
|
||||
lex.cur().error("Invalid symbolic constant type");
|
||||
}
|
||||
res->e_type = TypeExpr::new_atomic(val->type);
|
||||
lex.next();
|
||||
return res;
|
||||
}
|
||||
bool auto_apply = false;
|
||||
Expr* res = new Expr{Expr::_Var, lex.cur().loc};
|
||||
if (nv) {
|
||||
|
@ -1425,6 +1615,8 @@ bool parse_source(std::istream* is, src::FileDescr* fdescr) {
|
|||
parse_pragma(lex);
|
||||
} else if (lex.tp() == _Global) {
|
||||
parse_global_var_decls(lex);
|
||||
} else if (lex.tp() == _Const) {
|
||||
parse_const_decls(lex);
|
||||
} else {
|
||||
parse_func_def(lex);
|
||||
}
|
||||
|
|
55
crypto/func/test/co1.fc
Normal file
55
crypto/func/test/co1.fc
Normal file
|
@ -0,0 +1,55 @@
|
|||
const int1 = 1, int2 = 2;
|
||||
|
||||
const int int101 = 101;
|
||||
const int int111 = 111;
|
||||
|
||||
const int1r = int1;
|
||||
|
||||
const str1 = "const1", str2 = "aabbcc"s;
|
||||
|
||||
const slice str2r = str2;
|
||||
|
||||
const str1int = 0x636f6e737431;
|
||||
const str2int = 0xAABBCC;
|
||||
|
||||
const int nibbles = 4;
|
||||
|
||||
int iget1() { return int1; }
|
||||
int iget2() { return int2; }
|
||||
int iget3() { return int1 + int2; }
|
||||
|
||||
int iget1r() { return int1r; }
|
||||
|
||||
slice sget1() { return str1; }
|
||||
slice sget2() { return str2; }
|
||||
slice sget2r() { return str2r; }
|
||||
|
||||
const int int240 = ((int1 + int2) * 10) << 3;
|
||||
|
||||
int iget240() { return int240; }
|
||||
|
||||
builder newc() asm "NEWC";
|
||||
slice endcs(builder b) asm "ENDC" "CTOS";
|
||||
int sdeq (slice s1, slice s2) asm "SDEQ";
|
||||
builder stslicer(builder b, slice s) asm "STSLICER";
|
||||
|
||||
_ main() {
|
||||
int i1 = iget1();
|
||||
int i2 = iget2();
|
||||
int i3 = iget3();
|
||||
|
||||
throw_unless(int101, i1 == 1);
|
||||
throw_unless(102, i2 == 2);
|
||||
throw_unless(103, i3 == 3);
|
||||
|
||||
slice s1 = sget1();
|
||||
slice s2 = sget2();
|
||||
slice s3 = newc().stslicer(str1).stslicer(str2r).endcs();
|
||||
|
||||
throw_unless(int111, sdeq(s1, newc().store_uint(str1int, 12 * nibbles).endcs()));
|
||||
throw_unless(112, sdeq(s2, newc().store_uint(str2int, 6 * nibbles).endcs()));
|
||||
throw_unless(113, sdeq(s3, newc().store_uint(0x636f6e737431ABCDEF, 18 * nibbles).endcs()));
|
||||
|
||||
int i4 = iget240();
|
||||
throw_unless(104, i4 == 240);
|
||||
}
|
49
crypto/func/test/s1.fc
Normal file
49
crypto/func/test/s1.fc
Normal file
|
@ -0,0 +1,49 @@
|
|||
slice ascii_slice() method_id {
|
||||
return "string";
|
||||
}
|
||||
|
||||
slice raw_slice() method_id {
|
||||
return "abcdef"s;
|
||||
}
|
||||
|
||||
slice addr_slice() method_id {
|
||||
return "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a;
|
||||
}
|
||||
|
||||
int string_hex() method_id {
|
||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"u;
|
||||
}
|
||||
|
||||
int string_minihash() method_id {
|
||||
return "transfer(slice, int)"h;
|
||||
}
|
||||
|
||||
int string_maxihash() method_id {
|
||||
return "transfer(slice, int)"H;
|
||||
}
|
||||
|
||||
int string_crc32() method_id {
|
||||
return "transfer(slice, int)"c;
|
||||
}
|
||||
|
||||
builder newc() asm "NEWC";
|
||||
slice endcs(builder b) asm "ENDC" "CTOS";
|
||||
int sdeq (slice s1, slice s2) asm "SDEQ";
|
||||
|
||||
_ main() {
|
||||
slice s_ascii = ascii_slice();
|
||||
slice s_raw = raw_slice();
|
||||
slice s_addr = addr_slice();
|
||||
int i_hex = string_hex();
|
||||
int i_mini = string_minihash();
|
||||
int i_maxi = string_maxihash();
|
||||
int i_crc = string_crc32();
|
||||
throw_unless(101, sdeq(s_ascii, newc().store_uint(0x737472696E67, 12 * 4).endcs()));
|
||||
throw_unless(102, sdeq(s_raw, newc().store_uint(0xABCDEF, 6 * 4).endcs()));
|
||||
throw_unless(103, sdeq(s_addr, newc().store_uint(4, 3).store_int(-1, 8)
|
||||
.store_uint(0x3333333333333333333333333333333333333333333333333333333333333333, 256).endcs()));
|
||||
throw_unless(104, i_hex == 0x4142434445464748494A4B4C4D4E4F505152535455565758595A303132333435);
|
||||
throw_unless(105, i_mini == 0x7a62e8a8);
|
||||
throw_unless(106, i_maxi == 0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979);
|
||||
throw_unless(107, i_crc == 2235694568);
|
||||
}
|
|
@ -247,6 +247,11 @@ const Lexem& Lexer::next() {
|
|||
}
|
||||
lexem.set(std::string{src.get_ptr() + 1, end}, src.here(), qc == '`' ? Lexem::Unknown : Lexem::String);
|
||||
src.set_ptr(end + 1);
|
||||
c = src.cur_char();
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
lexem.val = c;
|
||||
src.set_ptr(end + 2);
|
||||
}
|
||||
// std::cerr << lexem.name_str() << ' ' << lexem.str << std::endl;
|
||||
return lexem;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace sym {
|
|||
typedef int var_idx_t;
|
||||
|
||||
struct SymValBase {
|
||||
enum { _Param, _Var, _Func, _Typename, _GlobVar };
|
||||
enum { _Param, _Var, _Func, _Typename, _GlobVar, _Const };
|
||||
int type;
|
||||
int idx;
|
||||
SymValBase(int _type, int _idx) : type(_type), idx(_idx) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue