nitron

commit e66c7fc7f6a34313fa6bc8f79c3be0a4e3c15072

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)