Replace prec rule w/ left_assoc and right_assoc
Consider shift/reduce conflicts to be compilation errors unless they are resolved by a specified associativity.
This commit is contained in:
parent
86bd6eaa75
commit
80ec303b10
19 changed files with 27040 additions and 25946 deletions
|
|
@ -111,7 +111,8 @@ class ParseTableBuilder {
|
|||
(item.lhs == rules::START())
|
||||
? ParseAction::Accept()
|
||||
: ParseAction::Reduce(item.lhs, item.consumed_symbols.size(),
|
||||
item.precedence(), conflict_manager.get_production_id(item.consumed_symbols));
|
||||
item.precedence(), item.associativity(),
|
||||
conflict_manager.get_production_id(item.consumed_symbols));
|
||||
|
||||
for (const auto &lookahead_sym : lookahead_symbols)
|
||||
if (should_add_action(state_id, lookahead_sym, action))
|
||||
|
|
|
|||
|
|
@ -41,15 +41,19 @@ ParseConflictManager::resolve(const ParseAction &new_action,
|
|||
return make_tuple(false, ConflictTypeResolved, "");
|
||||
else if (new_precedence > max_precedence)
|
||||
return make_tuple(true, ConflictTypeResolved, "");
|
||||
else {
|
||||
|
||||
// TODO: Add associativity annotations. In the event of a precedence
|
||||
// tie, return ConflictTypeError unless there is an associativity
|
||||
// annotation to break the tie.
|
||||
return make_tuple(false, ConflictTypeResolved, "");
|
||||
else if (min_precedence == max_precedence) {
|
||||
switch (new_action.associativity) {
|
||||
case rules::AssociativityLeft:
|
||||
return make_tuple(true, ConflictTypeResolved, "");
|
||||
case rules::AssociativityRight:
|
||||
return make_tuple(false, ConflictTypeResolved, "");
|
||||
default:
|
||||
return make_tuple(false, ConflictTypeError, conflict_description(new_action, old_action, symbol));
|
||||
}
|
||||
} else {
|
||||
return make_tuple(false, ConflictTypeError, conflict_description(new_action, old_action, symbol));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ParseActionTypeReduce:
|
||||
if (new_action.type == ParseActionTypeReduce) {
|
||||
|
|
@ -60,20 +64,13 @@ ParseConflictManager::resolve(const ParseAction &new_action,
|
|||
} else if (new_precedence < old_precedence) {
|
||||
return make_tuple(false, ConflictTypeResolved, "");
|
||||
} else {
|
||||
string message =
|
||||
"Lookahead: " + symbol_name(symbol) + "\n" +
|
||||
"Possible Actions:\n"
|
||||
"* " + action_description(old_action) + "\n" +
|
||||
"* " + action_description(new_action) + "\n";
|
||||
return make_tuple(false, ConflictTypeError, message);
|
||||
return make_tuple(false, ConflictTypeError, conflict_description(new_action, old_action, symbol));
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
return make_tuple(false, ConflictTypeNone, "");
|
||||
}
|
||||
|
||||
return make_tuple(false, ConflictTypeNone, "");
|
||||
}
|
||||
|
||||
size_t ParseConflictManager::get_production_id(const vector<rules::Symbol> &symbols) {
|
||||
|
|
@ -87,6 +84,16 @@ size_t ParseConflictManager::get_production_id(const vector<rules::Symbol> &symb
|
|||
return iter - begin;
|
||||
}
|
||||
|
||||
string ParseConflictManager::conflict_description(const ParseAction &new_action,
|
||||
const ParseAction &old_action,
|
||||
const rules::Symbol &symbol) const {
|
||||
return
|
||||
"Lookahead: " + symbol_name(symbol) + "\n" +
|
||||
"Possible Actions:\n"
|
||||
"* " + action_description(old_action) + "\n" +
|
||||
"* " + action_description(new_action);
|
||||
}
|
||||
|
||||
string ParseConflictManager::symbol_name(const rules::Symbol &symbol) const {
|
||||
if (symbol.is_built_in()) {
|
||||
if (symbol == rules::ERROR())
|
||||
|
|
@ -102,11 +109,22 @@ string ParseConflictManager::symbol_name(const rules::Symbol &symbol) const {
|
|||
}
|
||||
|
||||
string ParseConflictManager::action_description(const ParseAction &action) const {
|
||||
string result = "Reduce";
|
||||
for (const rules::Symbol &symbol : productions[action.production_id])
|
||||
result += " " + symbol_name(symbol);
|
||||
result += " -> " + symbol_name(action.symbol);
|
||||
return result;
|
||||
switch (action.type) {
|
||||
case ParseActionTypeReduce: {
|
||||
string result = "Reduce";
|
||||
for (const rules::Symbol &symbol : productions[action.production_id])
|
||||
result += " " + symbol_name(symbol);
|
||||
result += " -> " + symbol_name(action.symbol);
|
||||
return result;
|
||||
}
|
||||
|
||||
case ParseActionTypeShift: {
|
||||
return "Shift";
|
||||
}
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace build_tables
|
||||
|
|
|
|||
|
|
@ -27,15 +27,14 @@ class ParseConflictManager {
|
|||
|
||||
public:
|
||||
ParseConflictManager(const SyntaxGrammar &, const LexicalGrammar &);
|
||||
|
||||
size_t get_production_id(const std::vector<rules::Symbol> &);
|
||||
|
||||
std::tuple<bool, ConflictType, std::string>
|
||||
resolve(const ParseAction &, const ParseAction &, const rules::Symbol &) const;
|
||||
std::tuple<bool, ConflictType, std::string> resolve(
|
||||
const ParseAction &, const ParseAction &, const rules::Symbol &) const;
|
||||
|
||||
private:
|
||||
std::string symbol_name(const rules::Symbol &) const;
|
||||
std::string action_description(const ParseAction &) const;
|
||||
std::string conflict_description(const ParseAction &, const ParseAction &, const rules::Symbol &) const;
|
||||
};
|
||||
|
||||
} // namespace build_tables
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
#include "compiler/build_tables/parse_item.h"
|
||||
#include "compiler/build_tables/get_metadata.h"
|
||||
#include "compiler/rules/metadata.h"
|
||||
#include "tree_sitter/compiler.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
|
|
@ -18,6 +20,10 @@ bool ParseItem::operator==(const ParseItem &other) const {
|
|||
(rule == other.rule || rule->operator==(*other.rule));
|
||||
}
|
||||
|
||||
rules::Associativity ParseItem::associativity() const {
|
||||
return rules::Associativity(get_metadata(rule, rules::ASSOCIATIVITY));
|
||||
}
|
||||
|
||||
ostream &operator<<(ostream &stream, const ParseItem &item) {
|
||||
return stream << string("(item ") << item.lhs << string(" ") << *item.rule
|
||||
<< string(")");
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <vector>
|
||||
#include "compiler/build_tables/item.h"
|
||||
#include "compiler/rules/symbol.h"
|
||||
#include "compiler/rules/metadata.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
namespace build_tables {
|
||||
|
|
@ -15,6 +16,7 @@ class ParseItem : public Item {
|
|||
ParseItem(const rules::Symbol &lhs, rules::rule_ptr rule,
|
||||
const std::vector<rules::Symbol> &consumed_symbols);
|
||||
bool operator==(const ParseItem &other) const;
|
||||
rules::Associativity associativity() const;
|
||||
std::vector<rules::Symbol> consumed_symbols;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -13,46 +13,57 @@ using rules::Symbol;
|
|||
ParseAction::ParseAction(ParseActionType type, ParseStateId state_index,
|
||||
Symbol symbol, size_t consumed_symbol_count,
|
||||
set<int> precedence_values,
|
||||
rules::Associativity associativity,
|
||||
int production_id)
|
||||
: type(type),
|
||||
symbol(symbol),
|
||||
state_index(state_index),
|
||||
consumed_symbol_count(consumed_symbol_count),
|
||||
precedence_values(precedence_values),
|
||||
associativity(associativity),
|
||||
production_id(production_id) {}
|
||||
|
||||
ParseAction::ParseAction()
|
||||
: type(ParseActionTypeError),
|
||||
symbol(Symbol(-1)),
|
||||
state_index(-1),
|
||||
consumed_symbol_count(0) {}
|
||||
consumed_symbol_count(0),
|
||||
associativity(rules::AssociativityUnspecified) {}
|
||||
|
||||
ParseAction ParseAction::Error() {
|
||||
return ParseAction(ParseActionTypeError, -1, Symbol(-1), 0, { 0 }, 0);
|
||||
return ParseAction();
|
||||
}
|
||||
|
||||
ParseAction ParseAction::Accept() {
|
||||
return ParseAction(ParseActionTypeAccept, -1, Symbol(-1), 0, { 0 }, 0);
|
||||
ParseAction action;
|
||||
action.type = ParseActionTypeAccept;
|
||||
return action;
|
||||
}
|
||||
|
||||
ParseAction ParseAction::Shift(ParseStateId state_index,
|
||||
set<int> precedence_values) {
|
||||
return ParseAction(ParseActionTypeShift, state_index, Symbol(-1), 0,
|
||||
precedence_values, 0);
|
||||
precedence_values, rules::AssociativityUnspecified, -1);
|
||||
}
|
||||
|
||||
ParseAction ParseAction::ShiftExtra() {
|
||||
return ParseAction(ParseActionTypeShiftExtra, 0, Symbol(-1), 0, { 0 }, 0);
|
||||
ParseAction action;
|
||||
action.type = ParseActionTypeShiftExtra;
|
||||
return action;
|
||||
}
|
||||
|
||||
ParseAction ParseAction::ReduceExtra(Symbol symbol) {
|
||||
return ParseAction(ParseActionTypeReduceExtra, 0, symbol, 0, { 0 }, 0);
|
||||
ParseAction action;
|
||||
action.type = ParseActionTypeReduceExtra;
|
||||
action.symbol = symbol;
|
||||
return action;
|
||||
}
|
||||
|
||||
ParseAction ParseAction::Reduce(Symbol symbol, size_t consumed_symbol_count,
|
||||
int precedence, int production_id) {
|
||||
int precedence, rules::Associativity associativity,
|
||||
int production_id) {
|
||||
return ParseAction(ParseActionTypeReduce, 0, symbol, consumed_symbol_count,
|
||||
{ precedence }, production_id);
|
||||
{ precedence }, associativity, production_id);
|
||||
}
|
||||
|
||||
bool ParseAction::operator==(const ParseAction &other) const {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
#include "compiler/lex_table.h"
|
||||
#include "compiler/rules/symbol.h"
|
||||
#include "compiler/rules/metadata.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
|
||||
|
|
@ -24,7 +25,8 @@ typedef enum {
|
|||
class ParseAction {
|
||||
ParseAction(ParseActionType type, ParseStateId state_index,
|
||||
rules::Symbol symbol, size_t consumed_symbol_count,
|
||||
std::set<int> precedence_values, int production_id);
|
||||
std::set<int> precedence_values, rules::Associativity,
|
||||
int production_id);
|
||||
|
||||
public:
|
||||
ParseAction();
|
||||
|
|
@ -33,7 +35,7 @@ class ParseAction {
|
|||
static ParseAction Shift(ParseStateId state_index,
|
||||
std::set<int> precedence_values);
|
||||
static ParseAction Reduce(rules::Symbol symbol, size_t consumed_symbol_count,
|
||||
int precedence, int production_id);
|
||||
int precedence, rules::Associativity, int production_id);
|
||||
static ParseAction ShiftExtra();
|
||||
static ParseAction ReduceExtra(rules::Symbol symbol);
|
||||
bool operator==(const ParseAction &) const;
|
||||
|
|
@ -44,6 +46,7 @@ class ParseAction {
|
|||
ParseStateId state_index;
|
||||
size_t consumed_symbol_count;
|
||||
std::set<int> precedence_values;
|
||||
rules::Associativity associativity;
|
||||
int production_id;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,19 @@
|
|||
namespace tree_sitter {
|
||||
namespace rules {
|
||||
|
||||
typedef enum {
|
||||
enum MetadataKey {
|
||||
START_TOKEN,
|
||||
PRECEDENCE,
|
||||
IS_TOKEN,
|
||||
DESCRIPTION,
|
||||
} MetadataKey;
|
||||
ASSOCIATIVITY,
|
||||
};
|
||||
|
||||
enum Associativity {
|
||||
AssociativityUnspecified,
|
||||
AssociativityLeft,
|
||||
AssociativityRight,
|
||||
};
|
||||
|
||||
class Metadata : public Rule {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -47,19 +47,29 @@ rule_ptr pattern(const string &value) { return make_shared<Pattern>(value); }
|
|||
rule_ptr str(const string &value) { return make_shared<String>(value); }
|
||||
|
||||
rule_ptr keyword(const string &value) {
|
||||
return token(prec(KEYWORD_PRECEDENCE, str(value)));
|
||||
return token(left_assoc(KEYWORD_PRECEDENCE, str(value)));
|
||||
}
|
||||
|
||||
rule_ptr keypattern(const string &value) {
|
||||
return token(prec(KEYWORD_PRECEDENCE, pattern(value)));
|
||||
return token(left_assoc(KEYWORD_PRECEDENCE, pattern(value)));
|
||||
}
|
||||
|
||||
rule_ptr err(const rule_ptr &rule) {
|
||||
return choice({ rule, ERROR().copy() });
|
||||
}
|
||||
|
||||
rule_ptr prec(int precedence, const rule_ptr &rule) {
|
||||
return metadata(rule, { { PRECEDENCE, precedence } });
|
||||
rule_ptr left_assoc(int precedence, const rule_ptr &rule) {
|
||||
return metadata(rule, {
|
||||
{ PRECEDENCE, precedence },
|
||||
{ ASSOCIATIVITY, AssociativityLeft }
|
||||
});
|
||||
}
|
||||
|
||||
rule_ptr right_assoc(int precedence, const rule_ptr &rule) {
|
||||
return metadata(rule, {
|
||||
{ PRECEDENCE, precedence },
|
||||
{ ASSOCIATIVITY, AssociativityRight }
|
||||
});
|
||||
}
|
||||
|
||||
rule_ptr token(const rule_ptr &rule) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue