Skip to content

Commit

Permalink
Namespace rename and string_view bounds check (#54)
Browse files Browse the repository at this point in the history
* rename grammar namespace from 'presets' to 'grammar'

* return 0 character on end of string

* enable windows workflow

* apply clang-format

* bump version in CMake
  • Loading branch information
TheLartians committed Jun 15, 2020
1 parent 7cc26d8 commit 0978415
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 157 deletions.
10 changes: 3 additions & 7 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,7 @@ jobs:
- name: build
run: cmake --build build --config Debug -j4

# I have absolutely no idea why the windows tests freeze here.
# Abort for now and will come back later.
# - name: test
# run: |
# cd build
# ctest --build-config Debug
- name: test
run: cmake -E false
run: |
cd build
ctest --build-config Debug
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR)
# ---- Project ----

project(PEGParser
VERSION 2.0
VERSION 2.1
LANGUAGES CXX
)

Expand Down
3 changes: 3 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(PEGParserExamples CXX)

# --- Import tools ----

include(../cmake/tools.cmake)

# ---- Add dependencies ----

Expand Down
59 changes: 29 additions & 30 deletions include/peg_parser/generator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,34 @@ namespace peg_parser {
template <class R = void, typename... Args> class ParserGenerator : public Program<R, Args...> {
private:
presets::GrammarProgram grammarProgram;
std::unordered_map<std::string, std::shared_ptr<presets::Rule>> rules;
presets::GrammarNode::Shared separatorRule;
std::unordered_map<std::string, std::shared_ptr<grammar::Rule>> rules;
grammar::Node::Shared separatorRule;

public:
ParserGenerator() { grammarProgram = presets::createGrammarProgram(); }
ParserGenerator() { grammarProgram = presets::createPEGProgram(); }

std::shared_ptr<presets::Rule> getRule(const std::string &name) {
std::shared_ptr<grammar::Rule> getRule(const std::string &name) {
auto it = rules.find(name);
if (it != rules.end()) {
return it->second;
}
auto rule = presets::makeRule(name, presets::GrammarNode::Error());
auto rule = grammar::makeRule(name, grammar::Node::Error());
rules[name] = rule;
return rule;
}

presets::GrammarNode::Shared getRuleNode(const std::string &name) {
auto rule = presets::GrammarNode::WeakRule(getRule(std::string(name)));
grammar::Node::Shared getRuleNode(const std::string &name) {
auto rule = grammar::Node::WeakRule(getRule(std::string(name)));
if (separatorRule) {
auto separator = presets::GrammarNode::ZeroOrMore(separatorRule);
return presets::GrammarNode::Sequence({separator, rule, separator});
auto separator = grammar::Node::ZeroOrMore(separatorRule);
return grammar::Node::Sequence({separator, rule, separator});
} else {
return rule;
}
}

std::shared_ptr<presets::Rule> setRule(
const std::string &name, const presets::GrammarNode::Shared &grammar,
std::shared_ptr<grammar::Rule> setRule(
const std::string &name, const grammar::Node::Shared &grammar,
const typename Interpreter<R, Args...>::Callback &callback
= typename Interpreter<R, Args...>::Callback()) {
auto rule = getRule(name);
Expand All @@ -43,23 +43,23 @@ namespace peg_parser {
return rule;
}

presets::GrammarNode::Shared parseRule(const std::string_view &grammar) {
grammar::Node::Shared parseRule(const std::string_view &grammar) {
presets::RuleGetter rg = [this](const auto &name) { return getRuleNode(std::string(name)); };
return grammarProgram.run(grammar, rg);
}

std::shared_ptr<presets::Rule> setRule(
std::shared_ptr<grammar::Rule> setRule(
const std::string &name, const std::string_view &grammar,
const typename Interpreter<R, Args...>::Callback &callback
= typename Interpreter<R, Args...>::Callback()) {
return setRule(name, parseRule(grammar), callback);
}

template <class R2, typename... Args2, class C>
std::shared_ptr<presets::Rule> setProgramRule(const std::string &name,
std::shared_ptr<grammar::Rule> setProgramRule(const std::string &name,
Program<R2, Args2...> subprogram, C &&callback) {
auto rule = getRule(name);
rule->node = presets::GrammarNode::Rule(subprogram.parser.grammar);
rule->node = grammar::Node::Rule(subprogram.parser.grammar);
this->interpreter.setEvaluator(
rule, [callback = std::forward<C>(callback), interpreter = subprogram.interpreter](
auto e, Args &&... args) {
Expand All @@ -73,42 +73,41 @@ namespace peg_parser {
static_assert(sizeof...(Args2) == 0);
static_assert(std::is_convertible<R2, R>::value);
auto rule = getRule(name);
rule->node = presets::GrammarNode::Rule(subprogram.parser.grammar);
rule->node = grammar::Node::Rule(subprogram.parser.grammar);
this->interpreter.setEvaluator(rule,
[interpreter = subprogram.interpreter](auto e, auto &&...) {
return R(interpreter.interpret(e[0].syntax()).evaluate());
});
}

std::shared_ptr<presets::Rule> setFilteredRule(
std::shared_ptr<grammar::Rule> setFilteredRule(
const std::string &name, const std::string_view &grammar,
const presets::GrammarNode::FilterCallback &filter,
const grammar::Node::FilterCallback &filter,
const typename Interpreter<R, Args...>::Callback &callback
= typename Interpreter<R, Args...>::Callback()) {
return setRule(name,
presets::GrammarNode::Sequence(
{parseRule(grammar), presets::GrammarNode::Filter(filter)}),
grammar::Node::Sequence({parseRule(grammar), grammar::Node::Filter(filter)}),
callback);
}

void setSeparator(const std::shared_ptr<presets::Rule> &rule) {
void setSeparator(const std::shared_ptr<grammar::Rule> &rule) {
rule->hidden = true;
separatorRule = presets::GrammarNode::Rule(rule);
separatorRule = grammar::Node::Rule(rule);
}

std::shared_ptr<presets::Rule> setSeparatorRule(const std::string &name,
const presets::GrammarNode::Shared &grammar) {
std::shared_ptr<grammar::Rule> setSeparatorRule(const std::string &name,
const grammar::Node::Shared &grammar) {
auto rule = setRule(name, grammar);
setSeparator(rule);
return rule;
}

std::shared_ptr<presets::Rule> setSeparatorRule(const std::string &name,
std::shared_ptr<grammar::Rule> setSeparatorRule(const std::string &name,
const std::string_view &grammar) {
return setSeparatorRule(name, parseRule(grammar));
}

void setStart(const std::shared_ptr<presets::Rule> &rule) { this->parser.grammar = rule; }
void setStart(const std::shared_ptr<grammar::Rule> &rule) { this->parser.grammar = rule; }

void unsetSeparatorRule() { separatorRule.reset(); }

Expand All @@ -119,7 +118,7 @@ namespace peg_parser {
std::string ruleName;
std::string grammar;
typename Interpreter<R, Args...>::Callback callback;
presets::GrammarNode::FilterCallback filter;
grammar::Node::FilterCallback filter;

OperatorDelegate(ParserGenerator *p, const std::string &n) : parent(p), ruleName(n) {}
OperatorDelegate(const OperatorDelegate &) = delete;
Expand All @@ -134,14 +133,14 @@ namespace peg_parser {
return *this;
}

OperatorDelegate &operator<<(const presets::GrammarNode::FilterCallback &ft) {
OperatorDelegate &operator<<(const grammar::Node::FilterCallback &ft) {
this->filter = ft;
return *this;
}

operator std::shared_ptr<presets::Rule>() { return parent->getRule(ruleName); }
operator std::shared_ptr<grammar::Rule>() { return parent->getRule(ruleName); }

std::shared_ptr<presets::Rule> operator->() { return parent->getRule(ruleName); }
std::shared_ptr<grammar::Rule> operator->() { return parent->getRule(ruleName); }

~OperatorDelegate() {
if (grammar.size() > 0) {
Expand Down
66 changes: 31 additions & 35 deletions include/peg_parser/grammar.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,25 @@ namespace peg_parser {

struct SyntaxTree;

namespace presets {
namespace grammar {

using Letter = char;
struct GrammarNode;
struct Node;

struct Rule {
std::string name;
std::shared_ptr<GrammarNode> node;
std::shared_ptr<Node> node;
bool hidden = false;
bool cacheable = true;
Rule(const std::string_view &n, const std::shared_ptr<GrammarNode> &t) : name(n), node(t) {}
Rule(const std::string_view &n, const std::shared_ptr<Node> &t) : name(n), node(t) {}
};

inline std::shared_ptr<Rule> makeRule(const std::string_view &name,
const std::shared_ptr<GrammarNode> &node) {
const std::shared_ptr<Node> &node) {
return std::make_shared<Rule>(name, node);
}

struct GrammarNode {
struct Node {
using FilterCallback = std::function<bool(const std::shared_ptr<SyntaxTree> &)>;

enum class Symbol {
Expand All @@ -53,59 +53,55 @@ namespace peg_parser {
FILTER
};

using Shared = std::shared_ptr<GrammarNode>;
using Shared = std::shared_ptr<Node>;

Symbol symbol;

std::variant<std::vector<Shared>, Shared, std::weak_ptr<presets::Rule>,
std::shared_ptr<presets::Rule>, std::string, std::array<Letter, 2>,
std::variant<std::vector<Shared>, Shared, std::weak_ptr<grammar::Rule>,
std::shared_ptr<grammar::Rule>, std::string, std::array<Letter, 2>,
FilterCallback>
data;

private:
GrammarNode(Symbol s) : symbol(s) {}
template <class T> GrammarNode(Symbol s, const T &d) : symbol(s), data(d) {}
Node(Symbol s) : symbol(s) {}
template <class T> Node(Symbol s, const T &d) : symbol(s), data(d) {}

public:
static Shared Word(const std::string &word) {
return Shared(new GrammarNode(Symbol::WORD, word));
}
static Shared Any() { return Shared(new GrammarNode(Symbol::ANY)); }
static Shared Word(const std::string &word) { return Shared(new Node(Symbol::WORD, word)); }
static Shared Any() { return Shared(new Node(Symbol::ANY)); }
static Shared Range(Letter a, Letter b) {
return Shared(new GrammarNode(Symbol::RANGE, std::array<Letter, 2>({{a, b}})));
return Shared(new Node(Symbol::RANGE, std::array<Letter, 2>({{a, b}})));
}
static Shared Sequence(const std::vector<Shared> &args) {
return Shared(new GrammarNode(Symbol::SEQUENCE, args));
return Shared(new Node(Symbol::SEQUENCE, args));
}
static Shared Choice(const std::vector<Shared> &args) {
return Shared(new GrammarNode(Symbol::CHOICE, args));
return Shared(new Node(Symbol::CHOICE, args));
}
static Shared ZeroOrMore(const Shared &arg) {
return Shared(new GrammarNode(Symbol::ZERO_OR_MORE, arg));
return Shared(new Node(Symbol::ZERO_OR_MORE, arg));
}
static Shared OneOrMore(const Shared &arg) {
return Shared(new GrammarNode(Symbol::ONE_OR_MORE, arg));
}
static Shared Optional(const Shared &arg) {
return Shared(new GrammarNode(Symbol::OPTIONAL, arg));
return Shared(new Node(Symbol::ONE_OR_MORE, arg));
}
static Shared Also(const Shared &arg) { return Shared(new GrammarNode(Symbol::ALSO, arg)); }
static Shared Not(const Shared &arg) { return Shared(new GrammarNode(Symbol::NOT, arg)); }
static Shared Empty() { return Shared(new GrammarNode(Symbol::EMPTY)); }
static Shared Error() { return Shared(new GrammarNode(Symbol::ERROR)); }
static Shared Rule(const std::shared_ptr<presets::Rule> &rule) {
return Shared(new GrammarNode(Symbol::RULE, rule));
static Shared Optional(const Shared &arg) { return Shared(new Node(Symbol::OPTIONAL, arg)); }
static Shared Also(const Shared &arg) { return Shared(new Node(Symbol::ALSO, arg)); }
static Shared Not(const Shared &arg) { return Shared(new Node(Symbol::NOT, arg)); }
static Shared Empty() { return Shared(new Node(Symbol::EMPTY)); }
static Shared Error() { return Shared(new Node(Symbol::ERROR)); }
static Shared Rule(const std::shared_ptr<grammar::Rule> &rule) {
return Shared(new Node(Symbol::RULE, rule));
}
static Shared WeakRule(const std::weak_ptr<presets::Rule> &rule) {
return Shared(new GrammarNode(Symbol::WEAK_RULE, rule));
static Shared WeakRule(const std::weak_ptr<grammar::Rule> &rule) {
return Shared(new Node(Symbol::WEAK_RULE, rule));
}
static Shared EndOfFile() { return Shared(new GrammarNode(Symbol::END_OF_FILE)); }
static Shared EndOfFile() { return Shared(new Node(Symbol::END_OF_FILE)); }
static Shared Filter(const FilterCallback &callback) {
return Shared(new GrammarNode(Symbol::FILTER, callback));
return Shared(new Node(Symbol::FILTER, callback));
}
};

std::ostream &operator<<(std::ostream &stream, const GrammarNode &node);
std::ostream &operator<<(std::ostream &stream, const Node &node);

} // namespace presets
} // namespace grammar
} // namespace peg_parser
16 changes: 8 additions & 8 deletions include/peg_parser/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ namespace peg_parser {
};

private:
std::unordered_map<presets::Rule *, Callback> evaluators;
std::unordered_map<grammar::Rule *, Callback> evaluators;

static R __defaultEvaluator(const Expression &e, Args... args) {
size_t N = e.size();
Expand All @@ -97,21 +97,21 @@ namespace peg_parser {
public:
Callback defaultEvaluator = __defaultEvaluator;

std::shared_ptr<presets::Rule> makeRule(const std::string_view &name,
const presets::GrammarNode::Shared &node,
std::shared_ptr<grammar::Rule> makeRule(const std::string_view &name,
const grammar::Node::Shared &node,
const Callback &callback) {
auto rule = std::make_shared<presets::Rule>(name, node);
auto rule = std::make_shared<grammar::Rule>(name, node);
setEvaluator(rule, callback);
return rule;
}

std::shared_ptr<presets::Rule> makeRule(const std::string &name,
const std::shared_ptr<presets::Rule> &rule,
std::shared_ptr<grammar::Rule> makeRule(const std::string &name,
const std::shared_ptr<grammar::Rule> &rule,
const Callback &callback) {
return makeRule(name, presets::GrammarNode::Rule(rule), callback);
return makeRule(name, grammar::Node::Rule(rule), callback);
}

void setEvaluator(const std::shared_ptr<presets::Rule> &rule, const Callback &callback) {
void setEvaluator(const std::shared_ptr<grammar::Rule> &rule, const Callback &callback) {
if (callback) {
evaluators[rule.get()] = callback;
} else {
Expand Down
18 changes: 9 additions & 9 deletions include/peg_parser/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
namespace peg_parser {

struct SyntaxTree {
std::shared_ptr<presets::Rule> rule;
std::shared_ptr<grammar::Rule> rule;
std::string_view fullString;
std::vector<std::shared_ptr<SyntaxTree>> inner;
size_t begin, end;
Expand All @@ -16,7 +16,7 @@ namespace peg_parser {
bool active = true;
bool recursive = false;

SyntaxTree(const std::shared_ptr<presets::Rule> &r, std::string_view s, size_t p);
SyntaxTree(const std::shared_ptr<grammar::Rule> &r, std::string_view s, size_t p);

size_t length() const { return end - begin; }
std::string_view view() const { return fullString.substr(begin, length()); }
Expand All @@ -31,21 +31,21 @@ namespace peg_parser {

struct GrammarError : std::exception {
enum Type { UNKNOWN_SYMBOL, INVALID_RULE } type;
presets::GrammarNode::Shared node;
grammar::Node::Shared node;
mutable std::string buffer;
GrammarError(Type t, presets::GrammarNode::Shared n) : type(t), node(n) {}
GrammarError(Type t, grammar::Node::Shared n) : type(t), node(n) {}
const char *what() const noexcept override;
};

std::shared_ptr<presets::Rule> grammar;
std::shared_ptr<grammar::Rule> grammar;

Parser(const std::shared_ptr<presets::Rule> &grammar
= std::make_shared<presets::Rule>("undefined", presets::GrammarNode::Error()));
Parser(const std::shared_ptr<grammar::Rule> &grammar
= std::make_shared<grammar::Rule>("undefined", grammar::Node::Error()));

static Result parseAndGetError(const std::string_view &str,
std::shared_ptr<presets::Rule> grammar);
std::shared_ptr<grammar::Rule> grammar);
static std::shared_ptr<SyntaxTree> parse(const std::string_view &str,
std::shared_ptr<presets::Rule> grammar);
std::shared_ptr<grammar::Rule> grammar);

std::shared_ptr<SyntaxTree> parse(const std::string_view &str) const;
Result parseAndGetError(const std::string_view &str) const;
Expand Down
Loading

0 comments on commit 0978415

Please sign in to comment.