mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
updated func and tonlib
This commit is contained in:
parent
493ae2410c
commit
a73d202ba2
50 changed files with 1340 additions and 271 deletions
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -323,6 +323,20 @@ void Op::show(std::ostream& os, const std::vector<TmpVar>& vars, std::string pfx
|
|||
show_var_list(os, right, vars);
|
||||
os << std::endl;
|
||||
break;
|
||||
case _Tuple:
|
||||
os << pfx << dis << "MKTUPLE ";
|
||||
show_var_list(os, left, vars);
|
||||
os << " := ";
|
||||
show_var_list(os, right, vars);
|
||||
os << std::endl;
|
||||
break;
|
||||
case _UnTuple:
|
||||
os << pfx << dis << "UNTUPLE ";
|
||||
show_var_list(os, left, vars);
|
||||
os << " := ";
|
||||
show_var_list(os, right, vars);
|
||||
os << std::endl;
|
||||
break;
|
||||
case _IntConst:
|
||||
os << pfx << dis << "CONST ";
|
||||
show_var_list(os, left, vars);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -29,6 +29,7 @@ namespace funC {
|
|||
void CodeBlob::simplify_var_types() {
|
||||
for (TmpVar& var : vars) {
|
||||
TypeExpr::remove_indirect(var.v_type);
|
||||
var.v_type->recompute_width();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -354,7 +355,9 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
case _IntConst:
|
||||
case _GlobVar:
|
||||
case _Call:
|
||||
case _CallInd: {
|
||||
case _CallInd:
|
||||
case _Tuple:
|
||||
case _UnTuple: {
|
||||
// left = EXEC right;
|
||||
if (!next_var_info.count_used(left) && is_pure()) {
|
||||
// all variables in `left` are not needed
|
||||
|
@ -541,6 +544,8 @@ bool prune_unreachable(std::unique_ptr<Op>& ops) {
|
|||
case Op::_SetGlob:
|
||||
case Op::_Call:
|
||||
case Op::_CallInd:
|
||||
case Op::_Tuple:
|
||||
case Op::_UnTuple:
|
||||
case Op::_Import:
|
||||
reach = true;
|
||||
break;
|
||||
|
@ -724,6 +729,8 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case _Tuple:
|
||||
case _UnTuple:
|
||||
case _GlobVar:
|
||||
case _CallInd: {
|
||||
for (var_idx_t i : left) {
|
||||
|
@ -842,6 +849,8 @@ bool Op::mark_noreturn() {
|
|||
case _Import:
|
||||
case _IntConst:
|
||||
case _Let:
|
||||
case _Tuple:
|
||||
case _UnTuple:
|
||||
case _SetGlob:
|
||||
case _GlobVar:
|
||||
case _CallInd:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "parser/srcread.h"
|
||||
#include "func.h"
|
||||
|
@ -121,12 +121,49 @@ AsmOp AsmOp::BlkDrop(int a) {
|
|||
return AsmOp::Custom(os.str(), a, 0);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::BlkDrop2(int a, int b) {
|
||||
if (!b) {
|
||||
return BlkDrop(a);
|
||||
}
|
||||
std::ostringstream os;
|
||||
os << a << " " << b << " BLKDROP2";
|
||||
return AsmOp::Custom(os.str(), a + b, b);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::BlkReverse(int a, int b) {
|
||||
std::ostringstream os;
|
||||
os << a << " " << b << " REVERSE";
|
||||
return AsmOp::Custom(os.str(), a + b, a + b);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::Tuple(int a) {
|
||||
switch (a) {
|
||||
case 1:
|
||||
return AsmOp::Custom("SINGLE", 1, 1);
|
||||
case 2:
|
||||
return AsmOp::Custom("PAIR", 2, 1);
|
||||
case 3:
|
||||
return AsmOp::Custom("TRIPLE", 3, 1);
|
||||
}
|
||||
std::ostringstream os;
|
||||
os << a << " TUPLE";
|
||||
return AsmOp::Custom(os.str(), a, 1);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::UnTuple(int a) {
|
||||
switch (a) {
|
||||
case 1:
|
||||
return AsmOp::Custom("UNSINGLE", 1, 1);
|
||||
case 2:
|
||||
return AsmOp::Custom("UNPAIR", 1, 2);
|
||||
case 3:
|
||||
return AsmOp::Custom("UNTRIPLE", 1, 3);
|
||||
}
|
||||
std::ostringstream os;
|
||||
os << a << " UNTUPLE";
|
||||
return AsmOp::Custom(os.str(), 1, a);
|
||||
}
|
||||
|
||||
AsmOp AsmOp::IntConst(td::RefInt256 x) {
|
||||
if (x->signed_fits_bits(8)) {
|
||||
return AsmOp::Const(dec_string(std::move(x)) + " PUSHINT");
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -318,7 +318,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
stack.o << AsmOp::Custom(name + " GETGLOB", 0, 1);
|
||||
if (left.size() != 1) {
|
||||
assert(left.size() <= 15);
|
||||
stack.o << exec_arg_op("UNTUPLE", (int)left.size(), 1, (int)left.size());
|
||||
stack.o << AsmOp::UnTuple((int)left.size());
|
||||
}
|
||||
for (auto i : left) {
|
||||
stack.push_new_var(i);
|
||||
|
@ -396,6 +396,32 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case _Tuple:
|
||||
case _UnTuple: {
|
||||
if (disabled()) {
|
||||
return true;
|
||||
}
|
||||
std::vector<bool> last;
|
||||
for (var_idx_t x : right) {
|
||||
last.push_back(var_info[x] && var_info[x]->is_last());
|
||||
}
|
||||
stack.rearrange_top(right, std::move(last));
|
||||
stack.opt_show();
|
||||
int k = (int)stack.depth() - (int)right.size();
|
||||
assert(k >= 0);
|
||||
if (cl == _Tuple) {
|
||||
stack.o << AsmOp::Tuple((int)right.size());
|
||||
assert(left.size() == 1);
|
||||
} else {
|
||||
stack.o << AsmOp::UnTuple((int)left.size());
|
||||
assert(right.size() == 1);
|
||||
}
|
||||
stack.s.resize(k);
|
||||
for (int i = 0; i < (int)left.size(); i++) {
|
||||
stack.push_new_var(left.at(i));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case _Call:
|
||||
case _CallInd: {
|
||||
if (disabled()) {
|
||||
|
@ -483,7 +509,7 @@ bool Op::generate_code_step(Stack& stack) {
|
|||
assert(stack.s[k + i].first == right[i]);
|
||||
}
|
||||
if (right.size() > 1) {
|
||||
stack.o << exec_arg_op("TUPLE", (int)right.size(), (int)right.size(), 1);
|
||||
stack.o << AsmOp::Tuple((int)right.size());
|
||||
}
|
||||
if (!right.empty()) {
|
||||
std::string name = sym::symbols.get_name(fun_ref->sym_idx);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
@ -36,7 +36,7 @@ namespace funC {
|
|||
extern int verbosity;
|
||||
extern bool op_rewrite_comments;
|
||||
|
||||
constexpr int optimize_depth = 12;
|
||||
constexpr int optimize_depth = 20;
|
||||
|
||||
enum Keyword {
|
||||
_Eof = -1,
|
||||
|
@ -101,6 +101,7 @@ enum Keyword {
|
|||
_Extern,
|
||||
_Inline,
|
||||
_InlineRef,
|
||||
_AutoApply,
|
||||
_MethodId,
|
||||
_Operator,
|
||||
_Infix,
|
||||
|
@ -134,7 +135,7 @@ class IdSc {
|
|||
*/
|
||||
|
||||
struct TypeExpr {
|
||||
enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Map, te_Type, te_ForAll } constr;
|
||||
enum te_type { te_Unknown, te_Var, te_Indirect, te_Atomic, te_Tensor, te_Tuple, te_Map, te_Type, te_ForAll } constr;
|
||||
enum {
|
||||
_Int = Keyword::_Int,
|
||||
_Cell = Keyword::_Cell,
|
||||
|
@ -160,6 +161,9 @@ struct TypeExpr {
|
|||
: constr(_constr), value((int)list.size()), args(std::move(list)) {
|
||||
compute_width();
|
||||
}
|
||||
TypeExpr(te_type _constr, TypeExpr* elem0) : constr(_constr), value(1), args{elem0} {
|
||||
compute_width();
|
||||
}
|
||||
TypeExpr(te_type _constr, TypeExpr* elem0, std::vector<TypeExpr*> list)
|
||||
: constr(_constr), value((int)list.size() + 1), args{elem0} {
|
||||
args.insert(args.end(), list.begin(), list.end());
|
||||
|
@ -185,6 +189,9 @@ struct TypeExpr {
|
|||
bool is_map() const {
|
||||
return constr == te_Map;
|
||||
}
|
||||
bool is_tuple() const {
|
||||
return constr == te_Tuple;
|
||||
}
|
||||
bool has_fixed_width() const {
|
||||
return minw == maxw;
|
||||
}
|
||||
|
@ -226,6 +233,15 @@ struct TypeExpr {
|
|||
static TypeExpr* new_tensor(TypeExpr* te1, TypeExpr* te2, TypeExpr* te3) {
|
||||
return new_tensor({te1, te2, te3});
|
||||
}
|
||||
static TypeExpr* new_tuple(TypeExpr* arg0) {
|
||||
return new TypeExpr{te_Tuple, arg0};
|
||||
}
|
||||
static TypeExpr* new_tuple(std::vector<TypeExpr*> list, bool red = false) {
|
||||
return new_tuple(new_tensor(std::move(list), red));
|
||||
}
|
||||
static TypeExpr* new_tuple(std::initializer_list<TypeExpr*> list) {
|
||||
return new_tuple(new_tensor(std::move(list)));
|
||||
}
|
||||
static TypeExpr* new_var() {
|
||||
return new TypeExpr{te_Var, --type_vars, 1};
|
||||
}
|
||||
|
@ -505,6 +521,8 @@ struct Op {
|
|||
_SetGlob,
|
||||
_Import,
|
||||
_Return,
|
||||
_Tuple,
|
||||
_UnTuple,
|
||||
_If,
|
||||
_While,
|
||||
_Until,
|
||||
|
@ -789,7 +807,8 @@ struct Expr {
|
|||
_Apply,
|
||||
_VarApply,
|
||||
_TypeApply,
|
||||
_Tuple,
|
||||
_MkTuple,
|
||||
_Tensor,
|
||||
_Const,
|
||||
_Var,
|
||||
_Glob,
|
||||
|
@ -843,6 +862,12 @@ struct Expr {
|
|||
bool is_type() const {
|
||||
return flags & _IsType;
|
||||
}
|
||||
bool is_type_apply() const {
|
||||
return cls == _TypeApply;
|
||||
}
|
||||
bool is_mktuple() const {
|
||||
return cls == _MkTuple;
|
||||
}
|
||||
void chk_rvalue(const Lexem& lem) const;
|
||||
void chk_lvalue(const Lexem& lem) const;
|
||||
void chk_type(const Lexem& lem) const;
|
||||
|
@ -855,7 +880,8 @@ struct Expr {
|
|||
}
|
||||
int define_new_vars(CodeBlob& code);
|
||||
int predefine_vars();
|
||||
std::vector<var_idx_t> pre_compile(CodeBlob& code) const;
|
||||
std::vector<var_idx_t> pre_compile(CodeBlob& code, bool lval = false) const;
|
||||
static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here);
|
||||
var_idx_t new_tmp(CodeBlob& code) const;
|
||||
std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const {
|
||||
return {new_tmp(code)};
|
||||
|
@ -1004,6 +1030,7 @@ struct AsmOp {
|
|||
static AsmOp BlkSwap(int a, int b);
|
||||
static AsmOp BlkPush(int a, int b);
|
||||
static AsmOp BlkDrop(int a);
|
||||
static AsmOp BlkDrop2(int a, int b);
|
||||
static AsmOp BlkReverse(int a, int b);
|
||||
static AsmOp make_stk2(int a, int b, const char* str, int delta);
|
||||
static AsmOp make_stk3(int a, int b, int c, const char* str, int delta);
|
||||
|
@ -1024,6 +1051,8 @@ struct AsmOp {
|
|||
return AsmOp(a_custom, args, retv, custom_op);
|
||||
}
|
||||
static AsmOp Parse(std::string custom_op, int args, int retv = 1);
|
||||
static AsmOp Tuple(int a);
|
||||
static AsmOp UnTuple(int a);
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const AsmOp& op) {
|
||||
|
@ -1261,6 +1290,8 @@ struct StackTransform {
|
|||
bool is_blkpush(int i, int j) const;
|
||||
bool is_blkpush(int* i, int* j) const;
|
||||
bool is_blkdrop(int* i) const;
|
||||
bool is_blkdrop2(int i, int j) const;
|
||||
bool is_blkdrop2(int* i, int* j) const;
|
||||
bool is_reverse(int i, int j) const;
|
||||
bool is_reverse(int* i, int* j) const;
|
||||
bool is_nip_seq(int i, int j = 0) const;
|
||||
|
@ -1270,7 +1301,10 @@ struct StackTransform {
|
|||
bool is_pop_blkdrop(int* i, int* k) const;
|
||||
bool is_2pop_blkdrop(int i, int j, int k) const;
|
||||
bool is_2pop_blkdrop(int* i, int* j, int* k) const;
|
||||
bool is_const_rot() const;
|
||||
bool is_const_rot(int c) const;
|
||||
bool is_const_rot(int* c) const;
|
||||
bool is_const_pop(int c, int i) const;
|
||||
bool is_const_pop(int* c, int* i) const;
|
||||
|
||||
void show(std::ostream& os, int mode = 0) const;
|
||||
|
||||
|
@ -1307,11 +1341,12 @@ struct Optimizer {
|
|||
AsmOpCons* op_cons_[n];
|
||||
int offs_[n];
|
||||
StackTransform tr_[n];
|
||||
int mode_{0};
|
||||
Optimizer() {
|
||||
}
|
||||
Optimizer(bool debug) : debug_(debug) {
|
||||
Optimizer(bool debug, int mode = 0) : debug_(debug), mode_(mode) {
|
||||
}
|
||||
Optimizer(AsmOpConsList code, bool debug = false) : Optimizer(debug) {
|
||||
Optimizer(AsmOpConsList code, bool debug = false, int mode = 0) : Optimizer(debug, mode) {
|
||||
set_code(std::move(code));
|
||||
}
|
||||
void set_code(AsmOpConsList code_);
|
||||
|
@ -1327,12 +1362,15 @@ struct Optimizer {
|
|||
void show_head() const;
|
||||
void show_left() const;
|
||||
void show_right() const;
|
||||
bool find_const_op(int* op_idx, int cst);
|
||||
bool is_const_push_swap() const;
|
||||
bool rewrite_const_push_swap();
|
||||
bool is_const_push_xchgs();
|
||||
bool rewrite_const_push_xchgs();
|
||||
bool is_const_rot() const;
|
||||
bool rewrite_const_rot();
|
||||
bool is_const_rot(int* c) const;
|
||||
bool rewrite_const_rot(int c);
|
||||
bool is_const_pop(int* c, int* i) const;
|
||||
bool rewrite_const_pop(int c, int i);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2);
|
||||
bool simple_rewrite(int p, AsmOp&& new_op1, AsmOp&& new_op2, AsmOp&& new_op3);
|
||||
|
@ -1374,6 +1412,7 @@ struct Optimizer {
|
|||
bool is_blkswap(int* i, int* j);
|
||||
bool is_blkpush(int* i, int* j);
|
||||
bool is_blkdrop(int* i);
|
||||
bool is_blkdrop2(int* i, int* j);
|
||||
bool is_reverse(int* i, int* j);
|
||||
bool is_nip_seq(int* i, int* j);
|
||||
bool is_pop_blkdrop(int* i, int* k);
|
||||
|
@ -1381,8 +1420,8 @@ struct Optimizer {
|
|||
AsmOpConsList extract_code();
|
||||
};
|
||||
|
||||
AsmOpConsList optimize_code_head(AsmOpConsList op_list);
|
||||
AsmOpConsList optimize_code(AsmOpConsList op_list);
|
||||
AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode = 0);
|
||||
AsmOpConsList optimize_code(AsmOpConsList op_list, int mode);
|
||||
void optimize_code(AsmOpList& ops);
|
||||
|
||||
struct Stack {
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
namespace funC {
|
||||
|
||||
/*
|
||||
|
@ -164,7 +166,8 @@ bool Expr::deduce_type(const Lexem& lem) {
|
|||
|
||||
int Expr::define_new_vars(CodeBlob& code) {
|
||||
switch (cls) {
|
||||
case _Tuple:
|
||||
case _Tensor:
|
||||
case _MkTuple:
|
||||
case _TypeApply: {
|
||||
int res = 0;
|
||||
for (const auto& x : args) {
|
||||
|
@ -189,7 +192,8 @@ int Expr::define_new_vars(CodeBlob& code) {
|
|||
|
||||
int Expr::predefine_vars() {
|
||||
switch (cls) {
|
||||
case _Tuple:
|
||||
case _Tensor:
|
||||
case _MkTuple:
|
||||
case _TypeApply: {
|
||||
int res = 0;
|
||||
for (const auto& x : args) {
|
||||
|
@ -201,6 +205,7 @@ int Expr::predefine_vars() {
|
|||
if (!sym) {
|
||||
assert(val < 0 && here.defined());
|
||||
sym = sym::define_symbol(~val, false, here);
|
||||
// std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl;
|
||||
if (!sym) {
|
||||
throw src::ParseError{here, std::string{"redefined variable `"} + sym::symbols.get_name(~val) + "`"};
|
||||
}
|
||||
|
@ -216,12 +221,51 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const {
|
|||
return code.create_tmp_var(e_type, &here);
|
||||
}
|
||||
|
||||
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
|
||||
std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) {
|
||||
while (lhs->is_type_apply()) {
|
||||
lhs = lhs->args.at(0);
|
||||
}
|
||||
while (rhs->is_type_apply()) {
|
||||
rhs = rhs->args.at(0);
|
||||
}
|
||||
if (lhs->is_mktuple()) {
|
||||
if (rhs->is_mktuple()) {
|
||||
return pre_compile_let(code, lhs->args.at(0), rhs->args.at(0), here);
|
||||
}
|
||||
auto right = rhs->pre_compile(code);
|
||||
TypeExpr::remove_indirect(rhs->e_type);
|
||||
auto unpacked_type = rhs->e_type->args.at(0);
|
||||
std::vector<var_idx_t> tmp{code.create_tmp_var(unpacked_type, &rhs->here)};
|
||||
code.emplace_back(lhs->here, Op::_UnTuple, tmp, std::move(right));
|
||||
auto tvar = new Expr{_Var};
|
||||
tvar->set_val(tmp[0]);
|
||||
tvar->set_location(rhs->here);
|
||||
tvar->e_type = unpacked_type;
|
||||
pre_compile_let(code, lhs->args.at(0), tvar, here);
|
||||
return tmp;
|
||||
}
|
||||
auto right = rhs->pre_compile(code);
|
||||
if (lhs->cls == Expr::_GlobVar) {
|
||||
assert(lhs->sym);
|
||||
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, lhs->sym);
|
||||
op.flags |= Op::_Impure;
|
||||
} else {
|
||||
auto left = lhs->pre_compile(code, true);
|
||||
code.emplace_back(here, Op::_Let, std::move(left), right);
|
||||
}
|
||||
return right;
|
||||
}
|
||||
|
||||
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
|
||||
if (lval && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply)) {
|
||||
std::cerr << "lvalue expression constructor is " << cls << std::endl;
|
||||
throw src::Fatal{"cannot compile lvalue expression with unknown constructor"};
|
||||
}
|
||||
switch (cls) {
|
||||
case _Tuple: {
|
||||
case _Tensor: {
|
||||
std::vector<var_idx_t> res;
|
||||
for (const auto& x : args) {
|
||||
auto add = x->pre_compile(code);
|
||||
auto add = x->pre_compile(code, lval);
|
||||
res.insert(res.end(), add.cbegin(), add.cend());
|
||||
}
|
||||
return res;
|
||||
|
@ -253,7 +297,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
|
|||
return rvect;
|
||||
}
|
||||
case _TypeApply:
|
||||
return args[0]->pre_compile(code);
|
||||
return args[0]->pre_compile(code, lval);
|
||||
case _Var:
|
||||
case _Hole:
|
||||
return {val};
|
||||
|
@ -289,25 +333,22 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code) const {
|
|||
return rvect;
|
||||
}
|
||||
case _Letop: {
|
||||
auto right = args[1]->pre_compile(code);
|
||||
if (args[0]->cls == Expr::_GlobVar) {
|
||||
assert(args[0]->sym);
|
||||
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, args[0]->sym);
|
||||
op.flags |= Op::_Impure;
|
||||
} else {
|
||||
auto left = args[0]->pre_compile(code);
|
||||
code.emplace_back(here, Op::_Let, std::move(left), right);
|
||||
}
|
||||
return right;
|
||||
return pre_compile_let(code, args.at(0), args.at(1), here);
|
||||
}
|
||||
case _LetFirst: {
|
||||
auto rvect = new_tmp_vect(code);
|
||||
auto right = args[1]->pre_compile(code);
|
||||
auto left = args[0]->pre_compile(code);
|
||||
auto left = args[0]->pre_compile(code, true);
|
||||
left.push_back(rvect[0]);
|
||||
code.emplace_back(here, Op::_Let, std::move(left), std::move(right));
|
||||
return rvect;
|
||||
}
|
||||
case _MkTuple: {
|
||||
auto left = new_tmp_vect(code);
|
||||
auto right = args[0]->pre_compile(code);
|
||||
code.emplace_back(here, Op::_Tuple, left, std::move(right));
|
||||
return left;
|
||||
}
|
||||
case _CondExpr: {
|
||||
auto cond = args[0]->pre_compile(code);
|
||||
assert(cond.size() == 1);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -46,6 +46,8 @@ void define_keywords() {
|
|||
.add_kw_char(';')
|
||||
.add_kw_char('(')
|
||||
.add_kw_char(')')
|
||||
.add_kw_char('[')
|
||||
.add_kw_char(']')
|
||||
.add_kw_char('{')
|
||||
.add_kw_char('}')
|
||||
.add_kw_char('=')
|
||||
|
@ -118,6 +120,7 @@ void define_keywords() {
|
|||
.add_keyword("impure", Kw::_Impure)
|
||||
.add_keyword("inline", Kw::_Inline)
|
||||
.add_keyword("inline_ref", Kw::_InlineRef)
|
||||
.add_keyword("auto_apply", Kw::_AutoApply)
|
||||
.add_keyword("method_id", Kw::_MethodId)
|
||||
.add_keyword("operator", Kw::_Operator)
|
||||
.add_keyword("infix", Kw::_Infix)
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -134,6 +134,16 @@ bool Optimizer::say(std::string str) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::find_const_op(int* op_idx, int cst) {
|
||||
for (int i = 0; i < l2_; i++) {
|
||||
if (op_[i]->is_gconst() && tr_[i].get(0) == cst) {
|
||||
*op_idx = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Optimizer::is_const_push_swap() const {
|
||||
return l_ >= 3 && op_[0]->is_gconst() && op_[1]->is_push() && op_[1]->a >= 1 && op_[2]->is_swap();
|
||||
}
|
||||
|
@ -150,21 +160,44 @@ bool Optimizer::rewrite_const_push_swap() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::is_const_rot() const {
|
||||
return pb_ >= 3 && pb_ <= l2_ && op_[0]->is_gconst() && tr_[pb_ - 1].is_const_rot();
|
||||
bool Optimizer::is_const_rot(int* c) const {
|
||||
return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_rot(c);
|
||||
}
|
||||
|
||||
bool Optimizer::rewrite_const_rot() {
|
||||
bool Optimizer::rewrite_const_rot(int c) {
|
||||
p_ = pb_;
|
||||
q_ = 2;
|
||||
int idx = -1;
|
||||
if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) {
|
||||
return false;
|
||||
}
|
||||
show_left();
|
||||
oq_[0] = std::move(op_[0]);
|
||||
oq_[1] = std::move(op_[1]);
|
||||
oq_[0] = std::move(op_[idx]);
|
||||
oq_[1] = std::move(op_[idx ? 0 : 1]);
|
||||
*oq_[1] = AsmOp::Custom("ROT", 3, 3);
|
||||
show_right();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::is_const_pop(int* c, int* i) const {
|
||||
return pb_ >= 3 && pb_ <= l2_ && tr_[pb_ - 1].is_const_pop(c, i);
|
||||
}
|
||||
|
||||
bool Optimizer::rewrite_const_pop(int c, int i) {
|
||||
p_ = pb_;
|
||||
q_ = 2;
|
||||
int idx = -1;
|
||||
if (!(p_ >= 2 && find_const_op(&idx, c) && idx < p_)) {
|
||||
return false;
|
||||
}
|
||||
show_left();
|
||||
oq_[0] = std::move(op_[idx]);
|
||||
oq_[1] = std::move(op_[idx ? 0 : 1]);
|
||||
*oq_[1] = AsmOp::Pop(i);
|
||||
show_right();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Optimizer::is_const_push_xchgs() {
|
||||
if (!(pb_ >= 2 && pb_ <= l2_ && op_[0]->is_gconst())) {
|
||||
return false;
|
||||
|
@ -424,6 +457,10 @@ bool Optimizer::is_blkdrop(int* i) {
|
|||
return is_pred([i](const auto& t) { return t.is_blkdrop(i) && *i > 0 && *i < 16; });
|
||||
}
|
||||
|
||||
bool Optimizer::is_blkdrop2(int* i, int* j) {
|
||||
return is_pred([i, j](const auto& t) { return t.is_blkdrop2(i, j) && *i > 0 && *i < 16 && *j > 0 && *j < 16; });
|
||||
}
|
||||
|
||||
bool Optimizer::is_reverse(int* i, int* j) {
|
||||
return is_pred([i, j](const auto& t) { return t.is_reverse(i, j) && *i >= 2 && *i <= 17 && *j < 16; });
|
||||
}
|
||||
|
@ -488,38 +525,42 @@ bool Optimizer::find_at_least(int pb) {
|
|||
p_ = q_ = 0;
|
||||
pb_ = pb;
|
||||
// show_stack_transforms();
|
||||
int i = -100, j = -100, k = -100;
|
||||
int i = -100, j = -100, k = -100, c = 0;
|
||||
return (is_const_push_swap() && 3 >= pb && rewrite_const_push_swap()) || (is_nop() && simple_rewrite_nop()) ||
|
||||
(is_const_rot() && rewrite_const_rot()) || (is_const_push_xchgs() && rewrite_const_push_xchgs()) ||
|
||||
(!(mode_ & 1) && is_const_rot(&c) && rewrite_const_rot(c)) ||
|
||||
(is_const_push_xchgs() && rewrite_const_push_xchgs()) || (is_const_pop(&c, &i) && rewrite_const_pop(c, i)) ||
|
||||
(is_xchg(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j))) || (is_push(&i) && simple_rewrite(AsmOp::Push(i))) ||
|
||||
(is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) || (is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) ||
|
||||
(is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
|
||||
(is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
|
||||
(is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
|
||||
(is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
|
||||
(is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
|
||||
(is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) ||
|
||||
(is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) ||
|
||||
(is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) ||
|
||||
(is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) ||
|
||||
(is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) ||
|
||||
(is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) ||
|
||||
(is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) ||
|
||||
(is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) ||
|
||||
(is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) ||
|
||||
(is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
|
||||
(is_pop_blkdrop(&i, &k) && simple_rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
|
||||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
|
||||
? simple_rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
|
||||
: simple_rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
|
||||
(is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) ||
|
||||
(is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) ||
|
||||
(is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) ||
|
||||
(is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) ||
|
||||
(is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) ||
|
||||
(is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) ||
|
||||
(is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) ||
|
||||
(is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k)));
|
||||
(is_pop(&i) && simple_rewrite(AsmOp::Pop(i))) ||
|
||||
(!(mode_ & 1) &&
|
||||
((is_rot() && simple_rewrite(AsmOp::Custom("ROT", 3, 3))) ||
|
||||
(is_rotrev() && simple_rewrite(AsmOp::Custom("-ROT", 3, 3))) ||
|
||||
(is_2dup() && simple_rewrite(AsmOp::Custom("2DUP", 2, 4))) ||
|
||||
(is_2swap() && simple_rewrite(AsmOp::Custom("2SWAP", 2, 4))) ||
|
||||
(is_2over() && simple_rewrite(AsmOp::Custom("2OVER", 2, 4))) ||
|
||||
(is_tuck() && simple_rewrite(AsmOp::Custom("TUCK", 2, 3))) ||
|
||||
(is_2drop() && simple_rewrite(AsmOp::Custom("2DROP", 2, 0))) ||
|
||||
(is_xchg2(&i, &j) && simple_rewrite(AsmOp::Xchg2(i, j))) ||
|
||||
(is_xcpu(&i, &j) && simple_rewrite(AsmOp::XcPu(i, j))) ||
|
||||
(is_puxc(&i, &j) && simple_rewrite(AsmOp::PuXc(i, j))) ||
|
||||
(is_push2(&i, &j) && simple_rewrite(AsmOp::Push2(i, j))) ||
|
||||
(is_blkswap(&i, &j) && simple_rewrite(AsmOp::BlkSwap(i, j))) ||
|
||||
(is_blkpush(&i, &j) && simple_rewrite(AsmOp::BlkPush(i, j))) ||
|
||||
(is_blkdrop(&i) && simple_rewrite(AsmOp::BlkDrop(i))) ||
|
||||
(is_reverse(&i, &j) && simple_rewrite(AsmOp::BlkReverse(i, j))) ||
|
||||
(is_nip_seq(&i, &j) && simple_rewrite(AsmOp::Xchg(i, j), AsmOp::BlkDrop(i))) ||
|
||||
(is_pop_blkdrop(&i, &k) && simple_rewrite(AsmOp::Pop(i), AsmOp::BlkDrop(k))) ||
|
||||
(is_blkdrop2(&i, &j) && simple_rewrite(AsmOp::BlkDrop2(i, j))) ||
|
||||
(is_2pop_blkdrop(&i, &j, &k) && (k >= 3 && k <= 13 && i != j + 1 && i <= 15 && j <= 14
|
||||
? simple_rewrite(AsmOp::Xchg2(j + 1, i), AsmOp::BlkDrop(k + 2))
|
||||
: simple_rewrite(AsmOp::Pop(i), AsmOp::Pop(j), AsmOp::BlkDrop(k)))) ||
|
||||
(is_xchg3(&i, &j, &k) && simple_rewrite(AsmOp::Xchg3(i, j, k))) ||
|
||||
(is_xc2pu(&i, &j, &k) && simple_rewrite(AsmOp::Xc2Pu(i, j, k))) ||
|
||||
(is_xcpuxc(&i, &j, &k) && simple_rewrite(AsmOp::XcPuXc(i, j, k))) ||
|
||||
(is_xcpu2(&i, &j, &k) && simple_rewrite(AsmOp::XcPu2(i, j, k))) ||
|
||||
(is_puxc2(&i, &j, &k) && simple_rewrite(AsmOp::PuXc2(i, j, k))) ||
|
||||
(is_puxcpu(&i, &j, &k) && simple_rewrite(AsmOp::PuXcPu(i, j, k))) ||
|
||||
(is_pu2xc(&i, &j, &k) && simple_rewrite(AsmOp::Pu2Xc(i, j, k))) ||
|
||||
(is_push3(&i, &j, &k) && simple_rewrite(AsmOp::Push3(i, j, k)))));
|
||||
}
|
||||
|
||||
bool Optimizer::find() {
|
||||
|
@ -544,17 +585,17 @@ bool Optimizer::optimize() {
|
|||
return f;
|
||||
}
|
||||
|
||||
AsmOpConsList optimize_code_head(AsmOpConsList op_list) {
|
||||
Optimizer opt(std::move(op_list), op_rewrite_comments);
|
||||
AsmOpConsList optimize_code_head(AsmOpConsList op_list, int mode) {
|
||||
Optimizer opt(std::move(op_list), op_rewrite_comments, mode);
|
||||
opt.optimize();
|
||||
return opt.extract_code();
|
||||
}
|
||||
|
||||
AsmOpConsList optimize_code(AsmOpConsList op_list) {
|
||||
AsmOpConsList optimize_code(AsmOpConsList op_list, int mode) {
|
||||
std::vector<std::unique_ptr<AsmOp>> v;
|
||||
while (op_list) {
|
||||
if (!op_list->car->is_comment()) {
|
||||
op_list = optimize_code_head(std::move(op_list));
|
||||
op_list = optimize_code_head(std::move(op_list), mode);
|
||||
}
|
||||
if (op_list) {
|
||||
v.push_back(std::move(op_list->car));
|
||||
|
@ -568,11 +609,14 @@ AsmOpConsList optimize_code(AsmOpConsList op_list) {
|
|||
}
|
||||
|
||||
void optimize_code(AsmOpList& ops) {
|
||||
std::unique_ptr<AsmOpCons> op_list;
|
||||
AsmOpConsList op_list;
|
||||
for (auto it = ops.list_.rbegin(); it < ops.list_.rend(); ++it) {
|
||||
op_list = AsmOpCons::cons(std::make_unique<AsmOp>(std::move(*it)), std::move(op_list));
|
||||
}
|
||||
op_list = optimize_code(std::move(op_list));
|
||||
op_list = optimize_code(std::move(op_list), 1);
|
||||
op_list = optimize_code(std::move(op_list), 1);
|
||||
op_list = optimize_code(std::move(op_list), 0);
|
||||
op_list = optimize_code(std::move(op_list), 0);
|
||||
ops.list_.clear();
|
||||
while (op_list) {
|
||||
ops.list_.push_back(std::move(*(op_list->car)));
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
#include "td/utils/crypto.h"
|
||||
|
@ -100,14 +100,21 @@ TypeExpr* parse_type1(Lexer& lex) {
|
|||
lex.cur().error_at("`", "` is not a type identifier");
|
||||
}
|
||||
}
|
||||
lex.expect('(');
|
||||
if (lex.tp() == ')') {
|
||||
int c;
|
||||
if (lex.tp() == '[') {
|
||||
lex.next();
|
||||
return TypeExpr::new_unit();
|
||||
c = ']';
|
||||
} else {
|
||||
lex.expect('(');
|
||||
c = ')';
|
||||
}
|
||||
if (lex.tp() == c) {
|
||||
lex.next();
|
||||
return c == ')' ? TypeExpr::new_unit() : TypeExpr::new_tuple({});
|
||||
}
|
||||
auto t1 = parse_type(lex);
|
||||
if (lex.tp() != ',') {
|
||||
lex.expect(')');
|
||||
lex.expect(c);
|
||||
return t1;
|
||||
}
|
||||
std::vector<TypeExpr*> tlist{1, t1};
|
||||
|
@ -115,8 +122,8 @@ TypeExpr* parse_type1(Lexer& lex) {
|
|||
lex.next();
|
||||
tlist.push_back(parse_type(lex));
|
||||
}
|
||||
lex.expect(')');
|
||||
return TypeExpr::new_tensor(std::move(tlist));
|
||||
lex.expect(c);
|
||||
return c == ')' ? TypeExpr::new_tensor(std::move(tlist)) : TypeExpr::new_tuple(std::move(tlist));
|
||||
}
|
||||
|
||||
TypeExpr* parse_type(Lexer& lex) {
|
||||
|
@ -302,7 +309,7 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) {
|
|||
Expr* make_func_apply(Expr* fun, Expr* x) {
|
||||
Expr* res;
|
||||
if (fun->cls == Expr::_Glob) {
|
||||
if (x->cls == Expr::_Tuple) {
|
||||
if (x->cls == Expr::_Tensor) {
|
||||
res = new Expr{Expr::_Apply, fun->sym, x->args};
|
||||
} else {
|
||||
res = new Expr{Expr::_Apply, fun->sym, {x}};
|
||||
|
@ -317,28 +324,36 @@ Expr* make_func_apply(Expr* fun, Expr* x) {
|
|||
|
||||
Expr* parse_expr(Lexer& lex, CodeBlob& code, bool nv = false);
|
||||
|
||||
// parse ( E { , E } ) | () | id | num | _
|
||||
// parse ( E { , E } ) | () | [ E { , E } ] | [] | id | num | _
|
||||
Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
||||
if (lex.tp() == '(') {
|
||||
if (lex.tp() == '(' || lex.tp() == '[') {
|
||||
bool tf = (lex.tp() == '[');
|
||||
int clbr = (tf ? ']' : ')');
|
||||
SrcLocation loc{lex.cur().loc};
|
||||
lex.next();
|
||||
if (lex.tp() == ')') {
|
||||
if (lex.tp() == clbr) {
|
||||
lex.next();
|
||||
Expr* res = new Expr{Expr::_Tuple, {}};
|
||||
Expr* res = new Expr{Expr::_Tensor, {}};
|
||||
res->flags = Expr::_IsRvalue;
|
||||
res->here = loc;
|
||||
res->e_type = TypeExpr::new_unit();
|
||||
if (tf) {
|
||||
res = new Expr{Expr::_MkTuple, {res}};
|
||||
res->flags = Expr::_IsRvalue;
|
||||
res->here = loc;
|
||||
res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
Expr* res = parse_expr(lex, code, nv);
|
||||
if (lex.tp() != ',') {
|
||||
lex.expect(')');
|
||||
lex.expect(clbr);
|
||||
return res;
|
||||
}
|
||||
std::vector<TypeExpr*> type_list;
|
||||
type_list.push_back(res->e_type);
|
||||
int f = res->flags;
|
||||
res = new Expr{Expr::_Tuple, {res}};
|
||||
res = new Expr{Expr::_Tensor, {res}};
|
||||
while (lex.tp() == ',') {
|
||||
lex.next();
|
||||
auto x = parse_expr(lex, code, nv);
|
||||
|
@ -351,8 +366,14 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
}
|
||||
res->here = loc;
|
||||
res->flags = f;
|
||||
res->e_type = TypeExpr::new_tensor(std::move(type_list));
|
||||
lex.expect(')');
|
||||
res->e_type = TypeExpr::new_tensor(std::move(type_list), !tf);
|
||||
if (tf) {
|
||||
res = new Expr{Expr::_MkTuple, {res}};
|
||||
res->flags = f;
|
||||
res->here = loc;
|
||||
res->e_type = TypeExpr::new_tuple(res->args.at(0)->e_type);
|
||||
}
|
||||
lex.expect(clbr);
|
||||
return res;
|
||||
}
|
||||
int t = lex.tp();
|
||||
|
@ -382,7 +403,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
lex.next();
|
||||
return res;
|
||||
}
|
||||
if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type) {
|
||||
if (t == _Int || t == _Cell || t == _Slice || t == _Builder || t == _Cont || t == _Type || t == _Tuple) {
|
||||
Expr* res = new Expr{Expr::_Type, lex.cur().loc};
|
||||
res->flags = Expr::_IsType;
|
||||
res->e_type = TypeExpr::new_atomic(t);
|
||||
|
@ -458,7 +479,7 @@ Expr* parse_expr100(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
// parse E { E }
|
||||
Expr* parse_expr90(Lexer& lex, CodeBlob& code, bool nv) {
|
||||
Expr* res = parse_expr100(lex, code, nv);
|
||||
while (lex.tp() == '(' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) {
|
||||
while (lex.tp() == '(' || lex.tp() == '[' || (lex.tp() == _Ident && !is_special_ident(lex.cur().val))) {
|
||||
if (res->is_type()) {
|
||||
Expr* x = parse_expr100(lex, code, true);
|
||||
x->chk_lvalue(lex.cur()); // chk_lrvalue() ?
|
||||
|
@ -523,7 +544,7 @@ Expr* parse_expr80(Lexer& lex, CodeBlob& code, bool nv) {
|
|||
lex.next();
|
||||
auto x = parse_expr100(lex, code, false);
|
||||
x->chk_rvalue(lex.cur());
|
||||
if (x->cls == Expr::_Tuple) {
|
||||
if (x->cls == Expr::_Tensor) {
|
||||
res = new Expr{Expr::_Apply, name, {obj}};
|
||||
res->args.insert(res->args.end(), x->args.begin(), x->args.end());
|
||||
} else {
|
||||
|
@ -1269,7 +1290,7 @@ void parse_func_def(Lexer& lex) {
|
|||
|
||||
bool parse_source(std::istream* is, const src::FileDescr* fdescr) {
|
||||
src::SourceReader reader{is, fdescr};
|
||||
Lexer lex{reader, true};
|
||||
Lexer lex{reader, true, ";,()[] ~."};
|
||||
while (lex.tp() != _Eof) {
|
||||
if (lex.tp() == _Global) {
|
||||
parse_global_var_decls(lex);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -742,6 +742,28 @@ bool StackTransform::is_blkdrop(int *i) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
// 0 1 .. j-1 j+i j+i+1 ...
|
||||
bool StackTransform::is_blkdrop2(int i, int j) const {
|
||||
if (!is_valid() || d != i || i <= 0 || j < 0 || dp < i + j || n != j || !is_trivial_after(j)) {
|
||||
return false;
|
||||
}
|
||||
for (int s = 0; s < j; s++) {
|
||||
if (get(s) != s) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StackTransform::is_blkdrop2(int *i, int *j) const {
|
||||
if (is_valid() && is_blkdrop2(d, n)) {
|
||||
*i = d;
|
||||
*j = n;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// equivalent to i times PUSH s(j)
|
||||
bool StackTransform::is_blkpush(int *i, int *j) const {
|
||||
if (!is_valid() || d >= 0) {
|
||||
|
@ -846,8 +868,27 @@ bool StackTransform::is_2pop_blkdrop(int *i, int *j, int *k) const {
|
|||
}
|
||||
|
||||
// PUSHCONST c ; ROT == 1 -1000 0 2 3
|
||||
bool StackTransform::is_const_rot() const {
|
||||
return is_valid() && d == -1 && is_trivial_after(3) && get(0) == 1 && get(1) <= c_start && get(2) == 0;
|
||||
bool StackTransform::is_const_rot(int c) const {
|
||||
return is_valid() && d == -1 && is_trivial_after(3) && get(0) == 1 && c <= c_start && get(1) == c && get(2) == 0;
|
||||
}
|
||||
|
||||
bool StackTransform::is_const_rot(int *c) const {
|
||||
return is_valid() && (*c = get(1)) <= c_start && is_const_rot(*c);
|
||||
}
|
||||
|
||||
// PUSHCONST c ; POP s(i) == 0 1 .. i-1 -1000 i+1 ...
|
||||
bool StackTransform::is_const_pop(int c, int i) const {
|
||||
return is_valid() && !d && n == 1 && i > 0 && c <= c_start && get(i - 1) == c;
|
||||
}
|
||||
|
||||
bool StackTransform::is_const_pop(int *c, int *i) const {
|
||||
if (is_valid() && !d && n == 1 && A[0].second <= c_start) {
|
||||
*i = A[0].first + 1;
|
||||
*c = A[0].second;
|
||||
return is_const_pop(*c, *i);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void StackTransform::show(std::ostream &os, int mode) const {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Copyright 2017-2019 Telegram Systems LLP
|
||||
Copyright 2017-2020 Telegram Systems LLP
|
||||
*/
|
||||
#include "func.h"
|
||||
|
||||
|
@ -47,6 +47,12 @@ void TypeExpr::compute_width() {
|
|||
maxw = w_inf;
|
||||
}
|
||||
break;
|
||||
case te_Tuple:
|
||||
minw = maxw = 1;
|
||||
for (TypeExpr* arg : args) {
|
||||
arg->compute_width();
|
||||
}
|
||||
break;
|
||||
case te_Indirect:
|
||||
minw = args[0]->minw;
|
||||
maxw = args[0]->maxw;
|
||||
|
@ -84,6 +90,14 @@ bool TypeExpr::recompute_width() {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
case te_Tuple: {
|
||||
for (TypeExpr* arg : args) {
|
||||
if (arg->minw > 1 || arg->maxw < 1 || arg->minw > arg->maxw) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -233,7 +247,9 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
|
|||
}
|
||||
}
|
||||
case te_Tensor: {
|
||||
os << "(";
|
||||
if (lex_level > -127) {
|
||||
os << "(";
|
||||
}
|
||||
auto c = args.size();
|
||||
if (c) {
|
||||
for (const auto& x : args) {
|
||||
|
@ -243,7 +259,25 @@ std::ostream& TypeExpr::print(std::ostream& os, int lex_level) {
|
|||
}
|
||||
}
|
||||
}
|
||||
return os << ")";
|
||||
if (lex_level > -127) {
|
||||
os << ")";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
case te_Tuple: {
|
||||
os << "[";
|
||||
auto c = args.size();
|
||||
if (c == 1 && args[0]->constr == te_Tensor) {
|
||||
args[0]->print(os, -127);
|
||||
} else if (c) {
|
||||
for (const auto& x : args) {
|
||||
x->print(os);
|
||||
if (--c) {
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
}
|
||||
return os << "]";
|
||||
}
|
||||
case te_Map: {
|
||||
assert(args.size() == 2);
|
||||
|
@ -312,7 +346,7 @@ void check_update_widths(TypeExpr* te1, TypeExpr* te2) {
|
|||
check_width_compat(te1, te2);
|
||||
te1->minw = te2->minw = std::max(te1->minw, te2->minw);
|
||||
te1->maxw = te2->maxw = std::min(te1->maxw, te2->maxw);
|
||||
assert(te1->minw <= te2->minw);
|
||||
assert(te1->minw <= te1->maxw);
|
||||
}
|
||||
|
||||
void unify(TypeExpr*& te1, TypeExpr*& te2) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue