forked from solstice/solstice
Type parser
This commit is contained in:
4
Makefile
4
Makefile
@@ -10,7 +10,7 @@ PREFIX ?= /usr/local
|
|||||||
BINDIR = $(PREFIX)/bin
|
BINDIR = $(PREFIX)/bin
|
||||||
LIBDIR = /usr/lib
|
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))
|
OBJS = $(patsubst $(SRC_DIR)/%.c, $(BUILD_DIR)/%.o, $(SRCS))
|
||||||
TARGET = solstice
|
TARGET = solstice
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ $(BUILD_DIR)/solstice.tar.gz: $(TARGET) $(LIBS_DIR)
|
|||||||
package: $(BUILD_DIR)/solstice.tar.gz
|
package: $(BUILD_DIR)/solstice.tar.gz
|
||||||
|
|
||||||
$(BUILD_DIR):
|
$(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:
|
clean:
|
||||||
rm -rf $(BUILD_DIR) $(TARGET)
|
rm -rf $(BUILD_DIR) $(TARGET)
|
||||||
|
|||||||
10
src/main.c
10
src/main.c
@@ -1,5 +1,6 @@
|
|||||||
#include "lexer/SolsType.h"
|
#include "lexer/SolsType.h"
|
||||||
#include "lexer/lexer.h"
|
#include "lexer/lexer.h"
|
||||||
|
#include "typeparser/typeparser.h"
|
||||||
#include "parser/parser.h"
|
#include "parser/parser.h"
|
||||||
#include "codegen/codegen.h"
|
#include "codegen/codegen.h"
|
||||||
#include "include/error.h"
|
#include "include/error.h"
|
||||||
@@ -139,8 +140,15 @@ int main(int argc, char** argv) {
|
|||||||
exit(1);
|
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
|
// Parse file
|
||||||
ResultType(SolsParser, charptr) parser = createSolsParser(&lexer.as.success.output);
|
ResultType(SolsParser, charptr) parser = createSolsParser(&typed.as.success);
|
||||||
if (parser.error) {
|
if (parser.error) {
|
||||||
printf("Error while creating parser: %s\n", parser.as.error);
|
printf("Error while creating parser: %s\n", parser.as.error);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|||||||
@@ -55,7 +55,16 @@ ResultType(Nothing, charptr) addChildToSolsNode(SolsNode* parent, SolsNode child
|
|||||||
}
|
}
|
||||||
parent->children.at = tmp;
|
parent->children.at = tmp;
|
||||||
}
|
}
|
||||||
parent->children.at[parent->children.count] = child;
|
parent->children.at[parent->children.count] = deepCopySolsNode(child);
|
||||||
parent->children.count++;
|
parent->children.count++;
|
||||||
return Success(Nothing, charptr, {});
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -59,4 +59,7 @@ ResultType(SolsNode, charptr) createSolsNode(SolsNodeType type, ...);
|
|||||||
// Failure: char* detailing what went wrong (usually memory failure)
|
// Failure: char* detailing what went wrong (usually memory failure)
|
||||||
ResultType(Nothing, charptr) addChildToSolsNode(SolsNode* parent, SolsNode child);
|
ResultType(Nothing, charptr) addChildToSolsNode(SolsNode* parent, SolsNode child);
|
||||||
|
|
||||||
|
// Deep copies a SolsNode
|
||||||
|
SolsNode deepCopySolsNode(SolsNode node);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -6,6 +6,21 @@
|
|||||||
#include <groundvm.h>
|
#include <groundvm.h>
|
||||||
|
|
||||||
SolsTokenPrecedence getPrecedence(SolsToken *token) {
|
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) {
|
switch (token->type) {
|
||||||
case STT_LINE_END: return STP_NEWLINE;
|
case STT_LINE_END: return STP_NEWLINE;
|
||||||
case STT_KW_PUTS: return STP_PUTS;
|
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];
|
SolsNode codeBlock = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||||
parser->currentParent->children.count--;
|
parser->currentParent->children.count--;
|
||||||
|
|
||||||
// We need to get the actual node from the parent to modify it
|
addChildToSolsNode(&parser->currentParent->children.at[0], parser->currentParent->children.at[1]);
|
||||||
SolsNode* defNode = &parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
|
||||||
addChildToSolsNode(defNode, codeBlock);
|
|
||||||
|
|
||||||
return Success(Nothing, charptr, {});
|
return Success(Nothing, charptr, {});
|
||||||
}
|
}
|
||||||
|
|||||||
230
src/typeparser/typeparser.c
Normal file
230
src/typeparser/typeparser.c
Normal 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);
|
||||||
|
}
|
||||||
11
src/typeparser/typeparser.h
Normal file
11
src/typeparser/typeparser.h
Normal 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
9
tests/closure.sols
Normal 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)
|
||||||
Reference in New Issue
Block a user