2 Commits

15 changed files with 357 additions and 150 deletions

View File

@@ -2,7 +2,6 @@
#include "SolsScope.h"
#include <groundvm.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
@@ -266,21 +265,24 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
}
case SNT_LITERAL: {
switch (node->as.literal.type) {
case SLT_INT: {
case STT_INT: {
return Success(SolsType, charptr, {STT_INT});
}
case SLT_DOUBLE: {
case STT_DOUBLE: {
return Success(SolsType, charptr, {STT_DOUBLE});
}
case SLT_STRING: {
case STT_STRING: {
return Success(SolsType, charptr, {STT_STRING});
}
case SLT_BOOL: {
case STT_BOOL: {
return Success(SolsType, charptr, {STT_BOOL});
}
case SLT_CHAR: {
case STT_CHAR: {
return Success(SolsType, charptr, {STT_CHAR});
}
default: {
return Error(SolsType, charptr, "Cannot handle literal of specified type");
}
}
break;
}
@@ -397,11 +399,6 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
Estr typeName = CREATE_ESTR(node->children.at[0].as.idName);
APPEND_ESTR(typeName, "_SOLS_GENERIC_");
for (size_t i = 0; i < node->children.count - 1; i++) {
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->children.at[i + 1].as.type, scope);
if (arg.error) {
return Error(SolsType, charptr, arg.as.error);
}
APPEND_ESTR(typeName, arg.as.success.value.refName);
APPEND_ESTR(typeName, "_");
}
SolsVariable* variable = findSolsVariable(scope, typeName.str);
@@ -554,29 +551,16 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
return Error(SolsType, charptr, "Not yet implemented");
}
SolsVMRegister assignSlot(SolsLiteral literal, SolsScope* scope) {}
SolsVMRegister reserveSlot(SolsScope* scope) {}
/*
static inline ResultType(GroundProgram, charptr) generateLiteralNode(SolsNode* node, SolsScope* scope) {
// We don't even need to do anything lmao
return Success(GroundProgram, charptr, groundCreateProgram());
}
static inline ResultType(GroundProgram, charptr) generatePutsNode(SolsNode* node, SolsScope* scope) {
if (node->children.count < 1) {
return Error(GroundProgram, charptr, "puts requires arguments");
}
GroundInstruction inst = groundCreateInstruction(PRINTLN);
for (size_t i = 0; i < node->children.count; i++) {
// Validate arg
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[i], scope);
if (type.error) {
return Error(GroundProgram, charptr, type.as.error);
}
groundAddReferenceToInstruction(&inst, node->children.at[i].accessArg);
}
GroundProgram program = groundCreateProgram();
groundAddInstructionToProgram(&program, inst);
return Success(GroundProgram, charptr, program);
}
static inline ResultType(GroundProgram, charptr) generateSetNode(SolsNode* node, SolsScope* scope) {
if (node->children.count < 2) {
return Error(GroundProgram, charptr, "set requires arguments");
@@ -2298,9 +2282,34 @@ ResultType(GroundProgram, charptr) generateSizeOfNode(SolsNode* node, SolsScope*
return Success(GroundProgram, charptr, gp);
}
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) {
*/
GroundProgram program = groundCreateProgram();
static inline ResultType(SolsVMInstructionList, charptr) generatePutsNode(SolsNode* node, SolsScope* scope) {
if (node->children.count < 1) {
return Error(SolsVMInstructionList, charptr, "puts requires arguments");
}
SolsVMInstruction inst = createInstruction();
inst.inst = SVM_IT_PUTS;
SolsVMInstructionList program = createInstList();
for (size_t i = 0; i < node->children.count; i++) {
// Validate arg
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[i], scope);
if (type.error) {
return Error(SolsVMInstructionList, charptr, type.as.error);
}
addArgToInstruction(&inst, (SolsVMInstructionArg) {
.type = SVM_AT_REGISTER,
.as.reg = 0
});
addInstToInstList(&program, inst);
}
return Success(SolsVMInstructionList, charptr, program);
}
ResultType(SolsVMInstructionList, charptr) generateCode(SolsNode* node, SolsScope* scope) {
SolsVMInstructionList program;
SolsScope backupScope = {NULL, 0};
@@ -2316,12 +2325,12 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
if (node->type == SNT_OP_SET && i == 0) {
continue; // Don't evaluate the left of set, just the right
}
ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope);
ResultType(SolsVMInstructionList, charptr) generated = generateCode(&node->children.at[i], scope);
if (generated.error) {
return Error(GroundProgram, charptr, createCodegenError(&node->children.at[i], generated.as.error));
return Error(SolsVMInstructionList, charptr, createCodegenError(&node->children.at[i], generated.as.error));
}
for (size_t j = 0; j < generated.as.success.size; j++) {
groundAddInstructionToProgram(&program, generated.as.success.instructions[j]);
addInstToInstList(&program, generated.as.success.instructions[j]);
}
}
if (node->type == SNT_CODE_BLOCK) {
@@ -2333,6 +2342,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
// Now generate code for this node
switch (node->type) {
case SNT_PUTS: generate(Puts);
/*
case SNT_LITERAL: generate(Literal);
case SNT_OP_SET: generate(Set);
case SNT_OP_ADD: generate(Add);
@@ -2363,6 +2373,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
case SNT_GENERIC_INIT: generate(GenericInit);
case SNT_AS: generate(As);
case SNT_SIZE_OF: generate(SizeOf);
*/
}
return Success(GroundProgram, charptr, program);
return Success(SolsVMInstructionList, charptr, program);
}

View File

@@ -1,32 +1,30 @@
#ifndef CODEGEN_H
#define CODEGEN_H
#include <groundvm.h>
#include "SolsScope.h"
#include "../parser/SolsNode.h"
#include "../vm/vm.h"
Result(GroundProgram, charptr);
Result(SolsVMInstructionList, charptr);
// Generates a GroundProgram (from the Ground VM header) from
// a provided SolsNode.
// a provided SolsNode.
// Returns:
// Success: Generated GroundProgram
// Failure: charptr detailing what happened
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope);
ResultType(SolsVMInstructionList, charptr) generateCode(SolsNode* node, SolsScope* scope);
// Gets the type of a node generated by the parser for the type checker.
ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope);
// Macro to help with code generation (and soon error handling)
#define generate(nodetype) {\
ResultType(GroundProgram, charptr) __result = generate##nodetype##Node(node, scope);\
ResultType(SolsVMInstructionList, charptr) __result = generate##nodetype##Node(node, scope);\
if (__result.error) {\
return Error(GroundProgram, charptr, __result.as.error);\
return Error(SolsVMInstructionList, charptr, __result.as.error);\
}\
for (size_t i = 0; i < __result.as.success.size; i++) {\
groundAddInstructionToProgram(&program, __result.as.success.instructions[i]);\
}\
break;\
}

