diff --git a/crypto/func/abscode.cpp b/crypto/func/abscode.cpp index 21d172cf..933edc3d 100644 --- a/crypto/func/abscode.cpp +++ b/crypto/func/abscode.cpp @@ -179,7 +179,7 @@ void VarDescr::set_const_nan() { void VarDescr::operator|=(const VarDescr& y) { val &= y.val; - if (is_int_const() && cmp(int_const, y.int_const) != 0) { + if (is_int_const() && y.is_int_const() && cmp(int_const, y.int_const) != 0) { val &= ~_Const; } if (!(val & _Const)) { diff --git a/crypto/func/analyzer.cpp b/crypto/func/analyzer.cpp index 5d9b3991..989e9ebe 100644 --- a/crypto/func/analyzer.cpp +++ b/crypto/func/analyzer.cpp @@ -388,7 +388,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { for (; l_it < left.cend(); ++l_it, ++r_it) { if (std::find(l_it + 1, left.cend(), *l_it) == left.cend()) { auto p = next_var_info[*l_it]; - new_var_info.add_var(*r_it, !p || p->is_unused()); + new_var_info.add_var(*r_it, edit && (!p || p->is_unused())); new_left.push_back(*l_it); new_right.push_back(*r_it); } @@ -500,7 +500,12 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) { } changes = (new_var_info.size() == n); } while (changes <= edit); + assert(left.size() == 1); + bool last = new_var_info.count_used(left) == 0; new_var_info += left; + if (last) { + new_var_info[left[0]]->flags |= VarDescr::_Last; + } return set_var_info(std::move(new_var_info)); } case _Again: { diff --git a/crypto/func/builtins.cpp b/crypto/func/builtins.cpp index b8524bb9..29691034 100644 --- a/crypto/func/builtins.cpp +++ b/crypto/func/builtins.cpp @@ -29,8 +29,12 @@ using namespace std::literals::string_literals; int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt; std::vector glob_func, glob_vars; +std::set prohibited_var_names; SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { + if (name.back() == '_') { + prohibited_var_names.insert(name); + } sym_idx_t name_idx = sym::symbols.lookup(name, 1); if (sym::symbols.is_keyword(name_idx)) { std::cerr << "fatal: global function `" << name << "` already defined as a keyword" << std::endl; diff --git a/crypto/func/func.h b/crypto/func/func.h index 27656fed..10039ffa 100644 --- a/crypto/func/func.h +++ b/crypto/func/func.h @@ -19,6 +19,7 @@ #pragma once #include #include +#include #include #include #include @@ -40,7 +41,7 @@ extern std::string generated_from; constexpr int optimize_depth = 20; -const std::string func_version{"0.4.2"}; +const std::string func_version{"0.4.3"}; enum Keyword { _Eof = -1, @@ -839,6 +840,7 @@ struct SymValConst : sym::SymValBase { extern int glob_func_cnt, undef_func_cnt, glob_var_cnt; extern std::vector glob_func, glob_vars; +extern std::set prohibited_var_names; /* * diff --git a/crypto/func/gen-abscode.cpp b/crypto/func/gen-abscode.cpp index a2b98878..6af8e5b8 100644 --- a/crypto/func/gen-abscode.cpp +++ b/crypto/func/gen-abscode.cpp @@ -205,6 +205,10 @@ int Expr::predefine_vars() { case _Var: if (!sym) { assert(val < 0 && here.defined()); + if (prohibited_var_names.count(sym::symbols.get_name(~val))) { + throw src::ParseError{ + here, PSTRING() << "symbol `" << sym::symbols.get_name(~val) << "` cannot be redefined as a variable"}; + } sym = sym::define_symbol(~val, false, here); // std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl; if (!sym) { diff --git a/crypto/func/parse-func.cpp b/crypto/func/parse-func.cpp index 19481a07..06c695bf 100644 --- a/crypto/func/parse-func.cpp +++ b/crypto/func/parse-func.cpp @@ -172,6 +172,10 @@ FormalArg parse_formal_arg(Lexer& lex, int fa_idx) { lex.expect(_Ident, "formal parameter name"); } loc = lex.cur().loc; + if (prohibited_var_names.count(sym::symbols.get_name(lex.cur().val))) { + throw src::ParseError{ + loc, PSTRING() << "symbol `" << sym::symbols.get_name(lex.cur().val) << "` cannot be redefined as a variable"}; + } SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc); if (!new_sym_def) { lex.cur().error_at("cannot define symbol `", "`"); @@ -397,7 +401,7 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) { def = sym::define_global_symbol(func_name, 0, cur.loc); assert(def && "cannot define global function"); ++undef_func_cnt; - make_new_glob_func(def, TypeExpr::new_hole()); // was: ... ::new_func() + make_new_glob_func(def, TypeExpr::new_func()); // was: ... ::new_func() return true; } SymVal* val = dynamic_cast(def->value); @@ -1369,6 +1373,10 @@ std::vector parse_type_var_list(Lexer& lex) { throw src::ParseError{lex.cur().loc, "free type identifier expected"}; } auto loc = lex.cur().loc; + if (prohibited_var_names.count(sym::symbols.get_name(lex.cur().val))) { + throw src::ParseError{loc, PSTRING() << "symbol `" << sym::symbols.get_name(lex.cur().val) + << "` cannot be redefined as a variable"}; + } SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc); if (!new_sym_def || new_sym_def->value) { lex.cur().error_at("redefined type variable `", "`"); diff --git a/crypto/parser/symtable.cpp b/crypto/parser/symtable.cpp index a8843da9..d52d9648 100644 --- a/crypto/parser/symtable.cpp +++ b/crypto/parser/symtable.cpp @@ -32,8 +32,8 @@ int scope_level; SymTable<100003> symbols; -SymDef* sym_def[symbols.hprime]; -SymDef* global_sym_def[symbols.hprime]; +SymDef* sym_def[symbols.hprime + 1]; +SymDef* global_sym_def[symbols.hprime + 1]; std::vector> symbol_stack; std::vector scope_opened_at; diff --git a/crypto/parser/symtable.h b/crypto/parser/symtable.h index 9489b2bc..51d59dfa 100644 --- a/crypto/parser/symtable.h +++ b/crypto/parser/symtable.h @@ -161,8 +161,8 @@ struct SymDef { } }; -extern SymDef* sym_def[symbols.hprime]; -extern SymDef* global_sym_def[symbols.hprime]; +extern SymDef* sym_def[symbols.hprime + 1]; +extern SymDef* global_sym_def[symbols.hprime + 1]; extern std::vector> symbol_stack; extern std::vector scope_opened_at;