Author: mesyeti <mesyeti@mesyeti.uk>
add methods
basic/examples/methods.bas | 19 ++++++++ basic/source/frontend/c89.c | 77 ++++++++++++++++++++++++++++++++-- basic/source/parser.c | 2 basic/source/parser.h | 2 basic/source/semanticAnalysis.c | 40 ++++++++++++++---- basic/source/state.c | 16 +++++++ basic/source/state.h | 4 + basic/source/string.c | 2 basic/source/string.h | 2 basic/test.bas | 2
diff --git a/basic/examples/methods.bas b/basic/examples/methods.bas new file mode 100644 index 0000000000000000000000000000000000000000..e264ed1f9b568b040745b81607956fd8c2c1f5ce --- /dev/null +++ b/basic/examples/methods.bas @@ -0,0 +1,19 @@ +'NITRON + +program test + +extern func puts(str as ptr(char)) i32 +extern func printf(str as ptr(char), val as int) i32 + +type Manul + value as int +end + +sub Manul_Print(this as ptr(Manul)) + printf("manul = %d\n", this.value) +end + +dim manul as Manul +manul.value = 5 + +manul.Print() diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c index c6cb13fcaeaa9f8a82c709ab0d229db6d303e1fc..3fafe168557c18f557f82fa3cffa655951c5d0d9 100644 --- a/basic/source/frontend/c89.c +++ b/basic/source/frontend/c89.c @@ -10,6 +10,12 @@ static FILE* out; static bool inMain; static bool inFunc; +// state +static bool isMethod = false; +static Node* methodParam; +static UsedType methodType; +static Function funcCall; + static void Finish(bool program) { if (program) { fprintf(out, "}\n"); @@ -33,9 +39,9 @@ fprintf(out, "int main(int argc, char** argv) {\n"); } -static void Unexpected(ErrorInfo err, NodeType type) { - PrintError(err, "Unexpected '%s'", Parser_TypeStr(type)); -} +// static void Unexpected(ErrorInfo err, NodeType type) { +// PrintError(err, "Unexpected '%s'", Parser_TypeStr(type)); +// } static void CompileUsedType(UsedType used) { Type* type = State_GetTypeFromUsed(used); @@ -80,6 +86,16 @@ CompileDec(node->dec); fprintf(out, " {\n"); inFunc = true; + State_AddScope(); + + // add parameters + for (size_t i = 0; i < node->dec.paramsNum; ++ i) { + Var var; + var.type = SemanticAnalysis_NodeAsUsedType(node->dec.params[i].type); + var.name = NewString(node->dec.params[i].name); + + State_AddVar(var); + } for (size_t i = 0; i < node->bodyLen; ++ i) { Compiler_CompileBodyNode(&node->body[i]); @@ -87,6 +103,7 @@ } fprintf(out, "}\n"); + State_FreeScope(); inFunc = false; } @@ -98,6 +115,17 @@ Type* type = &state.types[usedType.typeIdx]; CompileType(node->varType); fprintf(out, " nitron_%s = %s;\n", node->name, type->type == TYPE_PRIM? "0" : "{0}"); + + // add variable to state + Var var; + var.type = SemanticAnalysis_NodeAsUsedType(node->varType); + var.name = NewString(node->name); + + if (node->array) { + var.type.array = node->arrayLen->integer.value; + } + + State_AddVar(var); } static void CompileExprNode(Node* node); @@ -105,6 +133,18 @@ static void CompileFuncCallExpr(FuncCallNode* node) { fprintf(out, "("); + if (isMethod) { + if (funcCall.params[0].type.ptr == methodType.ptr + 1) { + fprintf(out, "&"); + } + + CompileExprNode(methodParam); + + if (node->paramsNum > 0) { + fprintf(out, ", "); + } + } + for (size_t i = 0; i < node->paramsNum; ++ i) { CompileExprNode(&node->params[i]); @@ -144,8 +184,33 @@ } break; } case NODE_BINARY_OP: { + Node* left = node->bin.left; + Node leftNode; // set `left` to this if it's a method + + if (node->bin.op == TOKEN_LPAREN) + if (node->bin.left->i.type == NODE_BINARY_OP) + if (node->bin.left->bin.op == TOKEN_DOT) + if (node->bin.left->i.flags == 1) { + isMethod = true; + methodParam = node->bin.left->bin.left; + + UsedType methodType = SemanticAnalysis_EvalType(node->bin.left->bin.left); + + leftNode.i = left->i; + leftNode.i.type = NODE_IDENTIFIER; + leftNode.ident.name = State_FindMethod( + &state.types[methodType.typeIdx], node->bin.left->bin.right->ident.name + )->name; + + left = &leftNode; + } + + if (node->bin.op == TOKEN_LPAREN) { + funcCall = state.types[SemanticAnalysis_EvalType(node->bin.left).typeIdx].func; + } + fprintf(out, "("); - CompileExprNode(node->bin.left); + CompileExprNode(left); switch (node->bin.op) { case TOKEN_ADD: fprintf(out, "+"); break; @@ -162,7 +227,7 @@ case TOKEN_ACCESS_XOR: fprintf(out, "^"); break; case TOKEN_ADDRESS_AND: fprintf(out, "&"); break; case TOKEN_BIT_OR: fprintf(out, "|"); break; case TOKEN_DOT: { - UsedType type = SemanticAnalysis_NodeAsUsedType(node->bin.left); + UsedType type = SemanticAnalysis_EvalType(node->bin.left); if (type.ptr) { fprintf(out, "->"); @@ -299,7 +364,7 @@ for (size_t i = 0; i < type->structLen; ++ i) { fprintf(out, " "); CompileUsedType(type->structure[i].type); - fprintf(out, " %s;\n", type->structure[i].name); + fprintf(out, " nitron_%s;\n", type->structure[i].name); } fprintf(out, "} nitron_%s;", type->name); diff --git a/basic/source/parser.c b/basic/source/parser.c index cb7ce0fb159f75ed5430e4cee67cdfbd1c15a76f..2e2135c7576eef6685f888487f4563ffb4028ed8 100644 --- a/basic/source/parser.c +++ b/basic/source/parser.c @@ -51,7 +51,7 @@ return ret; } -#define INFO(TYPE) ((NodeInfo) {TYPE, p->tokens[p->i].err}) +#define INFO(TYPE) ((NodeInfo) {TYPE, p->tokens[p->i].err, 0}) static Node ParseBinary(Parser* p); static Node ParseNode(Parser* p); diff --git a/basic/source/parser.h b/basic/source/parser.h index 44d7f5966696bb6110814a2ea14725cbc7ff4b7d..15a947e63cb6672b56c65b0162bdac7cbe1bd583 100644 --- a/basic/source/parser.h +++ b/basic/source/parser.h @@ -30,6 +30,7 @@ typedef struct { NodeType type; ErrorInfo err; + uint8_t flags; } NodeInfo; typedef union Node Node; @@ -49,6 +50,7 @@ NodeInfo i; char* name; } IdentifierNode; +// set the flag to 1 if this is a function call to a method typedef struct { NodeInfo i; Node* left; diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c index 9eb9f24829a08d064b4b1e59d41ca94eb3143539..98268be0227c22f91703d573f47cd89be6f81a75 100644 --- a/basic/source/semanticAnalysis.c +++ b/basic/source/semanticAnalysis.c @@ -52,8 +52,9 @@ } UsedType SemanticAnalysis_NodeAsUsedType(Node* node) { UsedType ret; - ret.ptr = 0; - ret.array = false; // no arrays yet + ret.ptr = 0; + ret.array = false; // no arrays yet + ret.method = false; while (true) { switch (node->i.type) { @@ -81,7 +82,7 @@ } } #define GET_PRIM(NAME, PTR) \ - ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0}) + ((UsedType) {(PTR), State_GetType(NAME) - state.types, 0, false}) static bool AssignCompatible(UsedType left, UsedType right) { Type* leftType = State_GetTypeFromUsed(left); @@ -133,6 +134,27 @@ return leftType->structure[i].type; } } + // now see if this is a method instead of a member + Var* method = State_FindMethod(leftType, member); + if (method) { + Type* methodFunc = &state.types[method->type.typeIdx]; + + if ((method->type.ptr > 1) || (method->type.array > 0)) { + PrintError(node->i.err, "Cannot use this type as a method"); + } + if (methodFunc->type != TYPE_FUNC) { + PrintError(node->i.err, "Using non-function type as method"); + } + if (methodFunc->func.paramsLen == 0) { + PrintError(node->i.err, "Cannot use function with zero parameters as a method"); + } + + UsedType ret = method->type; + ret.method = true; + node->i.flags = 1; + return ret; + } + PrintError(node->i.err, "Type '%s' does not have member '%s'", leftType->name, member); return GET_PRIM("unit", 0); } @@ -149,14 +171,14 @@ Node* call = node->bin.right; Function* func = &leftType->func; - if (func->paramsLen != call->funcCall.paramsNum) { + if (func->paramsLen - (left.method? 1 : 0) != call->funcCall.paramsNum) { PrintError( call->i.err, "Expected %d parameters, got %d", - func->paramsLen, call->funcCall.paramsNum + func->paramsLen - (left.method? 1 : 0), call->funcCall.paramsNum ); } - for (size_t i = 0; i < func->paramsLen; ++ i) { + for (size_t i = left.method? 1 : 0; i < func->paramsLen; ++ i) { UsedType type = SemanticAnalysis_EvalType(&call->funcCall.params[i]); UsedType param = func->params[i].type; Type* paramType = State_GetTypeFromUsed(param); @@ -191,7 +213,6 @@ } } static UsedType EvalArrayAccess(Node* node, UsedType left, UsedType right) { - Type* leftType = State_GetTypeFromUsed(left); Type* rightType = State_GetTypeFromUsed(right); if ((left.array > 0) || (left.ptr > 0)) { @@ -364,6 +385,7 @@ PrintError( node->i.err, "Incompatible types in '%s' operation", Lexer_TypeVAsString(node->bin.op) ); + break; } } case TOKEN_ACCESS_XOR: @@ -505,7 +527,7 @@ size_t funcTypeIdx = State_AddType(type); // create variable for this function Var funcVar; - funcVar.type = (UsedType) {0, funcTypeIdx, 0}; + funcVar.type = (UsedType) {0, funcTypeIdx, 0, false}; funcVar.name = NewString(node->funcDef.dec.name); State_AddVar(funcVar); @@ -567,7 +589,7 @@ size_t funcTypeIdx = State_AddType(type); // create variable for this function Var funcVar; - funcVar.type = (UsedType) {0, funcTypeIdx, 0}; + funcVar.type = (UsedType) {0, funcTypeIdx, 0, false}; funcVar.name = node->funcDef.dec.name; State_AddVar(funcVar); diff --git a/basic/source/state.c b/basic/source/state.c index 5cdc7e708e75eeffb2abc3afebb589af987f5e59..b137474190ac3a1f250a5378eae8bae9353681aa 100644 --- a/basic/source/state.c +++ b/basic/source/state.c @@ -4,6 +4,7 @@ #include "mem.h" #include "util.h" #include "state.h" #include "parser.h" +#include "string.h" #include "semanticAnalysis.h" State state; @@ -145,3 +146,18 @@ } free(nodes); return true; } + +Var* State_FindMethod(Type* type, const char* name) { + if (!type) return NULL; + + String methodName = String_New(); + + String_Add(&methodName, type->name); + String_Add(&methodName, "_"); + String_Add(&methodName, name); + + Var* ret = State_GetVar(methodName.contents); + + String_Free(&methodName); + return ret; +} diff --git a/basic/source/state.h b/basic/source/state.h index d84934b50ebd589ab8c216db5de343191c424019..993d767c25cd8c8b66b9fefd8222882ad7b37907 100644 --- a/basic/source/state.h +++ b/basic/source/state.h @@ -20,6 +20,9 @@ typedef struct { size_t ptr; size_t typeIdx; size_t array; // 0 if not array, contains length if not array + + // only for function call types + bool method; } UsedType; typedef struct { @@ -86,5 +89,6 @@ void State_DumpInfo(void); Type* State_GetTypeFromUsed(UsedType type); bool State_IsInt(Type type); bool State_ImportFile(const char* path); +Var* State_FindMethod(Type* type, const char* name); #endif diff --git a/basic/source/string.c b/basic/source/string.c index 7e42275935d2fa0e7044dae2263a0c206aadf2de..82d4d566a937815423e06b18e70c8e882a1c9d67 100644 --- a/basic/source/string.c +++ b/basic/source/string.c @@ -22,7 +22,7 @@ void String_Free(String* string) { free(string->contents); } -void String_Add(String* string, char* value) { +void String_Add(String* string, const char* value) { size_t newLen = strlen(string->contents) + strlen(value) + 1; size_t newCap = string->capacity; diff --git a/basic/source/string.h b/basic/source/string.h index 98e30f87cba52e57745b1493d7be6621416d8936..7dc422a10119438914983d3d9ba958fa8e60ca4c 100644 --- a/basic/source/string.h +++ b/basic/source/string.h @@ -11,7 +11,7 @@ String String_New(void); String String_FromChar(char ch); void String_Free(String* string); -void String_Add(String* string, char* value); +void String_Add(String* string, const char* value); void String_AddChar(String* string, char ch); size_t String_Len(String* string); diff --git a/basic/test.bas b/basic/test.bas index f97a4e6ee087a0b54c594adc79818f59c0105506..97e2e57c6abe01b20032e1dc6f5e3366e8b9c4cc 100644 --- a/basic/test.bas +++ b/basic/test.bas @@ -16,3 +16,5 @@ dim myArray[5] as i32 myArray[0] = 4 printf("myArray[0] = %d\n", myArray[0]) + +printf("127 ^ 4 = %d\n", 127 ^ 4)