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

[Tolk] Completely rework stdlib: multiple files and renaming

- split stdlib.tolk into multiple files (tolk-stdlib/ folder)
  (the "core" common.tolk is auto-imported, the rest are
  needed to be explicitly imported like "@stdlib/tvm-dicts.tolk")
- all functions were renamed to long and clear names
- new naming is camelCase
This commit is contained in:
tolk-vm 2024-10-31 11:16:19 +04:00
parent e2edadba92
commit 12ff28ac94
No known key found for this signature in database
GPG key ID: 7905DD7FE0324B12
48 changed files with 2966 additions and 2458 deletions

View file

@ -29,9 +29,14 @@
#include "td/utils/port/path.h"
#include <getopt.h>
#include <fstream>
#include <utility>
#include <sys/stat.h>
#include <filesystem>
#ifdef TD_DARWIN
#include <mach-o/dyld.h>
#elif TD_WINDOWS
#include <windows.h>
#else // linux
#include <unistd.h>
#endif
#include "git.h"
using namespace tolk;
@ -50,42 +55,89 @@ void usage(const char* progname) {
std::exit(2);
}
static bool stdlib_file_exists(std::filesystem::path& stdlib_tolk) {
static bool stdlib_folder_exists(const char* stdlib_folder) {
struct stat f_stat;
stdlib_tolk = stdlib_tolk.lexically_normal();
int res = stat(stdlib_tolk.c_str(), &f_stat);
return res == 0 && S_ISREG(f_stat.st_mode);
int res = stat(stdlib_folder, &f_stat);
return res == 0 && (f_stat.st_mode & S_IFMT) == S_IFDIR;
}
static std::string auto_discover_stdlib_location(const char* argv0) {
// first, the user can specify env var that points directly to stdlib (useful for non-standard compiler locations)
if (const char* env_var = getenv("TOLK_STDLIB")) {
return env_var;
// getting current executable path is a complicated and not cross-platform task
// for instance, we can't just use argv[0] or even filesystem::canonical
// https://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe/1024937
static bool get_current_executable_filename(std::string& out) {
#ifdef TD_DARWIN
char name_buf[1024];
unsigned int size = 1024;
if (0 == _NSGetExecutablePath(name_buf, &size)) { // may contain ../, so normalize it
char *exe_path = realpath(name_buf, nullptr);
if (exe_path != nullptr) {
out = exe_path;
return true;
}
}
#elif TD_WINDOWS
char exe_path[1024];
if (GetModuleFileNameA(nullptr, exe_path, 1024)) {
out = exe_path;
std::replace(out.begin(), out.end(), '\\', '/'); // modern Windows correctly deals with / separator
return true;
}
#else // linux
char exe_path[1024];
ssize_t res = readlink("/proc/self/exe", exe_path, 1024 - 1);
if (res >= 0) {
exe_path[res] = 0;
out = exe_path;
return true;
}
#endif
return false;
}
// simple join "/some/folder/" (guaranteed to end with /) and "../relative/path"
static std::string join_path(std::string dir, const char* relative) {
while (relative[0] == '.' && relative[1] == '.' && relative[2] == '/') {
size_t slash_pos = dir.find_last_of('/', dir.size() - 2); // last symbol is slash, find before it
if (slash_pos != std::string::npos) {
dir = dir.substr(0, slash_pos + 1);
}
relative += 3;
}
return dir + relative;
}
static std::string auto_discover_stdlib_folder() {
// if the user launches tolk compiler from a package installed (e.g. /usr/bin/tolk),
// locate stdlib in /usr/share/ton/smartcont (this folder exists on package installation)
// (note, that paths are not absolute, they are relative to the launched binary)
// consider https://github.com/ton-blockchain/packages for actual paths
std::filesystem::path executable_dir = std::filesystem::canonical(argv0).remove_filename();
std::string executable_filename;
if (!get_current_executable_filename(executable_filename)) {
return {};
}
// extract dirname to concatenate with relative paths (separator / is ok even for windows)
size_t slash_pos = executable_filename.find_last_of('/');
std::string executable_dir = executable_filename.substr(0, slash_pos + 1);
#ifdef TD_DARWIN
auto def_location = executable_dir / "../share/ton/ton/smartcont/stdlib.tolk";
std::string def_location = join_path(executable_dir, "../share/ton/ton/smartcont/tolk-stdlib");
#elif TD_WINDOWS
auto def_location = executable_dir / "smartcont/stdlib.tolk";
std::string def_location = join_path(executable_dir, "smartcont/tolk-stdlib");
#else // linux
auto def_location = executable_dir / "../share/ton/smartcont/stdlib.tolk";
std::string def_location = join_path(executable_dir, "../share/ton/smartcont/tolk-stdlib");
#endif
if (stdlib_file_exists(def_location)) {
if (stdlib_folder_exists(def_location.c_str())) {
return def_location;
}
// so, the binary is not from a system package
// maybe it's just built from sources? e.g. ~/ton/cmake-build-debug/tolk/tolk
// then, check the ~/ton/crypto/smartcont folder
auto near_when_built_from_sources = executable_dir / "../../crypto/smartcont/stdlib.tolk";
if (stdlib_file_exists(near_when_built_from_sources)) {
std::string near_when_built_from_sources = join_path(executable_dir, "../../crypto/smartcont/tolk-stdlib");
if (stdlib_folder_exists(near_when_built_from_sources.c_str())) {
return near_when_built_from_sources;
}
@ -95,10 +147,31 @@ static std::string auto_discover_stdlib_location(const char* argv0) {
td::Result<std::string> fs_read_callback(CompilerSettings::FsReadCallbackKind kind, const char* query) {
switch (kind) {
case CompilerSettings::FsReadCallbackKind::Realpath: {
td::Result<std::string> res_realpath;
if (query[0] == '@' && strlen(query) > 8 && !strncmp(query, "@stdlib/", 8)) {
// import "@stdlib/filename" or import "@stdlib/filename.tolk"
std::string path = G.settings.stdlib_folder + static_cast<std::string>(query + 7);
if (strncmp(path.c_str() + path.size() - 5, ".tolk", 5) != 0) {
path += ".tolk";
}
res_realpath = td::realpath(td::CSlice(path.c_str()));
} else {
// import "relative/to/cwd/path.tolk"
res_realpath = td::realpath(td::CSlice(query));
}
if (res_realpath.is_error()) {
// note, that for non-existing files, `realpath()` on Linux/Mac returns an error,
// whereas on Windows, it returns okay, but fails after, on reading, with a message "cannot open file"
return td::Status::Error(std::string{"cannot find file "} + query);
}
return res_realpath;
}
case CompilerSettings::FsReadCallbackKind::ReadFile: {
struct stat f_stat;
int res = stat(query, &f_stat);
if (res != 0 || !S_ISREG(f_stat.st_mode)) {
int res = stat(query, &f_stat); // query here is already resolved realpath
if (res != 0 || (f_stat.st_mode & S_IFMT) != S_IFREG) {
return td::Status::Error(std::string{"cannot open file "} + query);
}
@ -110,15 +183,8 @@ td::Result<std::string> fs_read_callback(CompilerSettings::FsReadCallbackKind ki
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");
return td::Status::Error("unknown query kind");
}
}
}
@ -185,16 +251,26 @@ int main(int argc, char* const argv[]) {
return 2;
}
// locate stdlib.tolk based on env or default system paths
G.settings.stdlib_filename = auto_discover_stdlib_location(argv[0]);
if (G.settings.stdlib_filename.empty()) {
std::cerr << "Failed to discover stdlib.tolk.\n"
// locate tolk-stdlib/ based on env or default system paths
if (const char* env_var = getenv("TOLK_STDLIB")) {
std::string stdlib_filename = static_cast<std::string>(env_var) + "/common.tolk";
td::Result<std::string> res = td::realpath(td::CSlice(stdlib_filename.c_str()));
if (res.is_error()) {
std::cerr << "Environment variable TOLK_STDLIB is invalid: " << res.move_as_error().message().c_str() << std::endl;
return 2;
}
G.settings.stdlib_folder = env_var;
} else {
G.settings.stdlib_folder = auto_discover_stdlib_folder();
}
if (G.settings.stdlib_folder.empty()) {
std::cerr << "Failed to discover Tolk stdlib.\n"
"Probably, you have a non-standard Tolk installation.\n"
"Please, provide env variable TOLK_STDLIB referencing to it.\n";
"Please, provide env variable TOLK_STDLIB referencing to tolk-stdlib/ folder.\n";
return 2;
}
if (G.is_verbosity(2)) {
std::cerr << "stdlib located at " << G.settings.stdlib_filename << std::endl;
std::cerr << "stdlib folder: " << G.settings.stdlib_folder << std::endl;
}
if (optind != argc - 1) {
@ -202,8 +278,8 @@ int main(int argc, char* const argv[]) {
return 2;
}
G.settings.entrypoint_filename = argv[optind];
G.settings.read_callback = fs_read_callback;
return tolk_proceed(G.settings.entrypoint_filename);
int exit_code = tolk_proceed(argv[optind]);
return exit_code;
}