nitron

commit 960cce87cbc5b54bbdd3d947fad0cafff5fe0b05

Author: mesyeti <mesyeti@mesyeti.uk>

add return statement

 basic-std/std/string.bas | 16 ++++++++++++++++
 basic/source/compiler.c | 1 +
 basic/source/compiler.h | 1 +
 basic/source/frontend/c89.c | 9 ++++++++-
 basic/source/lexer.c | 6 +++++-
 basic/source/lexer.h | 1 +
 basic/source/parser.c | 19 +++++++++++++++++++
 basic/source/parser.h | 9 ++++++++-
 basic/source/semanticAnalysis.c | 34 ++++++++++++++++++++++++++++------
 basic/test.bas | 7 +++++--


diff --git a/basic/source/compiler.c b/basic/source/compiler.c
index be44878fc65b5df8a663184962e55f7e58d23efc..072ca73bd890e46aea621791e1360e012bb54ced 100644
--- a/basic/source/compiler.c
+++ b/basic/source/compiler.c
@@ -21,6 +21,7 @@ 		case NODE_DIM:       frontend.compileDim(&node->dim);           break;
 		case NODE_EXTERN:    frontend.compileExtern(&node->external);   break;
 		case NODE_IF:        frontend.compileIf(&node->ifStat);         break;
 		case NODE_WHILE:     frontend.compileWhile(&node->whileStat);   break;
+		case NODE_RETURN:    frontend.compileReturn(&node->ret);        break;
 		case NODE_BINARY_OP: {
 			if (node->bin.op == TOKEN_ASSIGN) {
 				frontend.compileAssign(&node->bin);




diff --git a/basic/source/compiler.h b/basic/source/compiler.h
index 7cbc036cf50b6ad3ce9329f9063de654d0cdc20f..2eb287227d27604cf79181892b55e170c0121c78 100644
--- a/basic/source/compiler.h
+++ b/basic/source/compiler.h
@@ -13,6 +13,7 @@ 	void (*compileExtern)(ExternNode* node);
 	void (*compileIf)(IfNode* node);
 	void (*compileAssign)(BinaryNode* node);
 	void (*compileWhile)(WhileNode* node);
+	void (*compileReturn)(ReturnNode* node);
 } Frontend;
 
 void Frontend_Init(Frontend p_frontend);




diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c
index 7f31c59e4d8756607456a1a398d947edb0273c77..e43c247e61169a45b121bef627ea133e6adcf3af 100644
--- a/basic/source/frontend/c89.c
+++ b/basic/source/frontend/c89.c
@@ -261,6 +261,12 @@
 	fprintf(out, "} nitron_%s;", type->name);
 }
 
+static void CompileReturn(ReturnNode* node) {
+	fprintf(out, "return ");
+	CompileExprNode(node->node);
+	fprintf(out, ";\n");
+}
+
 Frontend Frontend_C89() {
 	char* path = ConcatString(options.out, ".c");
 
@@ -332,6 +338,7 @@ 		.compileFuncCall  = &CompileFuncCall,
 		.compileExtern    = &CompileExtern,
 		.compileIf        = &CompileIf,
 		.compileAssign    = &CompileAssign,
-		.compileWhile     = &CompileWhile
+		.compileWhile     = &CompileWhile,
+		.compileReturn    = &CompileReturn
 	};
 }




diff --git a/basic/source/lexer.c b/basic/source/lexer.c
index 2f729de40820e9a1df853dc5ff5598c062812166..f299bbce43069c349f3be6346898beb3a7c8187b 100644
--- a/basic/source/lexer.c
+++ b/basic/source/lexer.c
@@ -197,7 +197,8 @@ 				{"do",       TOKEN_DO},
 				{"type",     TOKEN_TYPE},
 				{"union",    TOKEN_UNION},
 				{"program",  TOKEN_PROGRAM},
