mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-13 03:32:22 +00:00
Since I've implemented AST, now I can drop forward declarations. Instead, I traverse AST of all files and register global symbols (functions, constants, global vars) as a separate step, in advance. That's why, while converting AST to Expr/Op, all available symbols are already registered. This greatly simplifies "intermediate state" of yet unknown functions and checking them afterward. Redeclaration of local variables (inside the same scope) is now also prohibited.
143 lines
4.9 KiB
C++
143 lines
4.9 KiB
C++
/*
|
|
This file is part of TON Blockchain Library.
|
|
|
|
TON Blockchain Library is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
TON Blockchain Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with TON Blockchain Library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace tolk {
|
|
|
|
struct ASTNodeBase;
|
|
|
|
struct SrcFile {
|
|
struct SrcPosition {
|
|
int offset;
|
|
int line_no;
|
|
int char_no;
|
|
std::string_view line_str;
|
|
};
|
|
|
|
struct ImportStatement {
|
|
const SrcFile* imported_file;
|
|
};
|
|
|
|
int file_id; // an incremental counter through all parsed files
|
|
std::string rel_filename; // relative to cwd
|
|
std::string abs_filename; // absolute from root
|
|
std::string text; // file contents loaded into memory, every Token::str_val points inside it
|
|
const ASTNodeBase* ast = nullptr; // when a file has been parsed, its ast_tolk_file is kept here
|
|
std::vector<ImportStatement> imports; // to check strictness (can't use a symbol without importing its file)
|
|
|
|
SrcFile(int file_id, std::string rel_filename, std::string abs_filename, std::string&& text)
|
|
: file_id(file_id)
|
|
, rel_filename(std::move(rel_filename))
|
|
, abs_filename(std::move(abs_filename))
|
|
, text(std::move(text)) { }
|
|
|
|
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_entrypoint_file() const { return file_id == 1; /* after stdlib, the entrypoint file is parsed */ }
|
|
|
|
bool is_offset_valid(int offset) const;
|
|
SrcPosition convert_offset(int offset) const;
|
|
};
|
|
|
|
|
|
// SrcLocation points to a location (line, column) in some loaded .tolk source SrcFile.
|
|
// Note, that instead of storing src_file, line_no, etc., only 2 ints are stored.
|
|
// The purpose is: sizeof(SrcLocation) == 8, so it's just passed/stored without pointers/refs, just like int64_t.
|
|
// When decoding SrcLocation into human-readable format, it's converted to SrcFile::SrcPosition via offset.
|
|
class SrcLocation {
|
|
friend class Lexer;
|
|
|
|
int file_id = -1; // = SrcFile::file_id (note, that get_src_file() does linear search)
|
|
int char_offset = -1; // offset from SrcFile::text
|
|
|
|
public:
|
|
|
|
SrcLocation() = default;
|
|
explicit SrcLocation(const SrcFile* src_file) : file_id(src_file->file_id) {
|
|
}
|
|
|
|
bool is_defined() const { return file_id != -1; }
|
|
bool is_stdlib() const { return file_id == 0; }
|
|
const SrcFile* get_src_file() const;
|
|
|
|
// similar to `this->get_src_file() == symbol->get_src_file() || symbol->get_src_file()->is_stdlib()`
|
|
// (but effectively, avoiding linear search)
|
|
bool is_symbol_from_same_or_builtin_file(SrcLocation symbol_loc) const {
|
|
return file_id == symbol_loc.file_id || symbol_loc.file_id < 1;
|
|
}
|
|
|
|
void show(std::ostream& os) const;
|
|
void show_context(std::ostream& os) const;
|
|
std::string to_string() const;
|
|
|
|
void show_general_error(std::ostream& os, const std::string& message, const std::string& err_type) const;
|
|
void show_note(const std::string& err_msg) const;
|
|
void show_warning(const std::string& err_msg) const;
|
|
void show_error(const std::string& err_msg) const;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, SrcLocation loc);
|
|
|
|
using AllSrcFiles = std::vector<const SrcFile*>;
|
|
|
|
class AllRegisteredSrcFiles {
|
|
std::vector<SrcFile*> all_src_files;
|
|
int last_registered_file_id = -1;
|
|
int last_parsed_file_id = -1;
|
|
|
|
public:
|
|
SrcFile *find_file(int file_id) const;
|
|
SrcFile* find_file(const std::string& abs_filename) const;
|
|
|
|
SrcFile* locate_and_register_source_file(const std::string& rel_filename, SrcLocation included_from);
|
|
SrcFile* get_next_unparsed_file();
|
|
|
|
AllSrcFiles get_all_files() const;
|
|
};
|
|
|
|
struct Fatal final : std::exception {
|
|
std::string message;
|
|
|
|
explicit Fatal(std::string _msg) : message(std::move(_msg)) {
|
|
}
|
|
const char* what() const noexcept override {
|
|
return message.c_str();
|
|
}
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Fatal& fatal);
|
|
|
|
struct ParseError : std::exception {
|
|
SrcLocation where;
|
|
std::string message;
|
|
ParseError(SrcLocation _where, std::string _msg) : where(_where), message(std::move(_msg)) {
|
|
}
|
|
|
|
const char* what() const noexcept override {
|
|
return message.c_str();
|
|
}
|
|
void show(std::ostream& os) const;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& os, const ParseError& error);
|
|
|
|
} // namespace tolk
|