Type parser

This commit is contained in:
2026-03-05 19:32:31 +11:00
parent f1eee4f6a8
commit 00ef8a7d56
8 changed files with 290 additions and 7 deletions

View File

@@ -10,7 +10,7 @@ PREFIX ?= /usr/local
BINDIR = $(PREFIX)/bin
LIBDIR = /usr/lib
SRCS = $(SRC_DIR)/main.c $(SRC_DIR)/codegen/SolsScope.c $(SRC_DIR)/codegen/codegen.c $(SRC_DIR)/lexer/SolsLiteral.c $(SRC_DIR)/lexer/SolsToken.c $(SRC_DIR)/lexer/SolsType.c $(SRC_DIR)/lexer/lexer.c $(SRC_DIR)/parser/SolsNode.c $(SRC_DIR)/parser/parser.c
SRCS = $(SRC_DIR)/main.c $(SRC_DIR)/codegen/SolsScope.c $(SRC_DIR)/codegen/codegen.c $(SRC_DIR)/lexer/SolsLiteral.c $(SRC_DIR)/lexer/SolsToken.c $(SRC_DIR)/lexer/SolsType.c $(SRC_DIR)/lexer/lexer.c $(SRC_DIR)/parser/SolsNode.c $(SRC_DIR)/parser/parser.c $(SRC_DIR)/typeparser/typeparser.c
OBJS = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRCS))
TARGET = solstice
@@ -38,7 +38,7 @@ $(BUILD_DIR)/solstice.tar.gz: $(TARGET) $(LIBS_DIR)
package: $(BUILD_DIR)/solstice.tar.gz
$(BUILD_DIR):
mkdir -p $(BUILD_DIR) $(BUILD_DIR)/codegen $(BUILD_DIR)/lexer $(BUILD_DIR)/parser
mkdir -p $(BUILD_DIR) $(BUILD_DIR)/codegen $(BUILD_DIR)/lexer $(BUILD_DIR)/parser $(BUILD_DIR)/typeparser
clean:
rm -rf $(BUILD_DIR) $(TARGET)

View File

@@ -1,5 +1,6 @@
#include "lexer/SolsType.h"
#include "lexer/lexer.h"
#include "typeparser/typeparser.h"
#include "parser/parser.h"
#include "codegen/codegen.h"
#include "include/error.h"
@@ -139,8 +140,15 @@ int main(int argc, char** argv) {
exit(1);
}
// Detect and parse types
ResultType(SolsTokens, charptr) typed = addTypeInfo(&lexer.as.success.output);
if (typed.error) {
printf("%s\n", typed.as.error);
exit(1);
}
// Parse file
ResultType(SolsParser, charptr) parser = createSolsParser(&lexer.as.success.output);
ResultType(SolsParser, charptr) parser = createSolsParser(&typed.as.success);
if (parser.error) {
printf("Error while creating parser: %s\n", parser.as.error);
exit(1);

View File

@@ -55,7 +55,16 @@ ResultType(Nothing, charptr) addChildToSolsNode(SolsNode* parent, SolsNode child
}
parent->children.at = tmp;
}
parent->children.at[parent->children.count] = child;
parent->children.at[parent->children.count] = deepCopySolsNode(child);
parent->children.count++;
return Success(Nothing, charptr, {});
}
SolsNode deepCopySolsNode(SolsNode node) {
SolsNode copy = node;
copy.children.at = malloc(sizeof(SolsNode) * node.children.capacity);
for (size_t i = 0; i < node.children.count; i++) {
copy.children.at[i] = deepCopySolsNode(node.children.at[i]);
}
return copy;
}

View File

@@ -59,4 +59,7 @@ ResultType(SolsNode, charptr) createSolsNode(SolsNodeType type, ...);
// Failure: char* detailing what went wrong (usually memory failure)
ResultType(Nothing, charptr) addChildToSolsNode(SolsNode* parent, SolsNode child);
// Deep copies a SolsNode
SolsNode deepCopySolsNode(SolsNode node);
#endif

View File