-				{"import",   TOKEN_IMPORT}
+				{"import",   TOKEN_IMPORT},
+				{"return",   TOKEN_RETURN}
 			};
 
 			for (size_t i = 0; i < sizeof(keywords) / sizeof(Keyword); ++ i) {
@@ -232,6 +233,9 @@ 		case TOKEN_WHILE:      return "while";
 		case TOKEN_DO:         return "do";
 		case TOKEN_TYPE:       return "type";
 		case TOKEN_UNION:      return "union";
+		case TOKEN_PROGRAM:    return "program";
+		case TOKEN_IMPORT:     return "import";
+		case TOKEN_RETURN:     return "return";
 		case TOKEN_IDENTIFIER: return "identifier";
 		case TOKEN_STRING:     return "string";
 		case TOKEN_INT:        return "int";




diff --git a/basic/source/lexer.h b/basic/source/lexer.h
index f83f268cf819277e0caf9781d9332cba025e9c6e..51ca0c421bfd058f71baa5718e2da06105738e5d 100644
--- a/basic/source/lexer.h
+++ b/basic/source/lexer.h
@@ -26,6 +26,7 @@ 	TOKEN_TYPE,
 	TOKEN_UNION,
 	TOKEN_PROGRAM,
 	TOKEN_IMPORT,
+	TOKEN_RETURN,
 
 	// misc
 	TOKEN_IDENTIFIER,




diff --git a/basic/source/parser.c b/basic/source/parser.c
index 2a585fc994f18509254620a874fd36f3069027f9..e1783ab6ee4a5e007d49a3464ba2d24b692a56ed 100644
--- a/basic/source/parser.c
+++ b/basic/source/parser.c
@@ -682,6 +682,20 @@ 	node.import = ret;
 	return node;
 }
 
