Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ed3975285 | |||
| 1da7f91313 | |||
| 6a936bf282 | |||
| 8a8e4381bf | |||
| b78a5ee7bb | |||
| cbc92b5b1d | |||
| 45c9d9ee37 | |||
| 3003605031 | |||
| c68bf1b662 | |||
| 3c36e92261 | |||
| 246a212cb9 |
37
libs/box.sols
Normal file
37
libs/box.sols
Normal file
@@ -0,0 +1,37 @@
|
||||
struct _box {
|
||||
private ptr = 0
|
||||
def get() int { return 0 }
|
||||
def set() int { return 0 }
|
||||
def free() int { return 0 }
|
||||
}
|
||||
|
||||
ground {
|
||||
extern "_box"
|
||||
}
|
||||
|
||||
/*
|
||||
Shared mutable object. Use with caution - may cause impurities!
|
||||
*/
|
||||
struct Box[T] {
|
||||
|
||||
private box = new _box
|
||||
|
||||
def get() T {
|
||||
retval = new T
|
||||
ground { callmethod &self &box !get &retval }
|
||||
return retval
|
||||
}
|
||||
|
||||
def set(T in) int {
|
||||
ground { callmethod &self &box !set $in &retval }
|
||||
return 0
|
||||
}
|
||||
|
||||
def free() int {
|
||||
ground { callmethod &self &box !free &retval }
|
||||
return 0
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
}
|
||||
9
libs/socket.sols
Normal file
9
libs/socket.sols
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Function that blocks the main thread which listens to TCP connections.
|
||||
All connection data will be pass
|
||||
*/
|
||||
def socket_Listen(fun(string) string handler, int port) int {}
|
||||
|
||||
ground {
|
||||
extern "socket"
|
||||
}
|
||||
@@ -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, ©Scope);
|
||||
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, ©Scope);
|
||||
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(©Scope, 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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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, {});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -5,7 +5,7 @@ if exists("b:current_syntax")
|
||||
endif
|
||||
|
||||
" Keywords
|
||||
syn keyword solsKeyword puts if while def lambda return use struct new private protected constructor destructor duplicator as ground
|
||||
syn keyword solsKeyword puts if while def lambda return use struct new private protected constructor destructor duplicator as ground module
|
||||
syn keyword solsBool true false
|
||||
|
||||
" Types
|
||||
@@ -28,6 +28,7 @@ syn match solsDelimiter /[{}(),;\[\]]/
|
||||
" Comments
|
||||
syn match solsComment /\/\/.*$/
|
||||
syn match solsComment /#.*$/
|
||||
syn region solsComment start="/\*" end="\*/" contains=@Spell
|
||||
|
||||
" Highlight links
|
||||
hi def link solsKeyword Keyword
|
||||
|
||||
Reference in New Issue
Block a user