View File

@@ -4,30 +4,30 @@
#include <inttypes.h>
#include <stdio.h>
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsLiteralType type, ...) {
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsTypeType type, ...) {
va_list args;
va_start(args, type);
SolsLiteral literal = {
.type = type
};
switch (type) {
case SLT_INT: {
case STT_INT: {
literal.as.intv = va_arg(args, int64_t);
break;
}
case SLT_DOUBLE: {
case STT_DOUBLE: {
literal.as.doublev = va_arg(args, double);
break;
}
case SLT_BOOL: {
case STT_BOOL: {
literal.as.boolv = (bool) va_arg(args, int);
break;
}
case SLT_CHAR: {
case STT_CHAR: {
literal.as.charv = (char) va_arg(args, int);
break;
}
case SLT_STRING: {
case STT_STRING: {
char* input = va_arg(args, char*);
if (input == NULL) {
va_end(args);
@@ -41,38 +41,44 @@ ResultType(SolsLiteral, charptr) createSolsLiteral(SolsLiteralType type, ...) {
strcpy(literal.as.stringv, input);
break;
}
default: {
return Error(SolsLiteral, charptr, "Cannot create literal of specified type");
}
}
va_end(args);
return Success(SolsLiteral, charptr, literal);
}
void freeSolsLiteral(SolsLiteral* lit) {
if (lit->type == SLT_STRING && lit->as.stringv != NULL) {
if (lit->type == STT_STRING && lit->as.stringv != NULL) {
free(lit->as.stringv);
}
}
void printSolsLiteral(SolsLiteral* lit) {
switch (lit->type) {
case SLT_INT: {
case STT_INT: {
printf("%" PRId64, lit->as.intv);
break;
}
case SLT_DOUBLE: {
case STT_DOUBLE: {
printf("%f", lit->as.doublev);
break;
}
case SLT_STRING: {
case STT_STRING: {
printf("%s", lit->as.stringv);
break;
}
case SLT_BOOL: {
case STT_BOOL: {
printf(lit->as.boolv ? "true" : "false");
break;
}
case SLT_CHAR: {
case STT_CHAR: {
printf("%c", lit->as.charv);
break;
}
default: {
break;
}
}
}

View File

@@ -4,6 +4,8 @@
#include <inttypes.h>
#include <stdarg.h>
#include "SolsType.h"
#include "../include/error.h"
#include "../include/nothing.h"
@@ -16,7 +18,7 @@ typedef enum SolsLiteralType {
// Stores literal values which will be added to the Ground code.
// Not much explaining needed here.
typedef struct SolsLiteral {
SolsLiteralType type;
SolsTypeType type;
union {
int64_t intv;
char* stringv;
@@ -38,7 +40,7 @@ Result(SolsLiteral, charptr);
// An error will only be returned if there is an issue copying a provided char*.
// There is no way to detect incorrectly provided types, so ensure that the right type
// is provided!!!!
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsLiteralType type, ...);
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsTypeType type, ...);
// Frees a SolsLiteral. Primarily concerned with freeing .as.stringv
void freeSolsLiteral(SolsLiteral* lit);

View File

@@ -1,7 +1,6 @@
#include "SolsType.h"
#include "../include/error.h"
#include "../include/estr.h"
#include <groundvm.h>
#include <string.h>
ResultType(SolsType, charptr) createSolsType(SolsTypeType in) {
@@ -250,52 +249,6 @@ bool compareTypes(SolsType* left, SolsType* right) {
}
}
ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type, struct SolsScope* scope) {
switch (type->type) {
case STT_INT: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "int"));
}
case STT_DOUBLE: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "double"));
}
case STT_STRING: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "string"));
}
case STT_BOOL: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "bool"));
}
case STT_CHAR: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "char"));
}
case STT_FUN: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "function"));
}
case STT_TEMPLATE: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "struct"));
}
case STT_OBJECT: {
if (!type->needsGroundStruct) {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, type->identifierType));
} else {
// FIXME do this later
return Error(GroundArg, charptr, "Anonymous structs are not supported yet");
}
}
case STT_UNKNOWN: {
if (!type->needsGroundStruct) {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, type->identifierType));
} else {
// FIXME do this later
return Error(GroundArg, charptr, "Anonymous structs are not supported yet");
}
}
case STT_NONE: {
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, "none"));
}
}
return Error(GroundArg, charptr, "How did we get here?");
}
ResultType(SolsType, charptr) findStructMemberType(SolsType* type, char* member) {
for (size_t i = 0; i < type->children.count; i++) {
if (strcmp(type->children.at[i].name, member) == 0) {

View File

@@ -2,7 +2,6 @@
#define SOLSTYPE_H
#include <stdlib.h>
#include <groundvm.h>
#include "../include/error.h"
#include "../include/nothing.h"
@@ -114,13 +113,8 @@ ResultType(Nothing, charptr) addChildToSolsType(SolsType* type, SolsType child,
// Makes a deep copy of a SolsType.
ResultType(SolsType, charptr) copySolsType(SolsType* type);
Result(GroundArg, charptr);
struct SolsScope;
// Represents a SolsType as a GroundArg (in typeref form)
ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type, struct SolsScope* scope);
// Frees a SolsType
void freeSolsType(SolsType* type);

View File

@@ -260,7 +260,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
tokencopy[strlen(token) - 2] = '\0';
// Create a literal
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_STRING, tokencopy);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_STRING, tokencopy);
// Free our copy of the string, createSolsLiteral creates a copy
free(tokencopy);
if (literal.error) {
@@ -285,7 +285,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
return Error(SolsToken, charptr, "Characters can only hold one character at a time (try using \"this\" for strings?)");
}
if (token[2] == '\'') {
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_CHAR, token[1]);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_CHAR, token[1]);
if (literal.error) {
Estr str = CREATE_ESTR(literal.as.error);
APPEND_ESTR(str, " (in identifyToken() function)");
@@ -319,7 +319,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
}
if (isInt) {
int64_t newInt = atoll(token);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_INT, newInt);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_INT, newInt);
if (literal.error) {
Estr str = CREATE_ESTR(literal.as.error);
APPEND_ESTR(str, " (in identifyToken() function)");
@@ -334,7 +334,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
if (isDouble) {
double newDouble = atof(token);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_DOUBLE, newDouble);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_DOUBLE, newDouble);
if (literal.error) {
Estr str = CREATE_ESTR(literal.as.error);
APPEND_ESTR(str, " (in identifyToken() function)");
@@ -350,7 +350,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
// Handle boolean (true/false)
if (strcmp(token, "true") == 0) {
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_BOOL, true);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_BOOL, true);
if (literal.error) {
Estr str = CREATE_ESTR(literal.as.error);
APPEND_ESTR(str, " (in identifyToken() function)");
@@ -363,7 +363,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
return Success(SolsToken, charptr, tok);
}
if (strcmp(token, "false") == 0) {
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_BOOL, false);
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_BOOL, false);
if (literal.error) {
Estr str = CREATE_ESTR(literal.as.error);
APPEND_ESTR(str, " (in identifyToken() function)");

View File

@@ -14,7 +14,6 @@
#include <sys/stat.h>
#include <libgen.h>
#endif
#include <groundvm.h>
extern bool groundDisableTypeChecking;
@@ -66,7 +65,7 @@ Args parseArgs(int argc, char** argv) {
return args;
}
i++;
args.outputFile = argv[i];
args.outputFile = argv[i];
}
else if (strcmp("-c", argv[i]) == 0 || strcmp("--compile", argv[i]) == 0) {
if (args.action != SA_EXEC) {
@@ -81,7 +80,7 @@ Args parseArgs(int argc, char** argv) {
return args;
}
i++;
args.outputFile = argv[i];
args.outputFile = argv[i];
}
else {
args.inputFile = argv[i];
@@ -168,12 +167,16 @@ int main(int argc, char** argv) {
};
// Do codegen on root node
ResultType(GroundProgram, charptr) codegen = generateCode(&parser.as.success.output, &scope);
ResultType(SolsVMInstructionList, charptr) codegen = generateCode(&parser.as.success.output, &scope);
if (codegen.error) {
printf("%s\n", codegen.as.error);
return 1;
}
#warning fix runtime
/*
switch (args.action) {
case SA_PRINT: {
groundPrintProgram(&codegen.as.success);
@@ -232,7 +235,7 @@ int main(int argc, char** argv) {
return 1;
}
// Link with ld
// Link with ld
Estr ldcmd = CREATE_ESTR("ld -o ");
APPEND_ESTR(ldcmd, args.outputFile);
APPEND_ESTR(ldcmd, " ");
@@ -250,5 +253,7 @@ int main(int argc, char** argv) {
}
}
*/
return 0;
}

View File

@@ -2,7 +2,6 @@
#define SOLSNODE_H
#include <stdarg.h>
#include <groundvm.h>
#include "../include/error.h"
@@ -52,9 +51,6 @@ typedef struct SolsNode {
struct SolsNode* at;
} children;
LineInfo line;
// Used by the code generator, unless value is a literal do not use in parser
GroundArg accessArg;
} SolsNode;
Result(SolsNode, charptr);

