Skip to content

Commit 6c30e5a

Browse files
committed
[Tolk] Embedded stdlib.tolk, CompilerState, strict includes
Several related changes: - stdlib.tolk is embedded into a distribution (deb package or tolk-js), the user won't have to download it and store as a project file; it's an important step to maintain correct language versioning - stdlib.tolk is auto-included, that's why all its functions are available out of the box - strict includes: you can't use symbol `f` from another file unless you've #include'd this file - drop all C++ global variables holding compilation state, merge them into a single struct CompilerState located at compiler-state.h; for instance, stdlib filename is also there
1 parent f0e6470 commit 6c30e5a

21 files changed

+587
-489
lines changed

crypto/smartcont/stdlib.tolk

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Standard library for Tolk
22
// (initially copied from stdlib.fc)
33
//
4+
#pragma version >=0.5;
45

56
/*
67
This file is part of TON Tolk Standard Library.
@@ -405,6 +406,7 @@ cell preload_dict(slice s) pure asm "PLDDICT";
405406

406407
/// Loads a dictionary as [load_dict], but returns only the remainder of the slice.
407408
slice skip_dict(slice s) pure asm "SKIPDICT";
409+
(slice, ()) ~skip_dict(slice s) pure asm "SKIPDICT";
408410

409411
/// Loads (Maybe ^Cell) from `slice` [s].
410412
/// In other words loads 1 bit and if it is true
@@ -661,6 +663,7 @@ int dict_empty?(cell c) pure asm "DICTEMPTY";
661663
cell config_param(int x) pure asm "CONFIGOPTPARAM";
662664
/// Checks whether c is a null. Note, that Tolk also has polymorphic null? built-in.
663665
int cell_null?(cell c) pure asm "ISNULL";
666+
int builder_null?(builder b) asm "ISNULL";
664667

665668
/// Creates an output action which would reserve exactly amount nanotoncoins (if mode = 0), at most amount nanotoncoins (if mode = 2), or all but amount nanotoncoins (if mode = 1 or mode = 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying amount nanotoncoins (or b − amount nanotoncoins, where b is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in mode means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in mode means `amount <- -amount` before performing any further actions. Bit +4 in mode means that amount is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, amount must be a non-negative integer, and mode must be in the range 0..15.
666669
() raw_reserve(int amount, int mode) asm "RAWRESERVE";

tolk/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ set(TOLK_SOURCE
44
src-file.cpp
55
lexer.cpp
66
symtable.cpp
7+
compiler-state.cpp
78
unify-types.cpp
89
parse-tolk.cpp
910
abscode.cpp
@@ -28,6 +29,12 @@ if (${TOLK_DEBUG}) # -DTOLK_DEBUG=1 in CMake options => #define TOLK_DEBUG (for
2829
target_compile_definitions(tolk PRIVATE TOLK_DEBUG=1)
2930
endif()
3031

32+
if (NOT USE_EMSCRIPTEN)
33+
get_filename_component(STDLIB_TOLK_IF_BUILD_FROM_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto/smartcont/stdlib.tolk" REALPATH)
34+
target_compile_definitions(tolk PRIVATE STDLIB_TOLK_IF_BUILD_FROM_SOURCES="${STDLIB_TOLK_IF_BUILD_FROM_SOURCES}")
35+
endif()
36+
37+
3138
if (USE_EMSCRIPTEN)
3239
add_executable(tolkfiftlib tolk-wasm.cpp ${TOLK_SOURCE})
3340
target_include_directories(tolkfiftlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

tolk/abscode.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
#include "tolk.h"
18+
#include "compiler-state.h"
1819

1920
namespace tolk {
2021

@@ -59,7 +60,7 @@ void TmpVar::dump(std::ostream& os) const {
5960

6061
void TmpVar::show(std::ostream& os, int omit_idx) const {
6162
if (cls & _Named) {
62-
os << symbols.get_name(name);
63+
os << G.symbols.get_name(name);
6364
if (omit_idx && (omit_idx >= 2 || (cls & _UniqueName))) {
6465
return;
6566
}

tolk/analyzer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
#include "tolk.h"
18+
#include "compiler-state.h"
1819

1920
namespace tolk {
2021

@@ -768,7 +769,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
768769
tolk_assert(left.size() == right.size());
769770
for (std::size_t i = 0; i < right.size(); i++) {
770771
const VarDescr* ov = values[right[i]];
771-
if (!ov && verbosity >= 5) {
772+
if (!ov && G.is_verbosity(5)) {
772773
std::cerr << "FATAL: error in assignment at right component #" << i << " (no value for _" << right[i] << ")"
773774
<< std::endl;
774775
for (auto x : left) {

tolk/builtins.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
#include "tolk.h"
18+
#include "compiler-state.h"
1819

1920
namespace tolk {
2021
using namespace std::literals::string_literals;
@@ -25,18 +26,11 @@ using namespace std::literals::string_literals;
2526
*
2627
*/
2728

