generics_retry #4

Merged
cosmonaut merged 3 commits from venko/wraith-lang:generics_retry into generics_retry 2021-05-25 19:13:27 +00:00
8 changed files with 306 additions and 3 deletions

View File

@ -43,11 +43,13 @@ add_executable(
src/codegen.h src/codegen.h
src/identcheck.h src/identcheck.h
src/parser.h src/parser.h
src/typeutils.h
src/util.h src/util.h
src/ast.c src/ast.c
src/codegen.c src/codegen.c
src/identcheck.c src/identcheck.c
src/parser.c src/parser.c
src/typeutils.c
src/util.c src/util.c
src/main.c src/main.c
# Generated code # Generated code

18
generic.w Normal file
View File

@ -0,0 +1,18 @@
struct Foo {
static Func2<U>(u: U) : U {
return u;
}
static Func<T>(t: T): T {
foo: T = t;
return Func2(foo);
}
}
struct Program {
static main(): int {
x: int = 4;
y: int = Foo.Func(x);
return x;
}
}

View File

@ -39,6 +39,12 @@ const char *SyntaxKindString(SyntaxKind syntaxKind)
return "FunctionSignature"; return "FunctionSignature";
case FunctionSignatureArguments: case FunctionSignatureArguments:
return "FunctionSignatureArguments"; return "FunctionSignatureArguments";
case GenericArgument:
return "GenericArgument";
case GenericArguments:
return "GenericArguments";
case GenericTypeNode:
return "GenericTypeNode";
case Identifier: case Identifier:
return "Identifier"; return "Identifier";
case IfStatement: case IfStatement:
@ -401,6 +407,14 @@ Node *MakeEmptyGenericArgumentsNode()
return node; 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 *MakeFunctionCallExpressionNode(
Node *identifierNode, Node *identifierNode,
Node *argumentSequenceNode) Node *argumentSequenceNode)
@ -599,6 +613,7 @@ void PrintNode(Node *node, uint32_t tabCount)
case FunctionSignature: case FunctionSignature:
printf("\n"); printf("\n");
PrintNode(node->functionSignature.identifier, tabCount + 1); PrintNode(node->functionSignature.identifier, tabCount + 1);
PrintNode(node->functionSignature.genericArguments, tabCount + 1);
PrintNode(node->functionSignature.arguments, tabCount + 1); PrintNode(node->functionSignature.arguments, tabCount + 1);
PrintNode(node->functionSignature.type, tabCount + 1); PrintNode(node->functionSignature.type, tabCount + 1);
PrintNode(node->functionSignature.modifiers, tabCount + 1); PrintNode(node->functionSignature.modifiers, tabCount + 1);
@ -614,6 +629,24 @@ void PrintNode(Node *node, uint32_t tabCount)
} }
return; return;
case GenericArgument:
printf("\n");
PrintNode(node->genericArgument.identifier, tabCount + 1);
/* Constraint nodes are not implemented. */
/* PrintNode(node->genericArgument.constraint, tabCount + 1); */
return;
case GenericArguments:
printf("\n");
for (i = 0; i < node->genericArguments.count; i += 1) {
PrintNode(node->genericArguments.arguments[i], tabCount + 1);
}
return;
case GenericTypeNode:
printf("%s\n", node->genericType.name);
return;
case Identifier: case Identifier:
if (node->typeTag == NULL) if (node->typeTag == NULL)
{ {
@ -744,6 +777,10 @@ TypeTag *MakeTypeTag(Node *node)
tag = MakeTypeTag(node->allocExpression.type); tag = MakeTypeTag(node->allocExpression.type);
break; break;
case GenericTypeNode:
tag->type = Generic;
tag->value.genericType = strdup(node->genericType.name);
default: default:
fprintf( fprintf(
stderr, stderr,
@ -780,6 +817,16 @@ char *TypeTagToString(TypeTag *tag)
return result; return result;
} }
case Custom: 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;
}
} }
} }