View File

@@ -4,7 +4,6 @@
#include "../include/estr.h"
#include "../include/ansii.h"
#include "../interactive/interactive.h"
#include <groundvm.h>
#include <string.h>
SolsTokenPrecedence getPrecedence(SolsToken *token) {
@@ -179,10 +178,7 @@ static inline ResultType(Nothing, charptr) parseIdentifier(SolsParser* parser) {
return Error(Nothing, charptr, err.str);
}
node.as.success.line = peek.as.success.line;
node.as.success.accessArg = (GroundArg) {
.type = VALREF,
.value.refName = peek.as.success.as.idName
};
#warning Fix identifiers
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
@@ -901,33 +897,41 @@ static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
return Error(Nothing, charptr, err.str);
}
node.as.success.line = peek.as.success.line;
/*
GroundValue value;
switch (peek.as.success.as.literal.type) {
case SLT_INT: {
case STT_INT: {
value = groundCreateValue(INT, peek.as.success.as.literal.as.intv);
break;
}
case SLT_DOUBLE: {
case STT_DOUBLE: {
value = groundCreateValue(DOUBLE, peek.as.success.as.literal.as.doublev);
break;
}
case SLT_STRING: {
case STT_STRING: {
value = groundCreateValue(STRING, peek.as.success.as.literal.as.stringv);
break;
}
case SLT_BOOL: {
case STT_BOOL: {
value = groundCreateValue(BOOL, peek.as.success.as.literal.as.boolv);
break;
}
case SLT_CHAR: {
case STT_CHAR: {
value = groundCreateValue(CHAR, peek.as.success.as.literal.as.charv);
break;
}
default: {
return Error(Nothing, charptr, "Cannot handle literal of specified type");
}
}
node.as.success.accessArg = (GroundArg) {
.type = VALUE,
.value.value = value
};
*/
#warning Fix literals in new VM
addChildToSolsNode(parser->currentParent, node.as.success);
return Success(Nothing, charptr, {});
}
@@ -1327,10 +1331,15 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
return Error(Nothing, charptr, nameNode.as.error);
}
nameNode.as.success.line = nameTok.as.success.line;
/*
nameNode.as.success.accessArg = (GroundArg) {
.type = VALREF,
.value.refName = nameTok.as.success.as.idName
};
*/
#warning Fix function definitions
addChildToSolsNode(&node.as.success, nameNode.as.success);
// Parse type signature
@@ -1605,7 +1614,7 @@ static inline ResultType(Nothing, charptr) parseUse(SolsParser* parser) {
}
node.as.success.as.idName = name.as.success.as.idName;
addChildToSolsNode(parser->currentParent, node.as.success);
} else if (name.as.success.type == STT_LITERAL && name.as.success.as.literal.type == SLT_STRING) {
} else if (name.as.success.type == STT_LITERAL && name.as.success.as.literal.type == STT_STRING) {
ResultType(SolsNode, charptr) node = createSolsNode(SNT_LOCAL_USE);
if (node.error) {
return Error(Nothing, charptr, node.as.error);

View File

@@ -59,7 +59,7 @@ ResultType(SolsType, charptr) parseType(SolsTokens* in, size_t* index) {
freeSolsType(&funType);
return retType;
}
// Allocate memory for returnType pointer
funType.returnType = malloc(sizeof(SolsType));
if (funType.returnType == NULL) {
@@ -91,7 +91,7 @@ ResultType(SolsType, charptr) parseType(SolsTokens* in, size_t* index) {
freeSolsType(&complexType);
return fieldType;
}
char* fieldName = NULL;
if (*index < in->count && in->at[*index].type == STT_IDENTIFIER) {
fieldName = in->at[*index].as.idName;
@@ -116,7 +116,7 @@ ResultType(SolsType, charptr) parseType(SolsTokens* in, size_t* index) {
(*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);
@@ -143,9 +143,9 @@ ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
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 ||
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);
@@ -153,13 +153,13 @@ ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
// 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) {
@@ -170,7 +170,7 @@ ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
} else {
tokenRes.as.success.line.content = NULL;
}
addTokenToSolsTokens(&tokens, tokenRes.as.success);
// SolsToken now owns typeRes.as.success and its buffers.
} else {
@@ -180,7 +180,7 @@ ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
// 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;
@@ -202,8 +202,8 @@ ResultType(SolsTokens, charptr) addTypeInfo(SolsTokens* in) {
case STT_LITERAL:
// Literals also need deep copy?
// SolsLiteral has stringv.
if (original.as.literal.type == SLT_STRING) {
copy.as.literal.type = SLT_STRING;
if (original.as.literal.type == STT_STRING) {
copy.as.literal.type = STT_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 {

150
src/vm/vm.c Normal file
View File

@@ -0,0 +1,150 @@
#include "vm.h"
#include <stdio.h>
#include <stdlib.h>
[[noreturn]] static void criticalRuntimeError(char* msg) {
fprintf(stderr, "SolsVM critical runtime error: %s\n", msg);
fprintf(stderr, "If you believe this to be a bug, please report at https://chookspace.com/solstice/solstice\n");
exit(EXIT_FAILURE);
}
static SolsVMValue* getRegister(SolsVMRegister reg, SolsVMState* state) {
switch (reg) {
case SVM_R0: return &state->registers.r0;
case SVM_R1: return &state->registers.r1;
case SVM_R2: return &state->registers.r2;
case SVM_R3: return &state->registers.r3;
case SVM_R4: return &state->registers.r4;
case SVM_R5: return &state->registers.r5;
case SVM_R6: return &state->registers.r6;
case SVM_R7: return &state->registers.r7;
case SVM_R8: return &state->registers.r8;
case SVM_R9: return &state->registers.r9;
case SVM_R10: return &state->registers.r10;
case SVM_R11: return &state->registers.r11;
case SVM_R12: return &state->registers.r12;
case SVM_R13: return &state->registers.r13;
case SVM_R14: return &state->registers.r14;
case SVM_R15: return &state->registers.r15;
}
}
static size_t getSizeOf(SolsTypeType type) {
switch (type) {
case STT_INT:
case STT_DOUBLE:
case STT_STRING:
return 8;
case STT_BOOL:
case STT_CHAR:
return 1;
case STT_FUN:
return sizeof(SolsVMFunction);
case STT_TEMPLATE:
return sizeof(SolsVMStruct);
case STT_OBJECT:
return 0; // Object has custom size, signal with 0
case STT_GENERIC:
case STT_UNKNOWN:
case STT_NONE:
criticalRuntimeError("Unresolved type during runtime");
}
}
/*
* puts instruction
* Args: register, core type
* Does: puts something on the console
*/
static inline void inst_puts(SolsVMInstruction* inst, SolsVMState* state) {
SolsVMValue reg = *getRegister(inst->args.at[0].as.reg, state);
switch (inst->args.at[1].as.type) {
case STT_INT: {
printf("%" PRId64 "\n", *(int64_t*)reg);
break;
}
case STT_DOUBLE: {
printf("%f\n", *(double*)reg);
break;
}
case STT_STRING: {
printf("%s\n", *(char**)reg);
break;
}
case STT_CHAR: {
printf("%c\n", *(char*)reg);
break;
}
case STT_BOOL: {
printf("%s\n", (*(bool*)reg) ? "true" : "false");
break;
}
case STT_FUN: {
printf("<function>\n");
break;
}
default: {
// FIXME handle structs and objects later
printf("<FIXME>\n");
break;
}
}
}
/*
* store instruction
* Stores a literal in a register
* Args: register, literal
* Does: Stores provided literal in the provided register
*/
static inline void inst_store(SolsVMInstruction* inst, SolsVMState* state) {
SolsVMValue* reg = getRegister(inst->args.at[0].as.reg, state);
if (*reg != NULL) free(*reg);
*reg = malloc(getSizeOf(inst->args.at[1].as.literal.type));
}
void runSolsVMInstruction(SolsVMInstruction* inst, SolsVMState* state) {
switch (inst->inst) {
case SVM_IT_PUTS: inst_puts(inst, state); break;
}
}
static inline void inst_put(SolsVMInstruction* inst, SolsVMState* state) {}
void runSolsVM(SolsVMInstructionList* list) {
SolsVMState state = {
.registers = {
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
},
.stackSize = 0
};
for (size_t i = 0; i < list->size; i++) {
runSolsVMInstruction(&list->instructions[i], &state);
}
// Cleanup - free registers and stack
if (state.registers.r0 != NULL) free(state.registers.r0);
if (state.registers.r1 != NULL) free(state.registers.r1);
if (state.registers.r2 != NULL) free(state.registers.r2);
if (state.registers.r3 != NULL) free(state.registers.r3);
if (state.registers.r4 != NULL) free(state.registers.r4);
if (state.registers.r5 != NULL) free(state.registers.r5);
if (state.registers.r6 != NULL) free(state.registers.r6);
if (state.registers.r7 != NULL) free(state.registers.r7);
if (state.registers.r8 != NULL) free(state.registers.r8);
if (state.registers.r9 != NULL) free(state.registers.r9);
if (state.registers.r10 != NULL) free(state.registers.r10);
if (state.registers.r11 != NULL) free(state.registers.r11);
if (state.registers.r12 != NULL) free(state.registers.r12);
if (state.registers.r13 != NULL) free(state.registers.r13);
if (state.registers.r14 != NULL) free(state.registers.r14);
if (state.registers.r15 != NULL) free(state.registers.r15);
for (size_t i = 0; i < state.stackSize; i++) {
if (state.stack[i] != NULL) free(state.stack[i]);
}
}

75
src/vm/vm.h Normal file
View File

@@ -0,0 +1,75 @@
#ifndef VM_H
#define VM_H
#define SVM_STACK_SIZE 8192
#include <stdint.h>
#include <stddef.h>
#include "../lexer/SolsLiteral.h"
#include "../lexer/SolsType.h"
typedef enum SolsVMRegister {
SVM_R0, SVM_R1, SVM_R2, SVM_R3, SVM_R4, SVM_R5, SVM_R6, SVM_R7, SVM_R8, SVM_R9, SVM_R10, SVM_R11, SVM_R12, SVM_R13, SVM_R14, SVM_R15
} SolsVMRegister;
typedef void* SolsVMValue;
typedef struct SolsVMState {
struct {
SolsVMValue r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15;
} registers;
SolsVMValue stack[SVM_STACK_SIZE];
uint32_t stackSize;
} SolsVMState;
typedef enum SolsVMInstructionType {
SVM_IT_PUTS
} SolsVMInstructionType;
typedef enum SolsVMInstructionArgType {
SVM_AT_LITERAL, SVM_AT_REGISTER, SVM_AT_TYPE
} SolsVMInstructionArgType;
typedef struct SolsVMInstructionArg {
SolsVMInstructionArgType type;
union {
SolsVMRegister reg;
SolsLiteral literal;
SolsTypeType type;
} as;
} SolsVMInstructionArg;
typedef struct SolsVMInstruction {
SolsVMInstructionType inst;
struct {
SolsVMInstructionArg* at;
size_t size;
size_t capacity;
} args;
} SolsVMInstruction;
SolsVMInstruction createInstruction();
void addArgToInstruction(SolsVMInstruction* inst, SolsVMInstructionArg arg);
typedef struct SolsVMInstructionList {
SolsVMInstruction* instructions;
size_t size;
size_t capacity;
} SolsVMInstructionList;
SolsVMInstructionList createInstList();
void addInstToInstList(SolsVMInstructionList* list, SolsVMInstruction inst);
typedef struct SolsVMFunction {
SolsVMInstructionList list;
SolsVMState state;
} SolsVMFunction;
typedef struct SolsVMStruct {
int x; // Placeholder
} SolsVMStruct;
void runSolsVM(SolsVMInstructionList* list);
#endif

10
src/vm/vm.md Normal file
View File

@@ -0,0 +1,10 @@
VM Architecture
* Everything is a `void*`, and the Solstice compiler will resolve all types before execution. No type safety is in the VM
* 16 registers which all hold a `void*`.
* `void*` can hold:
* A literal (int64_t, char*, double, bool, char)
* A function (stored as SolsVMFunction)
* A struct (stored as SolsVMStruct)
* An object (multiple fields after each other, each thing has 8 bytes of padding)
* Overwritten registers are freed

View File

@@ -8,8 +8,6 @@
#include "parser/parser.h"
#include "codegen/codegen.h"
#include <groundvm.h>
static char out_buf[65536];
static int out_pos = 0;