Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ed3975285 | |||
| 1da7f91313 | |||
| 6a936bf282 | |||
| 8a8e4381bf | |||
| b78a5ee7bb | |||
| cbc92b5b1d | |||
| 45c9d9ee37 | |||
| 3003605031 | |||
| c68bf1b662 | |||
| 3c36e92261 | |||
| 246a212cb9 |
37
libs/box.sols
Normal file
37
libs/box.sols
Normal file
@@ -0,0 +1,37 @@
|
||||
struct _box {
|
||||
private ptr = 0
|
||||
def get() int { return 0 }
|
||||
def set() int { return 0 }
|
||||
def free() int { return 0 }
|
||||
}
|
||||
|
||||
ground {
|
||||
extern "_box"
|
||||
}
|
||||
|
||||
/*
|
||||
Shared mutable object. Use with caution - may cause impurities!
|
||||
*/
|
||||
struct Box[T] {
|
||||
|
||||
private box = new _box
|
||||
|
||||
def get() T {
|
||||
retval = new T
|
||||
ground { callmethod &self &box !get &retval }
|
||||
return retval
|
||||
}
|
||||
|
||||
def set(T in) int {
|
||||
ground { callmethod &self &box !set $in &retval }
|
||||
return 0
|
||||
}
|
||||
|
||||
def free() int {
|
||||
ground { callmethod &self &box !free &retval }
|
||||
return 0
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
}
|
||||
9
libs/socket.sols
Normal file
9
libs/socket.sols
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Function that blocks the main thread which listens to TCP connections.
|
||||
All connection data will be pass
|
||||
*/
|
||||
def socket_Listen(fun(string) string handler, int port) int {}
|
||||
|
||||
ground {
|
||||
extern "socket"
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,32 @@
|
||||
#ifndef CODEGEN_H
|
||||
#define CODEGEN_H
|
||||
|
||||
#include <groundvm.h>
|
||||
|
||||
#include "SolsScope.h"
|
||||
|
||||
#include "../parser/SolsNode.h"
|
||||
#include "../vm/vm.h"
|
||||
|
||||
Result(SolsVMInstructionList, charptr);
|
||||
Result(GroundProgram, 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(SolsVMInstructionList, charptr) generateCode(SolsNode* node, SolsScope* scope);
|
||||
ResultType(GroundProgram, 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(SolsVMInstructionList, charptr) __result = generate##nodetype##Node(node, scope);\
|
||||
ResultType(GroundProgram, charptr) __result = generate##nodetype##Node(node, scope);\
|
||||
if (__result.error) {\
|
||||
return Error(SolsVMInstructionList, charptr, __result.as.error);\
|
||||
return Error(GroundProgram, charptr, __result.as.error);\
|
||||
}\
|
||||
for (size_t i = 0; i < __result.as.success.size; i++) {\
|
||||
groundAddInstructionToProgram(&program, __result.as.success.instructions[i]);\
|
||||
}\
|
||||
break;\
|
||||
}
|
||||
|
||||
@@ -4,30 +4,30 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsTypeType type, ...) {
|
||||
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsLiteralType type, ...) {
|
||||
va_list args;
|
||||
va_start(args, type);
|
||||
SolsLiteral literal = {
|
||||
.type = type
|
||||
};
|
||||
switch (type) {
|
||||
case STT_INT: {
|
||||
case SLT_INT: {
|
||||
literal.as.intv = va_arg(args, int64_t);
|
||||
break;
|
||||
}
|
||||
case STT_DOUBLE: {
|
||||
case SLT_DOUBLE: {
|
||||
literal.as.doublev = va_arg(args, double);
|
||||
break;
|
||||
}
|
||||
case STT_BOOL: {
|
||||
case SLT_BOOL: {
|
||||
literal.as.boolv = (bool) va_arg(args, int);
|
||||
break;
|
||||
}
|
||||
case STT_CHAR: {
|
||||
case SLT_CHAR: {
|
||||
literal.as.charv = (char) va_arg(args, int);
|
||||
break;
|
||||
}
|
||||
case STT_STRING: {
|
||||
case SLT_STRING: {
|
||||
char* input = va_arg(args, char*);
|
||||
if (input == NULL) {
|
||||
va_end(args);
|
||||
@@ -41,44 +41,38 @@ ResultType(SolsLiteral, charptr) createSolsLiteral(SolsTypeType 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 == STT_STRING && lit->as.stringv != NULL) {
|
||||
if (lit->type == SLT_STRING && lit->as.stringv != NULL) {
|
||||
free(lit->as.stringv);
|
||||
}
|
||||
}
|
||||
|
||||
void printSolsLiteral(SolsLiteral* lit) {
|
||||
switch (lit->type) {
|
||||
case STT_INT: {
|
||||
case SLT_INT: {
|
||||
printf("%" PRId64, lit->as.intv);
|
||||
break;
|
||||
}
|
||||
case STT_DOUBLE: {
|
||||
case SLT_DOUBLE: {
|
||||
printf("%f", lit->as.doublev);
|
||||
break;
|
||||
}
|
||||
case STT_STRING: {
|
||||
case SLT_STRING: {
|
||||
printf("%s", lit->as.stringv);
|
||||
break;
|
||||
}
|
||||
case STT_BOOL: {
|
||||
case SLT_BOOL: {
|
||||
printf(lit->as.boolv ? "true" : "false");
|
||||
break;
|
||||
}
|
||||
case STT_CHAR: {
|
||||
case SLT_CHAR: {
|
||||
printf("%c", lit->as.charv);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "SolsType.h"
|
||||
|
||||
#include "../include/error.h"
|
||||
#include "../include/nothing.h"
|
||||
|
||||
@@ -18,7 +16,7 @@ typedef enum SolsLiteralType {
|
||||
// Stores literal values which will be added to the Ground code.
|
||||
// Not much explaining needed here.
|
||||
typedef struct SolsLiteral {
|
||||
SolsTypeType type;
|
||||
SolsLiteralType type;
|
||||
union {
|
||||
int64_t intv;
|
||||
char* stringv;
|
||||
@@ -40,7 +38,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(SolsTypeType type, ...);
|
||||
ResultType(SolsLiteral, charptr) createSolsLiteral(SolsLiteralType type, ...);
|
||||
|
||||
// Frees a SolsLiteral. Primarily concerned with freeing .as.stringv
|
||||
void freeSolsLiteral(SolsLiteral* lit);
|
||||
|
||||
@@ -17,7 +17,8 @@ typedef enum SolsTokenType {
|
||||
STT_OP_INCREMENT, STT_OP_DECREMENT, STT_OP_SET,
|
||||
STT_OP_GREATER, STT_OP_LESSER, STT_OP_EQUAL, STT_OP_INEQUAL, STT_OP_EQGREATER, STT_OP_EQLESSER,
|
||||
STT_KW_DEF, STT_KW_LAMBDA, STT_KW_RETURN,
|
||||
STT_KW_USE, STT_KW_STRUCT, STT_KW_ENUM, STT_KW_CONSTRUCTOR, STT_KW_DESTRUCTOR, STT_KW_DUPLICATOR,
|
||||
STT_KW_USE, STT_KW_MODULE,
|
||||
STT_KW_STRUCT, STT_KW_ENUM, STT_KW_CONSTRUCTOR, STT_KW_DESTRUCTOR, STT_KW_DUPLICATOR,
|
||||
STT_KW_AS, STT_KW_SIZEOF,
|
||||
STT_KW_PRIVATE, STT_KW_PROTECTED,
|
||||
STT_KW_PUTS, STT_KW_IF, STT_KW_WHILE,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "SolsType.h"
|
||||
#include "../include/error.h"
|
||||
#include "../include/estr.h"
|
||||
#include <groundvm.h>
|
||||
#include <string.h>
|
||||
|
||||
ResultType(SolsType, charptr) createSolsType(SolsTypeType in) {
|
||||
@@ -15,6 +16,9 @@ ResultType(SolsType, charptr) createSolsType(SolsTypeType in) {
|
||||
.children.capacity = 32,
|
||||
.children.count = 0,
|
||||
.children.at = ptr,
|
||||
.genericChildren.at = NULL,
|
||||
.genericChildren.capacity = 0,
|
||||
.genericChildren.count = 0,
|
||||
.typeIsKnown = true,
|
||||
.needsGroundStruct = false,
|
||||
.metadata.isPrivate = false,
|
||||
@@ -40,6 +44,9 @@ ResultType(SolsType, charptr) createIdentifiedSolsType(char* in) {
|
||||
.children.capacity = 0,
|
||||
.children.count = 0,
|
||||
.children.at = NULL,
|
||||
.genericChildren.at = NULL,
|
||||
.genericChildren.capacity = 0,
|
||||
.genericChildren.count = 0,
|
||||
.typeIsKnown = false,
|
||||
.needsGroundStruct = false,
|
||||
.metadata.isPrivate = false,
|
||||
@@ -61,6 +68,9 @@ ResultType(SolsType, charptr) copySolsType(SolsType* type) {
|
||||
.children.count = type->children.count,
|
||||
.children.capacity = type->children.capacity,
|
||||
.children.at = NULL,
|
||||
.genericChildren.count = type->genericChildren.count,
|
||||
.genericChildren.capacity = type->genericChildren.capacity,
|
||||
.genericChildren.at = NULL,
|
||||
.metadata = type->metadata
|
||||
};
|
||||
|
||||
@@ -115,6 +125,24 @@ ResultType(SolsType, charptr) copySolsType(SolsType* type) {
|
||||
}
|
||||
}
|
||||
|
||||
if (type->genericChildren.capacity > 0) {
|
||||
SolsType* ptr = malloc(sizeof(SolsType) * type->genericChildren.capacity);
|
||||
if (ptr == NULL) {
|
||||
return Error(SolsType, charptr, "Couldn't allocate memory (in copySolsType() function)");
|
||||
}
|
||||
ret.genericChildren.at = ptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < type->genericChildren.count; i++) {
|
||||
ResultType(SolsType, charptr) copied = copySolsType(&type->genericChildren.at[i]);
|
||||
if (copied.error) {
|
||||
Estr err = CREATE_ESTR(copied.as.error);
|
||||
APPEND_ESTR(err, " (in copySolsType() function)");
|
||||
return Error(SolsType, charptr, err.str);
|
||||
}
|
||||
ret.genericChildren.at[i] = copied.as.success;
|
||||
}
|
||||
|
||||
return Success(SolsType, charptr, ret);
|
||||
}
|
||||
/*
|
||||
@@ -249,6 +277,65 @@ 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"));
|
||||
}
|
||||
case STT_GENERIC: {
|
||||
Estr typeName = CREATE_ESTR(type->identifierType);
|
||||
APPEND_ESTR(typeName, "_SOLS_GENERIC_");
|
||||
for (size_t i = 0; i < type->genericChildren.count; i++) {
|
||||
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&type->genericChildren.at[i], scope);
|
||||
if (arg.error) {
|
||||
return Error(GroundArg, charptr, arg.as.error);
|
||||
}
|
||||
APPEND_ESTR(typeName, arg.as.success.value.refName);
|
||||
APPEND_ESTR(typeName, "_");
|
||||
}
|
||||
return Success(GroundArg, charptr, groundCreateReference(TYPEREF, typeName.str));
|
||||
}
|
||||
}
|
||||
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) {
|
||||
@@ -313,3 +400,34 @@ void printSolsType(SolsType* type) {
|
||||
printf("}");
|
||||
}
|
||||
}
|
||||
|
||||
ResultType(Nothing, charptr) addGenericFieldToType(SolsType* type, SolsType field) {
|
||||
|
||||
if (type->genericChildren.at == NULL) {
|
||||
type->genericChildren.at = malloc(sizeof(SolsType) * 4);
|
||||
if (type->genericChildren.at == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory");
|
||||
}
|
||||
type->genericChildren.capacity = 4;
|
||||
type->genericChildren.count = 0;
|
||||
}
|
||||
|
||||
if (type->genericChildren.count >= type->genericChildren.capacity) {
|
||||
SolsType* tmp = realloc(type->genericChildren.at, type->genericChildren.capacity * 2 * sizeof(SolsType));
|
||||
if (tmp == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory");
|
||||
}
|
||||
type->genericChildren.capacity *= 2;
|
||||
}
|
||||
|
||||
type->genericChildren.at[type->genericChildren.count] = ({
|
||||
ResultType(SolsType, charptr) _res = copySolsType(&field);
|
||||
if (_res.error) {
|
||||
return Error(Nothing, charptr, _res.as.error);
|
||||
}
|
||||
_res.as.success;
|
||||
});
|
||||
type->genericChildren.count++;
|
||||
|
||||
return Success(Nothing, charptr, {});
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SOLSTYPE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <groundvm.h>
|
||||
|
||||
#include "../include/error.h"
|
||||
#include "../include/nothing.h"
|
||||
@@ -69,6 +70,13 @@ typedef struct SolsType {
|
||||
size_t capacity;
|
||||
} children;
|
||||
|
||||
// For use in generics
|
||||
struct {
|
||||
struct SolsType* at;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
} genericChildren;
|
||||
|
||||
struct {
|
||||
bool isPrivate;
|
||||
bool isProtected;
|
||||
@@ -113,8 +121,13 @@ 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);
|
||||
|
||||
@@ -124,6 +137,13 @@ bool compareTypes(SolsType* left, SolsType* right);
|
||||
// Finds the type of a struct member. Errors if the member is not found.
|
||||
ResultType(SolsType, charptr) findStructMemberType(SolsType* type, char* member);
|
||||
|
||||
// Adds a generic argument to a SolsType.
|
||||
// If you have
|
||||
// MyStruct[int, string]
|
||||
// you would add SolsType(STT_INT) and SolsType(STT_STRING) to the
|
||||
// SolsType for `MyStruct` using this function.
|
||||
ResultType(Nothing, charptr) addGenericFieldToType(SolsType* type, SolsType field);
|
||||
|
||||
void printSolsType(SolsType* type);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ struct _SolsTokenTypeMap SolsTokenTypeMap[] = {
|
||||
{"as", STT_KW_AS},
|
||||
{"sizeof", STT_KW_SIZEOF},
|
||||
{"pragma", STT_KW_PRAGMA},
|
||||
{"module", STT_KW_MODULE},
|
||||
{"{", STT_OPEN_CURLY},
|
||||
{"}", STT_CLOSE_CURLY},
|
||||
{"(", STT_OPEN_PAREN},
|
||||
@@ -260,7 +261,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
|
||||
tokencopy[strlen(token) - 2] = '\0';
|
||||
|
||||
// Create a literal
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_STRING, tokencopy);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_STRING, tokencopy);
|
||||
// Free our copy of the string, createSolsLiteral creates a copy
|
||||
free(tokencopy);
|
||||
if (literal.error) {
|
||||
@@ -285,7 +286,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(STT_CHAR, token[1]);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_CHAR, token[1]);
|
||||
if (literal.error) {
|
||||
Estr str = CREATE_ESTR(literal.as.error);
|
||||
APPEND_ESTR(str, " (in identifyToken() function)");
|
||||
@@ -319,7 +320,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
|
||||
}
|
||||
if (isInt) {
|
||||
int64_t newInt = atoll(token);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_INT, newInt);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_INT, newInt);
|
||||
if (literal.error) {
|
||||
Estr str = CREATE_ESTR(literal.as.error);
|
||||
APPEND_ESTR(str, " (in identifyToken() function)");
|
||||
@@ -334,7 +335,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
|
||||
|
||||
if (isDouble) {
|
||||
double newDouble = atof(token);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_DOUBLE, newDouble);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_DOUBLE, newDouble);
|
||||
if (literal.error) {
|
||||
Estr str = CREATE_ESTR(literal.as.error);
|
||||
APPEND_ESTR(str, " (in identifyToken() function)");
|
||||
@@ -350,7 +351,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
|
||||
|
||||
// Handle boolean (true/false)
|
||||
if (strcmp(token, "true") == 0) {
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_BOOL, true);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_BOOL, true);
|
||||
if (literal.error) {
|
||||
Estr str = CREATE_ESTR(literal.as.error);
|
||||
APPEND_ESTR(str, " (in identifyToken() function)");
|
||||
@@ -363,7 +364,7 @@ ResultType(SolsToken, charptr) identifyToken(const char* token) {
|
||||
return Success(SolsToken, charptr, tok);
|
||||
}
|
||||
if (strcmp(token, "false") == 0) {
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(STT_BOOL, false);
|
||||
ResultType(SolsLiteral, charptr) literal = createSolsLiteral(SLT_BOOL, false);
|
||||
if (literal.error) {
|
||||
Estr str = CREATE_ESTR(literal.as.error);
|
||||
APPEND_ESTR(str, " (in identifyToken() function)");
|
||||
|
||||
15
src/main.c
15
src/main.c
@@ -14,6 +14,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
#include <groundvm.h>
|
||||
|
||||
extern bool groundDisableTypeChecking;
|
||||
|
||||
@@ -65,7 +66,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) {
|
||||
@@ -80,7 +81,7 @@ Args parseArgs(int argc, char** argv) {
|
||||
return args;
|
||||
}
|
||||
i++;
|
||||
args.outputFile = argv[i];
|
||||
args.outputFile = argv[i];
|
||||
}
|
||||
else {
|
||||
args.inputFile = argv[i];
|
||||
@@ -167,16 +168,12 @@ int main(int argc, char** argv) {
|
||||
};
|
||||
|
||||
// Do codegen on root node
|
||||
ResultType(SolsVMInstructionList, charptr) codegen = generateCode(&parser.as.success.output, &scope);
|
||||
ResultType(GroundProgram, 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);
|
||||
@@ -235,7 +232,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, " ");
|
||||
@@ -253,7 +250,5 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SOLSNODE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <groundvm.h>
|
||||
|
||||
#include "../include/error.h"
|
||||
|
||||
@@ -18,8 +19,9 @@ typedef enum SolsNodeType {
|
||||
SNT_OP_SET,
|
||||
SNT_OP_GREATER, SNT_OP_LESSER, SNT_OP_EQUAL, SNT_OP_INEQUAL, SNT_OP_EQGREATER, SNT_OP_EQLESSER,
|
||||
SNT_DEF, SNT_LAMBDA, SNT_FUNCTION_CALL, SNT_RETURN,
|
||||
SNT_SET_PRIVATE, SNT_SET_PROTECTED, SNT_DEF_PRIVATE, SNT_DEF_PROTECTED,
|
||||
SNT_USE, SNT_LOCAL_USE, SNT_STRUCT, SNT_ENUM, SNT_CONSTRUCTOR, SNT_DESTRUCTOR, SNT_DUPLICATOR,
|
||||
SNT_SET_PRIVATE, SNT_SET_PROTECTED, SNT_DEF_PRIVATE, SNT_DEF_PROTECTED, SNT_STRUCT_PRIVATE, SNT_STRUCT_PROTECTED,
|
||||
SNT_USE, SNT_LOCAL_USE, SNT_MODULE,
|
||||
SNT_STRUCT, SNT_ENUM, SNT_CONSTRUCTOR, SNT_DESTRUCTOR, SNT_DUPLICATOR,
|
||||
SNT_STRUCT_AS, SNT_AS, SNT_SIZE_OF,
|
||||
SNT_PUTS, SNT_IF, SNT_WHILE, SNT_NEW,
|
||||
SNT_GROUND, SNT_ROOT, SNT_EXPR_IN_PAREN, SNT_DOT,
|
||||
@@ -51,6 +53,9 @@ 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);
|
||||
|
||||
@@ -4,8 +4,137 @@
|
||||
#include "../include/estr.h"
|
||||
#include "../include/ansii.h"
|
||||
#include "../interactive/interactive.h"
|
||||
#include <groundvm.h>
|
||||
#include <string.h>
|
||||
|
||||
char* parseEscapeSequences(const char* in) {
|
||||
size_t len = strlen(in);
|
||||
size_t currentPos = 0;
|
||||
|
||||
char* ret = malloc(len + 1);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (in[i] == '\\') {
|
||||
if (i + 1 >= len) {
|
||||
ret[currentPos++] = '\\';
|
||||
} else {
|
||||
switch (in[i+1]) {
|
||||
case '\\':
|
||||
ret[currentPos++] = '\\';
|
||||
i++;
|
||||
break;
|
||||
case 'n':
|
||||
ret[currentPos++] = '\n';
|
||||
i++;
|
||||
break;
|
||||
case 't':
|
||||
ret[currentPos++] = '\t';
|
||||
i++;
|
||||
break;
|
||||
case 'r':
|
||||
ret[currentPos++] = '\r';
|
||||
i++;
|
||||
break;
|
||||
case '"':
|
||||
ret[currentPos++] = '"';
|
||||
i++;
|
||||
break;
|
||||
case '\'':
|
||||
ret[currentPos++] = '\'';
|
||||
i++;
|
||||
break;
|
||||
case 'a':
|
||||
ret[currentPos++] = '\a';
|
||||
i++;
|
||||
break;
|
||||
case 'b':
|
||||
ret[currentPos++] = '\b';
|
||||
i++;
|
||||
break;
|
||||
case 'f':
|
||||
ret[currentPos++] = '\f';
|
||||
i++;
|
||||
break;
|
||||
case 'v':
|
||||
ret[currentPos++] = '\v';
|
||||
i++;
|
||||
break;
|
||||
case 'e':
|
||||
case 'E':
|
||||
ret[currentPos++] = '\x1b';
|
||||
i++;
|
||||
break;
|
||||
case 'x':
|
||||
case 'X': {
|
||||
i++; // consume 'x' or 'X'
|
||||
unsigned int val = 0;
|
||||
int count = 0;
|
||||
while (count < 2 && i + 1 < len) {
|
||||
char c = in[i+1];
|
||||
if (c >= '0' && c <= '9') {
|
||||
val = val * 16 + (c - '0');
|
||||
} else if (c >= 'a' && c <= 'f') {
|
||||
val = val * 16 + (c - 'a' + 10);
|
||||
} else if (c >= 'A' && c <= 'F') {
|
||||
val = val * 16 + (c - 'A' + 10);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
count++;
|
||||
}
|
||||
if (count > 0) {
|
||||
ret[currentPos++] = (char)val;
|
||||
} else {
|
||||
// No hex digits, treat as literal '\' and 'x' or 'X'
|
||||
ret[currentPos++] = '\\';
|
||||
ret[currentPos++] = in[i]; // which is 'x' or 'X'
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7': {
|
||||
unsigned int val = in[i+1] - '0';
|
||||
int count = 1;
|
||||
i++; // consume first octal digit
|
||||
while (count < 3 && i + 1 < len) {
|
||||
char c = in[i+1];
|
||||
if (c >= '0' && c <= '7') {
|
||||
val = val * 8 + (c - '0');
|
||||
i++;
|
||||
count++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret[currentPos++] = (char)val;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret[currentPos++] = '\\';
|
||||
ret[currentPos++] = in[i+1];
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret[currentPos++] = in[i];
|
||||
}
|
||||
}
|
||||
|
||||
ret[currentPos] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
SolsTokenPrecedence getPrecedence(SolsToken *token) {
|
||||
static size_t braceCount = 0;
|
||||
static size_t squareBracketCount = 0;
|
||||
@@ -166,6 +295,80 @@ void createParserError(SolsParser* parser, char* what) {
|
||||
parser->errors.count++;
|
||||
}
|
||||
|
||||
// Parses a type, inclusive of generic arguments.
|
||||
// Will always return a SolsNode with type SNT_TYPE, with the type in .as.type
|
||||
static ResultType(SolsNode, charptr) parseType(SolsParser* parser);
|
||||
static ResultType(SolsNode, charptr) parseType(SolsParser* parser) {
|
||||
// get next token
|
||||
ResultType(SolsToken, Nothing) next = parserConsume(parser);
|
||||
if (next.error) {
|
||||
return Error(SolsNode, charptr, "Expecting token");
|
||||
}
|
||||
char* idType = NULL;
|
||||
bool bracketConsumed = false;
|
||||
switch (next.as.success.type) {
|
||||
case STT_TYPE: {
|
||||
return createSolsNode(SNT_TYPE, next.as.success.as.type);
|
||||
}
|
||||
case STT_IDENTIFIER: {
|
||||
idType = next.as.success.as.idName;
|
||||
break;
|
||||
}
|
||||
case STT_OPEN_SQUARE: {
|
||||
if (parser->current < 2) {
|
||||
return Error(SolsNode, charptr, "wowowowowow you got the legendary error wowowow max couldn't be bothered to fix it properly so this is why you're getting the error lmao");
|
||||
}
|
||||
SolsToken node = parser->input->at[parser->current - 2];
|
||||
idType = node.as.idName;
|
||||
bracketConsumed = true;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return Error(SolsNode, charptr, "Expecting type identifier");
|
||||
}
|
||||
}
|
||||
|
||||
SolsType type = ({
|
||||
ResultType(SolsType, charptr) _res = createIdentifiedSolsType(idType);
|
||||
if (_res.error) {
|
||||
return Error(SolsNode, charptr, _res.as.error);
|
||||
}
|
||||
_res.as.success;
|
||||
});
|
||||
|
||||
if (!bracketConsumed) {
|
||||
next = parserPeek(parser, 1);
|
||||
if (next.error || next.as.success.type != STT_OPEN_SQUARE) {
|
||||
return createSolsNode(SNT_TYPE, type);
|
||||
}
|
||||
parserConsume(parser); // opening square bracket
|
||||
}
|
||||
|
||||
type.type = STT_GENERIC;
|
||||
|
||||
for (;;) {
|
||||
ResultType(SolsNode, charptr) childType = parseType(parser);
|
||||
if (childType.error) return childType;
|
||||
|
||||
addGenericFieldToType(&type, childType.as.success.as.type);
|
||||
|
||||
next = parserConsume(parser);
|
||||
if (next.error) {
|
||||
return Error(SolsNode, charptr, "Expecting ']' to end generic argument list");
|
||||
}
|
||||
|
||||
if (next.as.success.type == STT_CLOSE_SQUARE) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (next.as.success.type != STT_COMMA) {
|
||||
return Error(SolsNode, charptr, "Expecting ',' or ']' after generic argument");
|
||||
}
|
||||
}
|
||||
|
||||
return createSolsNode(SNT_TYPE, type);
|
||||
}
|
||||
|
||||
static inline ResultType(Nothing, charptr) parseIdentifier(SolsParser* parser) {
|
||||
ResultType(SolsToken, Nothing) peek = parserPeek(parser, 0);
|
||||
if (peek.error) {
|
||||
@@ -178,7 +381,10 @@ static inline ResultType(Nothing, charptr) parseIdentifier(SolsParser* parser) {
|
||||
return Error(Nothing, charptr, err.str);
|
||||
}
|
||||
node.as.success.line = peek.as.success.line;
|
||||
#warning Fix identifiers
|
||||
node.as.success.accessArg = (GroundArg) {
|
||||
.type = VALREF,
|
||||
.value.refName = peek.as.success.as.idName
|
||||
};
|
||||
addChildToSolsNode(parser->currentParent, node.as.success);
|
||||
return Success(Nothing, charptr, {});
|
||||
}
|
||||
@@ -897,41 +1103,33 @@ 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 STT_INT: {
|
||||
case SLT_INT: {
|
||||
value = groundCreateValue(INT, peek.as.success.as.literal.as.intv);
|
||||
break;
|
||||
}
|
||||
case STT_DOUBLE: {
|
||||
case SLT_DOUBLE: {
|
||||
value = groundCreateValue(DOUBLE, peek.as.success.as.literal.as.doublev);
|
||||
break;
|
||||
}
|
||||
case STT_STRING: {
|
||||
value = groundCreateValue(STRING, peek.as.success.as.literal.as.stringv);
|
||||
case SLT_STRING: {
|
||||
value = groundCreateValue(STRING, parseEscapeSequences(peek.as.success.as.literal.as.stringv));
|
||||
break;
|
||||
}
|
||||
case STT_BOOL: {
|
||||
case SLT_BOOL: {
|
||||
value = groundCreateValue(BOOL, peek.as.success.as.literal.as.boolv);
|
||||
break;
|
||||
}
|
||||
case STT_CHAR: {
|
||||
case SLT_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, {});
|
||||
}
|
||||
@@ -1208,19 +1406,11 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Pattern of type, name, comma
|
||||
|
||||
SolsType tmpType;
|
||||
|
||||
if (next.as.success.type == STT_TYPE) {
|
||||
tmpType = next.as.success.as.type;
|
||||
} else if (next.as.success.type == STT_IDENTIFIER) {
|
||||
tmpType = createIdentifiedSolsType(next.as.success.as.idName).as.success;
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Expecting a type or identifier of type in lambda argument list");
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
|
||||
parserConsume(parser);
|
||||
|
||||
char* argName;
|
||||
next = parserPeek(parser, 1);
|
||||
|
||||
@@ -1231,7 +1421,7 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Add type to constructed SolsType
|
||||
addChildToSolsType(&type.as.success, tmpType, argName);
|
||||
addChildToSolsType(&type.as.success, typeNode.as.success.as.type, argName);
|
||||
parserConsume(parser);
|
||||
|
||||
next = parserPeek(parser, 1);
|
||||
@@ -1249,32 +1439,17 @@ static inline ResultType(Nothing, charptr) parseLambda(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Parse type at the end
|
||||
ResultType(SolsToken, Nothing) retType = parserPeek(parser, 1);
|
||||
if (retType.error) {
|
||||
return Error(Nothing, charptr, "Expecting return type or identifier of type after lambda argument list");
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
|
||||
if (retType.as.success.type == STT_TYPE) {
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
if (type.as.success.returnType == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
||||
}
|
||||
*type.as.success.returnType = retType.as.success.as.type;
|
||||
} else if (retType.as.success.type == STT_IDENTIFIER) {
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
if (type.as.success.returnType == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
||||
}
|
||||
*type.as.success.returnType = createIdentifiedSolsType(retType.as.success.as.idName).as.success;
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Expecting return type or identifier of type after lambda argument list");
|
||||
}
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
*type.as.success.returnType = typeNode.as.success.as.type;
|
||||
|
||||
// Add type to node
|
||||
node.as.success.as.type = type.as.success;
|
||||
|
||||
parserConsume(parser); // Consumes return type
|
||||
|
||||
// Skip newlines before the opening curly brace
|
||||
while (parserPeek(parser, 1).as.success.type == STT_LINE_END) {
|
||||
parserConsume(parser);
|
||||
@@ -1331,15 +1506,10 @@ 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
|
||||
@@ -1358,19 +1528,11 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Pattern of type, name, comma
|
||||
|
||||
SolsType tmpType;
|
||||
|
||||
if (next.as.success.type == STT_TYPE) {
|
||||
tmpType = next.as.success.as.type;
|
||||
} else if (next.as.success.type == STT_IDENTIFIER) {
|
||||
tmpType = createIdentifiedSolsType(next.as.success.as.idName).as.success;
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Expecting a type or identifier of type in def argument list");
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
|
||||
parserConsume(parser);
|
||||
|
||||
char* argName;
|
||||
next = parserPeek(parser, 1);
|
||||
|
||||
@@ -1381,7 +1543,7 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Add type to constructed SolsType
|
||||
addChildToSolsType(&type.as.success, tmpType, argName);
|
||||
addChildToSolsType(&type.as.success, typeNode.as.success.as.type, argName);
|
||||
parserConsume(parser);
|
||||
|
||||
next = parserPeek(parser, 1);
|
||||
@@ -1399,32 +1561,17 @@ static inline ResultType(Nothing, charptr) parseDef(SolsParser* parser) {
|
||||
}
|
||||
|
||||
// Parse return type after argument list
|
||||
ResultType(SolsToken, Nothing) retType = parserPeek(parser, 1);
|
||||
if (retType.error) {
|
||||
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
|
||||
if (retType.as.success.type == STT_TYPE) {
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
if (type.as.success.returnType == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
||||
}
|
||||
*type.as.success.returnType = retType.as.success.as.type;
|
||||
} else if (retType.as.success.type == STT_IDENTIFIER) {
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
if (type.as.success.returnType == NULL) {
|
||||
return Error(Nothing, charptr, "Failed to allocate memory for type");
|
||||
}
|
||||
*type.as.success.returnType = createIdentifiedSolsType(retType.as.success.as.idName).as.success;
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Expecting return type or identifier of type after def argument list");
|
||||
}
|
||||
type.as.success.returnType = malloc(sizeof(SolsType));
|
||||
*type.as.success.returnType = typeNode.as.success.as.type;
|
||||
|
||||
// Add type to node
|
||||
node.as.success.as.type = type.as.success;
|
||||
|
||||
parserConsume(parser); // Consumes return type
|
||||
|
||||
// Skip newlines before the opening curly brace
|
||||
while (parserPeek(parser, 1).as.success.type == STT_LINE_END) {
|
||||
parserConsume(parser);
|
||||
@@ -1614,7 +1761,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 == STT_STRING) {
|
||||
} else if (name.as.success.type == STT_LITERAL && name.as.success.as.literal.type == SLT_STRING) {
|
||||
ResultType(SolsNode, charptr) node = createSolsNode(SNT_LOCAL_USE);
|
||||
if (node.error) {
|
||||
return Error(Nothing, charptr, node.as.error);
|
||||
@@ -1710,7 +1857,7 @@ static inline ResultType(Nothing, charptr) parseCloseParen(SolsParser* parser) {
|
||||
return Error(Nothing, charptr, "Extra closing parentheses");
|
||||
}
|
||||
|
||||
static inline ResultType(Nothing, charptr) parseConstructor(SolsParser* parser) {
|
||||
static inline ResultType(Nothing, charptr) parseConstructor(SolsParser* parser, bool isModule) {
|
||||
ResultType(SolsNode, charptr) node = createSolsNode(SNT_CONSTRUCTOR);
|
||||
ResultType(SolsType, charptr) type = createSolsType(STT_FUN);
|
||||
if (type.error) {
|
||||
@@ -1729,7 +1876,7 @@ static inline ResultType(Nothing, charptr) parseConstructor(SolsParser* parser)
|
||||
return Error(Nothing, charptr, "Expecting '('");
|
||||
}
|
||||
// Parse type signature
|
||||
for (;;) {
|
||||
if (!isModule) for (;;) {
|
||||
ResultType(SolsToken, Nothing) next = parserPeek(parser, 1);
|
||||
if (next.error) {
|
||||
return Error(Nothing, charptr, "Expecting ')' at end of constructor argument list");
|
||||
@@ -2141,7 +2288,7 @@ static inline ResultType(Nothing, charptr) parseStruct(SolsParser* parser) {
|
||||
if (protected) {
|
||||
return Error(Nothing, charptr, "Constructor cannot be protected");
|
||||
}
|
||||
ResultType(Nothing, charptr) constructorNode = parseConstructor(parser);
|
||||
ResultType(Nothing, charptr) constructorNode = parseConstructor(parser, false);
|
||||
if (constructorNode.error) {
|
||||
return Error(Nothing, charptr, constructorNode.as.error);
|
||||
}
|
||||
@@ -2276,15 +2423,11 @@ ResultType(Nothing, charptr) parseNew(SolsParser* parser) {
|
||||
if (newNode.error) {
|
||||
return Error(Nothing, charptr, newNode.as.error);
|
||||
}
|
||||
ResultType(SolsToken, Nothing) nameTok = parserConsume(parser);
|
||||
if (nameTok.error || !(nameTok.as.success.type == STT_IDENTIFIER || nameTok.as.success.type == STT_TYPE)) {
|
||||
return Error(Nothing, charptr, "Expecting identifier after 'new'");
|
||||
}
|
||||
if (nameTok.as.success.type == STT_IDENTIFIER) {
|
||||
newNode.as.success.as.type = createIdentifiedSolsType(nameTok.as.success.as.idName).as.success;
|
||||
} else if (nameTok.as.success.type == STT_TYPE) {
|
||||
newNode.as.success.as.type = nameTok.as.success.as.type;
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
newNode.as.success.as.type = typeNode.as.success.as.type;
|
||||
addChildToSolsNode(parser->currentParent, newNode.as.success);
|
||||
return Success(Nothing, charptr, {});
|
||||
}
|
||||
@@ -2378,6 +2521,264 @@ ResultType(Nothing, charptr) parseEnum(SolsParser* parser) {
|
||||
return Success(Nothing, charptr, {});
|
||||
}
|
||||
|
||||
static ResultType(Nothing, charptr) parseModule(SolsParser* parser);
|
||||
static ResultType(Nothing, charptr) parseModule(SolsParser* parser) {
|
||||
|
||||
// Modules are essentially the same as structs, except:
|
||||
// - they immediately create a new object
|
||||
// - they can't use generics
|
||||
// - they can't be passed around as easily
|
||||
//
|
||||
// Modules should be used either as:
|
||||
// - namespaces
|
||||
// - grouping for other modules
|
||||
|
||||
SolsNode structNode = ({
|
||||
ResultType(SolsNode, charptr) _result = createSolsNode(SNT_MODULE);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
ResultType(SolsToken, Nothing) nameTok = parserConsume(parser);
|
||||
if (nameTok.error || nameTok.as.success.type != STT_IDENTIFIER) {
|
||||
return Error(Nothing, charptr, "Expecting identifier after 'module'");
|
||||
}
|
||||
structNode.as.idName = nameTok.as.success.as.idName;
|
||||
|
||||
ResultType(SolsToken, Nothing) nextToken = parserConsume(parser);
|
||||
if (!nextToken.error) {
|
||||
if (nextToken.as.success.type != STT_OPEN_CURLY) {
|
||||
return Error(Nothing, charptr, "Expecting '{' after module identifier");
|
||||
}
|
||||
}
|
||||
// Ignore new lines between struct and opening curly brace
|
||||
for (;;) {
|
||||
ResultType(SolsToken, Nothing) token = parserPeek(parser, 1);
|
||||
if (token.error) {
|
||||
return Error(Nothing, charptr, "Expecting '{' after 'module'");
|
||||
}
|
||||
if (token.as.success.type == STT_LINE_END) {
|
||||
parserConsume(parser);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
bool done = false;
|
||||
// Skip newlines between struct values
|
||||
for (;;) {
|
||||
ResultType(SolsToken, Nothing) token = parserPeek(parser, 1);
|
||||
if (token.error) {
|
||||
return Error(Nothing, charptr, "Expecting '}' to end module");
|
||||
}
|
||||
if (token.as.success.type == STT_LINE_END) {
|
||||
parserConsume(parser);
|
||||
}
|
||||
else if (token.as.success.type == STT_CLOSE_CURLY) {
|
||||
done = true;
|
||||
parserConsume(parser);
|
||||
break;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) break;
|
||||
|
||||
bool private = false;
|
||||
bool protected = false;
|
||||
|
||||
// key = value\n
|
||||
SolsToken keyTok = ({
|
||||
ResultType(SolsToken, Nothing) _result = parserConsume(parser);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, "Expecting module key");
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
if (keyTok.type == STT_KW_PRIVATE) {
|
||||
// private key = value
|
||||
private = true;
|
||||
|
||||
ResultType(SolsToken, Nothing) result = parserConsume(parser);
|
||||
if (result.error) {
|
||||
return Error(Nothing, charptr, "Expecting identifier after 'private'");
|
||||
}
|
||||
keyTok = result.as.success;
|
||||
}
|
||||
if (keyTok.type == STT_KW_PROTECTED) {
|
||||
// protected key = value
|
||||
protected = true;
|
||||
|
||||
ResultType(SolsToken, Nothing) result = parserConsume(parser);
|
||||
if (result.error) {
|
||||
return Error(Nothing, charptr, "Expecting identifier after 'protected'");
|
||||
}
|
||||
keyTok = result.as.success;
|
||||
}
|
||||
if (keyTok.type == STT_KW_DEF) {
|
||||
// def fnName(Arg arg1, Arg arg2, ...) ReturnType {}
|
||||
ResultType(Nothing, charptr) defNode = parseDef(parser);
|
||||
if (defNode.error) {
|
||||
return Error(Nothing, charptr, defNode.as.error);
|
||||
}
|
||||
if (protected) parser->currentParent->children.at[parser->currentParent->children.count - 1].type = SNT_DEF_PROTECTED;
|
||||
if (private) parser->currentParent->children.at[parser->currentParent->children.count - 1].type = SNT_DEF_PRIVATE;
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
continue;
|
||||
}
|
||||
if (keyTok.type == STT_KW_STRUCT) {
|
||||
// struct StructName {...}
|
||||
ResultType(Nothing, charptr) newStructNode = parseStruct(parser);
|
||||
if (newStructNode.error) {
|
||||
return Error(Nothing, charptr, newStructNode.as.error);
|
||||
}
|
||||
if (protected) parser->currentParent->children.at[parser->currentParent->children.count - 1].type = SNT_STRUCT_PROTECTED;
|
||||
if (private) parser->currentParent->children.at[parser->currentParent->children.count - 1].type = SNT_STRUCT_PRIVATE;
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
}
|
||||
if (keyTok.type == STT_KW_CONSTRUCTOR) {
|
||||
// constructor {}
|
||||
if (private) {
|
||||
return Error(Nothing, charptr, "Constructor cannot be private");
|
||||
}
|
||||
if (protected) {
|
||||
return Error(Nothing, charptr, "Constructor cannot be protected");
|
||||
}
|
||||
ResultType(Nothing, charptr) constructorNode = parseConstructor(parser, true);
|
||||
if (constructorNode.error) {
|
||||
return Error(Nothing, charptr, constructorNode.as.error);
|
||||
}
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
continue;
|
||||
}
|
||||
if (keyTok.type == STT_KW_DESTRUCTOR) {
|
||||
// destructor {}
|
||||
if (private) {
|
||||
return Error(Nothing, charptr, "Destructor cannot be private");
|
||||
}
|
||||
if (protected) {
|
||||
return Error(Nothing, charptr, "Destructor cannot be protected");
|
||||
}
|
||||
ResultType(Nothing, charptr) destructorNode = parseDestructor(parser);
|
||||
if (destructorNode.error) {
|
||||
return Error(Nothing, charptr, destructorNode.as.error);
|
||||
}
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
continue;
|
||||
}
|
||||
if (keyTok.type == STT_KW_DUPLICATOR) {
|
||||
// duplicator {}
|
||||
if (private) {
|
||||
return Error(Nothing, charptr, "Duplicator cannot be private");
|
||||
}
|
||||
if (protected) {
|
||||
return Error(Nothing, charptr, "Duplicator cannot be protected");
|
||||
}
|
||||
ResultType(Nothing, charptr) duplicatorNode = parseDuplicator(parser);
|
||||
if (duplicatorNode.error) {
|
||||
return Error(Nothing, charptr, duplicatorNode.as.error);
|
||||
}
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
continue;
|
||||
}
|
||||
if (keyTok.type == STT_KW_AS) {
|
||||
if (private) {
|
||||
return Error(Nothing, charptr, "as method cannot be private");
|
||||
}
|
||||
if (protected) {
|
||||
return Error(Nothing, charptr, "as method cannot be protected");
|
||||
}
|
||||
ResultType(Nothing, charptr) asNode = parseStructAs(parser);
|
||||
if (asNode.error) {
|
||||
return Error(Nothing, charptr, asNode.as.error);
|
||||
}
|
||||
addChildToSolsNode(&structNode, parser->currentParent->children.at[parser->currentParent->children.count - 1]);
|
||||
parser->currentParent->children.count--;
|
||||
continue;
|
||||
}
|
||||
if (keyTok.type != STT_IDENTIFIER) {
|
||||
return Error(Nothing, charptr, "Expecting struct key");
|
||||
}
|
||||
SolsToken setTok = ({
|
||||
ResultType(SolsToken, Nothing) _result = parserConsume(parser);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, "Expecting '=' after struct key");
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
if (setTok.type != STT_OP_SET) {
|
||||
return Error(Nothing, charptr, "Expecting '=' after struct key");
|
||||
}
|
||||
SolsTokens tokens = ({
|
||||
ResultType(SolsTokens, charptr) _result = createSolsTokens();
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
// Collect tokens for value
|
||||
if (parserPeek(parser, 1).error) {
|
||||
return Error(Nothing, charptr, "Expecting value after '='");
|
||||
}
|
||||
for (;;) {
|
||||
ResultType(SolsToken, Nothing) token = parserPeek(parser, 1);
|
||||
if (token.error) {
|
||||
break;
|
||||
}
|
||||
if (getPrecedence(&token.as.success) <= STP_NEWLINE) {
|
||||
break;
|
||||
}
|
||||
addTokenToSolsTokens(&tokens, token.as.success);
|
||||
parserConsume(parser);
|
||||
}
|
||||
// Parse value
|
||||
SolsParser newParser = ({
|
||||
ResultType(SolsParser, charptr) _result = createSolsParser(&tokens);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
newParser.currentParent = &newParser.output;
|
||||
ResultType(Nothing, charptr) parsed = parse(&newParser);
|
||||
if (parsed.error) {
|
||||
addToParserErrors(parser, parsed.as.error);
|
||||
}
|
||||
// Construct set node
|
||||
SolsNode setNode = ({
|
||||
ResultType(SolsNode, charptr) _result = createSolsNode(SNT_OP_SET);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
if (protected) setNode.type = SNT_SET_PROTECTED;
|
||||
if (private) setNode.type = SNT_SET_PRIVATE;
|
||||
addChildToSolsNode(&setNode, ({
|
||||
ResultType(SolsNode, charptr) _result = createSolsNode(SNT_IDENTIFIER, keyTok.as.idName);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
}));
|
||||
addChildToSolsNode(&setNode, newParser.output.children.at[0]);
|
||||
|
||||
// Add set node to struct node
|
||||
addChildToSolsNode(&structNode, setNode);
|
||||
}
|
||||
// Add struct node to parent
|
||||
addChildToSolsNode(parser->currentParent, structNode);
|
||||
return Success(Nothing, charptr, {});
|
||||
|
||||
}
|
||||
|
||||
|
||||
ResultType(Nothing, charptr) parseAs(SolsParser* parser) {
|
||||
ResultType(SolsNode, charptr) asNode = createSolsNode(SNT_AS);
|
||||
if (asNode.error) {
|
||||
@@ -2429,62 +2830,23 @@ ResultType(Nothing, charptr) parseOpenSquare(SolsParser* parser) {
|
||||
if (openSquare.error) {
|
||||
return Error(Nothing, charptr, openSquare.as.error);
|
||||
}
|
||||
// Get previous node
|
||||
if (parser->currentParent->children.count == 0) {
|
||||
return Error(Nothing, charptr, "Expecting identifier of type before '['");
|
||||
}
|
||||
SolsNode prev = parser->currentParent->children.at[parser->currentParent->children.count - 1];
|
||||
if (prev.type != SNT_IDENTIFIER) {
|
||||
return Error(Nothing, charptr, "Expecting identifier of type before '['");
|
||||
|
||||
if (parser->current > 0) {
|
||||
parser->current--;
|
||||
if (parser->currentParent->children.count > 0) {
|
||||
parser->currentParent->children.count--;
|
||||
}
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Identifier required before open square");
|
||||
}
|
||||
|
||||
addChildToSolsNode(&openSquare.as.success, prev);
|
||||
parser->currentParent->children.count--;
|
||||
|
||||
// Collect generic arguments and add to node
|
||||
for (;;) {
|
||||
ResultType(SolsToken, Nothing) token = parserConsume(parser);
|
||||
if (token.error) {
|
||||
return Error(Nothing, charptr, "Expecting ']' to end generic argument list");
|
||||
}
|
||||
|
||||
if (token.as.success.type == STT_IDENTIFIER) {
|
||||
SolsType type = ({
|
||||
ResultType(SolsType, charptr) _result = createIdentifiedSolsType(token.as.success.as.idName);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
});
|
||||
addChildToSolsNode(&openSquare.as.success, ({
|
||||
ResultType(SolsNode, charptr) _result = createSolsNode(SNT_TYPE, type);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
}));
|
||||
} else if (token.as.success.type == STT_TYPE) {
|
||||
addChildToSolsNode(&openSquare.as.success, ({
|
||||
ResultType(SolsNode, charptr) _result = createSolsNode(SNT_TYPE, token.as.success.as.type);
|
||||
if (_result.error) {
|
||||
return Error(Nothing, charptr, _result.as.error);
|
||||
}
|
||||
_result.as.success;
|
||||
}));
|
||||
} else {
|
||||
return Error(Nothing, charptr, "Expecting identifier or type in generic argument list");
|
||||
}
|
||||
|
||||
// Expect comma or ']'
|
||||
ResultType(SolsToken, Nothing) comma = parserConsume(parser);
|
||||
if (comma.error) {
|
||||
return Error(Nothing, charptr, "Expecting ',' or ']' after generic argument");
|
||||
}
|
||||
if (comma.as.success.type == STT_CLOSE_SQUARE) {
|
||||
break;
|
||||
}
|
||||
ResultType(SolsNode, charptr) typeNode = parseType(parser);
|
||||
if (typeNode.error) {
|
||||
return Error(Nothing, charptr, typeNode.as.error);
|
||||
}
|
||||
|
||||
openSquare.as.success.as.type = typeNode.as.success.as.type;
|
||||
|
||||
addChildToSolsNode(parser->currentParent, openSquare.as.success);
|
||||
return Success(Nothing, charptr, {});
|
||||
}
|
||||
@@ -2590,6 +2952,7 @@ ResultType(Nothing, charptr) parse(SolsParser* parser) {
|
||||
case STT_KW_ENUM: PARSER_HANDLE(Enum);
|
||||
case STT_KW_NEW: PARSER_HANDLE(New);
|
||||
case STT_KW_USE: PARSER_HANDLE(Use);
|
||||
case STT_KW_MODULE: PARSER_HANDLE(Module);
|
||||
case STT_KW_DEF: PARSER_HANDLE(Def);
|
||||
case STT_OP_SET: PARSER_HANDLE(Set);
|
||||
case STT_OP_ADD: PARSER_HANDLE(Add);
|
||||
|
||||
@@ -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 == STT_STRING) {
|
||||
copy.as.literal.type = STT_STRING;
|
||||
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 {
|
||||
|
||||
150
src/vm/vm.c
150
src/vm/vm.c
@@ -1,150 +0,0 @@
|
||||
#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
75
src/vm/vm.h
@@ -1,75 +0,0 @@
|
||||
#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
10
src/vm/vm.md
@@ -1,10 +0,0 @@
|
||||
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
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "parser/parser.h"
|
||||
#include "codegen/codegen.h"
|
||||
|
||||
#include <groundvm.h>
|
||||
|
||||
|
||||
static char out_buf[65536];
|
||||
static int out_pos = 0;
|
||||
|
||||
@@ -5,7 +5,7 @@ if exists("b:current_syntax")
|
||||
endif
|
||||
|
||||
" Keywords
|
||||
syn keyword solsKeyword puts if while def lambda return use struct new private protected constructor destructor duplicator as ground
|
||||
syn keyword solsKeyword puts if while def lambda return use struct new private protected constructor destructor duplicator as ground module
|
||||
syn keyword solsBool true false
|
||||
|
||||
" Types
|
||||
@@ -28,6 +28,7 @@ syn match solsDelimiter /[{}(),;\[\]]/
|
||||
" Comments
|
||||
syn match solsComment /\/\/.*$/
|
||||
syn match solsComment /#.*$/
|
||||
syn region solsComment start="/\*" end="\*/" contains=@Spell
|
||||
|
||||
" Highlight links
|
||||
hi def link solsKeyword Keyword
|
||||
|
||||
Reference in New Issue
Block a user