11 Commits

19 changed files with 1524 additions and 559 deletions

37
libs/box.sols Normal file
View 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
View 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

View File

@@ -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;\
}

View File

@@ -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;
}
}
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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, {});
}

View File

@@ -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

View File

@@ -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)");

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

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 == 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 {

View File

@@ -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]);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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