diff --git a/src/ast.c b/src/ast.c index d87870b..f34fc61 100644 --- a/src/ast.c +++ b/src/ast.c @@ -1,5 +1,6 @@ #include "ast.h" +#include #include #include @@ -989,3 +990,209 @@ char *TypeTagToString(TypeTag *tag) } } } + +void LinkParentPointers(Node *node) +{ + static Node *parent = NULL; + + if (node == NULL) + { + fprintf(stderr, "wraith: Encountered NULL node while linking parent pointers.\n"); + return; + } + + node->parent = parent; + parent = node; + Recurse(node, *LinkParentPointers); +} + +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 StructDeclaration: + return GetIdFromStruct(node); + case FunctionDeclaration: + return GetIdFromFunction(node); + case Declaration: + return GetIdFromDeclaration(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 *LookupIdNode(Node *current, Node *prev, char *target) +{ + if (current == NULL) return NULL; + + /* 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(current)) + { + Node *candidateId = TryGetId(current); + if (candidateId != NULL && strcmp(target, candidateId->identifier.name) == 0) + { + return candidateId; + } + + /* If the candidate node was not the one we wanted, but the current 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 (current->syntaxKind == FunctionDeclaration) + { + Node *match = LookupFunctionArgId(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. */ + 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]; + Node *declId = TryGetId(decl); + if (declId != NULL) 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 (NodeMayHaveId(stmt)) + { + Node *candidateId = TryGetId(current); + if (candidateId != NULL && strcmp(target, candidateId->identifier.name) == 0) + { + return candidateId; + } + } + } + break; + } + return LookupIdNode(current->parent, current, target); +} diff --git a/src/ast.h b/src/ast.h index 8ad54a0..967cbe5 100644 --- a/src/ast.h +++ b/src/ast.h @@ -373,7 +373,10 @@ const char *SyntaxKindString(SyntaxKind syntaxKind); * function in all other cases. */ void Recurse(Node *node, void (*func)(Node*)); +void LinkParentPointers(Node *node); + TypeTag *MakeTypeTag(Node *node); char *TypeTagToString(TypeTag *tag); +Node *LookupIdNode(Node *current, Node *prev, char *target); #endif /* WRAITH_AST_H */ diff --git a/src/identcheck.c b/src/identcheck.c index d2bd6c6..39498b0 100644 --- a/src/identcheck.c +++ b/src/identcheck.c @@ -187,7 +187,7 @@ IdNode *MakeIdTree(Node *astNode, IdNode *parent) { char *name = astNode->identifier.name; mainNode = MakeIdNode(Placeholder, name, parent); - IdNode *lookupNode = LookupId(mainNode, NULL, name); + Node *lookupNode = LookupIdNode(astNode, NULL, name); if (lookupNode == NULL) { fprintf(stderr, "wraith: Could not find IdNode for id %s\n", name); diff --git a/src/main.c b/src/main.c index cbb7e80..044210c 100644 --- a/src/main.c +++ b/src/main.c @@ -86,6 +86,7 @@ int main(int argc, char *argv[]) } else { + LinkParentPointers(rootNode); { IdNode *idTree = MakeIdTree(rootNode, NULL); printf("\n");