Allow associativity to be specified in rules w/o precedence

This commit is contained in:
Max Brunsfeld 2015-10-13 11:23:02 -07:00
parent 4b817dc07c
commit 9959fe35b0
17 changed files with 78 additions and 56 deletions

View file

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

View file

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

View file

@ -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"),

View file

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

View file

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

View file

View 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) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -9,6 +9,12 @@
namespace tree_sitter {
namespace rules {
enum Associativity {
AssociativityNone,
AssociativityLeft,
AssociativityRight,
};
enum MetadataKey {
START_TOKEN,
PRECEDENCE,

View file

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

View file

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

View file

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