1
0
Fork 0
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:
starlightduck 2022-05-12 12:54:34 +03:00
parent 1e0b587023
commit 9356a16b84
7 changed files with 113 additions and 9 deletions

View file

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

View file

@ -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

View file

@ -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

View file

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

View file

@ -0,0 +1,6 @@
;; DO NOT COMPILE DIRECTLY!
;; Compile i1.fc
() sub1() impure {
i = 1;
}

View file

@ -0,0 +1,8 @@
;; DO NOT COMPILE DIRECTLY!
;; Compile i1.fc
() sub2() impure {
sub1();
sub0();
i = 2;
}