diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cb94d8..1b7a9e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,15 +41,13 @@ add_executable( # Source src/ast.h src/codegen.h - src/identcheck.h src/parser.h - src/typeutils.h + src/validation.h src/util.h src/ast.c src/codegen.c - src/identcheck.c src/parser.c - src/typeutils.c + src/validation.c src/util.c src/main.c # Generated code diff --git a/access.w b/access.w new file mode 100644 index 0000000..2534dd2 --- /dev/null +++ b/access.w @@ -0,0 +1,13 @@ +struct G { + Foo(t: bool): bool { + return t; + } +} + +struct Program { + static main(): int { + g: G = alloc G; + g.Foo(true); + return 0; + } +} \ No newline at end of file diff --git a/ordering.w b/ordering.w new file mode 100644 index 0000000..f446a68 --- /dev/null +++ b/ordering.w @@ -0,0 +1,15 @@ +struct Foo { + static Func(): void { + Func2(); + } + + static Func2(): void { + Func(); + } +} + +struct Program { + static main(): int { + return 0; + } +} \ No newline at end of file diff --git a/src/ast.c b/src/ast.c index 6252788..d57ef1f 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1,6 +1,5 @@ #include "ast.h" -#include #include #include @@ -1185,321 +1184,3 @@ void LinkParentPointers(Node *node, Node *prev) return; } } - -Node *GetIdFromStruct(Node *structDecl) -{ - if (structDecl->syntaxKind != StructDeclaration) - { - fprintf( - stderr, - "wraith: Attempted to call GetIdFromStruct on node with kind: " - "%s.\n", - SyntaxKindString(structDecl->syntaxKind)); - return NULL; - } - - return structDecl->structDeclaration.identifier; -} - -Node *GetIdFromFunction(Node *funcDecl) -{ - if (funcDecl->syntaxKind != FunctionDeclaration) - { - fprintf( - stderr, - "wraith: Attempted to call GetIdFromFunction on node with kind: " - "%s.\n", - SyntaxKindString(funcDecl->syntaxKind)); - return NULL; - } - - Node *sig = funcDecl->functionDeclaration.functionSignature; - return sig->functionSignature.identifier; -} - -Node *GetIdFromDeclaration(Node *decl) -{ - if (decl->syntaxKind != Declaration) - { - fprintf( - stderr, - "wraith: Attempted to call GetIdFromDeclaration on node with kind: " - "%s.\n", - SyntaxKindString(decl->syntaxKind)); - } - - return decl->declaration.identifier; -} - -bool AssignmentHasDeclaration(Node *assign) -{ - return ( - assign->syntaxKind == Assignment && - assign->assignmentStatement.left->syntaxKind == Declaration); -} - -Node *GetIdFromAssignment(Node *assign) -{ - if (assign->syntaxKind != Assignment) - { - fprintf( - stderr, - "wraith: Attempted to call GetIdFromAssignment on node with kind: " - "%s.\n", - SyntaxKindString(assign->syntaxKind)); - } - - if (AssignmentHasDeclaration(assign)) - { - return GetIdFromDeclaration(assign->assignmentStatement.left); - } - - return NULL; -} - -bool NodeMayHaveId(Node *node) -{ - switch (node->syntaxKind) - { - case StructDeclaration: - case FunctionDeclaration: - case Declaration: - case Assignment: - return true; - default: - return false; - } -} - -Node *TryGetId(Node *node) -{ - switch (node->syntaxKind) - { - case Assignment: - return GetIdFromAssignment(node); - case Declaration: - return GetIdFromDeclaration(node); - case FunctionDeclaration: - return GetIdFromFunction(node); - case StructDeclaration: - return GetIdFromStruct(node); - default: - return NULL; - } -} - -Node *LookupFunctionArgId(Node *funcDecl, char *target) -{ - Node *args = funcDecl->functionDeclaration.functionSignature - ->functionSignature.arguments; - - uint32_t i; - for (i = 0; i < args->functionArgumentSequence.count; i += 1) - { - Node *arg = args->functionArgumentSequence.sequence[i]; - if (arg->syntaxKind != Declaration) - { - fprintf( - stderr, - "wraith: Encountered %s node in function signature args " - "list.\n", - SyntaxKindString(arg->syntaxKind)); - continue; - } - - Node *argId = GetIdFromDeclaration(arg); - if (argId != NULL && strcmp(target, argId->identifier.name) == 0) - { - return argId; - } - } - - return NULL; -} - -Node *LookupStructInternalId(Node *structDecl, char *target) -{ - Node *decls = structDecl->structDeclaration.declarationSequence; - - uint32_t i; - for (i = 0; i < decls->declarationSequence.count; i += 1) - { - Node *match = TryGetId(decls->declarationSequence.sequence[i]); - if (match != NULL && strcmp(target, match->identifier.name) == 0) - return match; - } - - return NULL; -} - -Node *InspectNode(Node *node, char *target) -{ - /* If this node may have an identifier declaration inside it, attempt to - * look up the identifier - * node itself, returning it if it matches the given target name. */ - if (NodeMayHaveId(node)) - { - Node *candidateId = TryGetId(node); - if (candidateId != NULL && - strcmp(target, candidateId->identifier.name) == 0) - { - return candidateId; - } - } - - /* If the candidate node was not the one we wanted, but the node node is a - * function declaration, it's possible that the identifier we want is one of - * the function's parameters rather than the function's name itself. */ - if (node->syntaxKind == FunctionDeclaration) - { - Node *match = LookupFunctionArgId(node, target); - if (match != NULL) - return match; - } - - /* Likewise if the node node is a struct declaration, inspect the struct's - * internals - * to see if a top-level definition is the one we're looking for. */ - if (node->syntaxKind == StructDeclaration) - { - Node *match = LookupStructInternalId(node, target); - if (match != NULL) - return match; - } - - return NULL; -} - -Node *LookupIdNode(Node *current, Node *prev, char *target) -{ - if (current == NULL) - return NULL; - Node *match; - - /* First inspect the current node to see if it contains the target - * identifier. */ - match = InspectNode(current, target); - if (match != NULL) - return match; - - /* If this is the start of our search, we should not attempt to look at - * child nodes. Only looking up the AST is valid at this point. - * - * This has the notable side-effect that this function will return NULL if - * you attempt to look up a struct's internals starting from the node - * representing the struct itself. The same is true for functions. */ - if (prev == NULL) - { - return LookupIdNode(current->parent, current, target); - } - - uint32_t i; - uint32_t idxLimit; - switch (current->syntaxKind) - { - case DeclarationSequence: - for (i = 0; i < current->declarationSequence.count; i += 1) - { - Node *decl = current->declarationSequence.sequence[i]; - match = InspectNode(decl, target); - if (match != NULL) - return match; - /*Node *declId = TryGetId(decl); - if (declId != NULL && strcmp(target, declId->identifier.name) == 0) - return declId;*/ - } - break; - case StatementSequence: - idxLimit = current->statementSequence.count; - for (i = 0; i < current->statementSequence.count; i += 1) - { - if (current->statementSequence.sequence[i] == prev) - { - idxLimit = i; - break; - } - } - - for (i = 0; i < idxLimit; i += 1) - { - Node *stmt = current->statementSequence.sequence[i]; - if (stmt == prev) - continue; - - if (strcmp(target, "g") == 0) - { - printf("info: %s\n", SyntaxKindString(stmt->syntaxKind)); - } - - match = InspectNode(stmt, target); - if (match != NULL) - return match; - /*if (NodeMayHaveId(stmt)) - { - Node *candidateId = TryGetId(current); - if (candidateId != NULL && strcmp(target, - candidateId->identifier.name) == 0) return candidateId; - }*/ - } - break; - } - - return LookupIdNode(current->parent, current, target); -} - -void IdentifierPass(Node *node) -{ - if (node == NULL) - return; - - switch (node->syntaxKind) - { - case AllocExpression: - node->typeTag = MakeTypeTag(node); - break; - - case Declaration: - node->declaration.identifier->typeTag = MakeTypeTag(node); - break; - - case FunctionDeclaration: - node->functionDeclaration.functionSignature->functionSignature - .identifier->typeTag = MakeTypeTag(node); - break; - - case StructDeclaration: - node->structDeclaration.identifier->typeTag = MakeTypeTag(node); - break; - - case GenericArgument: - node->genericArgument.identifier->typeTag = MakeTypeTag(node); - break; - - case Identifier: - { - if (node->typeTag != NULL) - return; - - char *name = node->identifier.name; - Node *declaration = LookupIdNode(node, NULL, name); - if (declaration == NULL) - { - /* FIXME: Express this case as an error with AST information. */ - fprintf( - stderr, - "wraith: Could not find definition of identifier %s.\n", - name); - TypeTag *tag = (TypeTag *)malloc(sizeof(TypeTag)); - tag->type = Unknown; - node->typeTag = tag; - } - else - { - node->typeTag = declaration->typeTag; - } - break; - } - } - - Recurse(node, *IdentifierPass); -} \ No newline at end of file diff --git a/src/ast.h b/src/ast.h index 179d0e6..3d36cf6 100644 --- a/src/ast.h +++ b/src/ast.h @@ -1,7 +1,6 @@ #ifndef WRAITH_AST_H #define WRAITH_AST_H -#include "identcheck.h" #include /* -Wpedantic nameless union/struct silencing */ @@ -300,7 +299,6 @@ struct Node } unaryExpression; }; TypeTag *typeTag; - IdNode *idLink; }; const char *SyntaxKindString(SyntaxKind syntaxKind); @@ -381,5 +379,4 @@ char *TypeTagToString(TypeTag *tag); Node *LookupIdNode(Node *current, Node *prev, char *target); -void IdentifierPass(Node *node); #endif /* WRAITH_AST_H */ diff --git a/src/identcheck.c b/src/identcheck.c deleted file mode 100644 index 39498b0..0000000 --- a/src/identcheck.c +++ /dev/null @@ -1,507 +0,0 @@ -#include -#include -#include -#include -#include - -#include "ast.h" -#include "identcheck.h" - -IdNode *MakeIdNode(NodeType type, char *name, IdNode *parent) -{ - IdNode *node = (IdNode *)malloc(sizeof(IdNode)); - node->type = type; - node->name = strdup(name); - node->parent = parent; - node->childCount = 0; - node->childCapacity = 0; - node->children = NULL; - node->typeTag = NULL; - return node; -} - -void AddChildToNode(IdNode *node, IdNode *child) -{ - if (child == NULL) - return; - - if (node->children == NULL) - { - node->childCapacity = 2; - node->children = - (IdNode **)malloc(sizeof(IdNode *) * node->childCapacity); - } - else if (node->childCount == node->childCapacity) - { - node->childCapacity *= 2; - node->children = (IdNode **)realloc( - node->children, - sizeof(IdNode *) * node->childCapacity); - } - - node->children[node->childCount] = child; - node->childCount += 1; -} - -IdNode *MakeIdTree(Node *astNode, IdNode *parent) -{ - uint32_t i; - IdNode *mainNode; - switch (astNode->syntaxKind) - { - case AccessExpression: - AddChildToNode( - parent, - MakeIdTree(astNode->accessExpression.accessee, parent)); - AddChildToNode( - parent, - MakeIdTree(astNode->accessExpression.accessor, parent)); - return NULL; - - case AllocExpression: - astNode->typeTag = MakeTypeTag(astNode); - return NULL; - - case Assignment: - { - if (astNode->assignmentStatement.left->syntaxKind == Declaration) - { - return MakeIdTree(astNode->assignmentStatement.left, parent); - } - else - { - AddChildToNode( - parent, - MakeIdTree(astNode->assignmentStatement.left, parent)); - AddChildToNode( - parent, - MakeIdTree(astNode->assignmentStatement.right, parent)); - return NULL; - } - } - - case BinaryExpression: - AddChildToNode( - parent, - MakeIdTree(astNode->binaryExpression.left, parent)); - AddChildToNode( - parent, - MakeIdTree(astNode->binaryExpression.right, parent)); - return NULL; - - case Declaration: - { - Node *idNode = astNode->declaration.identifier; - mainNode = MakeIdNode(Variable, idNode->identifier.name, parent); - mainNode->typeTag = MakeTypeTag(astNode); - idNode->typeTag = mainNode->typeTag; - break; - } - - case DeclarationSequence: - { - mainNode = MakeIdNode(UnorderedScope, "", parent); - for (i = 0; i < astNode->declarationSequence.count; i++) - { - AddChildToNode( - mainNode, - MakeIdTree(astNode->declarationSequence.sequence[i], mainNode)); - } - break; - } - - case ForLoop: - { - Node *loopDecl = astNode->forLoop.declaration; - Node *loopBody = astNode->forLoop.statementSequence; - mainNode = MakeIdNode(OrderedScope, "for-loop", parent); - AddChildToNode(mainNode, MakeIdTree(loopDecl, mainNode)); - AddChildToNode(mainNode, MakeIdTree(loopBody, mainNode)); - break; - } - - case FunctionArgumentSequence: - for (i = 0; i < astNode->functionArgumentSequence.count; i++) - { - AddChildToNode( - parent, - MakeIdTree( - astNode->functionArgumentSequence.sequence[i], - parent)); - } - return NULL; - - case FunctionCallExpression: - AddChildToNode( - parent, - MakeIdTree(astNode->functionCallExpression.identifier, parent)); - AddChildToNode( - parent, - MakeIdTree( - astNode->functionCallExpression.argumentSequence, - parent)); - return NULL; - - case FunctionDeclaration: - { - Node *sigNode = astNode->functionDeclaration.functionSignature; - Node *idNode = sigNode->functionSignature.identifier; - char *funcName = idNode->identifier.name; - mainNode = MakeIdNode(Function, funcName, parent); - mainNode->typeTag = MakeTypeTag(astNode); - idNode->typeTag = mainNode->typeTag; - MakeIdTree(sigNode->functionSignature.genericArguments, mainNode); - MakeIdTree(sigNode->functionSignature.arguments, mainNode); - MakeIdTree(astNode->functionDeclaration.functionBody, mainNode); - break; - } - - case FunctionSignatureArguments: - { - for (i = 0; i < astNode->functionSignatureArguments.count; i++) - { - Node *argNode = astNode->functionSignatureArguments.sequence[i]; - AddChildToNode(parent, MakeIdTree(argNode, parent)); - } - return NULL; - } - - case GenericArgument: - { - char *name = astNode->genericArgument.identifier->identifier.name; - mainNode = MakeIdNode(GenericType, name, parent); - break; - } - - case GenericArguments: - { - for (i = 0; i < astNode->genericArguments.count; i += 1) - { - Node *argNode = astNode->genericArguments.arguments[i]; - AddChildToNode(parent, MakeIdTree(argNode, parent)); - } - return NULL; - } - - case Identifier: - { - char *name = astNode->identifier.name; - mainNode = MakeIdNode(Placeholder, name, parent); - Node *lookupNode = LookupIdNode(astNode, NULL, name); - if (lookupNode == NULL) - { - fprintf(stderr, "wraith: Could not find IdNode for id %s\n", name); - TypeTag *tag = (TypeTag *)malloc(sizeof(TypeTag)); - tag->type = Unknown; - astNode->typeTag = tag; - } - else - { - astNode->typeTag = lookupNode->typeTag; - } - break; - } - - case IfStatement: - { - Node *clause = astNode->ifStatement.expression; - Node *stmtSeq = astNode->ifStatement.statementSequence; - mainNode = MakeIdNode(OrderedScope, "if", parent); - MakeIdTree(clause, mainNode); - MakeIdTree(stmtSeq, mainNode); - break; - } - - case IfElseStatement: - { - Node *ifNode = astNode->ifElseStatement.ifStatement; - Node *elseStmts = astNode->ifElseStatement.elseStatement; - mainNode = MakeIdNode(OrderedScope, "if-else", parent); - IdNode *ifBranch = MakeIdTree(ifNode, mainNode); - AddChildToNode(mainNode, ifBranch); - IdNode *elseScope = MakeIdNode(OrderedScope, "else", mainNode); - MakeIdTree(elseStmts, elseScope); - AddChildToNode(mainNode, elseScope); - break; - } - - case ReferenceTypeNode: - AddChildToNode(parent, MakeIdTree(astNode->referenceType.type, parent)); - return NULL; - - case Return: - AddChildToNode( - parent, - MakeIdTree(astNode->returnStatement.expression, parent)); - return NULL; - - case StatementSequence: - { - for (i = 0; i < astNode->statementSequence.count; i++) - { - Node *argNode = astNode->statementSequence.sequence[i]; - AddChildToNode(parent, MakeIdTree(argNode, parent)); - } - return NULL; - } - - case StructDeclaration: - { - Node *idNode = astNode->structDeclaration.identifier; - Node *declsNode = astNode->structDeclaration.declarationSequence; - mainNode = MakeIdNode(Struct, idNode->identifier.name, parent); - mainNode->typeTag = MakeTypeTag(astNode); - for (i = 0; i < declsNode->declarationSequence.count; i++) - { - Node *decl = declsNode->declarationSequence.sequence[i]; - AddChildToNode(mainNode, MakeIdTree(decl, mainNode)); - } - break; - } - - case Type: - AddChildToNode(parent, MakeIdTree(astNode->type.typeNode, parent)); - return NULL; - - case UnaryExpression: - AddChildToNode( - parent, - MakeIdTree(astNode->unaryExpression.child, parent)); - return NULL; - - case Comment: - case CustomTypeNode: - case FunctionModifiers: - case FunctionSignature: - case Number: - case PrimitiveTypeNode: - case ReturnVoid: - case StaticModifier: - case StringLiteral: - return NULL; - } - - astNode->idLink = mainNode; - return mainNode; -} - -void PrintIdNode(IdNode *node) -{ - if (node == NULL) - { - fprintf( - stderr, - "wraith: Attempted to call PrintIdNode with null value.\n"); - return; - } - - switch (node->type) - { - case Placeholder: - printf("Placeholder (%s)\n", node->name); - break; - case OrderedScope: - printf("OrderedScope (%s)\n", node->name); - break; - case UnorderedScope: - printf("UnorderedScope (%s)\n", node->name); - break; - case Struct: - printf("%s : %s\n", node->name, TypeTagToString(node->typeTag)); - break; - case Function: - printf( - "%s : Function<%s>\n", - node->name, - TypeTagToString(node->typeTag)); - break; - case Variable: - printf("%s : %s\n", node->name, TypeTagToString(node->typeTag)); - break; - case GenericType: - printf("Generic type: %s\n", node->name); - break; - case Alloc: - printf("Alloc: %s\n", TypeTagToString(node->typeTag)); - break; - } -} - -void PrintIdTree(IdNode *tree, uint32_t tabCount) -{ - if (tree == NULL) - { - fprintf( - stderr, - "wraith: Attempted to call PrintIdTree on a null value.\n"); - return; - } - - uint32_t i; - for (i = 0; i < tabCount; i++) - { - printf("| "); - } - - PrintIdNode(tree); - - for (i = 0; i < tree->childCount; i++) - { - PrintIdTree(tree->children[i], tabCount + 1); - } -} - -int PrintAncestors(IdNode *node) -{ - if (node == NULL) - return -1; - - int i; - int indent = 1; - indent += PrintAncestors(node->parent); - for (i = 0; i < indent; i++) - { - printf(" "); - } - PrintIdNode(node); - return indent; -} - -IdNode *LookdownId(IdNode *root, NodeType targetType, char *targetName) -{ - if (root == NULL) - { - fprintf( - stderr, - "wraith: Attempted to call LookdownId on a null value.\n"); - return NULL; - } - - IdNode *result = NULL; - IdNode **frontier = (IdNode **)malloc(sizeof(IdNode *)); - frontier[0] = root; - uint32_t frontierCount = 1; - - while (frontierCount > 0) - { - IdNode *current = frontier[0]; - - if (current->type == targetType && - strcmp(current->name, targetName) == 0) - { - result = current; - break; - } - - uint32_t i; - for (i = 1; i < frontierCount; i++) - { - frontier[i - 1] = frontier[i]; - } - size_t newSize = frontierCount + current->childCount - 1; - if (frontierCount != newSize) - { - frontier = (IdNode **)realloc(frontier, sizeof(IdNode *) * newSize); - } - for (i = 0; i < current->childCount; i++) - { - frontier[frontierCount + i - 1] = current->children[i]; - } - frontierCount = newSize; - } - - free(frontier); - return result; -} - -bool ScopeHasOrdering(IdNode *node) -{ - switch (node->type) - { - case OrderedScope: - case Function: - case Variable: /* this is only technically true */ - return true; - default: - return false; - } -} - -IdNode *LookupId(IdNode *node, IdNode *prev, char *target) -{ - if (node == NULL) - { - return NULL; - } - - if (strcmp(node->name, target) == 0 && node->type != Placeholder) - { - return node; - } - - /* If this is the start of our search, we should not attempt to look at - * child nodes. Only looking up the scope tree is valid at this point. - * - * This has the notable side-effect that this function will return NULL if - * you attempt to look up a struct's internals starting from the node - * representing the struct itself. This is because an IdNode corresponds to - * the location *where an identifier is first declared.* Thus, an identifier - * has no knowledge of identifiers declared "inside" of it. - */ - if (prev == NULL) - { - return LookupId(node->parent, node, target); - } - - /* If the current node forms an ordered scope then we want to prevent - * ourselves from looking up identifiers declared after the scope we have - * just come from. - */ - uint32_t idxLimit; - if (ScopeHasOrdering(node)) - { - uint32_t i; - for (i = 0, idxLimit = 0; i < node->childCount; i++, idxLimit++) - { - if (node->children[i] == prev) - { - break; - } - } - } - else - { - idxLimit = node->childCount; - } - - uint32_t i; - for (i = 0; i < idxLimit; i++) - { - IdNode *child = node->children[i]; - if (child == prev || child->type == Placeholder) - { - /* Do not inspect the node we just came from or placeholders. */ - continue; - } - - if (strcmp(child->name, target) == 0) - { - return child; - } - - if (child->type == Struct) - { - uint32_t j; - for (j = 0; j < child->childCount; j++) - { - IdNode *grandchild = child->children[j]; - if (strcmp(grandchild->name, target) == 0) - { - return grandchild; - } - } - } - } - - return LookupId(node->parent, node, target); -} diff --git a/src/identcheck.h b/src/identcheck.h deleted file mode 100644 index 8b287dd..0000000 --- a/src/identcheck.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Validates identifier usage in an AST. */ - -#ifndef WRAITH_IDENTCHECK_H -#define WRAITH_IDENTCHECK_H - -#include - -#include "ast.h" - -struct TypeTag; -struct Node; - -typedef enum NodeType -{ - Placeholder, - UnorderedScope, - OrderedScope, - Struct, - Function, - Variable, - GenericType, - Alloc -} NodeType; - -typedef struct IdNode -{ - NodeType type; - char *name; - struct TypeTag *typeTag; - struct IdNode *parent; - struct IdNode **children; - uint32_t childCount; - uint32_t childCapacity; -} IdNode; - -typedef struct IdStatus -{ - enum StatusCode - { - Valid, - } StatusCode; -} IdStatus; - -IdNode *MakeIdTree(struct Node *astNode, IdNode *parent); -void PrintIdNode(IdNode *node); -void PrintIdTree(IdNode *tree, uint32_t tabCount); -int PrintAncestors(IdNode *node); -IdNode *LookdownId(IdNode *root, NodeType targetType, char *targetName); -IdNode *LookupId(IdNode *node, IdNode *prev, char *target); - -#endif /* WRAITH_IDENTCHECK_H */ diff --git a/src/main.c b/src/main.c index 1b7c70b..f3f8d36 100644 --- a/src/main.c +++ b/src/main.c @@ -2,9 +2,8 @@ #include #include "codegen.h" -#include "identcheck.h" #include "parser.h" -#include "typeutils.h" +#include "validation.h" int main(int argc, char *argv[]) { @@ -87,8 +86,11 @@ int main(int argc, char *argv[]) else { LinkParentPointers(rootNode, NULL); - IdentifierPass(rootNode); - /*ConvertASTCustomsToGenerics(rootNode);*/ + /* FIXME: ValidateIdentifiers should return some sort of + error status object. */ + ValidateIdentifiers(rootNode); + TagIdentifierTypes(rootNode); + ConvertCustomsToGenerics(rootNode); PrintNode(rootNode, 0); printf("Beginning codegen.\n"); diff --git a/src/typeutils.c b/src/typeutils.c deleted file mode 100644 index 4ebddea..0000000 --- a/src/typeutils.c +++ /dev/null @@ -1,82 +0,0 @@ -#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; - } - } -} - -/* FIXME: This function will need to be modified to handle type parameters over structs. */ -void ConvertASTCustomsToGenerics(Node *node) { - switch (node->syntaxKind) - { - 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 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; - } - - default: - Recurse(node, *ConvertASTCustomsToGenerics); - } -} diff --git a/src/typeutils.h b/src/typeutils.h deleted file mode 100644 index 2e752e0..0000000 --- a/src/typeutils.h +++ /dev/null @@ -1,13 +0,0 @@ -/* 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 */ diff --git a/src/validation.c b/src/validation.c new file mode 100644 index 0000000..e62c4dd --- /dev/null +++ b/src/validation.c @@ -0,0 +1,452 @@ +#include "validation.h" + +#include +#include +#include +#include + +Node *GetIdFromStruct(Node *structDecl) +{ + if (structDecl->syntaxKind != StructDeclaration) + { + fprintf( + stderr, + "wraith: Attempted to call GetIdFromStruct on node with kind: " + "%s.\n", + SyntaxKindString(structDecl->syntaxKind)); + return NULL; + } + + return structDecl->structDeclaration.identifier; +} + +Node *GetIdFromFunction(Node *funcDecl) +{ + if (funcDecl->syntaxKind != FunctionDeclaration) + { + fprintf( + stderr, + "wraith: Attempted to call GetIdFromFunction on node with kind: " + "%s.\n", + SyntaxKindString(funcDecl->syntaxKind)); + return NULL; + } + + Node *sig = funcDecl->functionDeclaration.functionSignature; + return sig->functionSignature.identifier; +} + +Node *GetIdFromDeclaration(Node *decl) +{ + if (decl->syntaxKind != Declaration) + { + fprintf( + stderr, + "wraith: Attempted to call GetIdFromDeclaration on node with kind: " + "%s.\n", + SyntaxKindString(decl->syntaxKind)); + } + + return decl->declaration.identifier; +} + +bool AssignmentHasDeclaration(Node *assign) +{ + return ( + assign->syntaxKind == Assignment && + assign->assignmentStatement.left->syntaxKind == Declaration); +} + +Node *GetIdFromAssignment(Node *assign) +{ + if (assign->syntaxKind != Assignment) + { + fprintf( + stderr, + "wraith: Attempted to call GetIdFromAssignment on node with kind: " + "%s.\n", + SyntaxKindString(assign->syntaxKind)); + } + + if (AssignmentHasDeclaration(assign)) + { + return GetIdFromDeclaration(assign->assignmentStatement.left); + } + + return NULL; +} + +bool NodeMayHaveId(Node *node) +{ + switch (node->syntaxKind) + { + case StructDeclaration: + case FunctionDeclaration: + case Declaration: + case Assignment: + return true; + default: + return false; + } +} + +Node *TryGetId(Node *node) +{ + switch (node->syntaxKind) + { + case Assignment: + return GetIdFromAssignment(node); + case Declaration: + return GetIdFromDeclaration(node); + case FunctionDeclaration: + return GetIdFromFunction(node); + case StructDeclaration: + return GetIdFromStruct(node); + default: + return NULL; + } +} + +Node *LookupFunctionArgId(Node *funcDecl, char *target) +{ + Node *args = funcDecl->functionDeclaration.functionSignature + ->functionSignature.arguments; + + uint32_t i; + for (i = 0; i < args->functionArgumentSequence.count; i += 1) + { + Node *arg = args->functionArgumentSequence.sequence[i]; + if (arg->syntaxKind != Declaration) + { + fprintf( + stderr, + "wraith: Encountered %s node in function signature args " + "list.\n", + SyntaxKindString(arg->syntaxKind)); + continue; + } + + Node *argId = GetIdFromDeclaration(arg); + if (argId != NULL && strcmp(target, argId->identifier.name) == 0) + return argId; + } + + return NULL; +} + +Node *LookupStructInternalId(Node *structDecl, char *target) +{ + Node *decls = structDecl->structDeclaration.declarationSequence; + + uint32_t i; + for (i = 0; i < decls->declarationSequence.count; i += 1) + { + Node *match = TryGetId(decls->declarationSequence.sequence[i]); + if (match != NULL && strcmp(target, match->identifier.name) == 0) + return match; + } + + return NULL; +} + +Node *InspectNode(Node *node, char *target) +{ + /* If this node may have an identifier declaration inside it, attempt to + * look up the identifier + * node itself, returning it if it matches the given target name. */ + if (NodeMayHaveId(node)) + { + Node *candidateId = TryGetId(node); + if (candidateId != NULL && + strcmp(target, candidateId->identifier.name) == 0) + return candidateId; + } + + /* If the candidate node was not the one we wanted, but the node node is a + * function declaration, it's possible that the identifier we want is one of + * the function's parameters rather than the function's name itself. */ + if (node->syntaxKind == FunctionDeclaration) + { + Node *match = LookupFunctionArgId(node, target); + if (match != NULL) + return match; + } + + /* Likewise if the node node is a struct declaration, inspect the struct's + * internals + * to see if a top-level definition is the one we're looking for. */ + if (node->syntaxKind == StructDeclaration) + { + Node *match = LookupStructInternalId(node, target); + if (match != NULL) + return match; + } + + return NULL; +} + +/* FIXME: Handle staged lookups for AccessExpressions. */ +/* FIXME: Similar to above, disallow inspection of struct internals outside of + * AccessExpressions. */ +Node *LookupId(Node *current, Node *prev, char *target) +{ + if (current == NULL) + return NULL; + + Node *match; + + /* First inspect the current node to see if it contains the target + * identifier. */ + match = InspectNode(current, target); + if (match != NULL) + return match; + + /* If this is the start of our search, we should not attempt to look at + * child nodes. Only looking up the AST is valid at this point. + * + * This has the notable side-effect that this function will return NULL if + * you attempt to look up a struct's internals starting from the node + * representing the struct itself. The same is true for functions. */ + if (prev == NULL) + return LookupId(current->parent, current, target); + + uint32_t i; + uint32_t idxLimit; + switch (current->syntaxKind) + { + case DeclarationSequence: + for (i = 0; i < current->declarationSequence.count; i += 1) + { + Node *decl = current->declarationSequence.sequence[i]; + match = InspectNode(decl, target); + if (match != NULL) + return match; + } + break; + case StatementSequence: + idxLimit = current->statementSequence.count; + for (i = 0; i < current->statementSequence.count; i += 1) + { + if (current->statementSequence.sequence[i] == prev) + { + idxLimit = i; + break; + } + } + + for (i = 0; i < idxLimit; i += 1) + { + Node *stmt = current->statementSequence.sequence[i]; + if (stmt == prev) + break; + + match = InspectNode(stmt, target); + if (match != NULL) + return match; + } + break; + } + + return LookupId(current->parent, current, target); +} + +/* FIXME: This function should be extended to handle multi-stage ID lookups for + * AccessExpression nodes. */ +/* FIXME: Make this function return an error status object of some kind. + * A non-OK status should halt compilation. */ +void ValidateIdentifiers(Node *node) +{ + if (node == NULL) + return; + + /* Skip over generic arguments. They contain Identifiers but are not + * actually identifiers, they declare types. */ + if (node->syntaxKind == GenericArguments) + return; + + if (node->syntaxKind != Identifier) + { + Recurse(node, *ValidateIdentifiers); + return; + } + + char *name = node->identifier.name; + Node *decl = LookupId(node, NULL, name); + if (decl == NULL) + { + /* FIXME: Express this case as an error with AST information, see the + * FIXME comment above. */ + fprintf( + stderr, + "wraith: Could not find definition of identifier %s.\n", + name); + } +} + +/* FIXME: This function should be extended to handle multi-stage ID lookups for + * AccessExpression nodes. */ +void TagIdentifierTypes(Node *node) +{ + if (node == NULL) + return; + + switch (node->syntaxKind) + { + case AllocExpression: + node->typeTag = MakeTypeTag(node); + break; + + case Declaration: + node->declaration.identifier->typeTag = MakeTypeTag(node); + break; + + case FunctionDeclaration: + node->functionDeclaration.functionSignature->functionSignature + .identifier->typeTag = MakeTypeTag(node); + break; + + case StructDeclaration: + node->structDeclaration.identifier->typeTag = MakeTypeTag(node); + break; + + case GenericArgument: + node->genericArgument.identifier->typeTag = MakeTypeTag(node); + break; + + case Identifier: + { + if (node->typeTag != NULL) + return; + + char *name = node->identifier.name; + Node *declaration = LookupId(node, NULL, name); + /* FIXME: Remove this case once ValidateIdentifiers returns error status + * info and halts compilation. See ValidateIdentifiers FIXME. */ + if (declaration == NULL) + { + TypeTag *tag = (TypeTag *)malloc(sizeof(TypeTag)); + tag->type = Unknown; + node->typeTag = tag; + } + else + { + node->typeTag = declaration->typeTag; + } + break; + } + } + + Recurse(node, *TagIdentifierTypes); +} + +Node *LookupType(Node *current, char *target) +{ + if (current == NULL) + return NULL; + + switch (current->syntaxKind) + { + /* If we've encountered a function declaration, check to see if it's generic + * and, if so, if one of its type parameters is the target. */ + case FunctionDeclaration: + { + Node *typeArgs = current->functionDeclaration.functionSignature + ->functionSignature.genericArguments; + uint32_t i; + for (i = 0; i < typeArgs->genericArguments.count; i += 1) + { + Node *arg = typeArgs->genericArguments.arguments[i]; + Node *argId = arg->genericArgument.identifier; + char *argName = argId->identifier.name; + /* note: return the GenericArgument, not the Identifier, so that + * the caller can differentiate between generics and customs. */ + if (strcmp(target, argName) == 0) + return arg; + } + + return LookupType(current->parent, target); + } + + case StructDeclaration: + { + Node *structId = GetIdFromStruct(current); + if (strcmp(target, structId->identifier.name) == 0) + return structId; + + return LookupType(current->parent, target); + } + + /* If we encounter a declaration sequence, search each of its children for + * struct definitions in case one of them is the target. */ + case DeclarationSequence: + { + uint32_t i; + for (i = 0; i < current->declarationSequence.count; i += 1) + { + Node *decl = current->declarationSequence.sequence[i]; + if (decl->syntaxKind == StructDeclaration) + { + Node *structId = GetIdFromStruct(decl); + if (strcmp(target, structId->identifier.name) == 0) + return structId; + } + } + + return LookupType(current->parent, target); + } + + default: + return LookupType(current->parent, target); + } +} + +/* FIXME: This function should be modified to handle type parameters over + * structs. */ +void ConvertCustomsToGenerics(Node *node) +{ + if (node == NULL) + return; + + switch (node->syntaxKind) + { + case Declaration: + { + Node *id = node->declaration.identifier; + Node *type = node->declaration.type->type.typeNode; + if (type->syntaxKind == CustomTypeNode) + { + char *target = id->typeTag->value.customType; + Node *typeLookup = LookupType(node, target); + if (typeLookup != NULL && typeLookup->syntaxKind == GenericArgument) + { + id->typeTag->type = Generic; + free(node->declaration.type); + node->declaration.type = + MakeGenericTypeNode(id->typeTag->value.genericType); + } + } + break; + } + + case FunctionSignature: + { + Node *id = node->functionSignature.identifier; + Node *type = node->functionSignature.type->type.typeNode; + if (type->syntaxKind == CustomTypeNode) + { + char *target = id->typeTag->value.customType; + Node *typeLookup = LookupType(node, target); + if (typeLookup != NULL && typeLookup->syntaxKind == GenericArgument) + { + id->typeTag->type = Generic; + free(node->functionSignature.type); + node->functionSignature.type = + MakeGenericTypeNode(id->typeTag->value.genericType); + } + } + break; + } + } + + Recurse(node, *ConvertCustomsToGenerics); +} diff --git a/src/validation.h b/src/validation.h new file mode 100644 index 0000000..50c5432 --- /dev/null +++ b/src/validation.h @@ -0,0 +1,10 @@ +#ifndef WRAITH_VALIDATION_H +#define WRAITH_VALIDATION_H + +#include "ast.h" + +void ValidateIdentifiers(Node *node); +void TagIdentifierTypes(Node *node); +void ConvertCustomsToGenerics(Node *node); + +#endif /* WRAITH_VALIDATION_H */