+static Node ParseReturn(Parser* p) {
+	ReturnNode ret;
+	ret.i = INFO(NODE_RETURN);
+
+	Advance(p);
+	ret.node = NodeToHeap(ParseBinary(p));
+
+	Expect(p, TOKEN_LINE);
+
+	Node node;
+	node.ret = ret;
+	return node;
+}
+
 static Node ParseNode(Parser* p) {
 	switch (p->tokens[p->i].type) {
 		case TOKEN_FUNC:
@@ -693,6 +707,7 @@ 		case TOKEN_WHILE:   return ParseWhile(p);
 		case TOKEN_TYPE:    return ParseTypeDef(p);
 		case TOKEN_PROGRAM: return ParseProgram(p);
 		case TOKEN_IMPORT:  return ParseImport(p);
+		case TOKEN_RETURN:  return ParseReturn(p);
 		case TOKEN_LPAREN:
 		case TOKEN_ACCESS:
 		case TOKEN_IDENTIFIER: {
@@ -1014,6 +1029,10 @@ 			break;
 		}
 		case NODE_IMPORT: {
 			free(node->import.name);
+			break;
+		}
+		case NODE_RETURN: {
+			Parser_FreeNode(node->ret.node);
 			break;
 		}
 		default: return;




diff --git a/basic/source/parser.h b/basic/source/parser.h
index 0bb03b42b3ad8fce6e3750b92757feabd3ccfe04..cd7ea068f2d262169b953c609cd28f97bdb95784 100644
--- a/basic/source/parser.h
+++ b/basic/source/parser.h
@@ -22,7 +22,8 @@ 	NODE_WHILE,
 	NODE_TYPE_DEF,
 	NODE_TYPE_BLOCK,
 	NODE_PROGRAM,
-	NODE_IMPORT
+	NODE_IMPORT,
+	NODE_RETURN
 } NodeType;
 
 typedef struct {
@@ -142,6 +143,11 @@ 	NodeInfo i;
 	char*    name;
 } ImportNode;
 
+typedef struct {
+	NodeInfo i;
+	Node*    node;
+} ReturnNode;
+
 union Node {
 	NodeInfo       i;
 	IntNode        integer;
@@ -159,6 +165,7 @@ 	WhileNode      whileStat;
 	TypeDefNode    typeDef;
 	TypeBlockNode  typeBlock;
 	ImportNode     import;
+	ReturnNode     ret;
 };
 
 typedef struct {




diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c
index 4f06c5c0abcf1332f55b78d69b6df72c7cfe7450..1235acabde83d5a7bd24ee4802f0f4808b4c0974 100644
--- a/basic/source/semanticAnalysis.c
+++ b/basic/source/semanticAnalysis.c
@@ -7,6 +7,8 @@ #include "state.h"
 #include "parser.h"
 #include "semanticAnalysis.h"
 
+static Function* thisFunc = NULL;
+
 void SemanticAnalysis_Init(size_t wordSize) {
 	State_Init();
 
@@ -31,6 +33,8 @@ 	Type type;
 	type.name = NewString("unit");
 	type.type = TYPE_UNIT;
 	State_AddType(type);
+
+	thisFunc = NULL;
 }
 
 void Expect(Node* node, NodeType type) {
@@ -79,19 +83,23 @@
 #define GET_PRIM(NAME, PTR) \
 	((UsedType) {(PTR), State_GetType(NAME) - state.types, 0})
 
-static UsedType EvalAssign(Node* node, UsedType left, UsedType right) {
+static bool AssignCompatible(UsedType left, UsedType right) {
 	Type* leftType  = State_GetTypeFromUsed(left);
 	Type* rightType = State_GetTypeFromUsed(right);
-
-	bool compatible = true;
 
 	if ((left.ptr != right.ptr) || (leftType->type != rightType->type)) {
-		compatible = false;
+		return false;
 	}
 	else if (leftType->type == TYPE_PRIM) {
-		if (leftType->primType != rightType->primType) compatible = false;
-		else if (leftType->size < rightType->size)     compatible = false;
+		if (leftType->primType != rightType->primType) return false;
+		else if (leftType->size < rightType->size)     return false;
 	}
+
+	return true;
+}
+
+static UsedType EvalAssign(Node* node, UsedType left, UsedType right) {
+	bool compatible = AssignCompatible(left, right);
 
 	if (!compatible) {
 		PrintError(
@@ -353,7 +361,9 @@ 				State_AddVar(var);
 			}
 
 			for (size_t i = 0; i < node->funcDef.bodyLen; ++ i) {
+				thisFunc = &func;
 				SemanticAnalysis_EvalType(&node->funcDef.body[i]);
+				thisFunc = NULL;
 			}
 			inFunc = false;
 			State_FreeScope();
@@ -499,6 +509,18 @@ 			return GET_PRIM("unit", 0);
 		}
 		case NODE_PROGRAM: return GET_PRIM("unit", 0);
 		case NODE_IMPORT:  return GET_PRIM("unit", 0);
+		case NODE_RETURN: {
+			if (!inFunc) {
+				PrintError(node->i.err, "Return statement outside of function");
+			}
+
+			UsedType type = SemanticAnalysis_EvalType(node->ret.node);
+
+			if (AssignCompatible(thisFunc->ret, type)) {
+				PrintError(node->i.err, "Return type does not match function type");
+			}
+			return GET_PRIM("unit", 0);
+		}
 		default: {
 			Unexpected(node);
 		}




diff --git a/basic/test.bas b/basic/test.bas
index 532d91881fffa19498acf9852c9bc48d1077876e..5efc554e8f2f83da16dc67a388ca4deac79a44ac 100644
--- a/basic/test.bas
+++ b/basic/test.bas
@@ -5,6 +5,9 @@
 extern func puts(str as ptr(char)) i32
 extern func printf(str as ptr(char), val as int) i32
 
-import lib
+func add(a as int, b as int) i32
+	return a + b
+end
 
-PrintStrLn("hello world!")
+printf("2 + 2 = %d\n", add(2, 2))
+printf("2 + 3 = %d\n", add(2, 3))




diff --git a/basic-std/std/string.bas b/basic-std/std/string.bas
new file mode 100644
index 0000000000000000000000000000000000000000..7846d0e933f514872229c0524e98165f35fc1b9f
--- /dev/null
+++ b/basic-std/std/string.bas
@@ -0,0 +1,16 @@
+'NITRON
+
+func StringLen(str as ptr(char)) int
+	dim ret as int
+
+	while ^str != 0 do
+		ret = ret + 1
+		str = str + 1
+	end
+
+	return ret
+end
+
+func StringEq(str1 as ptr(char), str2 as ptr(char)) bool
+
+end