11 Commits

10 changed files with 1382 additions and 210 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"
}

View File

@@ -53,7 +53,34 @@ static ResultType(SolsType, charptr) resolveValueType(SolsType* type, SolsScope*
if (type == NULL) {
return Error(SolsType, charptr, "Type is null");
}
if (type->type == STT_FUN) {
ResultType(SolsType, charptr) copiedResult = copySolsType(type);
if (copiedResult.error) {
return copiedResult;
}
SolsType resolved = copiedResult.as.success;
if (resolved.returnType != NULL && resolved.returnType->type != STT_NONE) {
ResultType(SolsType, charptr) resReturn = resolveValueType(resolved.returnType, scope);
if (resReturn.error) {
return resReturn;
}
*resolved.returnType = resReturn.as.success;
}
for (size_t i = 0; i < resolved.children.count; i++) {
ResultType(SolsType, charptr) resParam = resolveValueType(&resolved.children.at[i].type, scope);
if (resParam.error) {
return resParam;
}
resolved.children.at[i].type = resParam.as.success;
}
return Success(SolsType, charptr, resolved);
}
if (type->identifierType == NULL) {
if (type->type == STT_TEMPLATE && !type->metadata.isGenericStruct) {
SolsType resolved = *type;
resolved.type = STT_OBJECT;
return Success(SolsType, charptr, resolved);
}
return Success(SolsType, charptr, *type);
}
@@ -61,26 +88,62 @@ static ResultType(SolsType, charptr) resolveValueType(SolsType* type, SolsScope*
return Success(SolsType, charptr, *type);
}
if (type->type != STT_UNKNOWN &&
if (type->type != STT_UNKNOWN && type->type != STT_GENERIC &&
!(type->type == STT_OBJECT && type->children.count == 0)) {
return Success(SolsType, charptr, *type);
}
SolsVariable* var = findSolsVariable(scope, type->identifierType);
// If this identified type already has concrete children (from generic
// resolution), don't re-resolve from the scope — the caller already has
// the concrete version.
if (type->children.count > 0) {
return Success(SolsType, charptr, *type);
}
char* typeName = type->identifierType;
bool isGeneric = (type->type == STT_GENERIC);
Estr mangledName;
if (isGeneric) {
mangledName = CREATE_ESTR(type->identifierType);
APPEND_ESTR(mangledName, "_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) {
DESTROY_ESTR(mangledName);
return Error(SolsType, charptr, arg.as.error);
}
APPEND_ESTR(mangledName, arg.as.success.value.refName);
APPEND_ESTR(mangledName, "_");
}
typeName = mangledName.str;
}
SolsVariable* var = findSolsVariable(scope, typeName);
if (var == NULL) {
Estr estr = CREATE_ESTR("Unable to find type ");
APPEND_ESTR(estr, type->identifierType);
APPEND_ESTR(estr, typeName);
if (isGeneric) {
DESTROY_ESTR(mangledName);
}
return Error(SolsType, charptr, estr.str);
}
SolsType resolved = var->typeinfo;
ResultType(SolsType, charptr) resolvedResult = copySolsType(&var->typeinfo);
if (resolvedResult.error) {
if (isGeneric) {
DESTROY_ESTR(mangledName);
}
return Error(SolsType, charptr, resolvedResult.as.error);
}
SolsType resolved = resolvedResult.as.success;
if (resolved.type == STT_TEMPLATE) {
resolved.type = STT_OBJECT;
// Decrement to ignore constructor
resolved.children.count--;
if (resolved.children.count > 0) {
resolved.children.count--;
}
}
resolved.identifierType = type->identifierType;
resolved.identifierType = typeName;
if (resolved.type == STT_OBJECT && resolved.metadata.isEnum) {
return Success(SolsType, charptr, ({
@@ -299,7 +362,8 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
case SNT_DEF:
case SNT_CONSTRUCTOR:
case SNT_DESTRUCTOR:
case SNT_DUPLICATOR: {
case SNT_DUPLICATOR:
case SNT_STRUCT_AS: {
return Success(SolsType, charptr, node->as.type);
}
case SNT_FUNCTION_CALL: {
@@ -338,39 +402,18 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
return getNodeType(&node->children.at[node->children.count - 1], scope);
}
case SNT_NEW: {
SolsType type;
if (node->as.type.typeIsKnown) {
type = node->as.type;
} else {
SolsVariable* var = findSolsVariable(scope, node->as.type.identifierType);
if (var == NULL) {
Estr estr = CREATE_ESTR("Unable to find variable ");
if (node->type == SNT_TYPE) {
APPEND_ESTR(estr, node->as.type.identifierType);
}
return Error(SolsType, charptr, estr.str);
}
type = var->typeinfo;
}
if (type.metadata.isGenericField) {
return Success(SolsType, charptr, type);
}
switch (type.type) {
case STT_OBJECT:
char* typeName = node->as.type.identifierType;
if (typeName != NULL) {
SolsVariable* var = findSolsVariable(scope, typeName);
if (var != NULL && var->typeinfo.type == STT_OBJECT) {
return Error(SolsType, charptr, "Cannot use initialized type on new");
case STT_TEMPLATE: {
type.type = STT_OBJECT;
return Success(SolsType, charptr, type);
}
default: {
return Success(SolsType, charptr, type);
}
}
if (type.type == STT_OBJECT) {
return Error(SolsType, charptr, "Cannot use initialized type on new");
ResultType(SolsType, charptr) resolvedType = resolveValueType(&node->as.type, scope);
if (resolvedType.error) {
return Error(SolsType, charptr, resolvedType.as.error);
}
type.type = STT_OBJECT;
return Success(SolsType, charptr, type);
return Success(SolsType, charptr, resolvedType.as.success);
}
case SNT_DOT: {
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope);
@@ -381,7 +424,18 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
return Success(SolsType, charptr, type.as.success);
}
if (type.as.success.type != STT_OBJECT) {
return Error(SolsType, charptr, "Cannot use dot operator on non-object");
const char* typeNames[] = { "INT", "STRING", "DOUBLE", "BOOL", "CHAR", "FUN", "TEMPLATE", "OBJECT", "UNKNOWN", "GENERIC", "NONE" };
Estr err = CREATE_ESTR("Cannot use dot operator on non-object (actual type: ");
APPEND_ESTR(err, type.as.success.type <= STT_NONE ? typeNames[type.as.success.type] : "INVALID");
APPEND_ESTR(err, ", identifier: ");
APPEND_ESTR(err, type.as.success.identifierType ? type.as.success.identifierType : "NULL");
APPEND_ESTR(err, ") trying to access member ");
APPEND_ESTR(err, node->children.at[1].as.idName ? node->children.at[1].as.idName : "NULL");
APPEND_ESTR(err, " on line ");
char lineStr[32];
snprintf(lineStr, 32, "%zu", node->line.num);
APPEND_ESTR(err, lineStr);
return Error(SolsType, charptr, err.str);
}
ResultType(SolsType, charptr) child = findStructMemberType(&type.as.success, node->children.at[1].as.idName);
if (child.error) {
@@ -393,11 +447,11 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
return child;
}
case SNT_GENERIC_INIT: {
// Create a type name
Estr typeName = CREATE_ESTR(node->children.at[0].as.idName);
SolsType* genericType = &node->as.type;
Estr typeName = CREATE_ESTR(genericType->identifierType);
APPEND_ESTR(typeName, "_SOLS_GENERIC_");
for (size_t i = 0; i < node->children.count - 1; i++) {
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->children.at[i + 1].as.type, scope);
for (size_t i = 0; i < genericType->genericChildren.count; i++) {
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&genericType->genericChildren.at[i], scope);
if (arg.error) {
return Error(SolsType, charptr, arg.as.error);
}
@@ -409,7 +463,6 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
return Error(SolsType, charptr, "Unable to find created variable (this should not happen)");
}
return Success(SolsType, charptr, variable->typeinfo);
}
case SNT_AS: {
ResultType(SolsType, charptr) leftType = getNodeType(&node->children.at[0], scope);
@@ -549,6 +602,9 @@ ResultType(SolsType, charptr) getNodeType(SolsNode* node, SolsScope* scope) {
}
}
}
case SNT_TYPE: {
return Success(SolsType, charptr, node->as.type);
}
default: break;
}
return Error(SolsType, charptr, "Not yet implemented");
@@ -559,6 +615,40 @@ static inline ResultType(GroundProgram, charptr) generateLiteralNode(SolsNode* n
return Success(GroundProgram, charptr, groundCreateProgram());
}
static void renameTypeReferences(SolsType* type, char* oldName, char* newName) {
if (type == NULL) return;
if (type->identifierType != NULL && strcmp(type->identifierType, oldName) == 0) {
type->identifierType = strdup(newName);
}
for (size_t i = 0; i < type->children.count; i++) {
renameTypeReferences(&type->children.at[i].type, oldName, newName);
}
if (type->returnType != NULL && type->returnType->type != STT_NONE) {
renameTypeReferences(type->returnType, oldName, newName);
}
}
static void renameNodeTypeReferences(SolsNode* node, char* oldName, char* newName) {
if (node == NULL) return;
switch (node->type) {
case SNT_TYPE:
case SNT_LAMBDA:
case SNT_DEF:
case SNT_CONSTRUCTOR:
case SNT_DESTRUCTOR:
case SNT_DUPLICATOR:
case SNT_NEW:
case SNT_STRUCT_AS:
renameTypeReferences(&node->as.type, oldName, newName);
break;
default:
break;
}
for (size_t i = 0; i < node->children.count; i++) {
renameNodeTypeReferences(&node->children.at[i], oldName, newName);
}
}
static inline ResultType(GroundProgram, charptr) generatePutsNode(SolsNode* node, SolsScope* scope) {
if (node->children.count < 1) {
return Error(GroundProgram, charptr, "puts requires arguments");
@@ -590,7 +680,6 @@ static inline ResultType(GroundProgram, charptr) generateSetNode(SolsNode* node,
if (var == NULL) {
addVariableToScope(scope, node->children.at[0].as.idName, type.as.success);
} else {
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[0], scope);
if (type.error) {
return Error(GroundProgram, charptr, type.as.error);
}
@@ -1264,13 +1353,16 @@ ResultType(GroundProgram, charptr) generateFunctionCallNode(SolsNode* node, Sols
}
for (size_t i = 1; i < node->children.count; i++) {
ResultType(SolsType, charptr) type = getNodeType(&node->children.at[i], scope);
ResultType(SolsType, charptr) argtype = getNodeType(&node->children.at[i], scope);
if (type.error) {
return Error(GroundProgram, charptr, type.as.error);
}
if (compareTypes(&type.as.success, &type.as.success) == false) {
return Error(GroundProgram, charptr, "Types incorrect for function call");
size_t paramIdx = i - 1;
if (paramIdx < type.as.success.children.count) {
if (compareTypes(&argtype.as.success, &type.as.success.children.at[paramIdx].type) == false) {
return Error(GroundProgram, charptr, "Types incorrect for function call");
}
}
}
@@ -1338,12 +1430,42 @@ ResultType(GroundProgram, charptr) generateReturnNode(SolsNode* node, SolsScope*
}
if (scope->returnType.type == STT_UNKNOWN) {
scope->returnType = type.as.success;
ResultType(SolsType, charptr) resolvedType = resolveValueType(&node->children.at[0].as.type, scope);
if (resolvedType.error) {
return Error(GroundProgram, charptr, resolvedType.as.error);
}
scope->returnType = resolvedType.as.success;
scope->returnType.children.count++;
}
if (scope->returnType.type == STT_GENERIC && scope->returnType.genericChildren.count > 0 && scope->returnType.identifierType != NULL) {
Estr mangledName = CREATE_ESTR(scope->returnType.identifierType);
APPEND_ESTR(mangledName, "_SOLS_GENERIC_");
bool mangledOk = true;
for (size_t i = 0; i < scope->returnType.genericChildren.count && mangledOk; i++) {
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&scope->returnType.genericChildren.at[i], scope);
if (arg.error) {
mangledOk = false;
} else {
APPEND_ESTR(mangledName, arg.as.success.value.refName);
APPEND_ESTR(mangledName, "_");
}
}
if (mangledOk) {
SolsVariable* var = findSolsVariable(scope, mangledName.str);
if (var != NULL) {
SolsType* constructor = NULL;
for (size_t i = 0; i < var->typeinfo.children.count; i++) {
if (strcmp(var->typeinfo.children.at[i].name, "constructor") == 0) {
constructor = &var->typeinfo.children.at[i].type;
break;
}
}
if (constructor != NULL && constructor->returnType != NULL) {
scope->returnType = *constructor->returnType;
}
}
}
}
if (compareTypes(&type.as.success, &scope->returnType) == false) {
@@ -1639,13 +1761,41 @@ ResultType(Nothing, charptr) handleGenericStructNode(SolsNode* node, SolsScope*
addChildToSolsType(&genericType, childType.as.success, "constructor");
break;
}
// 'as T {}' needs to be generated based on the inputted types,
// it cannot be resolved here.
case SNT_STRUCT_AS: {
ResultType(SolsType, charptr) childType = getNodeType(child, &copyScope);
if (childType.error) {
return Error(Nothing, charptr, childType.as.error);
}
Estr methodName = CREATE_ESTR("");
SolsType* asType = &child->children.at[0].as.type;
if (asType->identifierType != NULL) {
methodName = CREATE_ESTR(asType->identifierType);
} else {
switch (asType->type) {
case STT_INT: methodName = CREATE_ESTR("int"); break;
case STT_STRING: methodName = CREATE_ESTR("string"); break;
case STT_DOUBLE: methodName = CREATE_ESTR("double"); break;
case STT_BOOL: methodName = CREATE_ESTR("bool"); break;
case STT_CHAR: methodName = CREATE_ESTR("char"); break;
default:
return Error(Nothing, charptr, "FIXME anonymous types not yet implemented in generic struct");
}
}
APPEND_ESTR(methodName, "_SOLS_AS");
childType.as.success.metadata.isPrivate = private;
childType.as.success.metadata.isProtected = protected;
addChildToSolsType(&genericType, childType.as.success, methodName.str);
break;
}
}
}
// Mark nested references to generic parameters so resolveValueType
// short-circuits instead of trying to look them up in the scope.
for (size_t i = 0; i < node->children.at[0].children.count; i++) {
markAsGenericField(&genericType, node->children.at[0].children.at[i].as.idName);
}
addVariableToScope(scope, node->as.idName, genericType);
return Success(Nothing, charptr, {});
}
@@ -1974,9 +2124,360 @@ ResultType(GroundProgram, charptr) generateStructNode(SolsNode* node, SolsScope*
return Success(GroundProgram, charptr, constants);
}
ResultType(GroundProgram, charptr) generateModuleNode(SolsNode* node, SolsScope* scope) {
SolsType type = ({
ResultType(SolsType, charptr) type = createSolsType(STT_TEMPLATE);
if (type.error) {
return Error(GroundProgram, charptr, type.as.error);
}
type.as.success;
});
SolsNode* constructor = NULL;
GroundProgram constants = groundCreateProgram();
GroundProgram structDef = groundCreateProgram();
GroundProgram initializer = groundCreateProgram();
GroundInstruction structDefInst = groundCreateInstruction(STRUCT);
Estr typeref = CREATE_ESTR(node->as.idName);
APPEND_ESTR(typeref, "_type");
groundAddReferenceToInstruction(&structDefInst, groundCreateReference(TYPEREF, typeref.str));
groundAddInstructionToProgram(&structDef, structDefInst);
for (size_t i = 0; i < node->children.count; i++) {
bool private = false;
bool protected = false;
// Add to type for type system
SolsNode* child = &node->children.at[i];
if (child->type == SNT_DEF_PRIVATE) {
private = true;
child->type = SNT_DEF;
}
if (child->type == SNT_SET_PRIVATE) {
private = true;
child->type = SNT_OP_SET;
}
if (child->type == SNT_STRUCT_PRIVATE) {
private = true;
child->type = SNT_STRUCT;
}
if (child->type == SNT_DEF_PROTECTED) {
protected = true;
child->type = SNT_DEF;
}
if (child->type == SNT_SET_PROTECTED) {
protected = true;
child->type = SNT_OP_SET;
}
if (child->type == SNT_STRUCT_PROTECTED) {
protected = true;
child->type = SNT_STRUCT;
}
if (child->type == SNT_DEF) {
ResultType(SolsType, charptr) childType = getNodeType(child, scope);
if (childType.error) {
return Error(GroundProgram, charptr, childType.as.error);
}
childType.as.success.metadata.isPrivate = private;
childType.as.success.metadata.isProtected = protected;
addChildToSolsType(&type, childType.as.success, child->children.at[0].as.idName);
// Add struct members to new scope
SolsScope childScope = copySolsScope(scope);
SolsType selfType = ({
ResultType(SolsType, charptr) _result = copySolsType(&type);
if (_result.error) {
return Error(GroundProgram, charptr, _result.as.error);
}
_result.as.success;
});
selfType.type = STT_OBJECT;
selfType.metadata.isProtected = true;
addVariableToScope(&childScope, "self", selfType);
// Generate the def node and add to struct
ResultType(GroundProgram, charptr) defNode = generateDefNode(child, &childScope);
if (defNode.error) {
return Error(GroundProgram, charptr, defNode.as.error);
}
for (size_t j = 0; j < defNode.as.success.size; j++) {
groundAddInstructionToProgram(&structDef, defNode.as.success.instructions[j]);
}
continue;
} else if (child->type == SNT_CONSTRUCTOR) {
constructor = child;
continue;
} else if (child->type == SNT_DESTRUCTOR) {
GroundInstruction destructorInst = groundCreateInstruction(FUN);
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(FNREF, "destructor"));
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(TYPEREF, "any"));
groundAddInstructionToProgram(&structDef, destructorInst);
SolsScope childScope = copySolsScope(scope);
SolsType selfType = ({
ResultType(SolsType, charptr) _result = copySolsType(&type);
if (_result.error) {
return Error(GroundProgram, charptr, _result.as.error);
}
_result.as.success;
});
selfType.type = STT_OBJECT;
addVariableToScope(&childScope, "self", selfType);
ResultType(GroundProgram, charptr) bodyCode = generateCode(child, &childScope);
if (bodyCode.error) return bodyCode;
for (size_t j = 0; j < bodyCode.as.success.size; j++) {
groundAddInstructionToProgram(&structDef, bodyCode.as.success.instructions[j]);
}
groundAddInstructionToProgram(&structDef, groundCreateInstruction(ENDFUN));
continue;
} else if (child->type == SNT_DUPLICATOR) {
GroundInstruction destructorInst = groundCreateInstruction(FUN);
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(FNREF, "duplicator"));
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(TYPEREF, "any"));
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(TYPEREF, "any"));
groundAddReferenceToInstruction(&destructorInst, groundCreateReference(DIRREF, "old"));
groundAddInstructionToProgram(&structDef, destructorInst);
SolsScope childScope = copySolsScope(scope);
SolsType selfType = ({
ResultType(SolsType, charptr) _result = copySolsType(&type);
if (_result.error) {
return Error(GroundProgram, charptr, _result.as.error);
}
_result.as.success;
});
selfType.type = STT_OBJECT;
selfType.metadata.isProtected = true;
addVariableToScope(&childScope, "self", selfType);
// Also add one as the old type
addVariableToScope(&childScope, "old", selfType);
ResultType(GroundProgram, charptr) bodyCode = generateCode(child, &childScope);
if (bodyCode.error) return bodyCode;
for (size_t j = 0; j < bodyCode.as.success.size; j++) {
groundAddInstructionToProgram(&structDef, bodyCode.as.success.instructions[j]);
}
GroundInstruction returnInst = groundCreateInstruction(RETURN);
groundAddReferenceToInstruction(&returnInst, groundCreateReference(VALREF, "self"));
groundAddInstructionToProgram(&structDef, returnInst);
groundAddInstructionToProgram(&structDef, groundCreateInstruction(ENDFUN));
continue;
} else if (child->type == SNT_STRUCT) {
SolsScope copyScope = copySolsScope(scope);
// Generate code for the struct
ResultType(GroundProgram, charptr) structCode = generateStructNode(child, &copyScope);
if (structCode.error) {
return structCode;
}
// Add struct to module
for (size_t i = 0; i < structCode.as.success.size; i++) {
groundAddInstructionToProgram(&structDef, structCode.as.success.instructions[i]);
}
// Move struct type info into module
SolsVariable* var = findSolsVariable(&copyScope, child->as.idName);
if (var == NULL) {
return Error(GroundProgram, charptr, "This error shouldn't happen lmao, for some reason the variable which should hold a struct isn't holding the struct");
}
} else if (child->type == SNT_STRUCT_AS) {
Estr methodName = CREATE_ESTR("");
SolsType* asType = &child->children.at[0].as.type;
if (asType->identifierType != NULL) {
methodName = CREATE_ESTR(asType->identifierType);
} else {
switch (asType->type) {
case STT_INT:
methodName = CREATE_ESTR("int");
break;
case STT_STRING:
methodName = CREATE_ESTR("string");
break;
case STT_DOUBLE:
methodName = CREATE_ESTR("double");
break;
case STT_BOOL:
methodName = CREATE_ESTR("bool");
break;
case STT_CHAR:
methodName = CREATE_ESTR("char");
break;
case STT_FUN:
case STT_TEMPLATE:
case STT_OBJECT:
case STT_UNKNOWN:
case STT_NONE:
// FIXME handle anonymous stuff later
return Error(GroundProgram, charptr, "FIXME anonymous types are not yet implemented");
break;
}
}
APPEND_ESTR(methodName, "_SOLS_AS");
ResultType(SolsType, charptr) resolved = resolveValueType(child->as.type.returnType, scope);
if (resolved.error) {
return Error(GroundProgram, charptr, resolved.as.error);
}
*child->as.type.returnType = resolved.as.success;
GroundInstruction asInst = groundCreateInstruction(FUN);
groundAddReferenceToInstruction(&asInst, groundCreateReference(FNREF, methodName.str));
groundAddReferenceToInstruction(&asInst, ({
ResultType(GroundArg, charptr) _result = createGroundArgFromSolsType(asType, scope);
if (_result.error) {
return Error(GroundProgram, charptr, _result.as.error);
}
_result.as.success;
}));
groundAddInstructionToProgram(&structDef, asInst);
SolsScope childScope = copySolsScope(scope);
SolsType selfType = ({
ResultType(SolsType, charptr) _result = copySolsType(&type);
if (_result.error) {
return Error(GroundProgram, charptr, _result.as.error);
}
_result.as.success;
});
selfType.type = STT_OBJECT;
selfType.metadata.isProtected = true;
addVariableToScope(&childScope, "self", selfType);
childScope.returnType = *asType;
ResultType(GroundProgram, charptr) bodyCode = generateCode(child, &childScope);
if (bodyCode.error) return bodyCode;
for (size_t j = 0; j < bodyCode.as.success.size; j++) {
groundAddInstructionToProgram(&structDef, bodyCode.as.success.instructions[j]);
}
groundAddInstructionToProgram(&structDef, groundCreateInstruction(ENDFUN));
child->as.type.metadata.isProtected = true;
addChildToSolsType(&type, child->as.type, methodName.str);
continue;
}
ResultType(SolsType, charptr) childType = getNodeType(&child->children.at[1], scope);
if (childType.error) {
return Error(GroundProgram, charptr, childType.as.error);
}
childType.as.success.metadata.isPrivate = private;
childType.as.success.metadata.isProtected = protected;
addChildToSolsType(&type, childType.as.success, child->children.at[0].as.idName);
// Generate constant initial value
ResultType(GroundProgram, charptr) childCode = generateCode(&child->children.at[1], scope);
if (childCode.error) {
return Error(GroundProgram, charptr, childCode.as.error);
}
for (size_t j = 0; j < childCode.as.success.size; j++) {
groundAddInstructionToProgram(&constants, childCode.as.success.instructions[j]);
}
// Add to struct
GroundInstruction structInst = groundCreateInstruction(SET);
groundAddReferenceToInstruction(&structInst, groundCreateReference(DIRREF, child->children.at[0].as.idName));
groundAddReferenceToInstruction(&structInst, child->children.at[1].accessArg);
groundAddInstructionToProgram(&structDef, structInst);
}
groundAddInstructionToProgram(&structDef, groundCreateInstruction(ENDSTRUCT));
// Construct constructor
if (constructor != NULL) {
GroundInstruction constructorInst = groundCreateInstruction(FUN);
Estr constructorName = CREATE_ESTR(typeref.str);
APPEND_ESTR(constructorName, "_SOLS_CONSTRUCTOR");
groundAddReferenceToInstruction(&constructorInst, groundCreateReference(FNREF, constructorName.str));
groundAddReferenceToInstruction(&constructorInst, groundCreateReference(TYPEREF, typeref.str));
// Module constructors do not take arguments
groundAddInstructionToProgram(&structDef, constructorInst);
GroundInstruction constructorSelf = groundCreateInstruction(INIT);
groundAddReferenceToInstruction(&constructorSelf, groundCreateReference(DIRREF, "self"));
groundAddReferenceToInstruction(&constructorSelf, groundCreateReference(TYPEREF, typeref.str));
groundAddInstructionToProgram(&structDef, constructorSelf);
SolsScope childScope = copySolsScope(scope);
addVariableToScope(&childScope, "self", type);
// Modify self so that all members are not private or protected
SolsVariable* variable = findSolsVariable(&childScope, "self");
if (variable == NULL) {
return Error(GroundProgram, charptr, "Failed to find self variable (this should never happen)");
}
for (size_t i = 0; i < variable->typeinfo.children.count; i++) {
variable->typeinfo.children.at[i].type.metadata.isPrivate = false;
variable->typeinfo.children.at[i].type.metadata.isProtected = false;
}
ResultType(GroundProgram, charptr) constructorCode = generateCode(&constructor->children.at[0], &childScope);
if (constructorCode.error) {
return Error(GroundProgram, charptr, constructorCode.as.error);
}
for (size_t i = 0; i < constructorCode.as.success.size; i++) {
groundAddInstructionToProgram(&structDef, constructorCode.as.success.instructions[i]);
}
GroundInstruction ret = groundCreateInstruction(RETURN);
groundAddReferenceToInstruction(&ret, groundCreateReference(VALREF, "self"));
groundAddInstructionToProgram(&structDef, ret);
groundAddInstructionToProgram(&structDef, groundCreateInstruction(ENDFUN));
*constructor->as.type.returnType = type;
constructor->as.type.returnType->type = STT_OBJECT;
addChildToSolsType(&type, constructor->as.type, "constructor");
addVariableToScope(scope, constructorName.str, constructor->as.type);
// Add to initializer
GroundInstruction inst = groundCreateInstruction(CALL);
groundAddReferenceToInstruction(&inst, groundCreateReference(FNREF, constructorName.str));
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, node->as.idName));
groundAddInstructionToProgram(&initializer, inst);
} else {
GroundInstruction inst = groundCreateInstruction(INIT);
groundAddReferenceToInstruction(&inst, groundCreateReference(DIRREF, node->as.idName));
groundAddReferenceToInstruction(&inst, groundCreateReference(TYPEREF, typeref.str));
groundAddInstructionToProgram(&initializer, inst);
}
// Add type to scope
addVariableToScope(scope, typeref.str, type);
// Add module to scope
type.type = STT_OBJECT;
addVariableToScope(scope, node->as.idName, type);
// Combine into one program
for (size_t i = 0; i < structDef.size; i++) {
groundAddInstructionToProgram(&constants, structDef.instructions[i]);
}
for (size_t i = 0; i < initializer.size; i++) {
groundAddInstructionToProgram(&constants, initializer.instructions[i]);
}
return Success(GroundProgram, charptr, constants);
}
ResultType(Nothing, charptr) resolveGeneric(char* genericName, SolsType* oldType, SolsType newType);
ResultType(Nothing, charptr) resolveGeneric(char* genericName, SolsType* oldType, SolsType newType) {
if ((oldType->type == STT_UNKNOWN || oldType->type == STT_GENERIC)
if ((oldType->type == STT_UNKNOWN
|| oldType->type == STT_GENERIC
|| (oldType->type == STT_TEMPLATE && oldType->metadata.isGenericField))
&& oldType->identifierType != NULL
&& strcmp(oldType->identifierType, genericName) == 0)
{
@@ -2014,7 +2515,6 @@ ResultType(Nothing, charptr) resolveNodeGeneric(char* genericName, SolsNode* nod
case SNT_TYPE:
case SNT_LAMBDA:
case SNT_DEF:
case SNT_OP_SET:
case SNT_CONSTRUCTOR:
case SNT_DESTRUCTOR:
case SNT_DUPLICATOR:
@@ -2043,30 +2543,23 @@ ResultType(Nothing, charptr) resolveNodeGeneric(char* genericName, SolsNode* nod
// Call this function when a generic struct is being used, and a new node needs to be generated
// node is the generic call node
ResultType(GroundProgram, charptr) generateGenericInitNode(SolsNode* node, SolsScope* scope) {
// Create a type name
Estr typeName = CREATE_ESTR(node->children.at[0].as.idName);
APPEND_ESTR(typeName, "_SOLS_GENERIC_");
for (size_t i = 0; i < node->children.count - 1; i++) {
ResultType(GroundArg, charptr) arg = createGroundArgFromSolsType(&node->children.at[i + 1].as.type, scope);
if (arg.error) {
return Error(GroundProgram, charptr, arg.as.error);
}
APPEND_ESTR(typeName, arg.as.success.value.refName);
APPEND_ESTR(typeName, "_");
SolsType* genericType = &node->as.type;
// Create a derived (mangled) type name from the base type + arguments
ResultType(GroundArg, charptr) argName = createGroundArgFromSolsType(genericType, scope);
if (argName.error) {
return Error(GroundProgram, charptr, argName.as.error);
}
node->accessArg = groundCreateReference(TYPEREF, typeName.str);
SolsVariable* variable = findSolsVariable(scope, typeName.str);
node->accessArg = argName.as.success;
// Already monomorphized — just return a type reference
SolsVariable* variable = findSolsVariable(scope, argName.as.success.value.refName);
if (variable != NULL) {
// We've already created this struct
char* tmpId = malloc(sizeof(char) * 64);
if (tmpId == NULL) {
return Error(GroundProgram, charptr, "Failed to allocate memory");
}
snprintf(tmpId, 64, "__SOLS_GENERIC_INIT_%zu", scope->tmpCounter++);
node->accessArg = groundCreateReference(TYPEREF, tmpId);
return Success(GroundProgram, charptr, groundCreateProgram());
}
variable = findSolsVariable(scope, node->children.at[0].as.idName);
// Find the generic struct definition
variable = findSolsVariable(scope, genericType->identifierType);
if (variable == NULL) {
return Error(GroundProgram, charptr, "Failed to find generic struct");
}
@@ -2083,16 +2576,16 @@ ResultType(GroundProgram, charptr) generateGenericInitNode(SolsNode* node, SolsS
if (type.metadata.genericStructNode == NULL) {
return Error(GroundProgram, charptr, "Generic struct node is null (this should never happen)");
}
if (node->children.count - 1 != type.metadata.genericStructNode->children.at[0].children.count) {
if (genericType->genericChildren.count != type.metadata.genericStructNode->children.at[0].children.count) {
return Error(GroundProgram, charptr, "Generic struct node has wrong number of arguments");
}
SolsNode* genericStructNode = type.metadata.genericStructNode;
// Deep-copy the node so we don't mutate the original AST
SolsNode concreteStructNode = deepCopySolsNode(*type.metadata.genericStructNode);
for (size_t i = 0; i < node->children.count - 1; i++) {
for (size_t i = 0; i < genericType->genericChildren.count; i++) {
char* genericFieldName = genericStructNode->children.at[0].children.at[i].as.idName;
SolsType concreteType = node->children.at[i + 1].as.type;
SolsType concreteType = genericType->genericChildren.at[i];
ResultType(Nothing, charptr) result = resolveGeneric(genericFieldName, &type, concreteType);
if (result.error) {
@@ -2105,9 +2598,13 @@ ResultType(GroundProgram, charptr) generateGenericInitNode(SolsNode* node, SolsS
}
}
// Rename type references from the short name to the mangled concrete name
// so that resolveValueType finds the concrete instance in the scope
renameNodeTypeReferences(&concreteStructNode, genericStructNode->as.idName, argName.as.success.value.refName);
// Now run struct codegen on the patched copy
// (renaming it first so it gets a unique type name in Ground)
concreteStructNode.as.idName = typeName.str;
concreteStructNode.as.idName = argName.as.success.value.refName;
concreteStructNode.children.at[0].children.count = 0;
return generateStructNode(&concreteStructNode, scope);
}
@@ -2298,10 +2795,177 @@ ResultType(GroundProgram, charptr) generateSizeOfNode(SolsNode* node, SolsScope*
return Success(GroundProgram, charptr, gp);
}
static ResultType(Nothing, charptr) resolveGenericTypesInSolsType(SolsType* type, SolsScope* scope, GroundProgram* structDefs, SolsNode* debugNode) {
if (type == NULL) {
return Success(Nothing, charptr, {});
}
for (size_t i = 0; i < type->genericChildren.count; i++) {
ResultType(Nothing, charptr) res = resolveGenericTypesInSolsType(&type->genericChildren.at[i], scope, structDefs, debugNode);
if (res.error) return res;
}
for (size_t i = 0; i < type->children.count; i++) {
ResultType(Nothing, charptr) res = resolveGenericTypesInSolsType(&type->children.at[i].type, scope, structDefs, debugNode);
if (res.error) return res;
}
if (type->returnType != NULL) {
ResultType(Nothing, charptr) res = resolveGenericTypesInSolsType(type->returnType, scope, structDefs, debugNode);
if (res.error) return res;
}
if (type->type == STT_GENERIC) {
// If it has 0 generic arguments, it's not a concrete generic type reference
// (it might be a placeholder/template name like MyStruct without arguments,
// or a generic parameter like T).
if (type->genericChildren.count == 0) {
return Success(Nothing, charptr, {});
}
ResultType(GroundArg, charptr) argName = createGroundArgFromSolsType(type, scope);
if (argName.error) {
return Error(Nothing, charptr, argName.as.error);
}
SolsVariable* variable = findSolsVariable(scope, argName.as.success.value.refName);
if (variable == NULL) {
variable = findSolsVariable(scope, type->identifierType);
if (variable == NULL) {
Estr estr = CREATE_ESTR("Failed to find generic struct ");
APPEND_ESTR(estr, type->identifierType);
return Error(Nothing, charptr, estr.str);
}
if (!variable->typeinfo.metadata.isGenericStruct) {
return Error(Nothing, charptr, "Specified type is not a generic struct");
}
SolsType structType = ({
ResultType(SolsType, charptr) _result = copySolsType(&variable->typeinfo);
if (_result.error) {
return Error(Nothing, charptr, _result.as.error);
}
_result.as.success;
});
if (structType.metadata.genericStructNode == NULL) {
return Error(Nothing, charptr, "Generic struct node is null");
}
if (type->genericChildren.count != structType.metadata.genericStructNode->children.at[0].children.count) {
return Error(Nothing, charptr, "Generic struct node has wrong number of arguments");
}
SolsNode* genericStructNode = structType.metadata.genericStructNode;
SolsNode concreteStructNode = deepCopySolsNode(*structType.metadata.genericStructNode);
for (size_t i = 0; i < type->genericChildren.count; i++) {
char* genericFieldName = genericStructNode->children.at[0].children.at[i].as.idName;
SolsType concreteType = type->genericChildren.at[i];
ResultType(Nothing, charptr) result = resolveGeneric(genericFieldName, &structType, concreteType);
if (result.error) {
return Error(Nothing, charptr, result.as.error);
}
result = resolveNodeGeneric(genericFieldName, &concreteStructNode, concreteType);
if (result.error) {
return Error(Nothing, charptr, result.as.error);
}
}
renameNodeTypeReferences(&concreteStructNode, genericStructNode->as.idName, argName.as.success.value.refName);
concreteStructNode.as.idName = argName.as.success.value.refName;
concreteStructNode.children.at[0].children.count = 0;
ResultType(GroundProgram, charptr) generatedStruct = generateStructNode(&concreteStructNode, scope);
if (generatedStruct.error) {
return Error(Nothing, charptr, generatedStruct.as.error);
}
for (size_t j = 0; j < generatedStruct.as.success.size; j++) {
groundAddInstructionToProgram(structDefs, generatedStruct.as.success.instructions[j]);
}
}
}
return Success(Nothing, charptr, {});
}
static ResultType(Nothing, charptr) resolveGenericTypesInAST(SolsNode* node, SolsScope* scope, GroundProgram* structDefs) {
if (node == NULL) {
return Success(Nothing, charptr, {});
}
if (node->type == SNT_TYPE || node->type == SNT_DEF || node->type == SNT_NEW || node->type == SNT_GENERIC_INIT) {
ResultType(Nothing, charptr) res = resolveGenericTypesInSolsType(&node->as.type, scope, structDefs, node);
if (res.error) return res;
}
if (node->type == SNT_STRUCT_AS) {
if (node->children.count > 0) {
ResultType(Nothing, charptr) res = resolveGenericTypesInAST(&node->children.at[0], scope, structDefs);
if (res.error) return res;
}
}
bool isGenericStructTemplate = (node->type == SNT_STRUCT && node->children.count > 0 && node->children.at[0].type == SNT_GENERIC && node->children.at[0].children.count > 0);
if (!isGenericStructTemplate) {
for (size_t i = 0; i < node->children.count; i++) {
ResultType(Nothing, charptr) res = resolveGenericTypesInAST(&node->children.at[i], scope, structDefs);
if (res.error) return res;
}
}
return Success(Nothing, charptr, {});
}
ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope) {
GroundProgram program = groundCreateProgram();
if (node->type == SNT_ROOT) {
// 1. Generate code for all SNT_STRUCT, SNT_USE, and SNT_LOCAL_USE children first (this registers them in scope and emits their definitions)
for (size_t i = 0; i < node->children.count; i++) {
if (node->children.at[i].type == SNT_STRUCT ||
node->children.at[i].type == SNT_USE ||
node->children.at[i].type == SNT_LOCAL_USE) {
ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope);
if (generated.error) {
return Error(GroundProgram, charptr, createCodegenError(&node->children.at[i], generated.as.error));
}
for (size_t j = 0; j < generated.as.success.size; j++) {
groundAddInstructionToProgram(&program, generated.as.success.instructions[j]);
}
}
}
// 2. Resolve and monomorphize all generic types referenced in the entire AST
GroundProgram structDefs = groundCreateProgram();
ResultType(Nothing, charptr) res = resolveGenericTypesInAST(node, scope, &structDefs);
if (res.error) {
return Error(GroundProgram, charptr, res.as.error);
}
for (size_t j = 0; j < structDefs.size; j++) {
groundAddInstructionToProgram(&program, structDefs.instructions[j]);
}
// 3. Generate code for the remaining children
for (size_t i = 0; i < node->children.count; i++) {
if (node->children.at[i].type != SNT_STRUCT &&
node->children.at[i].type != SNT_USE &&
node->children.at[i].type != SNT_LOCAL_USE) {
ResultType(GroundProgram, charptr) generated = generateCode(&node->children.at[i], scope);
if (generated.error) {
return Error(GroundProgram, charptr, createCodegenError(&node->children.at[i], generated.as.error));
}
for (size_t j = 0; j < generated.as.success.size; j++) {
groundAddInstructionToProgram(&program, generated.as.success.instructions[j]);
}
}
}
return Success(GroundProgram, charptr, program);
}
SolsScope backupScope = {NULL, 0};
if (node->type != SNT_IF && node->type != SNT_WHILE && node->type != SNT_LAMBDA &&
@@ -2354,6 +3018,7 @@ ResultType(GroundProgram, charptr) generateCode(SolsNode* node, SolsScope* scope
case SNT_FUNCTION_CALL: generate(FunctionCall);
case SNT_RETURN: generate(Return);
case SNT_USE: generate(Use);
case SNT_MODULE: generate(Module);
case SNT_LOCAL_USE: generate(LocalUse);
case SNT_GROUND: generate(InlineGround);
case SNT_STRUCT: generate(Struct);

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

@@ -16,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,
@@ -41,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,
@@ -62,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
};
@@ -116,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);
}
/*
@@ -292,6 +319,19 @@ ResultType(GroundArg, charptr) createGroundArgFromSolsType(SolsType* type, struc
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?");
}
@@ -360,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

@@ -70,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;
@@ -130,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},

View File

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

View File

@@ -7,6 +7,134 @@
#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;
@@ -167,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) {
@@ -912,7 +1114,7 @@ static inline ResultType(Nothing, charptr) parseLiteral(SolsParser* parser) {
break;
}
case SLT_STRING: {
value = groundCreateValue(STRING, peek.as.success.as.literal.as.stringv);
value = groundCreateValue(STRING, parseEscapeSequences(peek.as.success.as.literal.as.stringv));
break;
}
case SLT_BOOL: {
@@ -1204,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);
@@ -1227,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);
@@ -1245,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);
@@ -1349,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);
@@ -1372,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);
@@ -1390,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);
@@ -1701,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) {
@@ -1720,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");
@@ -2132,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);
}
@@ -2267,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, {});
}
@@ -2369,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) {
@@ -2420,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, {});
}
@@ -2581,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

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