1
0
mirror of https://github.com/exaloop/codon.git synced 2025-06-03 15:03:52 +08:00
2021-09-30 15:04:26 -04:00

166 lines
5.1 KiB
C++

/*
* peg.cpp --- PEG parser interface.
*
* (c) Seq project. All rights reserved.
* This file is subject to the terms and conditions defined in
* file 'LICENSE', which is part of this source code package.
*/
#include <any>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "parser/ast.h"
#include "parser/common.h"
#include "parser/peg/peg.h"
#include "parser/peg/rules.h"
#include "parser/visitors/format/format.h"
#include "util/peglib.h"
extern int _ocaml_time;
using namespace std;
namespace seq {
namespace ast {
static shared_ptr<peg::Grammar> grammar(nullptr);
static shared_ptr<peg::Grammar> ompGrammar(nullptr);
shared_ptr<peg::Grammar> initParser() {
auto g = make_shared<peg::Grammar>();
init_codon_rules(*g);
init_codon_actions(*g);
~(*g)["NLP"] <= peg::usr([](const char *s, size_t n, peg::SemanticValues &, any &dt) {
return any_cast<ParseContext &>(dt).parens ? 0 : (n >= 1 && s[0] == '\\' ? 1 : -1);
});
for (auto &x : *g) {
auto v = peg::LinkReferences(*g, x.second.params);
x.second.accept(v);
}
(*g)["program"].enablePackratParsing = true;
for (auto &rule : vector<string>{"arguments", "slices", "genexp", "parentheses",
"star_parens", "generics", "with_parens_item",
"params", "from_as_parens", "from_params"}) {
(*g)[rule].enter = [](const char *, size_t, any &dt) {
any_cast<ParseContext &>(dt).parens++;
};
(*g)[rule.c_str()].leave = [](const char *, size_t, size_t, any &, any &dt) {
any_cast<ParseContext &>(dt).parens--;
};
}
return g;
}
template <typename T>
T parseCode(const shared_ptr<Cache> &cache, const string &file, string code,
int line_offset, int col_offset, const string &rule) {
using namespace std::chrono;
auto t = high_resolution_clock::now();
// Initialize
if (!grammar)
grammar = initParser();
vector<tuple<size_t, size_t, string>> errors;
auto log = [&](size_t line, size_t col, const string &msg) {
errors.push_back({line, col, msg});
};
T result = nullptr;
auto ctx = make_any<ParseContext>(cache, 0, line_offset, col_offset);
auto r = (*grammar)[rule].parse_and_get_value(code.c_str(), code.size(), ctx, result,
file.c_str(), log);
auto ret = r.ret && r.len == code.size();
if (!ret)
r.error_info.output_log(log, code.c_str(), code.size());
exc::ParserException ex;
if (!errors.empty()) {
for (auto &e : errors)
ex.track(fmt::format("{}", get<2>(e)), SrcInfo(file, get<0>(e), get<1>(e), 0));
throw ex;
return nullptr;
}
_ocaml_time += duration_cast<milliseconds>(high_resolution_clock::now() - t).count();
return result;
}
StmtPtr parseCode(const shared_ptr<Cache> &cache, const string &file,
const string &code, int line_offset) {
return parseCode<StmtPtr>(cache, file, code + "\n", line_offset, 0, "program");
}
ExprPtr parseExpr(const shared_ptr<Cache> &cache, const string &code,
const seq::SrcInfo &offset) {
return parseCode<ExprPtr>(cache, offset.file, code, offset.line, offset.col,
"fstring");
}
StmtPtr parseFile(const shared_ptr<Cache> &cache, const string &file) {
vector<string> lines;
string code;
if (file == "-") {
for (string line; getline(cin, line);) {
lines.push_back(line);
code += line + "\n";
}
} else {
ifstream fin(file);
if (!fin)
error(fmt::format("cannot open {}", file).c_str());
for (string line; getline(fin, line);) {
lines.push_back(line);
code += line + "\n";
}
fin.close();
}
cache->imports[file].content = lines;
auto result = parseCode(cache, file, code);
// LOG("peg/{} := {}", file, result ? result->toString(0) : "<nullptr>");
// throw;
// LOG("fmt := {}", FormatVisitor::apply(result));
return result;
}
shared_ptr<peg::Grammar> initOpenMPParser() {
auto g = make_shared<peg::Grammar>();
init_omp_rules(*g);
init_omp_actions(*g);
for (auto &x : *g) {
auto v = peg::LinkReferences(*g, x.second.params);
x.second.accept(v);
}
(*g)["pragma"].enablePackratParsing = true;
return g;
}
vector<CallExpr::Arg> parseOpenMP(const shared_ptr<Cache> &cache, const string &code,
const seq::SrcInfo &loc) {
if (!ompGrammar)
ompGrammar = initOpenMPParser();
vector<tuple<size_t, size_t, string>> errors;
auto log = [&](size_t line, size_t col, const string &msg) {
errors.push_back({line, col, msg});
};
vector<CallExpr::Arg> result;
auto ctx = make_any<ParseContext>(cache, 0, 0, 0);
auto r = (*ompGrammar)["pragma"].parse_and_get_value(code.c_str(), code.size(), ctx,
result, "", log);
auto ret = r.ret && r.len == code.size();
if (!ret)
r.error_info.output_log(log, code.c_str(), code.size());
exc::ParserException ex;
if (!errors.empty()) {
ex.track(fmt::format("openmp {}", get<2>(errors[0])), loc);
throw ex;
}
return result;
}
} // namespace ast
} // namespace seq