1
0
Fork 0
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:
EmelyanenkoK 2022-05-06 10:30:46 +03:00
parent 0e955793ed
commit 0c772185ef
14 changed files with 397 additions and 26 deletions

View file

@ -298,9 +298,14 @@ add_library(src_parser ${PARSER_SOURCE})
target_include_directories(src_parser PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>) target_include_directories(src_parser PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(src_parser PUBLIC ton_crypto) 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}) add_executable(func func/func.cpp ${FUNC_LIB_SOURCE})
target_include_directories(func PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>) 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) if (WINGETOPT_FOUND)
target_link_libraries_system(func wingetopt) target_link_libraries_system(func wingetopt)
endif() endif()
@ -324,11 +329,6 @@ if (WINGETOPT_FOUND)
target_link_libraries_system(pow-miner wingetopt) target_link_libraries_system(pow-miner wingetopt)
endif() 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 .) set(TURN_OFF_LSAN cd .)
if (TON_USE_ASAN AND NOT WIN32) if (TON_USE_ASAN AND NOT WIN32)
set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0) set(TURN_OFF_LSAN export LSAN_OPTIONS=detect_leaks=0)

View file

@ -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() { void VarDescr::set_const_nan() {
set_const(td::make_refint()); 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); show_var_list(os, left, vars);
os << " := " << int_const << std::endl; os << " := " << int_const << std::endl;
break; break;
case _SliceConst:
os << pfx << dis << "SCONST ";
show_var_list(os, left, vars);
os << " := " << str_const << std::endl;
break;
case _Import: case _Import:
os << pfx << dis << "IMPORT "; os << pfx << dis << "IMPORT ";
show_var_list(os, left, vars); show_var_list(os, left, vars);

View file

@ -353,6 +353,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
} }
switch (cl) { switch (cl) {
case _IntConst: case _IntConst:
case _SliceConst:
case _GlobVar: case _GlobVar:
case _Call: case _Call:
case _CallInd: case _CallInd:
@ -540,6 +541,7 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
bool reach; bool reach;
switch (op.cl) { switch (op.cl) {
case Op::_IntConst: case Op::_IntConst:
case Op::_SliceConst:
case Op::_GlobVar: case Op::_GlobVar:
case Op::_SetGlob: case Op::_SetGlob:
case Op::_Call: case Op::_Call:
@ -707,6 +709,10 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
values.add_newval(left[0]).set_const(int_const); values.add_newval(left[0]).set_const(int_const);
break; break;
} }
case _SliceConst: {
values.add_newval(left[0]).set_const(str_const);
break;
}
case _Call: { case _Call: {
prepare_args(values); prepare_args(values);
auto func = dynamic_cast<const SymValAsmFunc*>(fun_ref->value); auto func = dynamic_cast<const SymValAsmFunc*>(fun_ref->value);
@ -848,6 +854,7 @@ bool Op::mark_noreturn() {
// fallthrough // fallthrough
case _Import: case _Import:
case _IntConst: case _IntConst:
case _SliceConst:
case _Let: case _Let:
case _Tuple: case _Tuple:
case _UnTuple: case _UnTuple:

View file

@ -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; std::ostringstream os;
os << arg << ' ' << push_op; 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) { 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) { AsmOp AsmOp::IntConst(td::RefInt256 x) {
if (x->signed_fits_bits(8)) { 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()) { if (!x->is_valid()) {
return AsmOp::Const("PUSHNAN"); return AsmOp::Const("PUSHNAN", x);
} }
int k = is_pos_pow2(x); int k = is_pos_pow2(x);
if (k >= 0) { if (k >= 0) {
return AsmOp::Const(k, "PUSHPOW2"); return AsmOp::Const(k, "PUSHPOW2", x);
} }
k = is_pos_pow2(x + 1); k = is_pos_pow2(x + 1);
if (k >= 0) { if (k >= 0) {
return AsmOp::Const(k, "PUSHPOW2DEC"); return AsmOp::Const(k, "PUSHPOW2DEC", x);
} }
k = is_pos_pow2(-x); k = is_pos_pow2(-x);
if (k >= 0) { if (k >= 0) {
return AsmOp::Const(k, "PUSHNEGPOW2"); return AsmOp::Const(k, "PUSHNEGPOW2", x);
} }
if (!x->mod_pow2_short(23)) { 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) { AsmOp AsmOp::BoolConst(bool f) {

View file

@ -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; std::vector<SymDef*> glob_func, glob_vars;
SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) {

View file

@ -302,6 +302,15 @@ bool Op::generate_code_step(Stack& stack) {
} }
return true; 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: case _GlobVar:
if (dynamic_cast<const SymValGlobVar*>(fun_ref->value)) { if (dynamic_cast<const SymValGlobVar*>(fun_ref->value)) {
bool used = false; bool used = false;

View file

@ -109,6 +109,7 @@ enum Keyword {
_Infix, _Infix,
_Infixl, _Infixl,
_Infixr, _Infixr,
_Const,
_PragmaHashtag _PragmaHashtag
}; };
@ -336,6 +337,8 @@ struct VarDescr {
static constexpr int FiniteUInt = FiniteInt | _Pos; static constexpr int FiniteUInt = FiniteInt | _Pos;
int val; int val;
td::RefInt256 int_const; 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) { 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 { bool operator<(var_idx_t other_idx) const {
@ -406,6 +409,7 @@ struct VarDescr {
} }
void set_const(long long value); void set_const(long long value);
void set_const(td::RefInt256 value); void set_const(td::RefInt256 value);
void set_const(std::string value);
void set_const_nan(); void set_const_nan();
void operator+=(const VarDescr& y) { void operator+=(const VarDescr& y) {
flags &= y.flags; flags &= y.flags;
@ -530,7 +534,8 @@ struct Op {
_While, _While,
_Until, _Until,
_Repeat, _Repeat,
_Again _Again,
_SliceConst
}; };
int cl; int cl;
enum { _Disabled = 1, _Reachable = 2, _NoReturn = 4, _ImpureR = 8, _ImpureW = 16, _Impure = 24 }; 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::vector<var_idx_t> left, right;
std::unique_ptr<Op> block0, block1; std::unique_ptr<Op> block0, block1;
td::RefInt256 int_const; 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 = _Undef) : cl(_cl), flags(0), fun_ref(nullptr), where(_where) {
} }
Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left) 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) 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) { : 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, Op(const SrcLocation& _where, int _cl, const std::vector<var_idx_t>& _left, const std::vector<var_idx_t>& _right,
SymDef* _fun = nullptr) SymDef* _fun = nullptr)
: cl(_cl), flags(0), fun_ref(_fun), where(_where), left(_left), right(_right) { : 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 int glob_func_cnt, undef_func_cnt, glob_var_cnt;
extern std::vector<SymDef*> glob_func, glob_vars; extern std::vector<SymDef*> glob_func, glob_vars;
@ -820,7 +853,8 @@ struct Expr {
_LetFirst, _LetFirst,
_Hole, _Hole,
_Type, _Type,
_CondExpr _CondExpr,
_SliceConst
}; };
int cls; int cls;
int val{0}; int val{0};
@ -828,6 +862,7 @@ struct Expr {
int flags{0}; int flags{0};
SrcLocation here; SrcLocation here;
td::RefInt256 intval; td::RefInt256 intval;
std::string strval;
SymDef* sym{nullptr}; SymDef* sym{nullptr};
TypeExpr* e_type{nullptr}; TypeExpr* e_type{nullptr};
std::vector<Expr*> args; std::vector<Expr*> args;
@ -910,6 +945,7 @@ struct AsmOp {
int a, b, c; int a, b, c;
bool gconst{false}; bool gconst{false};
std::string op; std::string op;
td::RefInt256 origin;
struct SReg { struct SReg {
int idx; int idx;
SReg(int _idx) : idx(_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)) { AsmOp(int _t, int _a, int _b, std::string _op) : t(_t), a(_a), b(_b), op(std::move(_op)) {
compute_gconst(); 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) : 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)) { 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 make_stk3(int a, int b, int c, const char* str, int delta);
static AsmOp IntConst(td::RefInt256 value); static AsmOp IntConst(td::RefInt256 value);
static AsmOp BoolConst(bool f); static AsmOp BoolConst(bool f);
static AsmOp Const(std::string push_op) { static AsmOp Const(std::string push_op, td::RefInt256 origin = {}) {
return AsmOp(a_const, 0, 1, std::move(push_op)); 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) { static AsmOp Comment(std::string comment) {
return AsmOp(a_none, std::string{"// "} + comment); return AsmOp(a_none, std::string{"// "} + comment);
} }

View file

@ -362,6 +362,11 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
code.close_pop_cur(args[2]->here); code.close_pop_cur(args[2]->here);
return rvect; return rvect;
} }
case _SliceConst: {
auto rvect = new_tmp_vect(code);
code.emplace_back(here, Op::_SliceConst, rvect, strval);
return rvect;
}
default: default:
std::cerr << "expression constructor is " << cls << std::endl; std::cerr << "expression constructor is " << cls << std::endl;
throw src::Fatal{"cannot compile expression with unknown constructor"}; throw src::Fatal{"cannot compile expression with unknown constructor"};

View file

@ -125,8 +125,8 @@ void define_keywords() {
.add_keyword("operator", Kw::_Operator) .add_keyword("operator", Kw::_Operator)
.add_keyword("infix", Kw::_Infix) .add_keyword("infix", Kw::_Infix)
.add_keyword("infixl", Kw::_Infixl) .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); sym::symbols.add_keyword("#pragma", Kw::_PragmaHashtag);
} }

View file

@ -19,6 +19,9 @@
#include "func.h" #include "func.h"
#include "td/utils/crypto.h" #include "td/utils/crypto.h"
#include "common/refint.h" #include "common/refint.h"
#include "openssl/digest.hpp"
#include "block/block.h"
#include "block-parse.h"
#include <fstream> #include <fstream>
namespace sym { namespace sym {
@ -229,6 +232,83 @@ void parse_global_var_decl(Lexer& lex) {
lex.next(); 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 parse_formal_args(Lexer& lex) {
FormalArgList args; FormalArgList args;
lex.expect('(', "formal argument list"); lex.expect('(', "formal argument list");
@ -246,6 +326,18 @@ FormalArgList parse_formal_args(Lexer& lex) {
return args; 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) { TypeExpr* extract_total_arg_type(const FormalArgList& arg_list) {
if (arg_list.empty()) { if (arg_list.empty()) {
return TypeExpr::new_unit(); return TypeExpr::new_unit();
@ -322,8 +414,6 @@ Expr* make_func_apply(Expr* fun, Expr* x) {
return res; return res;
} }
Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false);
// parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _ // parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _
Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) { Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
if (lex.tp() == '(' || lex.tp() == '[') { if (lex.tp() == '(' || lex.tp() == '[') {
@ -388,6 +478,87 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
lex.next(); lex.next();
return res; 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 == '_') { if (t == '_') {
Expr* res = new Expr{Expr::_Hole, lex.cur().loc}; Expr* res = new Expr{Expr::_Hole, lex.cur().loc};
res->val = -1; res->val = -1;
@ -429,6 +600,25 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
lex.next(); lex.next();
return res; 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; bool auto_apply = false;
Expr* res = new Expr{Expr::_Var, lex.cur().loc}; Expr* res = new Expr{Expr::_Var, lex.cur().loc};
if (nv) { if (nv) {
@ -1425,6 +1615,8 @@ bool parse_source(std::istream* is, src::FileDescr* fdescr) {
parse_pragma(lex); parse_pragma(lex);
} else if (lex.tp() == _Global) { } else if (lex.tp() == _Global) {
parse_global_var_decls(lex); parse_global_var_decls(lex);
} else if (lex.tp() == _Const) {
parse_const_decls(lex);
} else { } else {
parse_func_def(lex); parse_func_def(lex);
} }

55
crypto/func/test/co1.fc Normal file
View 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
View 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);
}

View file

@ -247,6 +247,11 @@ const Lexem& Lexer::next() {
} }
lexem.set(std::string{src.get_ptr() + 1, end}, src.here(), qc == '`' ? Lexem::Unknown : Lexem::String); lexem.set(std::string{src.get_ptr() + 1, end}, src.here(), qc == '`' ? Lexem::Unknown : Lexem::String);
src.set_ptr(end + 1); 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; // std::cerr << lexem.name_str() << ' ' << lexem.str << std::endl;
return lexem; return lexem;
} }

View file

@ -32,7 +32,7 @@ namespace sym {
typedef int var_idx_t; typedef int var_idx_t;
struct SymValBase { struct SymValBase {
enum { _Param, _Var, _Func, _Typename, _GlobVar }; enum { _Param, _Var, _Func, _Typename, _GlobVar, _Const };
int type; int type;
int idx; int idx;
SymValBase(int _type, int _idx) : type(_type), idx(_idx) { SymValBase(int _type, int _idx) : type(_type), idx(_idx) {