More work on ADTs

This commit is contained in:
Nathan Braswell
2015-11-09 13:26:02 -05:00
parent 3645099bbb
commit 2ea504ffc1
5 changed files with 718 additions and 692 deletions

View File

@@ -41,6 +41,7 @@ class Type {
void decreaseIndirection(); void decreaseIndirection();
void modifyIndirection(int mod); void modifyIndirection(int mod);
Type withIncreasedIndirection(); Type withIncreasedIndirection();
Type *withIncreasedIndirectionPtr();
Type withDecreasedIndirection(); Type withDecreasedIndirection();
Type* withoutReference(); Type* withoutReference();

View File

@@ -197,6 +197,15 @@ void ASTTransformation::secondPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* par
std::cout << "there are " << getNodes("adt_option", i).size() << " adt_options" << std::endl; std::cout << "there are " << getNodes("adt_option", i).size() << " adt_options" << std::endl;
std::string name = concatSymbolTree(getNode("identifier", i)); 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) NodeTree<ASTData>* adtDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations)
// Let's make an equality function prototype
Type *thisADTType = adtDef->getDataRef()->valueType;
NodeTree<ASTData>* equalityFunc = new NodeTree<ASTData>("function", ASTData(function, Symbol("operator==", true), new Type(std::vector<Type*>{thisADTType}, new Type(boolean))));
//NodeTree<ASTData>* equalityFunc = new NodeTree<ASTData>("function", ASTData(function, Symbol("operator==", true), new Type(std::vector<Type*>{thisADTType, thisADTType}, new Type(boolean))));
adtDef->addChild(equalityFunc);
addToScope("operator==", equalityFunc, adtDef);
addToScope("~enclosing_scope", adtDef, equalityFunc);
for (NodeTree<Symbol>* j : getNodes("adt_option", i)) { for (NodeTree<Symbol>* j : getNodes("adt_option", i)) {
std::string ident_name = concatSymbolTree(getNode("identifier", j)); std::string ident_name = concatSymbolTree(getNode("identifier", j));
std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl; std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl;
@@ -209,11 +218,11 @@ void ASTTransformation::secondPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* par
// 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 // 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("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))); enum_variant_function = new NodeTree<ASTData>("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector<Type*>{actual_type}, thisADTType)));
} else { } else {
enum_variant_identifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType)); enum_variant_identifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType));
// now a function in both cases... // 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))); enum_variant_function = new NodeTree<ASTData>("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector<Type*>(), thisADTType)));
} }
adtDef->addChild(enum_variant_identifier); adtDef->addChild(enum_variant_identifier);
addToScope(ident_name, enum_variant_identifier, adtDef); addToScope(ident_name, enum_variant_identifier, adtDef);

View File

