Allow associativity to be specified in rules w/o precedence
This commit is contained in:
parent
4b817dc07c
commit
9959fe35b0
17 changed files with 78 additions and 56 deletions
|
|
@ -11,12 +11,6 @@ namespace tree_sitter {
|
|||
class Rule;
|
||||
typedef std::shared_ptr<Rule> rule_ptr;
|
||||
|
||||
enum Associativity {
|
||||
AssociativityNone,
|
||||
AssociativityLeft,
|
||||
AssociativityRight,
|
||||
};
|
||||
|
||||
rule_ptr blank();
|
||||
rule_ptr choice(const std::vector<rule_ptr> &);
|
||||
rule_ptr repeat(const rule_ptr &);
|
||||
|
|
@ -27,7 +21,10 @@ rule_ptr pattern(const std::string &);
|
|||
rule_ptr str(const std::string &);
|
||||
rule_ptr err(const rule_ptr &);
|
||||
rule_ptr prec(int precedence, const rule_ptr &);
|
||||
rule_ptr prec(int precedence, const rule_ptr &, Associativity);
|
||||
rule_ptr prec_left(const rule_ptr &);
|
||||
rule_ptr prec_left(int precedence, const rule_ptr &);
|
||||
rule_ptr prec_right(const rule_ptr &);
|
||||
rule_ptr prec_right(int precedence, const rule_ptr &);
|
||||
rule_ptr token(const rule_ptr &rule);
|
||||
|
||||
class Grammar {
|
||||
|
|
|
|||
|
|
@ -32,13 +32,13 @@ describe("flatten_grammar", []() {
|
|||
// When multiple precedence values are nested, the inner precedence wins.
|
||||
Variable("variable1", VariableTypeNamed, seq({
|
||||
i_sym(1),
|
||||
prec(101, seq({
|
||||
prec_left(101, seq({
|
||||
i_sym(2),
|
||||
choice({
|
||||
prec(102, seq({
|
||||
prec_right(102, seq({
|
||||
i_sym(3),
|
||||
i_sym(4)
|
||||
}), AssociativityRight),
|
||||
})),
|
||||
i_sym(5),
|
||||
}),
|
||||
i_sym(6),
|
||||
|
|
@ -49,11 +49,11 @@ describe("flatten_grammar", []() {
|
|||
// When a precedence is applied to the end of a rule, its value is assigned
|
||||
// to the last step of the corresponding production.
|
||||
Variable("variable2", VariableTypeHidden, seq({
|
||||
prec(102, seq({
|
||||
prec_left(102, seq({
|
||||
i_sym(1),
|
||||
i_sym(2),
|
||||
})),
|
||||
prec(103, seq({
|
||||
prec_left(103, seq({
|
||||
i_sym(3),
|
||||
i_sym(4),
|
||||
})),
|
||||
|
|
|
|||
4
spec/fixtures/grammars/c.cc
vendored
4
spec/fixtures/grammars/c.cc
vendored
|
|
@ -137,8 +137,8 @@ extern const Grammar c = Grammar({
|
|||
sym("number") }) },
|
||||
|
||||
{ "math_expression", choice({
|
||||
prec(1, seq({ sym("expression"), str("+"), sym("expression") })),
|
||||
prec(2, seq({ sym("expression"), str("*"), sym("expression") })) }) },
|
||||
prec_left(1, seq({ sym("expression"), str("+"), sym("expression") })),
|
||||
prec_left(2, seq({ sym("expression"), str("*"), sym("expression") })) }) },
|
||||
|
||||
{ "call_expression", prec(3, seq({
|
||||
sym("expression"),
|
||||
|
|
|
|||
2
spec/fixtures/grammars/helpers.cc
vendored
2
spec/fixtures/grammars/helpers.cc
vendored
|
|
@ -29,7 +29,7 @@ rule_ptr in_brackets(rule_ptr rule) {
|
|||
}
|
||||
|
||||
rule_ptr infix_op(std::string op, std::string rule_name, int precedence) {
|
||||
return prec(precedence, seq({
|
||||
return prec_left(precedence, seq({
|
||||
sym(rule_name),
|
||||
str(op),
|
||||
sym(rule_name) }));
|
||||
|
|
|
|||
24
spec/fixtures/grammars/javascript.cc
vendored
24
spec/fixtures/grammars/javascript.cc
vendored
|
|
@ -68,13 +68,13 @@ extern const Grammar javascript = Grammar({
|
|||
{ "statement_block", prec(PREC_BLOCK,
|
||||
in_braces(err(repeat(sym("_statement"))))) },
|
||||
|
||||
{ "if_statement", prec(0, seq({
|
||||
{ "if_statement", prec_right(0, seq({
|
||||
str("if"),
|
||||
sym("_paren_expression"),
|
||||
sym("_statement"),
|
||||
optional(seq({
|
||||
str("else"),
|
||||
sym("_statement") })) }), AssociativityRight) },
|
||||
sym("_statement") })) })) },
|
||||
|
||||
{ "switch_statement", seq({
|
||||
str("switch"),
|
||||
|
|
@ -219,13 +219,13 @@ extern const Grammar javascript = Grammar({
|
|||
sym("arguments") })) },
|
||||
|
||||
{ "constructor_call", choice({
|
||||
prec(PREC_SHORT_NEW, seq({
|
||||
prec_right(PREC_SHORT_NEW, seq({
|
||||
str("new"),
|
||||
sym("_expression") }), AssociativityRight),
|
||||
prec(PREC_MEMBER, seq({
|
||||
sym("_expression") })),
|
||||
prec_right(PREC_MEMBER, seq({
|
||||
str("new"),
|
||||
sym("_expression"),
|
||||
sym("arguments") }), AssociativityRight) }) },
|
||||
sym("arguments") })) }) },
|
||||
|
||||
{ "member_access", prec(PREC_MEMBER, seq({
|
||||
sym("_expression"),
|
||||
|
|
@ -238,28 +238,28 @@ extern const Grammar javascript = Grammar({
|
|||
err(sym("_expression")),
|
||||
str("]") })) },
|
||||
|
||||
{ "assignment", prec(PREC_ASSIGN, seq({
|
||||
{ "assignment", prec_right(PREC_ASSIGN, seq({
|
||||
choice({
|
||||
sym("identifier"),
|
||||
sym("member_access"),
|
||||
sym("subscript_access") }),
|
||||
str("="),
|
||||
sym("_expression") }), AssociativityRight) },
|
||||
sym("_expression") })) },
|
||||
|
||||
{ "math_assignment", prec(PREC_ASSIGN, seq({
|
||||
{ "math_assignment", prec_right(PREC_ASSIGN, seq({
|
||||
choice({
|
||||
sym("identifier"),
|
||||
sym("member_access"),
|
||||
sym("subscript_access") }),
|
||||
choice({ str("+="), str("-="), str("*="), str("/=") }),
|
||||
sym("_expression") }), AssociativityRight) },
|
||||
sym("_expression") })) },
|
||||
|
||||
{ "ternary", prec(PREC_TERNARY, seq({
|
||||
{ "ternary", prec_right(PREC_TERNARY, seq({
|
||||
sym("_expression"),
|
||||
str("?"),
|
||||
sym("_expression"),
|
||||
str(":"),
|
||||
sym("_expression") }), AssociativityRight) },
|
||||
sym("_expression") })) },
|
||||
|
||||
{ "bool_op", choice({
|
||||
infix_op("||", "_expression", PREC_OR),
|
||||
|
|
|
|||
0
src/compiler/associativity.h
Normal file
0
src/compiler/associativity.h
Normal file
|
|
@ -108,7 +108,7 @@ class ParseTableBuilder {
|
|||
struct CompletionStatus {
|
||||
bool is_done;
|
||||
int precedence;
|
||||
Associativity associativity;
|
||||
rules::Associativity associativity;
|
||||
};
|
||||
|
||||
CompletionStatus get_completion_status(const ParseItem &item) {
|
||||
|
|
@ -118,7 +118,7 @@ class ParseTableBuilder {
|
|||
const ProductionStep &last_step = production[item.step_index - 1];
|
||||
return { true, last_step.precedence, last_step.associativity };
|
||||
}
|
||||
return { false, 0, AssociativityNone };
|
||||
return { false, 0, rules::AssociativityNone };
|
||||
}
|
||||
|
||||
void add_reduce_actions(const ParseItemSet &item_set, ParseStateId state_id) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class GetCompletionStatus : public rules::RuleFn<CompletionStatus> {
|
|||
if (status.is_done)
|
||||
return status;
|
||||
}
|
||||
return { false, 0, AssociativityNone };
|
||||
return { false, 0, rules::AssociativityNone };
|
||||
}
|
||||
|
||||
CompletionStatus apply_to(const rules::Metadata *rule) {
|
||||
|
|
@ -24,7 +24,7 @@ class GetCompletionStatus : public rules::RuleFn<CompletionStatus> {
|
|||
if (result.is_done && !result.associativity) {
|
||||
result.precedence = rule->value_for(rules::PRECEDENCE);
|
||||
result.associativity =
|
||||
(Associativity)(rule->value_for(rules::ASSOCIATIVITY));
|
||||
(rules::Associativity)(rule->value_for(rules::ASSOCIATIVITY));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -34,7 +34,7 @@ class GetCompletionStatus : public rules::RuleFn<CompletionStatus> {
|
|||
}
|
||||
|
||||
CompletionStatus apply_to(const rules::Blank *rule) {
|
||||
return { true, 0, AssociativityNone };
|
||||
return { true, 0, rules::AssociativityNone };
|
||||
}
|
||||
|
||||
CompletionStatus apply_to(const rules::Seq *rule) {
|
||||
|
|
@ -42,7 +42,7 @@ class GetCompletionStatus : public rules::RuleFn<CompletionStatus> {
|
|||
if (left_status.is_done)
|
||||
return apply(rule->right);
|
||||
else
|
||||
return { false, 0, AssociativityNone };
|
||||
return { false, 0, rules::AssociativityNone };
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define COMPILER_BUILD_TABLES_GET_COMPLETION_STATUS_H_
|
||||
|
||||
#include "tree_sitter/compiler.h"
|
||||
#include "compiler/rules/metadata.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
namespace build_tables {
|
||||
|
|
@ -9,7 +10,7 @@ namespace build_tables {
|
|||
struct CompletionStatus {
|
||||
bool is_done;
|
||||
int precedence;
|
||||
Associativity associativity;
|
||||
rules::Associativity associativity;
|
||||
};
|
||||
|
||||
CompletionStatus get_completion_status(const rule_ptr &);
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ pair<bool, ConflictType> ParseConflictManager::resolve(
|
|||
return { true, ConflictTypeResolved };
|
||||
} else if (min_precedence == max_precedence) {
|
||||
switch (new_action.associativity) {
|
||||
case AssociativityLeft:
|
||||
case rules::AssociativityLeft:
|
||||
return { true, ConflictTypeResolved };
|
||||
case AssociativityRight:
|
||||
case rules::AssociativityRight:
|
||||
return { false, ConflictTypeResolved };
|
||||
default:
|
||||
return { false, ConflictTypeUnresolved };
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ using rules::Symbol;
|
|||
ParseAction::ParseAction(ParseActionType type, ParseStateId state_index,
|
||||
Symbol symbol, size_t consumed_symbol_count,
|
||||
PrecedenceRange precedence_range,
|
||||
Associativity associativity, int production_id)
|
||||
rules::Associativity associativity, int production_id)
|
||||
: type(type),
|
||||
symbol(symbol),
|
||||
state_index(state_index),
|
||||
|
|
@ -28,7 +28,7 @@ ParseAction::ParseAction()
|
|||
symbol(Symbol(-1)),
|
||||
state_index(-1),
|
||||
consumed_symbol_count(0),
|
||||
associativity(AssociativityNone) {}
|
||||
associativity(rules::AssociativityNone) {}
|
||||
|
||||
ParseAction ParseAction::Error() {
|
||||
return ParseAction();
|
||||
|
|
@ -43,7 +43,7 @@ ParseAction ParseAction::Accept() {
|
|||
ParseAction ParseAction::Shift(ParseStateId state_index,
|
||||
PrecedenceRange precedence_range) {
|
||||
return ParseAction(ParseActionTypeShift, state_index, Symbol(-1), 0,
|
||||
precedence_range, AssociativityNone, -1);
|
||||
precedence_range, rules::AssociativityNone, -1);
|
||||
}
|
||||
|
||||
ParseAction ParseAction::ShiftExtra() {
|
||||
|
|
@ -60,7 +60,8 @@ ParseAction ParseAction::ReduceExtra(Symbol symbol) {
|
|||
}
|
||||
|
||||
ParseAction ParseAction::Reduce(Symbol symbol, size_t consumed_symbol_count,
|
||||
int precedence, Associativity associativity,
|
||||
int precedence,
|
||||
rules::Associativity associativity,
|
||||
unsigned int production_id) {
|
||||
return ParseAction(ParseActionTypeReduce, 0, symbol, consumed_symbol_count,
|
||||
{ precedence, precedence }, associativity, production_id);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ typedef enum {
|
|||
class ParseAction {
|
||||
ParseAction(ParseActionType type, ParseStateId state_index,
|
||||
rules::Symbol symbol, size_t consumed_symbol_count,
|
||||
PrecedenceRange range, Associativity, int production_id);
|
||||
PrecedenceRange range, rules::Associativity, int production_id);
|
||||
|
||||
public:
|
||||
ParseAction();
|
||||
|
|
@ -35,7 +35,7 @@ class ParseAction {
|
|||
static ParseAction Error();
|
||||
static ParseAction Shift(ParseStateId state_index, PrecedenceRange precedence);
|
||||
static ParseAction Reduce(rules::Symbol symbol, size_t consumed_symbol_count,
|
||||
int precedence, Associativity,
|
||||
int precedence, rules::Associativity,
|
||||
unsigned int production_id);
|
||||
static ParseAction ShiftExtra();
|
||||
static ParseAction ReduceExtra(rules::Symbol symbol);
|
||||
|
|
@ -47,7 +47,7 @@ class ParseAction {
|
|||
ParseStateId state_index;
|
||||
size_t consumed_symbol_count;
|
||||
PrecedenceRange precedence_range;
|
||||
Associativity associativity;
|
||||
rules::Associativity associativity;
|
||||
int production_id;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ using std::vector;
|
|||
class FlattenRule : public rules::RuleFn<void> {
|
||||
private:
|
||||
vector<int> precedence_stack;
|
||||
vector<Associativity> associativity_stack;
|
||||
vector<rules::Associativity> associativity_stack;
|
||||
Production production;
|
||||
|
||||
void apply_to(const rules::Symbol *sym) {
|
||||
|
|
@ -35,7 +35,8 @@ class FlattenRule : public rules::RuleFn<void> {
|
|||
if (precedence != 0)
|
||||
precedence_stack.push_back(precedence);
|
||||
if (associativity != 0)
|
||||
associativity_stack.push_back(static_cast<Associativity>(associativity));
|
||||
associativity_stack.push_back(
|
||||
static_cast<rules::Associativity>(associativity));
|
||||
|
||||
apply(metadata->rule);
|
||||
|
||||
|
|
@ -57,7 +58,8 @@ class FlattenRule : public rules::RuleFn<void> {
|
|||
|
||||
public:
|
||||
FlattenRule()
|
||||
: precedence_stack({ 0 }), associativity_stack({ AssociativityNone }) {}
|
||||
: precedence_stack({ 0 }),
|
||||
associativity_stack({ rules::AssociativityNone }) {}
|
||||
|
||||
Production flatten(const rule_ptr &rule) {
|
||||
apply(rule);
|
||||
|
|
|
|||
|
|
@ -9,6 +9,12 @@
|
|||
namespace tree_sitter {
|
||||
namespace rules {
|
||||
|
||||
enum Associativity {
|
||||
AssociativityNone,
|
||||
AssociativityLeft,
|
||||
AssociativityRight,
|
||||
};
|
||||
|
||||
enum MetadataKey {
|
||||
START_TOKEN,
|
||||
PRECEDENCE,
|
||||
|
|
|
|||
|
|
@ -63,13 +63,26 @@ rule_ptr err(const rule_ptr &rule) {
|
|||
return choice({ rule, rules::ERROR().copy() });
|
||||
}
|
||||
|
||||
rule_ptr prec(int precedence, const rule_ptr &rule, Associativity associativity) {
|
||||
rule_ptr prec_left(const rule_ptr &rule) {
|
||||
return metadata(rule, { { rules::ASSOCIATIVITY, rules::AssociativityLeft } });
|
||||
}
|
||||
|
||||
rule_ptr prec_left(int precedence, const rule_ptr &rule) {
|
||||
return metadata(rule, { { rules::PRECEDENCE, precedence },
|
||||
{ rules::ASSOCIATIVITY, associativity } });
|
||||
{ rules::ASSOCIATIVITY, rules::AssociativityLeft } });
|
||||
}
|
||||
|
||||
rule_ptr prec_right(const rule_ptr &rule) {
|
||||
return metadata(rule, { { rules::ASSOCIATIVITY, rules::AssociativityRight } });
|
||||
}
|
||||
|
||||
rule_ptr prec_right(int precedence, const rule_ptr &rule) {
|
||||
return metadata(rule, { { rules::PRECEDENCE, precedence },
|
||||
{ rules::ASSOCIATIVITY, rules::AssociativityRight } });
|
||||
}
|
||||
|
||||
rule_ptr prec(int precedence, const rule_ptr &rule) {
|
||||
return prec(precedence, rule, AssociativityLeft);
|
||||
return metadata(rule, { { rules::PRECEDENCE, precedence } });
|
||||
}
|
||||
|
||||
rule_ptr token(const rule_ptr &rule) {
|
||||
|
|
|
|||
|
|
@ -14,11 +14,12 @@ using std::vector;
|
|||
using std::set;
|
||||
|
||||
static const vector<Production> START_PRODUCTIONS_TOKEN_ONLY({
|
||||
Production({ ProductionStep(rules::Symbol(0, true), 0, AssociativityNone) }),
|
||||
Production({ ProductionStep(rules::Symbol(0, true), 0,
|
||||
rules::AssociativityNone) }),
|
||||
});
|
||||
|
||||
static const vector<Production> START_PRODUCTIONS({
|
||||
Production({ ProductionStep(rules::Symbol(0), 0, AssociativityNone) }),
|
||||
Production({ ProductionStep(rules::Symbol(0), 0, rules::AssociativityNone) }),
|
||||
});
|
||||
|
||||
static const vector<Production> NO_PRODUCTIONS({});
|
||||
|
|
@ -28,14 +29,14 @@ SyntaxVariable::SyntaxVariable(const string &name, VariableType type,
|
|||
: name(name), productions(productions), type(type) {}
|
||||
|
||||
ProductionStep::ProductionStep(const rules::Symbol &symbol, int precedence,
|
||||
Associativity associativity)
|
||||
rules::Associativity associativity)
|
||||
: symbol(symbol),
|
||||
precedence(precedence),
|
||||
associativity(associativity),
|
||||
rule_id(0) {}
|
||||
|
||||
ProductionStep::ProductionStep(const rules::Symbol &symbol, int precedence,
|
||||
Associativity associativity, int rule_id)
|
||||
rules::Associativity associativity, int rule_id)
|
||||
: symbol(symbol),
|
||||
precedence(precedence),
|
||||
associativity(associativity),
|
||||
|
|
|
|||
|
|
@ -6,18 +6,19 @@
|
|||
#include <set>
|
||||
#include "tree_sitter/compiler.h"
|
||||
#include "compiler/rules/symbol.h"
|
||||
#include "compiler/rules/metadata.h"
|
||||
#include "compiler/variable.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
|
||||
struct ProductionStep {
|
||||
ProductionStep(const rules::Symbol &, int, Associativity);
|
||||
ProductionStep(const rules::Symbol &, int, Associativity, int);
|
||||
ProductionStep(const rules::Symbol &, int, rules::Associativity);
|
||||
ProductionStep(const rules::Symbol &, int, rules::Associativity, int);
|
||||
bool operator==(const ProductionStep &) const;
|
||||
|
||||
rules::Symbol symbol;
|
||||
int precedence;
|
||||
Associativity associativity;
|
||||
rules::Associativity associativity;
|
||||
int rule_id;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue