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

@ -35,12 +35,6 @@ if (${TOLK_DEBUG}) # -DTOLK_DEBUG=1 in CMake options => #define TOLK_DEBUG (for
target_compile_definitions(tolk PRIVATE TOLK_DEBUG=1)
endif()
if (NOT USE_EMSCRIPTEN)
get_filename_component(STDLIB_TOLK_IF_BUILD_FROM_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/../crypto/smartcont/stdlib.tolk" REALPATH)
target_compile_definitions(tolk PRIVATE STDLIB_TOLK_IF_BUILD_FROM_SOURCES="${STDLIB_TOLK_IF_BUILD_FROM_SOURCES}")
endif()
if (USE_EMSCRIPTEN)
add_executable(tolkfiftlib tolk-wasm.cpp ${TOLK_SOURCE})
target_include_directories(tolkfiftlib PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)

View file

@ -1121,10 +1121,6 @@ void define_builtins() {
define_builtin_func("_~/_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 0));
define_builtin_func("_^/_", arith_bin_op, std::bind(compile_div, _1, _2, _3, 1));
define_builtin_func("_%_", arith_bin_op, std::bind(compile_mod, _1, _2, _3, -1));
define_builtin_func("divmod", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2));
define_builtin_func("~divmod", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2));
define_builtin_func("moddiv", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2), {}, {1, 0});
define_builtin_func("~moddiv", TypeExpr::new_map(Int2, Int2), AsmOp::Custom("DIVMOD", 2, 2), {}, {1, 0});
define_builtin_func("_<<_", arith_bin_op, compile_lshift);
define_builtin_func("_>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, -1));
define_builtin_func("_~>>_", arith_bin_op, std::bind(compile_rshift, _1, _2, _3, 0));
@ -1144,10 +1140,10 @@ void define_builtins() {
define_builtin_func("^_&=_", arith_bin_op, compile_bitwise_and);
define_builtin_func("^_|=_", arith_bin_op, compile_bitwise_or);
define_builtin_func("^_^=_", arith_bin_op, compile_bitwise_xor);
define_builtin_func("muldiv", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, -1));
define_builtin_func("muldivr", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 0));
define_builtin_func("muldivc", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 1));
define_builtin_func("muldivmod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2));
define_builtin_func("mulDivFloor", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, -1));
define_builtin_func("mulDivRound", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 0));
define_builtin_func("mulDivCeil", TypeExpr::new_map(Int3, Int), std::bind(compile_muldiv, _1, _2, _3, 1));
define_builtin_func("mulDivMod", TypeExpr::new_map(Int3, Int2), AsmOp::Custom("MULDIVMOD", 3, 2));
define_builtin_func("_==_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 2));
define_builtin_func("_!=_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 5));
define_builtin_func("_<_", arith_bin_op, std::bind(compile_cmp_int, _1, _2, 4));
@ -1162,24 +1158,23 @@ void define_builtins() {
define_builtin_func("__throw", impure_un_op, compile_throw, true);
define_builtin_func("__throw_arg", throw_arg_op, compile_throw_arg, true);
define_builtin_func("__throw_if_unless", TypeExpr::new_map(Int3, Unit), std::bind(compile_throw_if_unless, _1, _2), true);
define_builtin_func("load_int", fetch_int_op, std::bind(compile_fetch_int, _1, _2, true, true), {}, {1, 0});
define_builtin_func("load_uint", fetch_int_op, std::bind(compile_fetch_int, _1, _2, true, false), {}, {1, 0});
define_builtin_func("preload_int", prefetch_int_op, std::bind(compile_fetch_int, _1, _2, false, true));
define_builtin_func("preload_uint", prefetch_int_op, std::bind(compile_fetch_int, _1, _2, false, false));
define_builtin_func("store_int", store_int_op, std::bind(compile_store_int, _1, _2, true), {1, 0, 2});
define_builtin_func("store_uint", store_int_op, std::bind(compile_store_int, _1, _2, false), {1, 0, 2});
define_builtin_func("~store_int", store_int_method, std::bind(compile_store_int, _1, _2, true), {1, 0, 2});
define_builtin_func("~store_uint", store_int_method, std::bind(compile_store_int, _1, _2, false), {1, 0, 2});
define_builtin_func("load_bits", fetch_slice_op, std::bind(compile_fetch_slice, _1, _2, true), {}, {1, 0});
define_builtin_func("preload_bits", prefetch_slice_op, std::bind(compile_fetch_slice, _1, _2, false));
define_builtin_func("at", TypeExpr::new_forall({X}, TypeExpr::new_map(TupleInt, X)), compile_tuple_at);
define_builtin_func("touch", TypeExpr::new_forall({X}, TypeExpr::new_map(X, X)), AsmOp::Nop());
define_builtin_func("~touch", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
AsmOp::Nop());
define_builtin_func("~dump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
AsmOp::Custom("s0 DUMP", 1, 1), true);
define_builtin_func("~strdump", TypeExpr::new_forall({X}, TypeExpr::new_map(X, TypeExpr::new_tensor({X, Unit}))),
AsmOp::Custom("STRDUMP", 1, 1), true);
define_builtin_func("loadInt", fetch_int_op, std::bind(compile_fetch_int, _1, _2, true, true), {}, {1, 0});
define_builtin_func("loadUint", fetch_int_op, std::bind(compile_fetch_int, _1, _2, true, false), {}, {1, 0});
define_builtin_func("loadBits", fetch_slice_op, std::bind(compile_fetch_slice, _1, _2, true), {}, {1, 0});
define_builtin_func("preloadInt", prefetch_int_op, std::bind(compile_fetch_int, _1, _2, false, true));
define_builtin_func("preloadUint", prefetch_int_op, std::bind(compile_fetch_int, _1, _2, false, false));
define_builtin_func("preloadBits", prefetch_slice_op, std::bind(compile_fetch_slice, _1, _2, false));
define_builtin_func("storeInt", store_int_op, std::bind(compile_store_int, _1, _2, true), {1, 0, 2});
define_builtin_func("storeUint", store_int_op, std::bind(compile_store_int, _1, _2, false), {1, 0, 2});
define_builtin_func("~storeInt", store_int_method, std::bind(compile_store_int, _1, _2, true), {1, 0, 2});
define_builtin_func("~storeUint", store_int_method, std::bind(compile_store_int, _1, _2, false), {1, 0, 2});
define_builtin_func("tupleAt", TypeExpr::new_forall({X}, TypeExpr::new_map(TupleInt, X)), compile_tuple_at);
define_builtin_func("debugPrint", TypeExpr::new_forall({X}, TypeExpr::new_map(X, Unit)),
AsmOp::Custom("s0 DUMP DROP", 1, 1), true);
define_builtin_func("debugPrintString", TypeExpr::new_forall({X}, TypeExpr::new_map(X, Unit)),
AsmOp::Custom("STRDUMP DROP", 1, 1), true);
define_builtin_func("debugDumpStack", TypeExpr::new_map(Unit, Unit),
AsmOp::Custom("DUMPSTK", 0, 0), true);
}
} // namespace tolk

View file

@ -52,10 +52,9 @@ struct CompilerSettings {
int optimization_level = 2;
bool stack_layout_comments = true;
std::string entrypoint_filename;
std::string output_filename;
std::string boc_output_filename;
std::string stdlib_filename;
std::string stdlib_folder; // a path to tolk-stdlib/; files imported via @stdlib/xxx are there
FsReadCallback read_callback;
@ -82,8 +81,6 @@ struct CompilerState {
std::vector<SymDef*> all_code_functions, all_global_vars, all_get_methods, all_constants;
AllRegisteredSrcFiles all_src_files;
std::string generated_from;
bool is_verbosity(int gt_eq) const { return settings.verbosity >= gt_eq; }
};

View file

@ -979,12 +979,6 @@ void pipeline_convert_ast_to_legacy_Expr_Op(const AllSrcFiles& all_src_files) {
for (const SrcFile* file : all_src_files) {
tolk_assert(file->ast);
if (!file->is_stdlib_file()) {
// file->ast->debug_print();
G.generated_from += file->rel_filename;
G.generated_from += ", ";
}
for (AnyV v : file->ast->as<ast_tolk_file>()->get_toplevel_declarations()) {
if (auto v_func = v->try_as<ast_function_declaration>()) {
if (v_func->is_asm_function()) {

View file

@ -42,10 +42,11 @@ AllSrcFiles pipeline_discover_and_parse_sources(const std::string& stdlib_filena
for (AnyV v_toplevel : file->ast->as<ast_tolk_file>()->get_toplevel_declarations()) {
if (auto v_import = v_toplevel->try_as<ast_import_statement>()) {
size_t pos = file->rel_filename.rfind('/');
std::string rel_filename = pos == std::string::npos
? v_import->get_file_name()
: file->rel_filename.substr(0, pos + 1) + v_import->get_file_name();
std::string imported_str = v_import->get_file_name();
size_t cur_slash_pos = file->rel_filename.rfind('/');
std::string rel_filename = cur_slash_pos == std::string::npos || imported_str[0] == '@'
? std::move(imported_str)
: file->rel_filename.substr(0, cur_slash_pos + 1) + imported_str;
SrcFile* imported = G.all_src_files.locate_and_register_source_file(rel_filename, v_import->loc);
file->imports.push_back(SrcFile::ImportStatement{imported});

View file

@ -132,9 +132,20 @@ static void generate_output_func(SymDef* func_sym) {
}
}
void pipeline_generate_fif_output_to_std_cout() {
void pipeline_generate_fif_output_to_std_cout(const AllSrcFiles& all_src_files) {
std::cout << "\"Asm.fif\" include\n";
std::cout << "// automatically generated from " << G.generated_from << std::endl;
std::cout << "// automatically generated from ";
bool need_comma = false;
for (const SrcFile* file : all_src_files) {
if (!file->is_stdlib_file()) {
if (need_comma) {
std::cout << ", ";
}
std::cout << file->rel_filename;
need_comma = true;
}
}
std::cout << std::endl;
std::cout << "PROGRAM{\n";
bool has_main_procedure = false;

View file

@ -296,7 +296,7 @@ static void register_function(V<ast_function_declaration> v) {
v->error("`builtin` used for non-builtin function");
}
#ifdef TOLK_DEBUG
// in release, we don't need this check, since `builtin` is used only in stdlib.tolk, which is our responsibility
// in release, we don't need this check, since `builtin` is used only in stdlib, which is our responsibility
if (!func_val->sym_type->equals_to(func_type) || func_val->is_marked_as_pure() != v->marked_as_pure) {
v->error("declaration for `builtin` function doesn't match an actual one");
}

View file

@ -36,6 +36,6 @@ void pipeline_register_global_symbols(const AllSrcFiles&);
void pipeline_convert_ast_to_legacy_Expr_Op(const AllSrcFiles&);
void pipeline_find_unused_symbols();
void pipeline_generate_fif_output_to_std_cout();
void pipeline_generate_fif_output_to_std_cout(const AllSrcFiles&);
} // namespace tolk

View file

@ -87,6 +87,11 @@ AllSrcFiles AllRegisteredSrcFiles::get_all_files() const {
return src_files_immutable;
}
bool SrcFile::is_stdlib_file() const {
std::string_view rel(rel_filename);
return rel.size() > 10 && rel.substr(0, 8) == "@stdlib/"; // common.tolk, tvm-dicts.tolk, etc
}
bool SrcFile::is_offset_valid(int offset) const {
return offset >= 0 && offset < static_cast<int>(text.size());
}

View file

@ -51,7 +51,7 @@ struct SrcFile {
SrcFile(const SrcFile& other) = delete;
SrcFile &operator=(const SrcFile&) = delete;
bool is_stdlib_file() const { return file_id == 0; /* stdlib always exists, has no imports and parsed the first */ }
bool is_stdlib_file() const;
bool is_offset_valid(int offset) const;
SrcPosition convert_offset(int offset) const;

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;
}

View file

@ -34,21 +34,18 @@
using namespace tolk;
td::Result<std::string> compile_internal(char *config_json) {
static td::Result<std::string> compile_internal(char *config_json) {
TRY_RESULT(input_json, td::json_decode(td::MutableSlice(config_json)))
td::JsonObject& config = input_json.get_object();
TRY_RESULT(opt_level, td::get_json_object_int_field(config, "optimizationLevel", true, 2));
TRY_RESULT(stdlib_tolk, td::get_json_object_string_field(config, "stdlibLocation", false));
TRY_RESULT(stack_comments, td::get_json_object_bool_field(config, "withStackComments", true, false));
TRY_RESULT(entrypoint_filename, td::get_json_object_string_field(config, "entrypointFileName", false));
TRY_RESULT(experimental_options, td::get_json_object_string_field(config, "experimentalOptions", true));
G.settings.verbosity = 0;
G.settings.optimization_level = std::max(0, opt_level);
G.settings.stdlib_filename = stdlib_tolk;
G.settings.stack_layout_comments = stack_comments;
G.settings.entrypoint_filename = entrypoint_filename;
if (!experimental_options.empty()) {
G.settings.parse_experimental_options_cmd_arg(experimental_options.c_str());
}
@ -56,8 +53,8 @@ td::Result<std::string> compile_internal(char *config_json) {
std::ostringstream outs, errs;
std::cout.rdbuf(outs.rdbuf());
std::cerr.rdbuf(errs.rdbuf());
int tolk_res = tolk::tolk_proceed(entrypoint_filename);
if (tolk_res != 0) {
int exit_code = tolk_proceed(entrypoint_filename);
if (exit_code != 0) {
return td::Status::Error("Tolk compilation error: " + errs.str());
}
@ -78,32 +75,29 @@ td::Result<std::string> compile_internal(char *config_json) {
/// Callback used to retrieve file contents from a "not file system". See tolk-js for implementation.
/// The callback must fill either destContents or destError.
/// The implementor must use malloc() for them and use free() after tolk_compile returns.
typedef void (*CStyleReadFileCallback)(int kind, char const* data, char** destContents, char** destError);
typedef void (*WasmFsReadCallback)(int kind, char const* data, char** destContents, char** destError);
CompilerSettings::FsReadCallback wrapReadCallback(CStyleReadFileCallback _readCallback)
{
CompilerSettings::FsReadCallback readCallback;
if (_readCallback) {
readCallback = [=](CompilerSettings::FsReadCallbackKind kind, char const* data) -> td::Result<std::string> {
char* destContents = nullptr;
char* destError = nullptr;
static CompilerSettings::FsReadCallback wrap_wasm_read_callback(WasmFsReadCallback _readCallback) {
return [_readCallback](CompilerSettings::FsReadCallbackKind kind, char const* data) -> td::Result<std::string> {
char* destContents = nullptr;
char* destError = nullptr;
if (_readCallback) {
_readCallback(static_cast<int>(kind), data, &destContents, &destError);
if (!destContents && !destError) {
return td::Status::Error("Callback not supported");
}
if (destContents) {
return destContents;
}
}
if (destContents) {
return destContents;
}
if (destError) {
return td::Status::Error(std::string(destError));
};
}
return readCallback;
}
return td::Status::Error("Invalid callback from wasm");
};
}
extern "C" {
const char* version() {
auto version_json = td::JsonBuilder();
td::JsonBuilder version_json = td::JsonBuilder();
auto obj = version_json.enter_object();
obj("tolkVersion", TOLK_VERSION);
obj("tolkFiftLibCommitHash", GitMetadata::CommitSHA1());
@ -112,23 +106,22 @@ const char* version() {
return strdup(version_json.string_builder().as_cslice().c_str());
}
const char *tolk_compile(char *config_json, CStyleReadFileCallback callback) {
G.settings.read_callback = wrapReadCallback(callback);
const char *tolk_compile(char *config_json, WasmFsReadCallback callback) {
G.settings.read_callback = wrap_wasm_read_callback(callback);
td::Result<std::string> res = compile_internal(config_json);
if (res.is_error()) {
auto result = res.move_as_error();
auto error_res = td::JsonBuilder();
auto error_o = error_res.enter_object();
error_o("status", "error");
error_o("message", result.message().str());
error_o.leave();
td::JsonBuilder error_res = td::JsonBuilder();
auto obj = error_res.enter_object();
obj("status", "error");
obj("message", res.move_as_error().message().str());
obj.leave();
return strdup(error_res.string_builder().as_cslice().c_str());
}
auto res_string = res.move_as_ok();
std::string res_string = res.move_as_ok();
return strdup(res_string.c_str());
}
}
} // extern "C"

View file

@ -48,21 +48,16 @@ int tolk_proceed(const std::string &entrypoint_filename) {
define_builtins();
lexer_init();
// on any error, an exception is thrown, and the message is printed out below
// (currently, only a single error can be printed)
try {
if (G.settings.stdlib_filename.empty()) {
throw Fatal("stdlib filename not specified");
}
// on any error, an exception is thrown, and the message is printed out below
// (currently, only a single error can be printed)
AllSrcFiles all_files = pipeline_discover_and_parse_sources(G.settings.stdlib_filename, entrypoint_filename);
AllSrcFiles all_files = pipeline_discover_and_parse_sources("@stdlib/common.tolk", entrypoint_filename);
pipeline_register_global_symbols(all_files);
pipeline_convert_ast_to_legacy_Expr_Op(all_files);
pipeline_find_unused_symbols();
pipeline_generate_fif_output_to_std_cout();
pipeline_generate_fif_output_to_std_cout(all_files);
return 0;
} catch (Fatal& fatal) {