@@ -6,6 +6,21 @@
#include <groundvm.h>
SolsTokenPrecedence getPrecedence(SolsToken *token) {
static size_t braceCount = 0;
switch (token->type) {
case STT_OPEN_CURLY: {
braceCount++;
return STP_OTHER;
}
case STT_CLOSE_CURLY: {
braceCount--;
return STP_OTHER;
}
default: break;
}
if (braceCount > 0) {
return STP_OTHER;
}
switch (token->type) {
case STT_LINE_END: return STP_NEWLINE;
case STT_KW_PUTS: return STP_PUTS;
@@ -1399,9 +1414,7 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
parser->currentParent->children.count--;
// We need to get the actual node from the parent to modify it
SolsNode* defNode = &parser->currentParent->children.at[parser->currentParent->children.count - 1];
addChildToSolsNode(defNode, codeBlock);
addChildToSolsNode(&parser->currentParent->children.at[0], parser->currentParent->children.at[1]);
return Success(Nothing, charptr, {});
}

230
src/typeparser/typeparser.c Normal file
View File

@@ -0,0 +1,230 @@
#include "typeparser.h"
#include "../lexer/SolsToken.h"
#include "../include/error.h"
#include <string.h>
ResultType(SolsType, charptr) parseType(SolsTokens* in, size_t* index) {
if (*index >= in->count) {
return Error(SolsType, charptr, "Unexpected end of tokens while parsing type");
}
SolsToken* token = &in->at[*index];
if (token->type == STT_TYPE) {
// It's already a basic type token
ResultType(SolsType, charptr) res = copySolsType(&token->as.type);
(*index)++;
return res;
}
if (token->type == STT_IDENTIFIER) {
if (strcmp(token->as.idName, "fun") == 0) {
(*index)++; // skip fun
if (*index >= in->count || in->at[*index].type != STT_OPEN_PAREN) {
return Error(SolsType, charptr, "Expected '(' after 'fun' in type signature");
}
(*index)++; // skip (
ResultType(SolsType, charptr) funTypeRes = createSolsType(STT_FUN);
if (funTypeRes.error) return funTypeRes;
SolsType funType = funTypeRes.as.success;
if (*index < in->count && in->at[*index].type != STT_CLOSE_PAREN) {
for (;;) {
ResultType(SolsType, charptr) argType = parseType(in, index);
if (argType.error) {
freeSolsType(&funType);
return argType;
}
addChildToSolsType(&funType, argType.as.success, NULL);
freeSolsType(&argType.as.success); // addChildToSolsType copies it
if (*index < in->count && in->at[*index].type == STT_COMMA) {
(*index)++; // skip comma
} else {
break;
}
}
}
if (*index >= in->count || in->at[*index].type != STT_CLOSE_PAREN) {
freeSolsType(&funType);
return Error(SolsType, charptr, "Expected ')' after function arguments in type signature");
}
(*index)++; // skip )
// Return type
ResultType(SolsType, charptr) retType = parseType(in, index);
if (retType.error) {
freeSolsType(&funType);
return retType;
}
// Allocate memory for returnType pointer
funType.returnType = malloc(sizeof(SolsType));
if (funType.returnType == NULL) {
freeSolsType(&funType);
freeSolsType(&retType.as.success);
return Error(SolsType, charptr, "Couldn't allocate memory (in parseType() function)");
}
*funType.returnType = retType.as.success;
return Success(SolsType, charptr, funType);
}
if (strcmp(token->as.idName, "object") == 0 || strcmp(token->as.idName, "template") == 0) {
bool isTemplate = strcmp(token->as.idName, "template") == 0;
(*index)++; // skip object/template
if (*index >= in->count || in->at[*index].type != STT_OPEN_PAREN) {
return Error(SolsType, charptr, "Expected '(' after object/template in type signature");
}
(*index)++; // skip (
ResultType(SolsType, charptr) complexTypeRes = createSolsType(isTemplate ? STT_TEMPLATE : STT_OBJECT);
if (complexTypeRes.error) return complexTypeRes;
SolsType complexType = complexTypeRes.as.success;
if (*index < in->count && in->at[*index].type != STT_CLOSE_PAREN) {
for (;;) {
ResultType(SolsType, charptr) fieldType = parseType(in, index);
if (fieldType.error) {
freeSolsType(&complexType);
return fieldType;
}
char* fieldName = NULL;
if (*index < in->count && in->at[*index].type == STT_IDENTIFIER) {
fieldName = in->at[*index].as.idName;
(*index)++;
}
addChildToSolsType(&complexType, fieldType.as.success, fieldName);
freeSolsType(&fieldType.as.success);
if (*index < in->count && in->at[*index].type == STT_COMMA) {
(*index)++; // skip comma
} else {
break;
}
}
}
if (*index >= in->count || in->at[*index].type != STT_CLOSE_PAREN) {
freeSolsType(&complexType);
return Error(SolsType, charptr, "Expected ')' in type signature");
}
(*index)++; // skip )
return Success(SolsType, charptr, complexType);
}
// Handle user-defined types (as identifiers)
// For now, let's just create an OBJECT type with identifierType set
ResultType(SolsType, charptr) userTypeRes = createSolsType(STT_OBJECT);
if (userTypeRes.error) return userTypeRes;
SolsType userType = userTypeRes.as.success;
userType.identifierType = malloc(strlen(token->as.idName) + 1);
if (userType.identifierType == NULL) {
freeSolsType(&userType);
return Error(SolsType, charptr, "Couldn't allocate memory (in parseType() function)");
}
strcpy(userType.identifierType, token->as.idName);
(*index)++;
return Success(SolsType, charptr, userType);
}
return Error(SolsType, charptr, "Unexpected token while parsing type");
}
ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
ResultType(SolsTokens, charptr) tokensres = createSolsTokens();
if (tokensres.error) {
return tokensres;
}
SolsTokens tokens = tokensres.as.success;
for (size_t i = 0; i < in->count; ) {
if (in->at[i].type == STT_IDENTIFIER &&
(strcmp(in->at[i].as.idName, "fun") == 0 ||
strcmp(in->at[i].as.idName, "object") == 0 ||
strcmp(in->at[i].as.idName, "template") == 0)) {
size_t startIndex = i;
ResultType(SolsType, charptr) typeRes = parseType(in, &i);
if (typeRes.error) {
// For now, return error
return Error(SolsTokens, charptr, typeRes.as.error);
}
ResultType(SolsToken, charptr) tokenRes = createSolsToken(STT_TYPE, typeRes.as.success);
if (tokenRes.error) {
freeSolsType(&typeRes.as.success);
return Error(SolsTokens, charptr, tokenRes.as.error);
}
// Add line info from original token
tokenRes.as.success.line.num = in->at[startIndex].line.num;
if (in->at[startIndex].line.content) {
tokenRes.as.success.line.content = malloc(strlen(in->at[startIndex].line.content) + 1);
if (tokenRes.as.success.line.content) {
strcpy(tokenRes.as.success.line.content, in->at[startIndex].line.content);
}
} else {
tokenRes.as.success.line.content = NULL;
}
addTokenToSolsTokens(&tokens, tokenRes.as.success);
// SolsToken now owns typeRes.as.success and its buffers.
} else {
// Need to deep copy the token because addTokenToSolsTokens just copies the struct
// and freeSolsToken will free buffers.
// Wait, if we use the same tokens, it's fine.
// But 'in' tokens might be freed later.
// Actually, we are creating a *new* SolsTokens.
// So we should probably copy the token properly.
SolsToken original = in->at[i];
SolsToken copy = {0};
copy.type = original.type;
copy.line.num = original.line.num;
if (original.line.content) {
copy.line.content = malloc(strlen(original.line.content) + 1);
if (copy.line.content) strcpy(copy.line.content, original.line.content);
}
switch (original.type) {
case STT_IDENTIFIER:
copy.as.idName = malloc(strlen(original.as.idName) + 1);
if (copy.as.idName) strcpy(copy.as.idName, original.as.idName);
break;
case STT_KW_GROUND:
copy.as.inlineGround = malloc(strlen(original.as.inlineGround) + 1);
if (copy.as.inlineGround) strcpy(copy.as.inlineGround, original.as.inlineGround);
break;
case STT_LITERAL:
// Literals also need deep copy?
// SolsLiteral has stringv.
if (original.as.literal.type == SLT_STRING) {
copy.as.literal.type = SLT_STRING;
copy.as.literal.as.stringv = malloc(strlen(original.as.literal.as.stringv) + 1);
if (copy.as.literal.as.stringv) strcpy(copy.as.literal.as.stringv, original.as.literal.as.stringv);
} else {
copy.as.literal = original.as.literal;
}
break;
case STT_TYPE: {
ResultType(SolsType, charptr) copiedType = copySolsType(&original.as.type);
if (!copiedType.error) {
copy.as.type = copiedType.as.success;
}
break;
}
default:
copy.as = original.as;
break;
}
addTokenToSolsTokens(&tokens, copy);
i++;
}
}
return Success(SolsTokens, charptr, tokens);
}

View File

@@ -0,0 +1,11 @@
#ifndef TYPEPARSER_H
#define TYPEPARSER_H
#include "../lexer/SolsToken.h"
#include "../include/error.h"
// Scans a SolsTokens and identifies type signatures, like fun(int) string.
// These are then converted into a single STT_TYPE token.
ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in);
#endif

9
tests/closure.sols Normal file
View File

@@ -0,0 +1,9 @@
def createClosure(int x) fun(int) int {
return lambda(int y) int {
x + y
}
}
myVar = createClosure(5)
puts myVar(3)