mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-22 23:30:37 +01:00
Poincare: RuleGen now uses a more explicit grammar
Change-Id: I22ca00a7115d8c60fd0aa95ec17deec829e0a69d Examples: Integer.a and Integer["0"]
This commit is contained in:
@@ -3,10 +3,8 @@ dir=poincare/src/simplify/rules_generation
|
||||
rulegen_objs := $(addprefix $(dir)/,\
|
||||
rules_parser.o\
|
||||
rules_lexer.o\
|
||||
builder.o\
|
||||
node.o\
|
||||
rule.o\
|
||||
selector.o\
|
||||
)
|
||||
|
||||
$(dir)/rules_parser.cpp: $(dir)/rules_parser.y
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "builder.h"
|
||||
#include "rule.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
Builder::Builder(Type type, std::string * name, std::vector<Builder *> * children) :
|
||||
Node(name, (std::vector<Node *> *)children),
|
||||
m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
void Builder::generateFields(Rule * context, std::string &indentation) {
|
||||
Selector * selector = context->selector();
|
||||
switch (m_type) {
|
||||
case Type::ExpressionType:
|
||||
std::cout << indentation << ".m_action = ExpressionBuilder::Action::BuildFromTypeAndValue," << std::endl;
|
||||
std::cout << indentation << ".m_expressionType = Expression::Type::" << *m_name << "," << std::endl;
|
||||
break;
|
||||
case Type::Variable:
|
||||
std::cout << indentation << ".m_action = ExpressionBuilder::Action::Clone," << std::endl;
|
||||
assert(m_children->size() == 0);
|
||||
std::cout << indentation << ".m_matchIndex = " << selector->flatIndexOfChildNamed(*m_name) << "," << std::endl;
|
||||
break;
|
||||
case Type::Wildcard:
|
||||
std::cout << indentation << ".m_action = ExpressionBuilder::Action::BringUpWildcard," << std::endl;
|
||||
assert(m_children->size() == 0);
|
||||
std::cout << indentation << ".m_matchIndex = " << selector->flatIndexOfChildNamed(*m_name) << "," << std::endl;
|
||||
break;
|
||||
case Type::ExpressionGenerator:
|
||||
assert(false); // Not implemented yet.
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H
|
||||
#define POINCARE_SIMPLIFY_RULES_GENERATION_BUILDER_H
|
||||
|
||||
#include "node.h"
|
||||
#include <string>
|
||||
|
||||
class Builder : public Node {
|
||||
public:
|
||||
enum class Type {
|
||||
ExpressionGenerator,
|
||||
ExpressionType,
|
||||
Variable,
|
||||
Wildcard
|
||||
};
|
||||
Builder(Type type, std::string * name, std::vector<Builder *> * children = nullptr);
|
||||
protected:
|
||||
void generateFields(Rule * context, std::string &indentation) override;
|
||||
private:
|
||||
Type m_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,25 +1,113 @@
|
||||
#include "builder.h"
|
||||
#include "node.h"
|
||||
#include "rule.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
|
||||
Node::Node(std::string * name, std::vector<Node *> * children) :
|
||||
m_name(name),
|
||||
m_children(children)
|
||||
Node::Node(Type type, std::string * typeName) :
|
||||
m_type(type),
|
||||
m_typeName(typeName),
|
||||
m_referenceMode(ReferenceMode::None),
|
||||
m_referenceName(nullptr),
|
||||
m_value(nullptr),
|
||||
m_parent(nullptr)
|
||||
{
|
||||
if (children == nullptr) {
|
||||
m_children = new std::vector<Node *>();
|
||||
}
|
||||
for (Node * child : *m_children) {
|
||||
child->m_parent = this;
|
||||
}
|
||||
m_children = new std::vector<Node *>();
|
||||
}
|
||||
|
||||
Node::~Node() {
|
||||
delete m_children;
|
||||
}
|
||||
|
||||
void Node::setReference(ReferenceMode mode, std::string * referenceName) {
|
||||
assert(m_referenceName == nullptr);
|
||||
m_referenceName = referenceName;
|
||||
m_referenceMode = mode;
|
||||
}
|
||||
|
||||
void Node::setValue(std::string * value) {
|
||||
assert(m_value == nullptr);
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
void Node::setChildren(std::vector<Node *> * children) {
|
||||
assert(m_children->size() == 0);
|
||||
delete m_children;
|
||||
m_children = children;
|
||||
for (Node * child : *m_children) {
|
||||
child->m_parent = this;
|
||||
}
|
||||
}
|
||||
|
||||
// Generation
|
||||
|
||||
std::string Node::generateSelectorConstructor(Rule * context) {
|
||||
std::ostringstream result;
|
||||
switch (m_type) {
|
||||
case Node::Type::Any:
|
||||
switch (m_referenceMode) {
|
||||
case Node::ReferenceMode::None:
|
||||
case Node::ReferenceMode::SingleNode:
|
||||
result << "ExpressionSelector::Any(";
|
||||
break;
|
||||
case Node::ReferenceMode::Wildcard:
|
||||
result << "ExpressionSelector::Wildcard(";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Node::Type::Expression:
|
||||
if (m_value == nullptr) {
|
||||
result << "ExpressionSelector::Type(Expression::Type::" << *m_typeName << ", ";
|
||||
} else {
|
||||
result << "ExpressionSelector::TypeAndValue(Expression::Type::" << *m_typeName << ", " << *m_value << ",";
|
||||
}
|
||||
break;
|
||||
case Node::Type::Generator:
|
||||
//assert(false);
|
||||
break;
|
||||
}
|
||||
result << m_children->size() << ")";
|
||||
return result.str();
|
||||
}
|
||||
|
||||
std::string Node::generateBuilderConstructor(Rule * context) {
|
||||
Node * selector = context->selector();
|
||||
std::ostringstream result;
|
||||
switch (m_type) {
|
||||
case Node::Type::Any:
|
||||
switch (m_referenceMode) {
|
||||
case Node::ReferenceMode::None:
|
||||
assert(false);
|
||||
break;
|
||||
case Node::ReferenceMode::SingleNode:
|
||||
assert(m_referenceName != nullptr);
|
||||
result << "ExpressionBuilder::Clone(" << selector->flatIndexOfChildNamed(*m_referenceName) << ", " ;
|
||||
break;
|
||||
case Node::ReferenceMode::Wildcard:
|
||||
result << "ExpressionBuilder::BringUpWildcard(" << selector->flatIndexOfChildNamed(*m_referenceName) << ", ";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Node::Type::Expression:
|
||||
if (m_value == nullptr) {
|
||||
// Here we could assert that m_typeName is among the kinds that expect no value
|
||||
result << "ExpressionBuilder::BuildFromType(Expression::Type::" << *m_typeName << ", ";
|
||||
} else {
|
||||
// Here we could assert that m_typeName is among the kinds that expect a value
|
||||
result << "ExpressionBuilder::BuildFromTypeAndValue(Expression::Type::" << *m_typeName << ", " << *m_value << ", ";
|
||||
}
|
||||
break;
|
||||
case Node::Type::Generator:
|
||||
result << "ExpressionBuilder::CallExternalGenerator(SimplificationGenerator::" << *m_typeName << ", ";
|
||||
//assert(false);
|
||||
break;
|
||||
}
|
||||
result << m_children->size() << ")";
|
||||
return result.str();
|
||||
}
|
||||
|
||||
int Node::flatIndexOfChildNamed(std::string name) {
|
||||
if (name == *m_name) {
|
||||
if (m_referenceName != nullptr && *m_referenceName == name) {
|
||||
return 0;
|
||||
}
|
||||
int sum=1;
|
||||
@@ -54,17 +142,26 @@ std::string indentation_string(int i) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int Node::generate(Rule * context, int index, int indentationLevel) {
|
||||
void Node::generateSelectorTree(Rule * context) {
|
||||
generateTree(true, context, 0, 0);
|
||||
}
|
||||
|
||||
void Node::generateBuilderTree(Rule * context) {
|
||||
generateTree(false, context, 0, 0);
|
||||
}
|
||||
|
||||
int Node::generateTree(bool selector, Rule * context, int index, int indentationLevel) {
|
||||
std::string indentation = indentation_string(indentationLevel);
|
||||
std::string nextIndentation = indentation_string(indentationLevel+1);
|
||||
std::cout << indentation << "{" << std::endl;
|
||||
std::cout << nextIndentation << "// #" << index << std::endl;
|
||||
this->generateFields(context, nextIndentation);
|
||||
std::cout << nextIndentation << ".m_numberOfChildren = " << m_children->size() << "," << std::endl;
|
||||
std::cout << indentation << "}," << std::endl;
|
||||
std::cout << indentation;
|
||||
if (selector) {
|
||||
std::cout << generateSelectorConstructor(context);
|
||||
} else {
|
||||
std::cout << generateBuilderConstructor(context);
|
||||
}
|
||||
std::cout << ", // #" << index << std::endl;
|
||||
int generatedCount = 1;
|
||||
for (Node * child : *m_children) {
|
||||
generatedCount += child->generate(context, index+generatedCount, indentationLevel+1);
|
||||
generatedCount += child->generateTree(selector, context, index+generatedCount, indentationLevel+1);
|
||||
}
|
||||
return generatedCount;
|
||||
}
|
||||
|
||||
@@ -8,14 +8,39 @@ class Rule;
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node(std::string * name, std::vector<Node *> * m_children);
|
||||
enum class Type {
|
||||
Expression,
|
||||
Generator,
|
||||
Any
|
||||
};
|
||||
enum class ReferenceMode {
|
||||
None,
|
||||
SingleNode,
|
||||
Wildcard
|
||||
};
|
||||
|
||||
// Creating Nodes
|
||||
Node(Type type, std::string * typeName = nullptr);
|
||||
~Node();
|
||||
int generate(Rule * context = nullptr, int index = 0, int indentationLevel = 0);
|
||||
void setReference(ReferenceMode mode, std::string * referenceName);
|
||||
void setValue(std::string * value);
|
||||
void setChildren(std::vector<Node *> * children);
|
||||
|
||||
int totalDescendantCountIncludingSelf();
|
||||
int flatIndexOfChildNamed(std::string name);
|
||||
protected:
|
||||
virtual void generateFields(Rule * context, std::string &indentation) = 0;
|
||||
std::string * m_name;
|
||||
|
||||
void generateSelectorTree(Rule * context);
|
||||
void generateBuilderTree(Rule * context);
|
||||
private:
|
||||
int generateTree(bool selector, Rule * context, int index, int indentationLevel);
|
||||
std::string generateSelectorConstructor(Rule * context);
|
||||
std::string generateBuilderConstructor(Rule * context);
|
||||
|
||||
Type m_type;
|
||||
std::string * m_typeName;
|
||||
ReferenceMode m_referenceMode;
|
||||
std::string * m_referenceName;
|
||||
std::string * m_value;
|
||||
std::vector<Node *> * m_children;
|
||||
Node * m_parent;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "rule.h"
|
||||
#include <iostream>
|
||||
|
||||
Rule::Rule(Selector * selector, Builder * builder) :
|
||||
Rule::Rule(Node * selector, Node * builder) :
|
||||
m_selector(selector), m_builder(builder) {
|
||||
}
|
||||
|
||||
@@ -10,16 +10,16 @@ Rule::~Rule() {
|
||||
delete m_selector;
|
||||
}
|
||||
|
||||
Selector * Rule::selector() {
|
||||
Node * Rule::selector() {
|
||||
return m_selector;
|
||||
}
|
||||
|
||||
void Rule::generate(std::string rule_name) {
|
||||
std::cout << "const ExpressionSelector " << rule_name << "Selector[" << m_selector->totalDescendantCountIncludingSelf() << "] = {" << std::endl;
|
||||
m_selector->generate(this);
|
||||
std::cout << "constexpr ExpressionSelector " << rule_name << "Selector[" << m_selector->totalDescendantCountIncludingSelf() << "] = {" << std::endl;
|
||||
m_selector->generateSelectorTree(this);
|
||||
std::cout << "};" << std::endl;
|
||||
|
||||
std::cout << "const ExpressionBuilder " << rule_name << "Builder[" << m_builder->totalDescendantCountIncludingSelf() << "] = {" << std::endl;
|
||||
m_builder->generate(this);
|
||||
std::cout << "constexpr ExpressionBuilder " << rule_name << "Builder[" << m_builder->totalDescendantCountIncludingSelf() << "] = {" << std::endl;
|
||||
m_builder->generateBuilderTree(this);
|
||||
std::cout << "};" << std::endl;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_RULE_H
|
||||
#define POINCARE_SIMPLIFY_RULES_GENERATION_RULE_H
|
||||
|
||||
#include "selector.h"
|
||||
#include "builder.h"
|
||||
#include "node.h"
|
||||
|
||||
class Rule {
|
||||
public:
|
||||
Rule(Selector * selector, Builder * builder);
|
||||
Rule(Node * selector, Node * builder);
|
||||
~Rule();
|
||||
void generate(std::string rule_name);
|
||||
Selector * selector();
|
||||
Node * selector();
|
||||
private:
|
||||
Selector * m_selector;
|
||||
Builder * m_builder;
|
||||
Node * m_selector;
|
||||
Node * m_builder;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,14 +9,18 @@
|
||||
|
||||
%%
|
||||
|
||||
[A-Z][a-z]+ { yylval.string = new std::string(yytext); return(EXPRESSION_TYPE); }
|
||||
\$[a-zA-Z]+ { yylval.string = new std::string(yytext); return(EXPRESSION_GENERATOR); }
|
||||
[a-z]+\* { yylval.string = new std::string(yytext); return(WILDCARD); }
|
||||
[a-z]+ { yylval.string = new std::string(yytext); return(VARIABLE); }
|
||||
[a-z]+ { yylval.string = new std::string(yytext); return (IDENTIFIER); }
|
||||
[A-Za-z]+ { yylval.string = new std::string(yytext); return (CAPITALIZED_IDENTIFIER); }
|
||||
[0-9]+ { yylval.string = new std::string(yytext); return (VALUE); }
|
||||
\$ { return(DOLLAR); }
|
||||
\* { return (ASTERISK); }
|
||||
\-\> { return(SIMPLIFIES_TO); }
|
||||
\( { return(LEFT_PARENTHESIS); }
|
||||
\) { return(RIGHT_PARENTHESIS); }
|
||||
\[ { return(LEFT_BRACKET); }
|
||||
\] { return(RIGHT_BRACKET); }
|
||||
\, { return(COMMA); }
|
||||
\; { return(SEMICOLON); }
|
||||
\. { return(PERIOD); }
|
||||
|
||||
%%
|
||||
|
||||
@@ -23,39 +23,38 @@ int yyerror(std::vector<Rule *> ** rules, const char *s);
|
||||
* when parsing (a/b) we want to create a new Fraction), or a string (this will
|
||||
* be useful to retrieve the value of Integers for example). */
|
||||
%union {
|
||||
std::vector<Builder *> * builder_list;
|
||||
std::vector<Selector *> * selector_list;
|
||||
std::vector<Rule *> * rule_list;
|
||||
std::vector<Node *> * node_list;
|
||||
Rule * rule;
|
||||
Selector * selector;
|
||||
Builder * builder;
|
||||
Node * node;
|
||||
std::string * string;
|
||||
}
|
||||
|
||||
/* The INTEGER token uses the "string" part of the union to store its value */
|
||||
%token <string> INTEGER
|
||||
%token <string> SYMBOL
|
||||
/* The IDENTIFIER, CAPITALIZED_IDENTIFIER and VALUE token uses the "string" part
|
||||
* of the union to store their value */
|
||||
|
||||
%token <string> EXPRESSION_TYPE
|
||||
%token <string> EXPRESSION_GENERATOR
|
||||
%token <string> WILDCARD
|
||||
%token <string> VARIABLE
|
||||
%token <string> IDENTIFIER
|
||||
%token <string> CAPITALIZED_IDENTIFIER
|
||||
%token <string> VALUE
|
||||
|
||||
/* Some tokens don't store any value */
|
||||
|
||||
%token SIMPLIFIES_TO
|
||||
%token LEFT_PARENTHESIS
|
||||
%token RIGHT_PARENTHESIS
|
||||
%token LEFT_BRACKET
|
||||
%token RIGHT_BRACKET
|
||||
%token COMMA
|
||||
%token SEMICOLON
|
||||
%token PERIOD
|
||||
%token DOLLAR
|
||||
%token ASTERISK
|
||||
|
||||
/* The "rule_list" symbol uses the "rule_list" part of the union, and so on */
|
||||
%type <rule_list> rule_list;
|
||||
%type <rule> rule;
|
||||
%type <selector> selector;
|
||||
%type <selector_list> selector_list;
|
||||
%type <builder> builder;
|
||||
%type <builder_list> builder_list;
|
||||
|
||||
/* The "exp" symbol uses the "expression" part of the union. */
|
||||
/*%type <expression> exp;*/
|
||||
%type <node> node;
|
||||
%type <node_list> node_list;
|
||||
|
||||
%%
|
||||
|
||||
@@ -67,32 +66,39 @@ rule_list:
|
||||
| rule_list rule { $1->push_back($2); $$ = $1; }
|
||||
|
||||
rule:
|
||||
selector SIMPLIFIES_TO builder SEMICOLON { $$ = new Rule($1, $3); }
|
||||
node SIMPLIFIES_TO node SEMICOLON { $$ = new Rule($1, $3); }
|
||||
|
||||
selector:
|
||||
VARIABLE { $$ = new Selector(Selector::Type::Variable, $1); }
|
||||
| WILDCARD { $$ = new Selector(Selector::Type::Wildcard, $1); }
|
||||
| EXPRESSION_TYPE LEFT_PARENTHESIS selector_list RIGHT_PARENTHESIS {
|
||||
$$ = new Selector(Selector::Type::ExpressionType, $1, $3);
|
||||
node:
|
||||
CAPITALIZED_IDENTIFIER {
|
||||
$$ = new Node(Node::Type::Expression, $1);
|
||||
}
|
||||
| DOLLAR CAPITALIZED_IDENTIFIER {
|
||||
$$ = new Node(Node::Type::Generator, $2);
|
||||
}
|
||||
| IDENTIFIER {
|
||||
$$ = new Node(Node::Type::Any);
|
||||
$$->setReference(Node::ReferenceMode::SingleNode, $1);
|
||||
}
|
||||
| IDENTIFIER ASTERISK {
|
||||
$$ = new Node(Node::Type::Any);
|
||||
$$->setReference(Node::ReferenceMode::Wildcard, $1);
|
||||
}
|
||||
| node PERIOD IDENTIFIER {
|
||||
$$ = $1;
|
||||
$$->setReference(Node::ReferenceMode::SingleNode, $3);
|
||||
}
|
||||
| node LEFT_BRACKET IDENTIFIER RIGHT_BRACKET {
|
||||
$$ = $1;
|
||||
$$->setValue($3);
|
||||
}
|
||||
| node LEFT_PARENTHESIS node_list RIGHT_PARENTHESIS {
|
||||
$$ = $1;
|
||||
$$->setChildren($3);
|
||||
}
|
||||
|
||||
selector_list:
|
||||
selector { $$ = new std::vector<Selector *>(); $$->push_back($1); }
|
||||
| selector_list COMMA selector { $1->push_back($3); $$ = $1; }
|
||||
|
||||
builder:
|
||||
VARIABLE { $$ = new Builder(Builder::Type::Variable, $1); }
|
||||
| WILDCARD { $$ = new Builder(Builder::Type::Wildcard, $1); }
|
||||
| EXPRESSION_GENERATOR LEFT_PARENTHESIS builder_list RIGHT_PARENTHESIS {
|
||||
$$ = new Builder(Builder::Type::ExpressionGenerator, $1, $3);
|
||||
}
|
||||
| EXPRESSION_TYPE LEFT_PARENTHESIS builder_list RIGHT_PARENTHESIS {
|
||||
$$ = new Builder(Builder::Type::ExpressionType, $1, $3);
|
||||
}
|
||||
|
||||
builder_list:
|
||||
builder { $$ = new std::vector<Builder *>(); $$->push_back($1); }
|
||||
| builder_list COMMA builder { $1->push_back($3); $$ = $1; }
|
||||
node_list:
|
||||
node { $$ = new std::vector<Node *>(); $$->push_back($1); }
|
||||
| node_list COMMA node { $1->push_back($3); $$ = $1; }
|
||||
|
||||
%%
|
||||
|
||||
@@ -120,20 +126,16 @@ int main(void) {
|
||||
rules->at(i)->generate(name.str());
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << "const Simplification simplifications[" << rules->size() << "] = {" << std::endl;
|
||||
std::cout << "constexpr Simplification simplifications[" << rules->size() << "] = {" << std::endl;
|
||||
for (int i=0; i<rules->size(); i++) {
|
||||
std::stringstream name;
|
||||
name << "rule" << i;
|
||||
std::cout << " {" << std::endl;
|
||||
std::cout << " .m_selector = (ExpressionSelector *)" << name.str() << "Selector," << std::endl;
|
||||
std::cout << " .m_builder = (ExpressionBuilder *)" << name.str() << "Builder," << std::endl;
|
||||
std::cout << " }," << std::endl;
|
||||
std::cout << " Simplification((ExpressionSelector *)" << name.str() << "Selector, (ExpressionBuilder *)" << name.str() << "Builder)," << std::endl;
|
||||
}
|
||||
std::cout << "};" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "const int knumberOfSimplifications = " << rules->size() << ";" << std::endl;
|
||||
|
||||
std::cout << "constexpr int knumberOfSimplifications = " << rules->size() << ";" << std::endl;
|
||||
|
||||
delete rules;
|
||||
return 0;
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#include "selector.h"
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
Selector::Selector(Type type, std::string * name, std::vector<Selector *> * children) :
|
||||
Node(name, (std::vector<Node *> *)children),
|
||||
m_type(type)
|
||||
{
|
||||
}
|
||||
|
||||
void Selector::generateFields(Rule * context, std::string &indentation) {
|
||||
Selector * parent = (Selector *)m_parent;
|
||||
switch (m_type) {
|
||||
case Type::Variable:
|
||||
std::cout << indentation << ".m_match = ExpressionSelector::Match::Any," << std::endl;
|
||||
break;
|
||||
case Type::Wildcard:
|
||||
std::cout << indentation << ".m_match = ExpressionSelector::Match::Wildcard," << std::endl;
|
||||
// Wildcard should always be the last element of a parent
|
||||
assert(parent->m_children->back() == this);
|
||||
break;
|
||||
case Type::ExpressionType:
|
||||
std::cout << indentation << ".m_match = ExpressionSelector::Match::Type," << std::endl;
|
||||
std::cout << indentation << ".m_expressionType = Expression::Type::" << *m_name << "," << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#ifndef POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H
|
||||
#define POINCARE_SIMPLIFY_RULES_GENERATION_SELECTOR_H
|
||||
|
||||
#include "node.h"
|
||||
#include <string>
|
||||
|
||||
class Selector : public Node {
|
||||
public:
|
||||
enum class Type {
|
||||
Variable,
|
||||
Wildcard,
|
||||
ExpressionType
|
||||
};
|
||||
Selector(Type type, std::string * name, std::vector<Selector *> * children = nullptr);
|
||||
protected:
|
||||
void generateFields(Rule * context, std::string &indentation) override;
|
||||
private:
|
||||
Type m_type;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user