Fixed a limitToFunction bug or two, work on ADTs
This commit is contained in:
@@ -98,7 +98,7 @@ NodeTree<ASTData>* ASTTransformation::firstPass(std::string fileName, NodeTree<S
|
||||
}
|
||||
|
||||
} else if (i->getDataRef()->getName() == "adt_def") {
|
||||
std::string name = concatSymbolTree(i->getChildren()[0]);
|
||||
std::string name = concatSymbolTree(getNode("identifier", i));
|
||||
NodeTree<ASTData>* adt_dec = addToScope("~enclosing_scope", translationUnit, new NodeTree<ASTData>("adt_def", ASTData(adt_def, Symbol(name, true, name))));
|
||||
addToScope(name, adt_dec, translationUnit);
|
||||
translationUnit->addChild(adt_dec);
|
||||
@@ -193,16 +193,37 @@ void ASTTransformation::secondPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* par
|
||||
//Do the inside of classes here
|
||||
secondPassDoClassInsides(typeDef, typedefChildren, std::map<std::string, Type*>());
|
||||
} else if (i->getDataRef()->getName() == "adt_def") {
|
||||
std::string name = concatSymbolTree(i->getChildren()[0]);
|
||||
std::cout << "ADT DEF" << std::endl;
|
||||
std::cout << "there are " << getNodes("adt_option", i).size() << " adt_options" << std::endl;
|
||||
std::string name = concatSymbolTree(getNode("identifier", i));
|
||||
NodeTree<ASTData>* adtDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations)
|
||||
for (NodeTree<Symbol>* j : i->getChildren()) {
|
||||
if (j->getDataRef()->getName() == "identifier") {
|
||||
std::string ident_name = concatSymbolTree(j);
|
||||
std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl;
|
||||
NodeTree<ASTData>* enum_variant_identifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType));
|
||||
adtDef->addChild(enum_variant_identifier);
|
||||
addToScope(ident_name, enum_variant_identifier, adtDef);
|
||||
addToScope("~enclosing_scope", adtDef, enum_variant_identifier);
|
||||
for (NodeTree<Symbol>* j : getNodes("adt_option", i)) {
|
||||
std::string ident_name = concatSymbolTree(getNode("identifier", j));
|
||||
std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl;
|
||||
NodeTree<ASTData>* enum_variant_identifier;
|
||||
NodeTree<Symbol>* possibleType = getNode("type", j);
|
||||
NodeTree<ASTData>* enum_variant_function = nullptr;
|
||||
if (possibleType) {
|
||||
Type* actual_type = typeFromTypeNode(possibleType, adtDef, std::map<std::string, Type*>());
|
||||
enum_variant_identifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(ident_name, true), actual_type));
|
||||
|
||||
// also make a function prototype for a function that returns an instance of this type. If we don't contain a type, it's just the literal
|
||||
//enum_variant_function = new NodeTree<ASTData>("function", ASTData(function, Symbol("fun_"+ident_name, true), new Type(std::vector<Type*>{actual_type}, adtDef->getDataRef()->valueType)));
|
||||
enum_variant_function = new NodeTree<ASTData>("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector<Type*>{actual_type}, adtDef->getDataRef()->valueType)));
|
||||
} else {
|
||||
enum_variant_identifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType));
|
||||
// now a function in both cases...
|
||||
enum_variant_function = new NodeTree<ASTData>("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector<Type*>(), adtDef->getDataRef()->valueType)));
|
||||
}
|
||||
adtDef->addChild(enum_variant_identifier);
|
||||
addToScope(ident_name, enum_variant_identifier, adtDef);
|
||||
addToScope("~enclosing_scope", adtDef, enum_variant_identifier);
|
||||
// this comes second so it is added to the enclosing scope second so that the function is found last on identifer lookup so we can still access members that are not functions
|
||||
// as their names alias each other
|
||||
if (enum_variant_function) {
|
||||
adtDef->addChild(enum_variant_function);
|
||||
addToScope(ident_name, enum_variant_function, adtDef);
|
||||
addToScope("~enclosing_scope", adtDef, enum_variant_function);
|
||||
}
|
||||
}
|
||||
} else if (i->getDataRef()->getName() == "function") {
|
||||
@@ -518,7 +539,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
newNode->addChildren(parameters);
|
||||
// update type with actual type
|
||||
newNode->getDataRef()->valueType = new Type(mapNodesToTypePointers(parameters), newNode->getDataRef()->valueType);
|
||||
auto statement = transform(getNode("statement", children), scope, types, limitToFunction, templateTypeReplacements);
|
||||
auto statement = transform(getNode("statement", children), scope, types, false, templateTypeReplacements); // definitly do not limit this statement to functions
|
||||
if (name == "lambda")
|
||||
newNode->getDataRef()->closedVariables = findVariablesToClose(newNode, statement, scope);
|
||||
for (auto i : newNode->getDataRef()->closedVariables)
|
||||
@@ -564,7 +585,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
} else if (name == "expression" || name == "shiftand" || name == "term" || name == "unarad" || name == "access_operation") {
|
||||
//If this is an actual part of an expression, not just a premoted child
|
||||
if (children.size() > 2) {
|
||||
NodeTree<ASTData>* lhs = transform(children[0], scope, std::vector<Type>(),limitToFunction, templateTypeReplacements); //LHS does not inherit types
|
||||
NodeTree<ASTData>* lhs = transform(children[0], scope, std::vector<Type>(),false, templateTypeReplacements); //LHS does not inherit types, or limittofunction
|
||||
NodeTree<ASTData>* rhs;
|
||||
if (name == "access_operation") {
|
||||
std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl;
|
||||
@@ -1033,7 +1054,9 @@ NodeTree<ASTData>* ASTTransformation::functionLookup(NodeTree<ASTData>* scope, s
|
||||
if (possibleMatches.size()) {
|
||||
for (auto i : possibleMatches) {
|
||||
//We're not looking for types
|
||||
if (i->getDataRef()->type == type_def || i->getDataRef()->type == adt_def)
|
||||
//if (i->getDataRef()->type == type_def || i->getDataRef()->type == adt_def)
|
||||
// actually, lets make it we're only looking for things with type function
|
||||
if (i->getDataRef()->valueType->baseType != function_type)
|
||||
continue;
|
||||
Type* functionType = i->getDataRef()->valueType;
|
||||
|
||||
@@ -1389,11 +1412,6 @@ std::map<std::string, Type*> ASTTransformation::makeTemplateFunctionTypeMap(Node
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
// We need recursion protection
|
||||
std::vector<NodeTree<ASTData>*> ASTTransformation::scopeLookup(NodeTree<ASTData>* scope, std::string lookup, bool includeModules) {
|
||||
return scopeLookup(scope, lookup, includeModules, std::set<NodeTree<ASTData>*>());
|
||||
}
|
||||
|
||||
NodeTree<ASTData>* ASTTransformation::generateThis(NodeTree<ASTData>* scope) {
|
||||
// if we're looking for this, traverse up until we find the declaration of this object and assign it's type to this
|
||||
NodeTree<ASTData>* trans;
|
||||
@@ -1410,6 +1428,11 @@ NodeTree<ASTData>* ASTTransformation::generateThis(NodeTree<ASTData>* scope) {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
// We need recursion protection
|
||||
std::vector<NodeTree<ASTData>*> ASTTransformation::scopeLookup(NodeTree<ASTData>* scope, std::string lookup, bool includeModules) {
|
||||
return scopeLookup(scope, lookup, includeModules, std::set<NodeTree<ASTData>*>());
|
||||
}
|
||||
|
||||
std::vector<NodeTree<ASTData>*> ASTTransformation::scopeLookup(NodeTree<ASTData>* scope, std::string lookup, bool includeModules, std::set<NodeTree<ASTData>*> visited) {
|
||||
std::cout << "Scp]|[e looking up " << lookup << std::endl;
|
||||
std::cout << "current: " << scope->getDataRef()->toString() << std::endl;
|
||||
|
||||
@@ -17,19 +17,22 @@ void CGenerator::generateCompSet(std::map<std::string, NodeTree<ASTData>*> ASTs,
|
||||
std::cout << "\n\n =====GENERATE PASS===== \n\n" << std::endl;
|
||||
std::cout << "\n\nGenerate pass for: " << outputName << std::endl;
|
||||
buildString += outputName + ".c ";
|
||||
std::ofstream outputCFile, outputHFile;
|
||||
//std::ofstream outputCFile, outputHFile;
|
||||
std::ofstream outputCFile;
|
||||
outputCFile.open(outputName + "/" + outputName + ".c");
|
||||
outputHFile.open(outputName + "/" + outputName + ".h");
|
||||
if (outputCFile.is_open() || outputHFile.is_open()) {
|
||||
//outputHFile.open(outputName + "/" + outputName + ".h");
|
||||
//if (outputCFile.is_open() || outputHFile.is_open()) {
|
||||
if (outputCFile.is_open()) {
|
||||
// Prequel common to all files
|
||||
auto chPair = generateTranslationUnit(outputName, ASTs);
|
||||
outputHFile << "#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n" << chPair.first;
|
||||
outputCFile << "#include \"" + outputName + ".h\"\n\n" << chPair.second;
|
||||
//outputHFile << "#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n" << chPair.first;
|
||||
//outputCFile << "#include \"" + outputName + ".h\"\n\n" << chPair.second;
|
||||
outputCFile << "#include <stdbool.h>\n#include <stdlib.h>\n#include <stdio.h>\n" << chPair.first << "\n\n// C FILE BEGIN\n\n" << chPair.second;
|
||||
} else {
|
||||
std::cerr << "Cannot open file " << outputName << ".c/h" << std::endl;
|
||||
}
|
||||
outputCFile.close();
|
||||
outputHFile.close();
|
||||
//outputHFile.close();
|
||||
|
||||
buildString += linkerString;
|
||||
buildString += "-o " + outputName;
|
||||
@@ -54,150 +57,186 @@ std::string CGenerator::getID() {
|
||||
std::string CGenerator::generateTypeStruct(NodeTree<ASTData>* from) {
|
||||
auto data = from->getData();
|
||||
auto children = from->getChildren();
|
||||
std::string objectString;
|
||||
if (data.type == type_def)
|
||||
objectString = "struct __struct_dummy_";
|
||||
else if (data.type == adt_def)
|
||||
objectString = "enum __adt_dummy_";
|
||||
objectString += scopePrefix(from) + CifyName(data.symbol.getName()) + "__ {\n";
|
||||
std::string structString, enumString, functionString;
|
||||
std::string enumName = "__enum_dummy_" + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())+"__");
|
||||
enumString = "enum " + enumName + " {\n";
|
||||
structString = "struct __struct_dummy_";
|
||||
structString += prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())+"__") + " {\n";
|
||||
if (data.type == adt_def) {
|
||||
structString = "typedef " + structString + "enum " + enumName + " flag;\n union { \n";
|
||||
}
|
||||
tabLevel++;
|
||||
for (int i = (data.type == adt_def ? 1 : 0); i < children.size(); i++) {
|
||||
|
||||
for (auto child : children) {
|
||||
//std::cout << children[i]->getName() << std::endl;
|
||||
if (children[i]->getName() != "function")
|
||||
objectString += tabs() + generate(children[i], nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n");
|
||||
if (child->getName() != "function") {
|
||||
if (data.type == adt_def) {
|
||||
// if this is not a plain no-data adt member (so if it is a primitive or doesn't have a reference back to)
|
||||
// wait a sec, this is easier
|
||||
if ( child->getDataRef()->valueType->typeDefinition != from)
|
||||
structString += tabs() + ValueTypeToCType(child->getDataRef()->valueType, child->getDataRef()->symbol.getName()) + "; /* adt data member */\n";
|
||||
} else {
|
||||
structString += tabs() + generate(child, nullptr).oneString() + "\n";
|
||||
}
|
||||
enumString += tabs() + generate(child, nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n");
|
||||
} else {
|
||||
if (data.type == adt_def) {
|
||||
functionString += "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, "fun_" + child->getDataRef()->symbol.getName()) + "(" +
|
||||
(child->getDataRef()->valueType->parameterTypes.size() ? ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0], "in") : "") + "); /*adt func*/\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
tabLevel--;
|
||||
objectString += "};";
|
||||
return objectString;
|
||||
if (data.type == adt_def) {
|
||||
//structString += "} data; /*end union*/ \n";
|
||||
structString += "}; /*end union*/\n } " + CifyName(data.symbol.getName()) + "; /* end struct */";
|
||||
} else {
|
||||
structString += "};";
|
||||
}
|
||||
enumString += "};\n";
|
||||
if (data.type == adt_def)
|
||||
return enumString + structString + functionString;
|
||||
return structString;
|
||||
}
|
||||
|
||||
// This method recurseivly generates all aliases of some definition
|
||||
std::string CGenerator::generateAliasChains(std::map<std::string, NodeTree<ASTData>*> ASTs, NodeTree<ASTData>* definition) {
|
||||
std::string output;
|
||||
for (auto trans : ASTs) {
|
||||
for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) {
|
||||
for (auto declaration : i->second) {
|
||||
auto declarationData = declaration->getDataRef();
|
||||
if (declarationData->type == type_def
|
||||
&& declarationData->valueType->typeDefinition != declaration
|
||||
&& declarationData->valueType->typeDefinition == definition) {
|
||||
output += "typedef " +
|
||||
scopePrefix(definition) + CifyName(definition->getDataRef()->symbol.getName()) + " " +
|
||||
scopePrefix(declaration) + CifyName(declarationData->symbol.getName()) + ";\n";
|
||||
// Recursively add the ones that depend on this one
|
||||
output += generateAliasChains(ASTs, declaration);
|
||||
}
|
||||
std::string output;
|
||||
for (auto trans : ASTs) {
|
||||
for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) {
|
||||
for (auto declaration : i->second) {
|
||||
auto declarationData = declaration->getDataRef();
|
||||
if (declarationData->type == type_def
|
||||
&& declarationData->valueType->typeDefinition != declaration
|
||||
&& declarationData->valueType->typeDefinition == definition) {
|
||||
output += "typedef " +
|
||||
prefixIfNeeded(scopePrefix(definition), CifyName(definition->getDataRef()->symbol.getName())) + " " +
|
||||
prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData->symbol.getName())) + ";\n";
|
||||
// Recursively add the ones that depend on this one
|
||||
output += generateAliasChains(ASTs, declaration);
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
bool CGenerator::isUnderNodeWithType(NodeTree<ASTData>* from, ASTType type) {
|
||||
auto scope = from->getDataRef()->scope;
|
||||
auto upper = scope.find("~enclosing_scope");
|
||||
if (upper != scope.end()) {
|
||||
if (upper->second[0]->getDataRef()->type == type)
|
||||
return true;
|
||||
return isUnderNodeWithType(upper->second[0], type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CGenerator::isUnderTranslationUnit(NodeTree<ASTData>* from, NodeTree<ASTData>* node) {
|
||||
auto scope = from->getDataRef()->scope;
|
||||
for (auto i : scope)
|
||||
for (auto j : i.second)
|
||||
if (j == node)
|
||||
return true;
|
||||
auto scope = from->getDataRef()->scope;
|
||||
for (auto i : scope)
|
||||
for (auto j : i.second)
|
||||
if (j == node)
|
||||
return true;
|
||||
|
||||
auto upper = scope.find("~enclosing_scope");
|
||||
if (upper != scope.end())
|
||||
return isUnderTranslationUnit(upper->second[0], node);
|
||||
return false;
|
||||
auto upper = scope.find("~enclosing_scope");
|
||||
if (upper != scope.end())
|
||||
return isUnderTranslationUnit(upper->second[0], node);
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeTree<ASTData>* CGenerator::highestScope(NodeTree<ASTData>* node) {
|
||||
auto it = node->getDataRef()->scope.find("~enclosing_scope");
|
||||
while (it != node->getDataRef()->scope.end()) {
|
||||
node = it->second[0];
|
||||
it = node->getDataRef()->scope.find("~enclosing_scope");
|
||||
}
|
||||
return node;
|
||||
auto it = node->getDataRef()->scope.find("~enclosing_scope");
|
||||
while (it != node->getDataRef()->scope.end()) {
|
||||
node = it->second[0];
|
||||
it = node->getDataRef()->scope.find("~enclosing_scope");
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
// We do translation units in their own function so they can do the pariwise h/c stuff and regualr in function body generation does not
|
||||
std::pair<std::string, std::string> CGenerator::generateTranslationUnit(std::string name, std::map<std::string, NodeTree<ASTData>*> ASTs) {
|
||||
// We now pass in the entire map of ASTs and loop through them so that we generate out into a single file
|
||||
std::string cOutput, hOutput;
|
||||
// Ok, so we've got to do this in passes to preserve mututally recursive definitions.
|
||||
//
|
||||
// First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;".
|
||||
// Also, other typedefs follow after their naming.
|
||||
// Second Pass: All top level variable declarations
|
||||
// Third Pass: Define all actual structs of a class, in correct order (done with posets)
|
||||
// Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too).
|
||||
// (this includes object methods)
|
||||
// Fifth Pass: Define all functions (including object methods).
|
||||
// We now pass in the entire map of ASTs and loop through them so that we generate out into a single file
|
||||
std::string cOutput, hOutput;
|
||||
// Ok, so we've got to do this in passes to preserve mututally recursive definitions.
|
||||
//
|
||||
// First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;".
|
||||
// Also, other typedefs follow after their naming.
|
||||
// Second Pass: All top level variable declarations
|
||||
// Third Pass: Define all actual structs of a class, in correct order (done with posets)
|
||||
// Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too).
|
||||
// (this includes object methods)
|
||||
// Fifth Pass: Define all functions (including object methods).
|
||||
|
||||
// However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth
|
||||
// are done simultanously, but append to different strings that are then concatinated properly, in order.
|
||||
// However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth
|
||||
// are done simultanously, but append to different strings that are then concatinated properly, in order.
|
||||
|
||||
std::string importIncludes = "/**\n * Import Includes\n */\n\n";
|
||||
std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\n */\n\n";
|
||||
std::string variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n";
|
||||
std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n";
|
||||
std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n";
|
||||
std::string classStructs = "/**\n * Class Structs\n */\n\n";
|
||||
std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n";
|
||||
std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n";
|
||||
// There also exists functionTypedefString which is a member variable that keeps
|
||||
// track of utility typedefs that allow our C type generation to be more sane
|
||||
// it is emitted in the h file right before functionPrototypes
|
||||
std::string importIncludes = "/**\n * Import Includes\n */\n\n";
|
||||
std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\n */\n\n";
|
||||
std::string variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n";
|
||||
std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n";
|
||||
std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n";
|
||||
std::string classStructs = "/**\n * Class Structs\n */\n\n";
|
||||
std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n";
|
||||
std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n";
|
||||
// There also exists functionTypedefString which is a member variable that keeps
|
||||
// track of utility typedefs that allow our C type generation to be more sane
|
||||
// it is emitted in the h file right before functionPrototypes
|
||||
|
||||
|
||||
Poset<NodeTree<ASTData>*> typedefPoset;
|
||||
for (auto trans : ASTs) {
|
||||
auto children = trans.second->getChildren();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
if (children[i]->getDataRef()->type == type_def) {
|
||||
// If we're an alias type, continue. We handle those differently
|
||||
if (children[i]->getDataRef()->valueType->typeDefinition != children[i])
|
||||
continue;
|
||||
Poset<NodeTree<ASTData>*> typedefPoset;
|
||||
for (auto trans : ASTs) {
|
||||
auto children = trans.second->getChildren();
|
||||
for (int i = 0; i < children.size(); i++) {
|
||||
if (children[i]->getDataRef()->type == type_def) {
|
||||
// If we're an alias type, continue. We handle those differently
|
||||
if (children[i]->getDataRef()->valueType->typeDefinition != children[i])
|
||||
continue;
|
||||
|
||||
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies.
|
||||
// If it has dependencies, there's no harm in adding it here
|
||||
// Go through every child in the class looking for declaration statements. For each of these that is not a primitive type
|
||||
// we will add a dependency from this definition to that definition in the poset.
|
||||
std::vector<NodeTree<ASTData>*> classChildren = children[i]->getChildren();
|
||||
for (auto j : classChildren) {
|
||||
if (j->getDataRef()->type == declaration_statement) {
|
||||
Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration
|
||||
if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer
|
||||
typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency
|
||||
}
|
||||
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies.
|
||||
// If it has dependencies, there's no harm in adding it here
|
||||
// Go through every child in the class looking for declaration statements. For each of these that is not a primitive type
|
||||
// we will add a dependency from this definition to that definition in the poset.
|
||||
std::vector<NodeTree<ASTData>*> classChildren = children[i]->getChildren();
|
||||
for (auto j : classChildren) {
|
||||
if (j->getDataRef()->type == declaration_statement) {
|
||||
Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration
|
||||
if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer
|
||||
typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency
|
||||
}
|
||||
} else if (children[i]->getDataRef()->type == adt_def) {
|
||||
//
|
||||
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies.
|
||||
}
|
||||
} else if (children[i]->getDataRef()->type == adt_def) {
|
||||
//
|
||||
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies.
|
||||
}
|
||||
}
|
||||
//Now generate the typedef's in the correct, topological order
|
||||
for (NodeTree<ASTData>* i : typedefPoset.getTopoSort())
|
||||
classStructs += generateTypeStruct(i) + "\n";
|
||||
}
|
||||
//Now generate the typedef's in the correct, topological order
|
||||
for (NodeTree<ASTData>* i : typedefPoset.getTopoSort())
|
||||
classStructs += generateTypeStruct(i) + "\n";
|
||||
|
||||
// Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations)
|
||||
// Also, everything in all of the import's scopes
|
||||
// Also c passthrough
|
||||
for (auto trans : ASTs) {
|
||||
// First go through and emit all the passthroughs, etc
|
||||
for (auto i : trans.second->getChildren()) {
|
||||
if (i->getDataRef()->type == if_comp)
|
||||
topLevelCPassthrough += generate(i, nullptr).oneString();
|
||||
}
|
||||
// Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations)
|
||||
// Also, everything in all of the import's scopes
|
||||
// Also c passthrough
|
||||
for (auto trans : ASTs) {
|
||||
// First go through and emit all the passthroughs, etc
|
||||
for (auto i : trans.second->getChildren()) {
|
||||
if (i->getDataRef()->type == if_comp)
|
||||
topLevelCPassthrough += generate(i, nullptr).oneString();
|
||||
}
|
||||
|
||||
for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) {
|
||||
for (auto declaration : i->second) {
|
||||
std::vector<NodeTree<ASTData>*> decChildren = declaration->getChildren();
|
||||
ASTData declarationData = declaration->getData();
|
||||
switch(declarationData.type) {
|
||||
case identifier:
|
||||
{
|
||||
auto parent = declaration->getDataRef()->scope["~enclosing_scope"][0];
|
||||
if (parent->getChildren().size() == 1)
|
||||
variableDeclarations += ValueTypeToCType(declarationData.valueType, scopePrefix(declaration) + declarationData.symbol.getName()) + "; /*identifier*/\n";
|
||||
else
|
||||
variableDeclarations += ValueTypeToCType(declarationData.valueType, generate(parent->getChildren()[0], nullptr, true, nullptr).oneString()) + " = " + generate(parent->getChildren()[1], nullptr, true, nullptr).oneString() + ";";
|
||||
for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) {
|
||||
for (auto declaration : i->second) {
|
||||
std::vector<NodeTree<ASTData>*> decChildren = declaration->getChildren();
|
||||
ASTData declarationData = declaration->getData();
|
||||
switch(declarationData.type) {
|
||||
case identifier:
|
||||
{
|
||||
auto parent = declaration->getDataRef()->scope["~enclosing_scope"][0];
|
||||
if (parent->getChildren().size() == 1)
|
||||
variableDeclarations += ValueTypeToCType(declarationData.valueType, prefixIfNeeded(scopePrefix(declaration), declarationData.symbol.getName())) + "; /*identifier*/\n";
|
||||
else
|
||||
variableDeclarations += ValueTypeToCType(declarationData.valueType, generate(parent->getChildren()[0], nullptr, true, nullptr).oneString()) + " = " + generate(parent->getChildren()[1], nullptr, true, nullptr).oneString() + ";";
|
||||
variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType, declarationData.symbol.getName()) + "; /*extern identifier*/\n";
|
||||
break;
|
||||
}
|
||||
@@ -217,12 +256,11 @@ std::pair<std::string, std::string> CGenerator::generateTranslationUnit(std::str
|
||||
parameters += ValueTypeToCType(decChildren[j]->getData().valueType, generate(decChildren[j], nullptr).oneString());
|
||||
nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType);
|
||||
}
|
||||
functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType->returnType, ((declarationData.symbol.getName() == "main") ? "" : function_header + scopePrefix(declaration)) +
|
||||
CifyName(declarationData.symbol.getName() + nameDecoration)) +
|
||||
"(" + parameters + "); /*func*/\n";
|
||||
std::string funName = (declarationData.symbol.getName() == "main") ? "main" :
|
||||
function_header + prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName() + nameDecoration));
|
||||
functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType->returnType, funName) + "(" + parameters + "); /*func*/\n";
|
||||
// generate function
|
||||
std::cout << "Generating " << scopePrefix(declaration) +
|
||||
CifyName(declarationData.symbol.getName()) << std::endl;
|
||||
std::cout << "Generating " << prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) << std::endl;
|
||||
functionDefinitions += generate(declaration, nullptr).oneString();
|
||||
}
|
||||
}
|
||||
@@ -238,13 +276,12 @@ std::pair<std::string, std::string> CGenerator::generateTranslationUnit(std::str
|
||||
continue; // Aliases of objects are done with the thing it alises
|
||||
// Otherwise, we're actually a renaming of a primitive, can generate here
|
||||
plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType,
|
||||
scopePrefix(declaration) +
|
||||
CifyName(declarationData.symbol.getName())) + ";\n";
|
||||
prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()))) + ";\n";
|
||||
plainTypedefs += generateAliasChains(ASTs, declaration);
|
||||
} else {
|
||||
plainTypedefs += "typedef struct __struct_dummy_" +
|
||||
scopePrefix(declaration) + CifyName(declarationData.symbol.getName()) + "__ " +
|
||||
scopePrefix(declaration) + CifyName(declarationData.symbol.getName()) + ";\n";
|
||||
prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()) + "__") + " " +
|
||||
prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n";
|
||||
functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n";
|
||||
// We use a seperate string for this because we only include it if this is the file we're defined in
|
||||
std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n";
|
||||
@@ -264,19 +301,15 @@ std::pair<std::string, std::string> CGenerator::generateTranslationUnit(std::str
|
||||
case adt_def:
|
||||
{
|
||||
//type
|
||||
plainTypedefs += "/* adt " + declarationData.symbol.getName() + " */\n";
|
||||
//plainTypedefs += "typedef struct __adt_dummy_" +
|
||||
plainTypedefs += "typedef enum __adt_dummy_" +
|
||||
scopePrefix(declaration) + CifyName(declarationData.symbol.getName()) + "__ " +
|
||||
scopePrefix(declaration) + CifyName(declarationData.symbol.getName()) + ";\n";
|
||||
// We use a seperate string for this because we only include it if this is the file we're defined in
|
||||
std::string enumString = "/* Enum Definition for " + declarationData.symbol.getName() + " */\n";
|
||||
// skip the name of the thing
|
||||
for (int j = 1; j < decChildren.size(); j++) {
|
||||
std::cout << decChildren[j]->getName() << std::endl;
|
||||
if (decChildren[j]->getName() == "identifier") //If object method and not template
|
||||
enumString += "an_option \n";
|
||||
}
|
||||
//don't even need to do this anymore, it's all earlier
|
||||
//plainTypedefs += "/* adt " + declarationData.symbol.getName() + " */\n";
|
||||
//plainTypedefs += "typedef struct __struct_dummy_" +
|
||||
//prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())+ "__") + " " +
|
||||
//prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n";
|
||||
//// skip the name of the thing
|
||||
//for (int j = 1; j < decChildren.size(); j++) {
|
||||
//std::cout << decChildren[j]->getName() << std::endl;
|
||||
//}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -344,8 +377,8 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
preName += "(*";
|
||||
postName += ")";
|
||||
}
|
||||
// we're scope prefixing EVERYTHING
|
||||
return preName + scopePrefix(from) + CifyName(data.symbol.getName()) + postName; //Cifying does nothing if not an operator overload
|
||||
// we're scope prefixing EVERYTHING, but only if needed
|
||||
return preName + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())) + postName; //Cifying does nothing if not an operator overload
|
||||
}
|
||||
case function:
|
||||
{
|
||||
@@ -370,8 +403,9 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
if (justFuncName) {
|
||||
std::string funcName;
|
||||
if (data.symbol.getName() != "main")
|
||||
funcName += function_header + scopePrefix(from);
|
||||
funcName += CifyName(data.symbol.getName() + nameDecoration);
|
||||
funcName += function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration));
|
||||
else
|
||||
funcName += CifyName(data.symbol.getName() + nameDecoration);
|
||||
if (from->getDataRef()->closedVariables.size()) {
|
||||
std::string tmpStruct = "closureStruct" + getID();
|
||||
output.preValue += closureStructType(data.closedVariables) + " " + tmpStruct + " = {";
|
||||
@@ -384,7 +418,7 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
std::string preName;
|
||||
if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end())
|
||||
preName += "this->";
|
||||
varName = (varName == "this") ? varName : scopePrefix(var) + varName;
|
||||
varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName);
|
||||
// so that we can close over things that have been closed over by an enclosing closure
|
||||
output.preValue += "." + varName + " = &/*woo*/" + generate(var, enclosingObject, justFuncName, enclosingFunction).oneString() + "/*woo*/";
|
||||
//output.preValue += "." + varName + " = &" + preName + varName;
|
||||
@@ -396,8 +430,9 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
}
|
||||
} else {
|
||||
// Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock
|
||||
output = "\n" + ValueTypeToCType(data.valueType->returnType, ((data.symbol.getName() == "main") ? "" : function_header + scopePrefix(from)) +
|
||||
CifyName(data.symbol.getName() + nameDecoration)) + "(" + parameters + ") {\n" + generate(children[children.size()-1], enclosingObject, justFuncName, from).oneString();
|
||||
std::string funName = (data.symbol.getName() == "main") ? "main" : function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration));
|
||||
output = "\n" + ValueTypeToCType(data.valueType->returnType, funName) + "(" + parameters + ") {\n" +
|
||||
generate(children[children.size()-1], enclosingObject, justFuncName, from).oneString();
|
||||
output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject);
|
||||
output += "}\n";
|
||||
}
|
||||
@@ -615,6 +650,7 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
return CCodeTriple("");
|
||||
case simple_passthrough:
|
||||
{
|
||||
std::string pre_end_dec, end_assign;
|
||||
// Stuff is bit more interesting now! XXX
|
||||
std::string pre_passthrough, post_passthrough;
|
||||
// Handle input/output parameters
|
||||
@@ -623,17 +659,27 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
for (auto in_or_out : optParamAssignLists) {
|
||||
for (auto assign : in_or_out->getChildren()) {
|
||||
auto assignChildren = assign->getChildren();
|
||||
if (in_or_out->getDataRef()->type == in_passthrough_params)
|
||||
if (in_or_out->getDataRef()->type == in_passthrough_params) {
|
||||
std::string currentName = generate(assignChildren[0], enclosingObject, enclosingFunction).oneString();
|
||||
std::string toName;
|
||||
if (assignChildren.size() == 2)
|
||||
pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, assignChildren[1]->getDataRef()->symbol.getName()) + " = " + generate(assignChildren[0], enclosingObject, enclosingFunction).oneString() + ";\n";
|
||||
toName = assignChildren[1]->getDataRef()->symbol.getName();
|
||||
else
|
||||
pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, assignChildren[0]->getDataRef()->symbol.getName()) + " = " + generate(assignChildren[0], enclosingObject, enclosingFunction).oneString() + ";\n";
|
||||
else if (in_or_out->getDataRef()->type == out_passthrough_params)
|
||||
toName = assignChildren[0]->getDataRef()->symbol.getName();
|
||||
if (currentName != toName)
|
||||
pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, toName) + " = " + currentName + ";\n";
|
||||
} else if (in_or_out->getDataRef()->type == out_passthrough_params) {
|
||||
std::string currentName = generate(assignChildren[0], enclosingObject, justFuncName, enclosingFunction).oneString();
|
||||
std::string toName;
|
||||
if (assignChildren.size() == 2)
|
||||
post_passthrough += generate(assignChildren[0], enclosingObject, justFuncName, enclosingFunction).oneString() + " = " + assignChildren[1]->getDataRef()->symbol.getName() + ";\n";
|
||||
toName = assignChildren[1]->getDataRef()->symbol.getName();
|
||||
else
|
||||
post_passthrough += generate(assignChildren[0], enclosingObject, justFuncName, enclosingFunction).oneString() + " = " + assignChildren[0]->getDataRef()->symbol.getName() + ";\n";
|
||||
else
|
||||
toName += assignChildren[0]->getDataRef()->symbol.getName();
|
||||
std::string trans_dec_name = currentName + "_end_assign";
|
||||
pre_end_dec += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, trans_dec_name) + ";\n";
|
||||
post_passthrough += trans_dec_name + " = " + toName + ";\n";
|
||||
end_assign += currentName + " = " + trans_dec_name + ";\n";
|
||||
} else
|
||||
linkerString += " " + strSlice(generate(in_or_out, enclosingObject, justFuncName, enclosingFunction).oneString(), 1, -2) + " ";
|
||||
}
|
||||
}
|
||||
@@ -641,8 +687,11 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
// The actual passthrough string is the last child now, as we might
|
||||
// have passthrough_params be the first child
|
||||
// we don't generate, as that will escape the returns and we don't want that. We'll just grab the string
|
||||
//return pre_passthrough + strSlice(generate(children.back(, enclosingFunction), enclosingObject, justFuncName).oneString(), 3, -4) + post_passthrough;
|
||||
return pre_passthrough + strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4) + post_passthrough;
|
||||
// we don't want the scope stuff if we're at top level for an include, etc....
|
||||
if (isUnderNodeWithType(from,function))
|
||||
return pre_end_dec + "{" + pre_passthrough + strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4) + post_passthrough + "}\n" + end_assign;
|
||||
else
|
||||
return strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4);
|
||||
}
|
||||
case function_call:
|
||||
{
|
||||
@@ -704,7 +753,7 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++)
|
||||
nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType);
|
||||
// Note that we only add scoping to the object, as this specifies our member function too
|
||||
/*HERE*/ return function_header + scopePrefix(unaliasedTypeDef) + CifyName(unaliasedTypeDef->getDataRef()->symbol.getName()) +"__" +
|
||||
/*HERE*/ return function_header + prefixIfNeeded(scopePrefix(unaliasedTypeDef), CifyName(unaliasedTypeDef->getDataRef()->symbol.getName())) +"__" +
|
||||
CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject, true, enclosingFunction) + ",";
|
||||
//The comma lets the upper function call know we already started the param list
|
||||
//Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses
|
||||
@@ -746,11 +795,11 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
|
||||
//Check to see if we're inside of an object and this is a method call
|
||||
bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]);
|
||||
if (isSelfObjectMethod) {
|
||||
output += function_header + scopePrefix(children[0]) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__";
|
||||
output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(enclosingObject->getDataRef()->symbol.getName())) +"__";
|
||||
output += CifyName(name + nameDecoration) + "(";
|
||||
output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : "");
|
||||
} else {
|
||||
output += function_header + scopePrefix(children[0]) + CifyName(name + nameDecoration) + "(";
|
||||
output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(name + nameDecoration)) + "(";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -877,8 +926,9 @@ std::string CGenerator::generateObjectMethod(NodeTree<ASTData>* enclosingObject,
|
||||
|
||||
distructDoubleStack.back().push_back(children[i]);
|
||||
}
|
||||
std::string functionSignature = "\n" + ValueTypeToCType(data.valueType->returnType, function_header + scopePrefix(from) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"
|
||||
+ CifyName(data.symbol.getName()) + nameDecoration) + "(" + ValueTypeToCType(&enclosingObjectType, "this") + parameters + ")";
|
||||
std::string functionSignature = "\n" + ValueTypeToCType(data.valueType->returnType, function_header +
|
||||
prefixIfNeeded(scopePrefix(from), CifyName(enclosingObject->getDataRef()->symbol.getName())) + "__" +
|
||||
CifyName(data.symbol.getName()) + nameDecoration) + "(" + ValueTypeToCType(&enclosingObjectType, "this") + parameters + ")";
|
||||
*functionPrototype += functionSignature + ";\n";
|
||||
// Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock
|
||||
//
|
||||
@@ -928,7 +978,7 @@ std::string CGenerator::generateMethodIfExists(Type* type, std::string method, s
|
||||
std::string nameDecoration;
|
||||
for (Type *paramType : methodDef->getDataRef()->valueType->parameterTypes)
|
||||
nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType);
|
||||
return function_header + scopePrefix(typeDefinition) + CifyName(typeDefinition->getDataRef()->symbol.getName()) + "__" + method + nameDecoration + "(" + parameter + ");\n";
|
||||
return function_header + prefixIfNeeded(scopePrefix(typeDefinition), CifyName(typeDefinition->getDataRef()->symbol.getName())) + "__" + method + nameDecoration + "(" + parameter + ");\n";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
@@ -952,7 +1002,7 @@ std::string CGenerator::closureStructType(std::set<NodeTree<ASTData>*> closedVar
|
||||
// will actually change the underlying function's type. We cheat and just add a *
|
||||
//auto tmp = var->getDataRef()->valueType->withIncreasedIndirection();
|
||||
std::string varName = var->getDataRef()->symbol.getName();
|
||||
varName = (varName == "this") ? varName : scopePrefix(var) + varName;
|
||||
varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName);
|
||||
typedefString += ValueTypeToCType(var->getDataRef()->valueType->withoutReference(), "*"+varName) + ";";
|
||||
}
|
||||
std::string structName = "closureStructType" + getID();
|
||||
@@ -970,7 +1020,7 @@ std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string decl
|
||||
switch (type->baseType) {
|
||||
case none:
|
||||
if (type->typeDefinition)
|
||||
return_type = scopePrefix(type->typeDefinition) + CifyName(type->typeDefinition->getDataRef()->symbol.getName());
|
||||
return_type = prefixIfNeeded(scopePrefix(type->typeDefinition), CifyName(type->typeDefinition->getDataRef()->symbol.getName()));
|
||||
else
|
||||
return_type = "none";
|
||||
break;
|
||||
@@ -1128,4 +1178,20 @@ std::string CGenerator::scopePrefix(NodeTree<ASTData>* from) {
|
||||
// that parent object will get scoped. When we add a package system, we'll have to then add their scoping here
|
||||
return scopePrefix(from->getDataRef()->scope["~enclosing_scope"][0]);
|
||||
}
|
||||
std::string CGenerator::prefixIfNeeded(std::string prefix, std::string name) {
|
||||
return simpleComplexName(name, prefix + name);
|
||||
}
|
||||
std::string CGenerator::simpleComplexName(std::string simpleName, std::string complexName) {
|
||||
auto already = simpleComplexNameMap.find(complexName);
|
||||
if (already != simpleComplexNameMap.end())
|
||||
return already->second;
|
||||
if (usedNameSet.find(simpleName) == usedNameSet.end()) {
|
||||
usedNameSet.insert(simpleName);
|
||||
simpleComplexNameMap[complexName] = simpleName;
|
||||
return simpleName;
|
||||
}
|
||||
usedNameSet.insert(complexName);
|
||||
simpleComplexNameMap[complexName] = complexName;
|
||||
return complexName;
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ Importer::Importer(Parser* parserIn, std::vector<std::string> includePaths, std:
|
||||
collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false));
|
||||
collapseSymbols.push_back(Symbol("opt_parameter_list", false));
|
||||
collapseSymbols.push_back(Symbol("identifier_list", false));
|
||||
collapseSymbols.push_back(Symbol("adt_option_list", false));
|
||||
collapseSymbols.push_back(Symbol("statement_list", false));
|
||||
collapseSymbols.push_back(Symbol("parameter_list", false));
|
||||
collapseSymbols.push_back(Symbol("typed_parameter_list", false));
|
||||
|
||||
Reference in New Issue
Block a user