View File

@ -32,6 +32,7 @@ typedef enum
FunctionSignatureArguments, FunctionSignatureArguments,
GenericArgument, GenericArgument,
GenericArguments, GenericArguments,
GenericTypeNode,
Identifier, Identifier,
IfStatement, IfStatement,
IfElseStatement, IfElseStatement,
@ -89,7 +90,8 @@ typedef struct TypeTag
Unknown, Unknown,
Primitive, Primitive,
Reference, Reference,
Custom Custom,
Generic
} type; } type;
union union
{ {
@ -99,6 +101,8 @@ typedef struct TypeTag
struct TypeTag *referenceType; struct TypeTag *referenceType;
/* Valid when type = Custom. */ /* Valid when type = Custom. */
char *customType; char *customType;
/* Valid when type = Generic. */
char *genericType;
} value; } value;
} TypeTag; } TypeTag;
@ -215,6 +219,11 @@ struct Node
uint32_t count; uint32_t count;
} genericArguments; } genericArguments;
struct
{
char *name;
} genericType;
struct struct
{ {
char *name; char *name;
@ -330,6 +339,7 @@ Node *MakeGenericArgumentNode(Node *identifierNode, Node *constraintNode);
Node *MakeEmptyGenericArgumentsNode(); Node *MakeEmptyGenericArgumentsNode();
Node *StartGenericArgumentsNode(Node *genericArgumentNode); Node *StartGenericArgumentsNode(Node *genericArgumentNode);
Node *AddGenericArgument(Node *genericArgumentsNode, Node *genericArgumentNode); Node *AddGenericArgument(Node *genericArgumentsNode, Node *genericArgumentNode);
Node *MakeGenericTypeNode(char *name);
Node *MakeStructDeclarationNode( Node *MakeStructDeclarationNode(
Node *identifierNode, Node *identifierNode,
Node *declarationSequenceNode); Node *declarationSequenceNode);

View File

@ -150,9 +150,9 @@ IdNode *MakeIdTree(Node *astNode, IdNode *parent)
mainNode = MakeIdNode(Function, funcName, parent); mainNode = MakeIdNode(Function, funcName, parent);
mainNode->typeTag = MakeTypeTag(astNode); mainNode->typeTag = MakeTypeTag(astNode);
idNode->typeTag = mainNode->typeTag; idNode->typeTag = mainNode->typeTag;
MakeIdTree(sigNode->functionSignature.genericArguments, mainNode);
MakeIdTree(sigNode->functionSignature.arguments, mainNode); MakeIdTree(sigNode->functionSignature.arguments, mainNode);
MakeIdTree(astNode->functionDeclaration.functionBody, mainNode); MakeIdTree(astNode->functionDeclaration.functionBody, mainNode);
MakeIdTree(sigNode->functionSignature.genericArguments, mainNode);
break; break;
} }

View File

@ -4,6 +4,7 @@
#include "codegen.h" #include "codegen.h"
#include "identcheck.h" #include "identcheck.h"
#include "parser.h" #include "parser.h"
#include "typeutils.h"
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
@ -87,9 +88,19 @@ int main(int argc, char *argv[])
{ {
{ {
IdNode *idTree = MakeIdTree(rootNode, NULL); IdNode *idTree = MakeIdTree(rootNode, NULL);
printf("\n");
PrintIdTree(idTree, /*tabCount=*/0); 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"); printf("\n");
PrintNode(rootNode, /*tabCount=*/0); PrintNode(rootNode, /*tabCount=*/0);
} }
exitCode = Codegen(rootNode, optimizationLevel); exitCode = Codegen(rootNode, optimizationLevel);
} }

202
src/typeutils.c Normal file
View File

@ -0,0 +1,202 @@
#include "typeutils.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
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;
}
}

13
src/typeutils.h Normal file
View File

@ -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 */