@@ -81,7 +81,15 @@ std::string CGenerator::generateTypeStruct(NodeTree<ASTData>* from) {
enumString += tabs() + generate(child, nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n"); enumString += tabs() + generate(child, nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n");
} else { } else {
if (data.type == adt_def) { if (data.type == adt_def) {
functionString += "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, "fun_" + child->getDataRef()->symbol.getName()) + "(" + std::string fun_name = child->getDataRef()->symbol.getName();
std::string first_param;
if (fun_name == "operator==") {
fun_name = "fun_" + data.symbol.getName() + "__" + CifyName(fun_name);
first_param = ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0]->withIncreasedIndirectionPtr(), "this") + ", ";
} else {
fun_name = "fun_" + fun_name;
}
functionString += "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, fun_name) + "(" + first_param +
(child->getDataRef()->valueType->parameterTypes.size() ? ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0], "in") : "") + "); /*adt func*/\n"; (child->getDataRef()->valueType->parameterTypes.size() ? ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0], "in") : "") + "); /*adt func*/\n";
} }
} }
@@ -101,8 +109,8 @@ std::string CGenerator::generateTypeStruct(NodeTree<ASTData>* from) {
// This method recurseivly generates all aliases of some definition // 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 CGenerator::generateAliasChains(std::map<std::string, NodeTree<ASTData>*> ASTs, NodeTree<ASTData>* definition) {
std::string output; std::string output;
for (auto trans : ASTs) { for (auto trans : ASTs) {
for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) { for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) {
for (auto declaration : i->second) { for (auto declaration : i->second) {
auto declarationData = declaration->getDataRef(); auto declarationData = declaration->getDataRef();
@@ -117,75 +125,75 @@ for (auto trans : ASTs) {
} }
} }
} }
} }
return output; return output;
} }
bool CGenerator::isUnderNodeWithType(NodeTree<ASTData>* from, ASTType type) { bool CGenerator::isUnderNodeWithType(NodeTree<ASTData>* from, ASTType type) {
auto scope = from->getDataRef()->scope; auto scope = from->getDataRef()->scope;
auto upper = scope.find("~enclosing_scope"); auto upper = scope.find("~enclosing_scope");
if (upper != scope.end()) { if (upper != scope.end()) {
if (upper->second[0]->getDataRef()->type == type) if (upper->second[0]->getDataRef()->type == type)
return true; return true;
return isUnderNodeWithType(upper->second[0], type); return isUnderNodeWithType(upper->second[0], type);
} }
return false; return false;
} }
bool CGenerator::isUnderTranslationUnit(NodeTree<ASTData>* from, NodeTree<ASTData>* node) { bool CGenerator::isUnderTranslationUnit(NodeTree<ASTData>* from, NodeTree<ASTData>* node) {
auto scope = from->getDataRef()->scope; auto scope = from->getDataRef()->scope;
for (auto i : scope) for (auto i : scope)
for (auto j : i.second) for (auto j : i.second)
if (j == node) if (j == node)
return true; return true;
auto upper = scope.find("~enclosing_scope"); auto upper = scope.find("~enclosing_scope");
if (upper != scope.end()) if (upper != scope.end())
return isUnderTranslationUnit(upper->second[0], node); return isUnderTranslationUnit(upper->second[0], node);
return false; return false;
} }
NodeTree<ASTData>* CGenerator::highestScope(NodeTree<ASTData>* node) { NodeTree<ASTData>* CGenerator::highestScope(NodeTree<ASTData>* node) {
auto it = node->getDataRef()->scope.find("~enclosing_scope"); auto it = node->getDataRef()->scope.find("~enclosing_scope");
while (it != node->getDataRef()->scope.end()) { while (it != node->getDataRef()->scope.end()) {
node = it->second[0]; node = it->second[0];
it = node->getDataRef()->scope.find("~enclosing_scope"); it = node->getDataRef()->scope.find("~enclosing_scope");
} }
return node; 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 // 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) { 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 // 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; std::string cOutput, hOutput;
// Ok, so we've got to do this in passes to preserve mututally recursive definitions. // 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;". // First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;".
// Also, other typedefs follow after their naming. // Also, other typedefs follow after their naming.
// Second Pass: All top level variable declarations // Second Pass: All top level variable declarations
// Third Pass: Define all actual structs of a class, in correct order (done with posets) // 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). // Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too).
// (this includes object methods) // (this includes object methods)
// Fifth Pass: Define all functions (including 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 // 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. // 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 importIncludes = "/**\n * Import Includes\n */\n\n";
std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\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 variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n";
std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n"; std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n";
std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n"; std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n";
std::string classStructs = "/**\n * Class Structs\n */\n\n"; std::string classStructs = "/**\n * Class Structs\n */\n\n";
std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n"; std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n";
std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n"; std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n";
// There also exists functionTypedefString which is a member variable that keeps // 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 // track of utility typedefs that allow our C type generation to be more sane
// it is emitted in the h file right before functionPrototypes // it is emitted in the h file right before functionPrototypes
Poset<NodeTree<ASTData>*> typedefPoset; Poset<NodeTree<ASTData>*> typedefPoset;
for (auto trans : ASTs) { for (auto trans : ASTs) {
auto children = trans.second->getChildren(); auto children = trans.second->getChildren();
for (int i = 0; i < children.size(); i++) { for (int i = 0; i < children.size(); i++) {
if (children[i]->getDataRef()->type == type_def) { if (children[i]->getDataRef()->type == type_def) {
@@ -210,15 +218,15 @@ for (auto trans : ASTs) {
typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. 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 //Now generate the typedef's in the correct, topological order
for (NodeTree<ASTData>* i : typedefPoset.getTopoSort()) for (NodeTree<ASTData>* i : typedefPoset.getTopoSort())
classStructs += generateTypeStruct(i) + "\n"; classStructs += generateTypeStruct(i) + "\n";
// Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations) // 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, everything in all of the import's scopes
// Also c passthrough // Also c passthrough
for (auto trans : ASTs) { for (auto trans : ASTs) {
// First go through and emit all the passthroughs, etc // First go through and emit all the passthroughs, etc
for (auto i : trans.second->getChildren()) { for (auto i : trans.second->getChildren()) {
if (i->getDataRef()->type == if_comp) if (i->getDataRef()->type == if_comp)
@@ -753,7 +761,7 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++)
nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType);
// Note that we only add scoping to the object, as this specifies our member function too // Note that we only add scoping to the object, as this specifies our member function too
/*HERE*/ return function_header + prefixIfNeeded(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) + ","; CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject, true, enclosingFunction) + ",";
//The comma lets the upper function call know we already started the param list //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 //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses

View File

@@ -199,7 +199,7 @@ std::string Type::toString(bool showTraits) {
if (is_reference) if (is_reference)
typeString = "ref " + typeString; typeString = "ref " + typeString;
for (int i = 0; i < indirection; i++) for (int i = 0; i < indirection; i++)
typeString = "*" + typeString; typeString += "*";
if (indirection < 0) if (indirection < 0)
typeString += "negative indirection: " + intToString(indirection); typeString += "negative indirection: " + intToString(indirection);
if (traits.size() && showTraits) { if (traits.size() && showTraits) {
@@ -240,6 +240,11 @@ Type Type::withIncreasedIndirection() {
newOne->increaseIndirection(); newOne->increaseIndirection();
return *newOne; return *newOne;
} }
Type *Type::withIncreasedIndirectionPtr() {
Type *newOne = clone();
newOne->increaseIndirection();
return newOne;
}
Type Type::withDecreasedIndirection() { Type Type::withDecreasedIndirection() {
Type *newOne = clone(); Type *newOne = clone();
newOne->decreaseIndirection(); newOne->decreaseIndirection();

View File

@@ -1,4 +1,4 @@
import io:* /*import io:**/
adt options { adt options {
option0, option0,
@@ -11,12 +11,13 @@ adt maybe_int {
} }
fun handle_possibility(it: maybe_int) { fun handle_possibility(it: maybe_int) {
if (it == maybe_int::no_int()) if (it == maybe_int::no_int()) {
println("no int") /*println("no int")*/
}
/*if (it == maybe_int::an_int) {*/ /*if (it == maybe_int::an_int) {*/
else { else {
print("an int: ") /*print("an int: ")*/
println(it.an_int) /*println(it.an_int)*/
} }
} }
@@ -32,10 +33,12 @@ fun can_pass(it: options): options {
fun main():int { fun main():int {
var it: options = can_pass(options::option0()) var it: options = can_pass(options::option0())
if (it == options::option0()) if (it == options::option0()) {
println("nope") /*println("nope")*/
if (it == options::option1()) }
println("option1") if (it == options::option1()) {
/*println("option1")*/
}
var possibility = give_maybe(false) var possibility = give_maybe(false)
handle_possibility(possibility) handle_possibility(possibility)