diff --git a/CMakeLists.txt b/CMakeLists.txt index 9898440..4cb94d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,11 +43,13 @@ add_executable( src/codegen.h src/identcheck.h src/parser.h + src/typeutils.h src/util.h src/ast.c src/codegen.c src/identcheck.c src/parser.c + src/typeutils.c src/util.c src/main.c # Generated code diff --git a/generic.w b/generic.w index eb25bd1..63247ee 100644 --- a/generic.w +++ b/generic.w @@ -1,6 +1,11 @@ struct Foo { + static Func2(u: U) : U { + return u; + } + static Func(t: T): T { - return t; + foo: T = t; + return Func2(foo); } } diff --git a/src/ast.c b/src/ast.c index a6809a6..e705b5b 100644 --- a/src/ast.c +++ b/src/ast.c @@ -43,6 +43,8 @@ const char *SyntaxKindString(SyntaxKind syntaxKind) return "GenericArgument"; case GenericArguments: return "GenericArguments"; + case GenericTypeNode: + return "GenericTypeNode"; case Identifier: return "Identifier"; case IfStatement: @@ -405,6 +407,14 @@ Node *MakeEmptyGenericArgumentsNode() return node; } +Node *MakeGenericTypeNode(char *name) +{ + Node *node = (Node *)malloc(sizeof(Node)); + node->syntaxKind = GenericTypeNode; + node->genericType.name = strdup(name); + return node; +} + Node *MakeFunctionCallExpressionNode( Node *identifierNode, Node *argumentSequenceNode) @@ -633,6 +643,10 @@ void PrintNode(Node *node, uint32_t tabCount) } return; + case GenericTypeNode: + printf("%s\n", node->genericType.name); + return; + case Identifier: if (node->typeTag == NULL) { @@ -763,6 +777,10 @@ TypeTag *MakeTypeTag(Node *node) tag = MakeTypeTag(node->allocExpression.type); break; + case GenericTypeNode: + tag->type = Generic; + tag->value.genericType = strdup(node->genericType.name); + default: fprintf( stderr, @@ -799,6 +817,16 @@ char *TypeTagToString(TypeTag *tag) return result; } case Custom: - return tag->value.customType; + { + char *result = malloc(sizeof(char) * (strlen(tag->value.customType) + 8)); + sprintf(result, "Custom<%s>", tag->value.customType); + return result; + } + case Generic: + { + char *result = malloc(sizeof(char) * (strlen(tag->value.customType) + 9)); + sprintf(result, "Generic<%s>", tag->value.customType); + return result; + } } } diff --git a/src/ast.h b/src/ast.h index a4b367c..eb3cc10 100644 --- a/src/ast.h +++ b/src/ast.h @@ -32,6 +32,7 @@ typedef enum FunctionSignatureArguments, GenericArgument, GenericArguments, + GenericTypeNode, Identifier, IfStatement, IfElseStatement, @@ -89,7 +90,8 @@ typedef struct TypeTag Unknown, Primitive, Reference, - Custom + Custom, + Generic } type; union { @@ -99,6 +101,8 @@ typedef struct TypeTag struct TypeTag *referenceType; /* Valid when type = Custom. */ char *customType; + /* Valid when type = Generic. */ + char *genericType; } value; } TypeTag; @@ -215,6 +219,11 @@ struct Node uint32_t count; } genericArguments; + struct + { + char *name; + } genericType; + struct { char *name; @@ -330,6 +339,7 @@ Node *MakeGenericArgumentNode(Node *identifierNode, Node *constraintNode); Node *MakeEmptyGenericArgumentsNode(); Node *StartGenericArgumentsNode(Node *genericArgumentNode); Node *AddGenericArgument(Node *genericArgumentsNode, Node *genericArgumentNode); +Node *MakeGenericTypeNode(char *name); Node *MakeStructDeclarationNode( Node *identifierNode, Node *declarationSequenceNode); diff --git a/src/main.c b/src/main.c index eda6895..cbb7e80 100644 --- a/src/main.c +++ b/src/main.c @@ -4,6 +4,7 @@ #include "codegen.h" #include "identcheck.h" #include "parser.h" +#include "typeutils.h" int main(int argc, char *argv[]) { @@ -87,9 +88,19 @@ int main(int argc, char *argv[]) { { IdNode *idTree = MakeIdTree(rootNode, NULL); + printf("\n"); PrintIdTree(idTree, /*tabCount=*/0); + + printf("\nConverting custom types in the ID-tree.\n"); + ConvertIdCustomsToGenerics(idTree); + printf("\n"); + PrintIdTree(idTree, /*tabCount=*/0); + + printf("\nConverting custom type nodes in the AST.\n"); + ConvertASTCustomsToGenerics(rootNode); printf("\n"); PrintNode(rootNode, /*tabCount=*/0); + } exitCode = Codegen(rootNode, optimizationLevel); } diff --git a/src/typeutils.c b/src/typeutils.c new file mode 100644 index 0000000..1f20be8 --- /dev/null +++ b/src/typeutils.c @@ -0,0 +1,202 @@ +#include "typeutils.h" + +#include +#include +#include + +void ConvertIdCustomsToGenerics(IdNode *node) { + uint32_t i; + switch(node->type) + { + case UnorderedScope: + case OrderedScope: + case Struct: + /* FIXME: This case will need to be modified to handle type parameters over structs. */ + for (i = 0; i < node->childCount; i += 1) { + ConvertIdCustomsToGenerics(node->children[i]); + } + return; + + case Variable: { + TypeTag *varType = node->typeTag; + if (varType->type == Custom) { + IdNode *x = LookupId(node->parent, node, varType->value.customType); + if (x != NULL && x->type == GenericType) { + varType->type = Generic; + } + } + return; + } + + case Function: { + TypeTag *funcType = node->typeTag; + if (funcType->type == Custom) { + /* For functions we have to handle the type lookup manually since the generic type + * identifiers are declared as children of the function's IdNode. */ + for (i = 0; i < node->childCount; i += 1) { + IdNode *child = node->children[i]; + if (child->type == GenericType && strcmp(child->name, funcType->value.customType) == 0) { + funcType->type = Generic; + } + } + } + + for (i = 0; i < node->childCount; i += 1) { + ConvertIdCustomsToGenerics(node->children[i]); + } + return; + } + } +} + +void ConvertASTCustomsToGenerics(Node *node) { + uint32_t i; + switch (node->syntaxKind) { + case AccessExpression: + ConvertASTCustomsToGenerics(node->accessExpression.accessee); + ConvertASTCustomsToGenerics(node->accessExpression.accessor); + return; + + case AllocExpression: + ConvertASTCustomsToGenerics(node->allocExpression.type); + return; + + case Assignment: + ConvertASTCustomsToGenerics(node->assignmentStatement.left); + ConvertASTCustomsToGenerics(node->assignmentStatement.right); + return; + + case BinaryExpression: + ConvertASTCustomsToGenerics(node->binaryExpression.left); + ConvertASTCustomsToGenerics(node->binaryExpression.right); + return; + + case Comment: + return; + + case CustomTypeNode: + return; + + case Declaration: { + Node *type = node->declaration.type->type.typeNode; + Node *id = node->declaration.identifier; + if (id->typeTag->type == Generic && type->syntaxKind == CustomTypeNode) { + free(node->declaration.type); + node->declaration.type = MakeGenericTypeNode(id->typeTag->value.genericType); + } + return; + } + + case DeclarationSequence: + for (i = 0; i < node->declarationSequence.count; i += 1) { + ConvertASTCustomsToGenerics(node->declarationSequence.sequence[i]); + } + return; + + case ForLoop: + ConvertASTCustomsToGenerics(node->forLoop.declaration); + ConvertASTCustomsToGenerics(node->forLoop.startNumber); + ConvertASTCustomsToGenerics(node->forLoop.endNumber); + ConvertASTCustomsToGenerics(node->forLoop.statementSequence); + return; + + case FunctionArgumentSequence: + for (i = 0; i < node->functionArgumentSequence.count; i += 1) { + ConvertASTCustomsToGenerics(node->functionArgumentSequence.sequence[i]); + } + return; + + case FunctionCallExpression: + ConvertASTCustomsToGenerics(node->functionCallExpression.identifier); + ConvertASTCustomsToGenerics(node->functionCallExpression.argumentSequence); + return; + + case FunctionDeclaration: + ConvertASTCustomsToGenerics(node->functionDeclaration.functionSignature); + ConvertASTCustomsToGenerics(node->functionDeclaration.functionBody); + return; + + case FunctionModifiers: + return; + + case FunctionSignature:{ + Node *id = node->functionSignature.identifier; + Node *type = node->functionSignature.type; + if (id->typeTag->type == Generic && type->syntaxKind == CustomTypeNode) { + free(node->functionSignature.type); + node->functionSignature.type = MakeGenericTypeNode(id->typeTag->value.genericType); + } + ConvertASTCustomsToGenerics(node->functionSignature.arguments); + return; + } + + case FunctionSignatureArguments: + for (i = 0; i < node->functionSignatureArguments.count; i += 1) { + ConvertASTCustomsToGenerics(node->functionSignatureArguments.sequence[i]); + } + return; + + case GenericArgument: + return; + + case GenericArguments: + return; + + case GenericTypeNode: + return; + + case Identifier: + return; + + case IfStatement: + ConvertASTCustomsToGenerics(node->ifStatement.expression); + ConvertASTCustomsToGenerics(node->ifStatement.statementSequence); + return; + + case IfElseStatement: + ConvertASTCustomsToGenerics(node->ifElseStatement.ifStatement); + ConvertASTCustomsToGenerics(node->ifElseStatement.elseStatement); + return; + + case Number: + return; + + case PrimitiveTypeNode: + return; + + case ReferenceTypeNode: + return; + + case Return: + ConvertASTCustomsToGenerics(node->returnStatement.expression); + return; + + case ReturnVoid: + return; + + case StatementSequence: + for (i = 0; i < node->statementSequence.count; i += 1) { + ConvertASTCustomsToGenerics(node->statementSequence.sequence[i]); + } + return; + + case StaticModifier: + return; + + case StringLiteral: + return; + + case StructDeclaration: + /* FIXME: This case will need to be modified to handle type parameters over structs. */ + ConvertASTCustomsToGenerics(node->structDeclaration.identifier); + ConvertASTCustomsToGenerics(node->structDeclaration.declarationSequence); + return; + + case Type: + return; + + case UnaryExpression: + ConvertASTCustomsToGenerics(node->unaryExpression.child); + return; + } +} diff --git a/src/typeutils.h b/src/typeutils.h new file mode 100644 index 0000000..2e752e0 --- /dev/null +++ b/src/typeutils.h @@ -0,0 +1,13 @@ +/* Helper functions for working with types in the AST and ID-tree. */ + +#ifndef WRAITH_TYPEUTILS_H +#define WRAITH_TYPEUTILS_H + +#include "ast.h" +#include "identcheck.h" + +/* FIXME: These two functions will need to be modified to handle type parameters over structs. */ +void ConvertIdCustomsToGenerics(IdNode *node); +void ConvertASTCustomsToGenerics(Node *node); + +#endif /* WRAITH_TYPEUTILS_H */