28-
int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt;
29-
std::vector<SymDef*> glob_func, glob_vars, glob_get_methods;
30-
std::set<std::string> prohibited_var_names;
31-
3229
SymDef* define_builtin_func_impl(const std::string& name, SymValAsmFunc* func_val) {
3330
if (name.back() == '_') {
34-
prohibited_var_names.insert(name);
35-
}
36-
sym_idx_t name_idx = symbols.lookup(name, 1);
37-
if (symbols.is_keyword(name_idx)) {
38-
std::cerr << "fatal: global function `" << name << "` already defined as a keyword" << std::endl;
31+
G.prohibited_var_names.insert(name);
3932
}
33+
sym_idx_t name_idx = G.symbols.lookup(name, 1);
4034
SymDef* def = define_global_symbol(name_idx, true);
4135
if (!def) {
4236
std::cerr << "fatal: global function `" << name << "` already defined" << std::endl;

tolk/codegen.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
#include "tolk.h"
18+
#include "compiler-state.h"
1819

1920
namespace tolk {
2021

@@ -324,7 +325,7 @@ bool Op::generate_code_step(Stack& stack) {
324325
if (!used || disabled()) {
325326
return true;
326327
}
327-
std::string name = symbols.get_name(fun_ref->sym_idx);
328+
std::string name = G.symbols.get_name(fun_ref->sym_idx);
328329
stack.o << AsmOp::Custom(name + " GETGLOB", 0, 1);
329330
if (left.size() != 1) {
330331
tolk_assert(left.size() <= 15);
@@ -359,7 +360,7 @@ bool Op::generate_code_step(Stack& stack) {
359360
}
360361
func->compile(stack.o, res, args0, where); // compile res := f (args0)
361362
} else {
362-
std::string name = symbols.get_name(fun_ref->sym_idx);
363+
std::string name = G.symbols.get_name(fun_ref->sym_idx);
363364
stack.o << AsmOp::Custom(name + " CALLDICT", (int)right.size(), (int)left.size());
364365
}
365366
stack.o.undent();
@@ -497,7 +498,7 @@ bool Op::generate_code_step(Stack& stack) {
497498
} else {
498499
auto fv = dynamic_cast<const SymValCodeFunc*>(fun_ref->value);
499500
// todo can be fv == nullptr?
500-
std::string name = symbols.get_name(fun_ref->sym_idx);
501+
std::string name = G.symbols.get_name(fun_ref->sym_idx);
501502
if (fv && (fv->is_inline() || fv->is_inline_ref())) {
502503
stack.o << AsmOp::Custom(name + " INLINECALLDICT", (int)right.size(), (int)left.size());
503504
} else if (fv && fv->code && fv->code->require_callxargs) {
@@ -534,7 +535,7 @@ bool Op::generate_code_step(Stack& stack) {
534535
stack.o << AsmOp::Tuple((int)right.size());
535536
}
536537
if (!right.empty()) {
537-
std::string name = symbols.get_name(fun_ref->sym_idx);
538+
std::string name = G.symbols.get_name(fun_ref->sym_idx);
538539
stack.o << AsmOp::Custom(name + " SETGLOB", 1, 0);
539540
}
540541
stack.s.resize(k);
@@ -894,14 +895,14 @@ void CodeBlob::generate_code(AsmOpList& out, int mode) {
894895
}
895896
ops->generate_code_all(stack);
896897
stack.apply_wrappers(require_callxargs && (mode & Stack::_InlineAny) ? args : -1);
897-
if (!(mode & Stack::_DisableOpt)) {
898-
optimize_code(out);
899-
}
900898
}
901899

902900
void CodeBlob::generate_code(std::ostream& os, int mode, int indent) {
903901
AsmOpList out_list(indent, &vars);
904902
generate_code(out_list, mode);
903+
if (G.settings.optimization_level >= 2) {
904+
optimize_code(out_list);
905+
}
905906
out_list.out(os, mode);
906907
}
907908

tolk/compiler-state.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
This file is part of TON Blockchain Library.
3+
4+
TON Blockchain Library is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 2 of the License, or
7+
(at your option) any later version.
8+
9+
TON Blockchain Library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
#include "compiler-state.h"
18+
19+
namespace tolk {
20+
21+
std::string tolk_version{"0.5.0"};
22+
23+
CompilerState G; // the only mutable global variable in tolk internals
24+
25+
void GlobalPragma::enable(SrcLocation loc) {
26+
if (deprecated_from_v_) {
27+
loc.show_warning(PSTRING() << "#pragma " << name_ <<
28+
" is deprecated since Tolk v" << deprecated_from_v_ <<
29+
". Please, remove this line from your code.");
30+
return;
31+
}
32+
if (!loc.get_src_file()->is_entrypoint_file()) {
33+
// todo generally it's not true; rework pragmas completely
34+
loc.show_warning(PSTRING() << "#pragma " << name_ <<
35+
" should be used in the main file only.");
36+
}
37+
38+
enabled_ = true;
39+
}
40+
41+
void GlobalPragma::always_on_and_deprecated(const char *deprecated_from_v) {
42+
deprecated_from_v_ = deprecated_from_v;
43+
enabled_ = true;
44+
}
45+
46+
47+
} // namespace tolk

tolk/compiler-state.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
This file is part of TON Blockchain Library.
3+
4+
TON Blockchain Library is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU Lesser General Public License as published by
6+
the Free Software Foundation, either version 2 of the License, or
7+
(at your option) any later version.
8+
9+
TON Blockchain Library is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU Lesser General Public License for more details.
13+
14+
You should have received a copy of the GNU Lesser General Public License
15+
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
#pragma once
18+
19+
#include "src-file.h"
20+
#include "symtable.h"
21+
#include "td/utils/Status.h"
22+
#include <set>
23+
#include <string>
24+
25+
namespace tolk {
26+
27+
extern std::string tolk_version;
28+
29+
class GlobalPragma {
30+
std::string name_;
31+
bool enabled_ = false;
32+
const char* deprecated_from_v_ = nullptr;
33+
34+
public:
35+
explicit GlobalPragma(std::string name) : name_(std::move(name)) { }
36+
37+
const std::string& name() const { return name_; }
38+
39+
bool enabled() const { return enabled_; }
40+
void enable(SrcLocation loc);
41+
void always_on_and_deprecated(const char* deprecated_from_v);
42+
};
43+
44+
// CompilerSettings contains settings that can be passed via cmd line or (partially) wasm envelope.
45+
// They are filled once at start and are immutable since the compilation started.
46+
struct CompilerSettings {
47+
enum class FsReadCallbackKind { Realpath, ReadFile };
48+
49+
using FsReadCallback = std::function<td::Result<std::string>(FsReadCallbackKind, const char*)>;
50+
51+
int verbosity = 0;
52+
int optimization_level = 2;
53+
bool stack_layout_comments = true;
54+
55+
std::string entrypoint_filename;
56+
std::string output_filename;
57+
std::string boc_output_filename;
58+
std::string stdlib_filename;
59+
60+
FsReadCallback read_callback;
61+
};
62+
63+
// CompilerState contains a mutable state that is changed while the compilation is going on.
64+
// It's a "global state" of all compilation.
65+
// Historically, in FunC, this global state was spread along many global C++ variables.
66+
// Now, no global C++ variables except `CompilerState G` are present.
67+
struct CompilerState {
68+
CompilerSettings settings;
69+
70+
SymTable symbols;
71+
int scope_level = 0;
72+
SymDef* sym_def[SymTable::SIZE_PRIME + 1]{};
73+
SymDef* global_sym_def[SymTable::SIZE_PRIME + 1]{};
74+
std::vector<std::pair<int, SymDef>> symbol_stack;
75+
std::vector<SrcLocation> scope_opened_at;
76+
77+
AllRegisteredSrcFiles all_src_files;
78+
79+
int glob_func_cnt = 0, glob_var_cnt = 0, const_cnt = 0;
80+
std::vector<SymDef*> glob_func, glob_vars, glob_get_methods;
81+
std::set<std::string> prohibited_var_names;
82+
83+
std::string generated_from;
84+
GlobalPragma pragma_allow_post_modification{"allow-post-modification"};
85+
GlobalPragma pragma_compute_asm_ltr{"compute-asm-ltr"};
86+
GlobalPragma pragma_remove_unused_functions{"remove-unused-functions"};
87+
88+
bool is_verbosity(int gt_eq) const { return settings.verbosity >= gt_eq; }
89+
};
90+
91+
extern CompilerState G;
92+
93+
} // namespace tolk

tolk/gen-abscode.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
You should have received a copy of the GNU Lesser General Public License
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
17-
#include <numeric>
1817
#include "tolk.h"
18+
#include "compiler-state.h"
1919

2020
using namespace std::literals::string_literals;
2121

@@ -122,7 +122,7 @@ bool Expr::deduce_type(const Lexer& lex) {
122122
} catch (UnifyError& ue) {
123123
std::ostringstream os;
124124
os << "cannot implicitly assign an expression of type " << args[1]->e_type
125-
<< " to a variable or pattern of type " << rhs_type << " in modifying method `" << symbols.get_name(val)
125+
<< " to a variable or pattern of type " << rhs_type << " in modifying method `" << G.symbols.get_name(val)
126126
<< "` : " << ue;
127127
lex.error(os.str());
128128
}
@@ -197,14 +197,14 @@ int Expr::predefine_vars() {
197197
case _Var:
198198
if (!sym) {
199199
tolk_assert(val < 0 && here.is_defined());
200-
if (prohibited_var_names.count(symbols.get_name(~val))) {
200+
if (G.prohibited_var_names.count(G.symbols.get_name(~val))) {
201201
throw ParseError{
202-
here, PSTRING() << "symbol `" << symbols.get_name(~val) << "` cannot be redefined as a variable"};
202+
here, PSTRING() << "symbol `" << G.symbols.get_name(~val) << "` cannot be redefined as a variable"};
203203
}
204204
sym = define_symbol(~val, false, here);
205205
// std::cerr << "predefining variable " << symbols.get_name(~val) << std::endl;
206206
if (!sym) {
207-
throw ParseError{here, std::string{"redefined variable `"} + symbols.get_name(~val) + "`"};
207+
throw ParseError{here, std::string{"redefined variable `"} + G.symbols.get_name(~val) + "`"};
208208
}
209209
sym->value = new SymVal{SymValKind::_Var, -1, e_type};
210210
return 1;

tolk/lexer.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
1616
*/
1717
#include "lexer.h"
18+
#include "compiler-state.h"
1819
#include "symtable.h"
1920
#include <cassert>
2021

@@ -426,7 +427,7 @@ struct ChunkIdentifierOrKeyword final : ChunkLexerBase {
426427
if (TokenType kw_tok = maybe_keyword(str_val)) {
427428
lex->add_token(kw_tok, str_val);
428429
} else {
429-
symbols.lookup_add(static_cast<std::string>(str_val));
430+
G.symbols.lookup_add(static_cast<std::string>(str_val));
430431
lex->add_token(tok_identifier, str_val);
431432
}
432433
return true;
@@ -452,7 +453,7 @@ struct ChunkIdentifierInBackticks final : ChunkLexerBase {
452453

453454
std::string_view str_val(str_begin + 1, lex->c_str() - str_begin - 1);
454455
lex->skip_chars(1);
455-
symbols.lookup_add(static_cast<std::string>(str_val));
456+
G.symbols.lookup_add(static_cast<std::string>(str_val));
456457
lex->add_token(tok_identifier, str_val);
457458
return true;
458459
}
@@ -611,7 +612,7 @@ void Lexer::next_special(TokenType parse_next_as, const char* str_expected) {
611612

612613
int Lexer::cur_sym_idx() const {
613614
assert(tok() == tok_identifier);
614-
return symbols.lookup_add(cur_str_std_string());
615+
return G.symbols.lookup_add(cur_str_std_string());
615616
}
616617

617618
void Lexer::error(const std::string& err_msg) const {

0 commit comments

Comments
 (0)