mirror of
https://github.com/ton-blockchain/ton
synced 2025-02-12 19:22:37 +00:00
Implement #include
keyword with advanced checks and backtrace
This commit is contained in:
parent
1e0b587023
commit
9356a16b84
7 changed files with 113 additions and 9 deletions
|
@ -178,6 +178,18 @@ void usage(const char* progname) {
|
|||
std::exit(2);
|
||||
}
|
||||
|
||||
void output_inclusion_stack() {
|
||||
while (!funC::inclusion_locations.empty()) {
|
||||
src::SrcLocation loc = funC::inclusion_locations.top();
|
||||
funC::inclusion_locations.pop();
|
||||
if (loc.fdescr) {
|
||||
std::cerr << "note: included from ";
|
||||
loc.show(std::cerr);
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string output_filename;
|
||||
|
||||
int main(int argc, char* const argv[]) {
|
||||
|
@ -241,7 +253,7 @@ int main(int argc, char* const argv[]) {
|
|||
int ok = 0, proc = 0;
|
||||
try {
|
||||
while (optind < argc) {
|
||||
funC::generated_from += std::string{"`"} + argv[optind] + "` ";
|
||||
// funC::generated_from += std::string{"`"} + argv[optind] + "` ";
|
||||
ok += funC::parse_source_file(argv[optind++]);
|
||||
proc++;
|
||||
}
|
||||
|
@ -268,14 +280,17 @@ int main(int argc, char* const argv[]) {
|
|||
funC::generate_output();
|
||||
} catch (src::Fatal& fatal) {
|
||||
std::cerr << "fatal: " << fatal << std::endl;
|
||||
output_inclusion_stack();
|
||||
std::exit(1);
|
||||
} catch (src::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
output_inclusion_stack();
|
||||
std::exit(1);
|
||||
} catch (funC::UnifyError& unif_err) {
|
||||
std::cerr << "fatal: ";
|
||||
unif_err.print_message(std::cerr);
|
||||
std::cerr << std::endl;
|
||||
output_inclusion_stack();
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,10 +35,11 @@ namespace funC {
|
|||
|
||||
extern int verbosity;
|
||||
extern bool op_rewrite_comments;
|
||||
extern std::string generated_from;
|
||||
|
||||
constexpr int optimize_depth = 20;
|
||||
|
||||
const std::string func_version{"0.1.0"};
|
||||
const std::string func_version{"0.2.0"};
|
||||
|
||||
enum Keyword {
|
||||
_Eof = -1,
|
||||
|
@ -110,7 +111,8 @@ enum Keyword {
|
|||
_Infixl,
|
||||
_Infixr,
|
||||
_Const,
|
||||
_PragmaHashtag
|
||||
_PragmaHashtag,
|
||||
_IncludeHashtag
|
||||
};
|
||||
|
||||
void define_keywords();
|
||||
|
@ -828,9 +830,11 @@ extern std::vector<SymDef*> glob_func, glob_vars;
|
|||
|
||||
// defined in parse-func.cpp
|
||||
bool parse_source(std::istream* is, const src::FileDescr* fdescr);
|
||||
bool parse_source_file(const char* filename);
|
||||
bool parse_source_file(const char* filename, src::Lexem lex = {});
|
||||
bool parse_source_stdin();
|
||||
|
||||
extern std::stack<src::SrcLocation> inclusion_locations;
|
||||
|
||||
/*
|
||||
*
|
||||
* EXPRESSIONS
|
||||
|
|
|
@ -127,7 +127,9 @@ void define_keywords() {
|
|||
.add_keyword("infixl", Kw::_Infixl)
|
||||
.add_keyword("infixr", Kw::_Infixr)
|
||||
.add_keyword("const", Kw::_Const);
|
||||
sym::symbols.add_keyword("#pragma", Kw::_PragmaHashtag);
|
||||
|
||||
sym::symbols.add_keyword("#pragma", Kw::_PragmaHashtag)
|
||||
.add_keyword("#include", Kw::_IncludeHashtag);
|
||||
}
|
||||
|
||||
} // namespace funC
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "block/block.h"
|
||||
#include "block-parse.h"
|
||||
#include <fstream>
|
||||
#include <climits>
|
||||
|
||||
namespace sym {
|
||||
|
||||
|
@ -1607,12 +1608,35 @@ void parse_pragma(Lexer& lex) {
|
|||
|
||||
std::vector<const src::FileDescr*> source_fdescr;
|
||||
|
||||
std::vector<std::string> source_files;
|
||||
std::stack<src::SrcLocation> inclusion_locations;
|
||||
|
||||
void parse_include(Lexer& lex, const src::FileDescr* fdescr) {
|
||||
auto include = lex.cur();
|
||||
lex.expect(_IncludeHashtag);
|
||||
if (lex.tp() != _String) {
|
||||
lex.expect(_String, "source file name");
|
||||
}
|
||||
std::string val = lex.cur().str;
|
||||
std::string parent_dir = fdescr->filename;
|
||||
if (parent_dir.rfind('/') != std::string::npos) {
|
||||
val = parent_dir.substr(0, parent_dir.rfind('/') + 1) + val;
|
||||
}
|
||||
lex.next();
|
||||
lex.expect(';');
|
||||
if (!parse_source_file(val.c_str(), include)) {
|
||||
include.error(std::string{"failed parsing included file `"} + val + "`");
|
||||
}
|
||||
}
|
||||
|
||||
bool parse_source(std::istream* is, src::FileDescr* fdescr) {
|
||||
src::SourceReader reader{is, fdescr};
|
||||
Lexer lex{reader, true, ";,()[] ~."};
|
||||
while (lex.tp() != _Eof) {
|
||||
if (lex.tp() == _PragmaHashtag) {
|
||||
parse_pragma(lex);
|
||||
} else if (lex.tp() == _IncludeHashtag) {
|
||||
parse_include(lex, fdescr);
|
||||
} else if (lex.tp() == _Global) {
|
||||
parse_global_var_decls(lex);
|
||||
} else if (lex.tp() == _Const) {
|
||||
|
@ -1624,17 +1648,48 @@ bool parse_source(std::istream* is, src::FileDescr* fdescr) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool parse_source_file(const char* filename) {
|
||||
bool parse_source_file(const char* filename, src::Lexem lex) {
|
||||
if (!filename || !*filename) {
|
||||
throw src::Fatal{"source file name is an empty string"};
|
||||
auto msg = "source file name is an empty string";
|
||||
if (lex.tp) {
|
||||
lex.error(msg);
|
||||
} else {
|
||||
throw src::Fatal{msg};
|
||||
}
|
||||
}
|
||||
char realpath_buf[PATH_MAX] = {0, };
|
||||
realpath(filename, realpath_buf);
|
||||
std::string real_filename = std::string{realpath_buf};
|
||||
if (std::count(source_files.begin(), source_files.end(), real_filename)) {
|
||||
if (verbosity >= 2) {
|
||||
if (lex.tp) {
|
||||
lex.loc.show_warning(std::string{"skipping file "} + real_filename + " because it was already included");
|
||||
} else {
|
||||
std::cerr << "warning: skipping file " << real_filename << " because it was already included" << std::endl;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (lex.tp) { // included
|
||||
funC::generated_from += std::string{"incl:"};
|
||||
}
|
||||
funC::generated_from += std::string{"`"} + filename + "` ";
|
||||
source_files.push_back(real_filename);
|
||||
src::FileDescr* cur_source = new src::FileDescr{filename};
|
||||
source_fdescr.push_back(cur_source);
|
||||
std::ifstream ifs{filename};
|
||||
if (ifs.fail()) {
|
||||
throw src::Fatal{std::string{"cannot open source file `"} + filename + "`"};
|
||||
auto msg = std::string{"cannot open source file `"} + filename + "`";
|
||||
if (lex.tp) {
|
||||
lex.error(msg);
|
||||
} else {
|
||||
throw src::Fatal{msg};
|
||||
}
|
||||
}
|
||||
return parse_source(&ifs, cur_source);
|
||||
inclusion_locations.push(lex.loc);
|
||||
bool res = parse_source(&ifs, cur_source);
|
||||
inclusion_locations.pop();
|
||||
return res;
|
||||
}
|
||||
|
||||
bool parse_source_stdin() {
|
||||
|
|
14
crypto/func/test/i1.fc
Normal file
14
crypto/func/test/i1.fc
Normal file
|
@ -0,0 +1,14 @@
|
|||
global int i;
|
||||
|
||||
#include "i1sub1.fc";
|
||||
|
||||
() sub0() impure { i = 0; }
|
||||
|
||||
#include "i1sub2.fc";
|
||||
|
||||
() main() impure {
|
||||
sub0();
|
||||
sub1();
|
||||
sub2();
|
||||
i = 9;
|
||||
}
|
6
crypto/func/test/i1sub1.fc
Normal file
6
crypto/func/test/i1sub1.fc
Normal file
|
@ -0,0 +1,6 @@
|
|||
;; DO NOT COMPILE DIRECTLY!
|
||||
;; Compile i1.fc
|
||||
|
||||
() sub1() impure {
|
||||
i = 1;
|
||||
}
|
8
crypto/func/test/i1sub2.fc
Normal file
8
crypto/func/test/i1sub2.fc
Normal file
|
@ -0,0 +1,8 @@
|
|||
;; DO NOT COMPILE DIRECTLY!
|
||||
;; Compile i1.fc
|
||||
|
||||
() sub2() impure {
|
||||
sub1();
|
||||
sub0();
|
||||
i = 2;
|
||||
}
|
Loading…
Reference in a new issue