1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-03-09 15:40:10 +00:00

[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
This commit is contained in:
tolk-vm 2024-10-31 11:02:01 +04:00
parent f0e6470d0b
commit 6c30e5a7eb
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
21 changed files with 604 additions and 506 deletions

View file

@ -24,16 +24,23 @@
from all source files in the program, then also delete it here.
*/
#include "tolk.h"
#include "compiler-state.h"
#include "td/utils/port/path.h"
#include <getopt.h>
#include <fstream>
#include <utility>
#include <sys/stat.h>
#include "git.h"
using namespace tolk;
void usage(const char* progname) {
std::cerr
<< "usage: " << progname << " [options] <filename.tolk>\n"
"\tGenerates Fift TVM assembler code from a .tolk file\n"
"-o<fif-filename>\tWrites generated code into specified .fif file instead of stdout\n"
"-b<boc-filename>\tGenerate Fift instructions to save TVM bytecode into .boc file\n"
"-s<stdlib.tolk>\tSpecify stdlib location (same as env TOLK_STDLIB; if unset, auto-discover)\n"
"-O<level>\tSets optimization level (2 by default)\n"
"-S\tDon't include stack layout comments into Fift output\n"
"-e\tIncreases verbosity level (extra output into stderr)\n"
@ -41,28 +48,100 @@ void usage(const char* progname) {
std::exit(2);
}
static std::string auto_discover_stdlib_location() {
if (const char* env_var = getenv("TOLK_STDLIB")) {
return env_var;
}
// this define is automatically set if just building this repo locally with cmake
#ifdef STDLIB_TOLK_IF_BUILD_FROM_SOURCES
return STDLIB_TOLK_IF_BUILD_FROM_SOURCES;
#endif
// this define is automatically set when compiling a linux package for distribution
// (since binaries and smartcont/ folder are installed to a predefined path)
// todo provide in cmake
#ifdef STDLIB_TOLK_IF_BUILD_TO_PACKAGE
return STDLIB_TOLK_IF_BUILD_TO_PACKAGE;
#endif
return {};
}
td::Result<std::string> fs_read_callback(CompilerSettings::FsReadCallbackKind kind, const char* query) {
switch (kind) {
case CompilerSettings::FsReadCallbackKind::ReadFile: {
struct stat f_stat;
int res = stat(query, &f_stat);
if (res != 0 || !S_ISREG(f_stat.st_mode)) {
return td::Status::Error(std::string{"cannot open file "} + query);
}
size_t file_size = static_cast<size_t>(f_stat.st_size);
std::string str;
str.resize(file_size);
FILE* f = fopen(query, "rb");
fread(str.data(), file_size, 1, f);
fclose(f);
return std::move(str);
}
case CompilerSettings::FsReadCallbackKind::Realpath: {
td::Result<std::string> res_realpath = td::realpath(td::CSlice(query));
if (res_realpath.is_error()) {
return td::Status::Error(std::string{"cannot find file "} + query);
}
return res_realpath;
}
default: {
return td::Status::Error("Unknown query kind");
}
}
}
class StdCoutRedirectToFile {
std::unique_ptr<std::fstream> output_file;
std::streambuf* backup_sbuf = nullptr;
public:
explicit StdCoutRedirectToFile(const std::string& output_filename) {
if (!output_filename.empty()) {
output_file = std::make_unique<std::fstream>(output_filename, std::fstream::trunc | std::fstream::out);
if (output_file->is_open()) {
backup_sbuf = std::cout.rdbuf(output_file->rdbuf());
}
}
}
~StdCoutRedirectToFile() {
if (backup_sbuf) {
std::cout.rdbuf(backup_sbuf);
}
}
bool is_failed() const { return output_file && !output_file->is_open(); }
};
int main(int argc, char* const argv[]) {
int i;
std::string output_filename;
while ((i = getopt(argc, argv, "o:b:O:Sevh")) != -1) {
while ((i = getopt(argc, argv, "o:b:s:O:Sevh")) != -1) {
switch (i) {
case 'o':
output_filename = optarg;
G.settings.output_filename = optarg;
break;
case 'b':
tolk::boc_output_filename = optarg;
G.settings.boc_output_filename = optarg;
break;
case 's':
G.settings.stdlib_filename = optarg;
break;
case 'O':
tolk::opt_level = std::max(0, atoi(optarg));
G.settings.optimization_level = std::max(0, atoi(optarg));
break;
case 'S':
tolk::stack_layout_comments = false;
G.settings.stack_layout_comments = false;
break;
case 'e':
++tolk::verbosity;
G.settings.verbosity++;
break;
case 'v':
std::cout << "Tolk compiler v" << tolk::tolk_version << "\n";
std::cout << "Tolk compiler v" << tolk_version << "\n";
std::cout << "Build commit: " << GitMetadata::CommitSHA1() << "\n";
std::cout << "Build date: " << GitMetadata::CommitDate() << "\n";
std::exit(0);
@ -72,16 +151,24 @@ int main(int argc, char* const argv[]) {
}
}
std::ostream *outs = &std::cout;
StdCoutRedirectToFile redirect_cout(G.settings.output_filename);
if (redirect_cout.is_failed()) {
std::cerr << "Failed to create output file " << G.settings.output_filename << '\n';
return 2;
}
std::unique_ptr<std::fstream> fs;
if (!output_filename.empty()) {
fs = std::make_unique<std::fstream>(output_filename, std::fstream::trunc | std::fstream::out);
if (!fs->is_open()) {
std::cerr << "failed to create output file " << output_filename << '\n';
return 2;
}
outs = fs.get();
// if stdlib wasn't specify as an option — locate it based on env
if (G.settings.stdlib_filename.empty()) {
G.settings.stdlib_filename = auto_discover_stdlib_location();
}
if (G.settings.stdlib_filename.empty()) {
std::cerr << "Failed to discover stdlib.tolk.\n"
"Probably, you have a non-standard Tolk installation.\n"
"Please, provide env variable TOLK_STDLIB referencing to it.\n";
return 2;
}
if (G.is_verbosity(2)) {
std::cerr << "stdlib located at " << G.settings.stdlib_filename << '\n';
}
if (optind != argc - 1) {
@ -89,9 +176,8 @@ int main(int argc, char* const argv[]) {
return 2;
}
std::string entrypoint_file_name = argv[optind];
G.settings.entrypoint_filename = argv[optind];
G.settings.read_callback = fs_read_callback;
tolk::read_callback = tolk::fs_read_callback;
return tolk::tolk_proceed(entrypoint_file_name, *outs, std::cerr);
return tolk_proceed(G.settings.entrypoint_filename);
}