nitron

commit d62bb0092e497687f365ca9c18541345df99e744

Author: mesyeti <mesyeti@mesyeti.uk>

refactor function call parsing

 basic-std/std/io.bas | 2 
 basic/source/compiler.c | 23 +++--
 basic/source/compiler.h | 2 
 basic/source/frontend/c89.c | 28 +++++-
 basic/source/lexer.c | 6 +
 basic/source/lexer.h | 2 
 basic/source/parser.c | 83 +++++++++++++++++---
 basic/source/parser.h | 13 ++
 basic/source/semanticAnalysis.c | 137 ++++++++++++++++++++++------------
 basic/source/state.c | 31 +------
 basic/source/state.h | 40 +++++----
 basic/test2.bas | 4 


diff --git a/basic/source/compiler.c b/basic/source/compiler.c
index 072ca73bd890e46aea621791e1360e012bb54ced..ad14a7482ad0738f79589c9ed02bdc5e08e51b54 100644
--- a/basic/source/compiler.c
+++ b/basic/source/compiler.c
@@ -14,17 +14,19 @@ }
 
 void Compiler_CompileBodyNode(Node* node) {
 	switch (node->i.type) {
-		
-		case NODE_FUNC_CALL: frontend.compileFuncCall(&node->funcCall); break;
-		case NODE_FUNC_DEF:  frontend.compileFuncDef(&node->funcDef);   break;
-		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_FUNC_DEF:  frontend.compileFuncDef(&node->funcDef); break;
+		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);
+				break;
+			}
+			else if (node->bin.op == TOKEN_LPAREN) {
+				frontend.compileFuncCall(&node->bin);
 				break;
 			}
 		} // fall through
@@ -44,12 +46,15 @@ 			case NODE_TYPE_DEF:   break;
 			case NODE_TYPE_BLOCK: break;
 			case NODE_PROGRAM:    break;
 			case NODE_IMPORT:     break;
-			case NODE_FUNC_CALL:  frontend.compileFuncCall(&node->funcCall); break;
 			case NODE_IF:         frontend.compileIf(&node->ifStat);         break;
 			case NODE_WHILE:      frontend.compileWhile(&node->whileStat);   break;
 			case NODE_BINARY_OP: {
 				if (node->bin.op == TOKEN_ASSIGN) {
 					frontend.compileAssign(&node->bin);
+					break;
+				}
+				else if (node->bin.op == TOKEN_LPAREN) {
+					frontend.compileFuncCall(&node->bin);
 					break;
 				}
 			} // fall through




diff --git a/basic/source/compiler.h b/basic/source/compiler.h
index 2eb287227d27604cf79181892b55e170c0121c78..471c75bedd63c48688dc0a0d87a7117bf44a72b3 100644
--- a/basic/source/compiler.h
+++ b/basic/source/compiler.h
@@ -8,7 +8,7 @@ 	void (*finish)(bool program);
 	void (*beginMain)(void);
 	void (*compileFuncDef)(FuncDefNode* node);
 	void (*compileDim)(DimNode* node);
-	void (*compileFuncCall)(FuncCallNode* node);
+	void (*compileFuncCall)(BinaryNode* node);
 	void (*compileExtern)(ExternNode* node);
 	void (*compileIf)(IfNode* node);
 	void (*compileAssign)(BinaryNode* node);




diff --git a/basic/source/frontend/c89.c b/basic/source/frontend/c89.c
index e43c247e61169a45b121bef627ea133e6adcf3af..8a88fe5c2d03d09db7aec0a358f2f3d18013d88e 100644
--- a/basic/source/frontend/c89.c
+++ b/basic/source/frontend/c89.c
@@ -98,7 +98,7 @@
 static void CompileExprNode(Node* node);
 
 static void CompileFuncCallExpr(FuncCallNode* node) {
-	fprintf(out, "%s(", node->func);
+	fprintf(out, "(");
 
 	for (size_t i = 0; i < node->paramsNum; ++ i) {
 		CompileExprNode(&node->params[i]);
@@ -142,6 +142,7 @@ 						fprintf(out, ".");
 					}
 					break;
 				}
+				case TOKEN_LPAREN: break; // function call, nothing to do
 				default: assert(0);
 			}
 
@@ -165,13 +166,16 @@ 			CompileExprNode(node->unary.operand);
 			fprintf(out, ")");
 			break;
 		}
-		case NODE_FUNC_CALL: CompileFuncCallExpr(&node->funcCall); break;
+		case NODE_FUNC_CALL: CompileFuncCallExpr(&node->bin.right->funcCall); break;
 		default: assert(0);
 	}
 }
 
-static void CompileFuncCall(FuncCallNode* node) {
-	CompileFuncCallExpr(node);
+static void CompileFuncCall(BinaryNode* node) {
+	Node node2;
+	node2.bin = *node;
+
+	CompileExprNode(&node2);
 	fprintf(out, ";\n");
 }
 
@@ -298,15 +302,25 @@ 	}
 
 	// declare all globals
 	for (size_t i = 0; i < state.scopeSize[0]; ++ i) {
-		Var* var = &state.scopes[0][i];
+		Var*  var     = &state.scopes[0][i];
+		Type* varType = State_GetTypeFromUsed(var->type);
+
+		if (varType->type == TYPE_FUNC) continue;
 
 		CompileUsedType(var->type);
 		fprintf(out, " nitron_%s;\n", var->name);
 	}
 
 	// declare all functions
-	for (size_t i = 0; i < state.funcNum; ++ i) {
-		Function* func = &state.funcs[i];
+	for (size_t i = 0; i < state.scopeSize[0]; ++ i) {
+		Var*  var     = &state.scopes[0][i];
+		Type* varType = State_GetTypeFromUsed(var->type);
+
+		if ((var->type.ptr > 0) || (var->type.array > 0) || (varType->type != TYPE_FUNC)) {
+			continue;
+		}
+
+		Function* func = &varType->func;
 
 		if (func->sub) {
 			fprintf(out, "void");




diff --git a/basic/source/lexer.c b/basic/source/lexer.c
index f299bbce43069c349f3be6346898beb3a7c8187b..9d5185d1937492c9c9dcf83cf7da9c350119df2a 100644
--- a/basic/source/lexer.c
+++ b/basic/source/lexer.c
@@ -147,7 +147,9 @@ 		case '>':  *token = TOKEN(TOKEN_GREATER, NULL); return LEXER_TOKEN;
 		case '&':  *token = TOKEN(TOKEN_ADDRESS, NULL); return LEXER_TOKEN;
 		case '^':  *token = TOKEN(TOKEN_ACCESS,  NULL); return LEXER_TOKEN;
 		case '\n': *token = TOKEN(TOKEN_LINE,    NULL); return LEXER_TOKEN;
-		case '\'': {
+		case '[':  *token = TOKEN(TOKEN_LSQUARE, NULL); return LEXER_TOKEN;
+		case ']':  *token = TOKEN(TOKEN_RSQUARE, NULL); return LEXER_TOKEN;
+		case '\'': { // comment
 			while (true) {
 				GET_CHAR(ch);
 
@@ -244,6 +246,8 @@ 		case TOKEN_LPAREN:     return "lparen";
 		case TOKEN_RPAREN:     return "rparen";
 		case TOKEN_DOT:        return "dot";
 		case TOKEN_COMMA:      return "comma";
+		case TOKEN_LSQUARE:    return "left square";
+		case TOKEN_RSQUARE:    return "right square";
 		case TOKEN_ADD:        return "add";
 		case TOKEN_SUBTRACT:   return "subtract";
 		case TOKEN_MULTIPLY:   return "multiply";




diff --git a/basic/source/lexer.h b/basic/source/lexer.h
index 51ca0c421bfd058f71baa5718e2da06105738e5d..3e69d894e04c7addcd8704162ca225d804184f27 100644
--- a/basic/source/lexer.h
+++ b/basic/source/lexer.h
@@ -39,6 +39,8 @@ 	TOKEN_LPAREN,
 	TOKEN_RPAREN,
 	TOKEN_DOT,
 	TOKEN_COMMA,
+	TOKEN_LSQUARE,
+	TOKEN_RSQUARE,
 
 	// operators
 	TOKEN_ADD,




diff --git a/basic/source/parser.c b/basic/source/parser.c
index e1783ab6ee4a5e007d49a3464ba2d24b692a56ed..b0c758165c06d351f4e31a0c0f9a51cefb78376b 100644
--- a/basic/source/parser.c
+++ b/basic/source/parser.c
@@ -91,11 +91,6 @@ 	Advance(p);
 
 	switch (token->type) {
 		case TOKEN_IDENTIFIER: {
-			if (p->tokens[p->i].type == TOKEN_LPAREN) {
-				-- p->i;
-				return ParseFuncCall(p);
-			}
-
 			ret.ident = (IdentifierNode) {INFO(NODE_IDENTIFIER), NewString(token->contents)};
 			return ret;
 		}
@@ -134,6 +129,33 @@ 		default:             return false;
 	}
 }
 
+static Node ParseFuncArray(Parser* p) {
+	Node left = ParseAtom(p);
+
+	while ((p->tokens[p->i].type == TOKEN_LPAREN) || (p->tokens[p->i].type == TOKEN_LSQUARE)) {
+		if (p->tokens[p->i].type == TOKEN_LPAREN) { // function call
+			Node callNode = ParseFuncCall(p); // parse parameter list
+
+			left.bin = (BinaryNode) {
+				INFO(NODE_BINARY_OP), NodeToHeap(left), NodeToHeap(callNode), TOKEN_LPAREN
+			};
+		}
+		else { // array access
+			Advance(p);
+			Node idxNode = ParseBinary(p);
+
+			Expect(p, TOKEN_RSQUARE);
+			Advance(p);
+
+			left.bin = (BinaryNode) {
+				INFO(NODE_BINARY_OP), NodeToHeap(left), NodeToHeap(idxNode), TOKEN_LSQUARE
+			};
+		}
+	}
+
+	return left;
+}
+
 static Node ParseUnary(Parser* p) {
 	Token* tok = &p->tokens[p->i];
 
@@ -150,7 +172,7 @@ 		};
 		return ret;
 	}
 	else {
-		return ParseAtom(p);
+		return ParseFuncArray(p);
 	}
 }
 
@@ -430,12 +452,21 @@ 	Expect(p, TOKEN_IDENTIFIER);
 	ret.name = NewString(p->tokens[p->i].contents);
 
 	Advance(p);
+
+	if (p->tokens[p->i].type == TOKEN_LSQUARE) {
+		Advance(p);
+		ret.array    = true;
+		ret.arrayLen = NodeToHeap(ParseBinary(p));
+
+		Expect(p, TOKEN_RSQUARE);
+		Advance(p);
+	}
+
 	Expect(p, TOKEN_AS);
 
 	Advance(p);
 	ret.varType  = SafeMalloc(sizeof(Node));
 	*ret.varType = ParseType(p);
-
 
 	Advance(p);
 	Expect(p, TOKEN_LINE);
@@ -448,9 +479,7 @@
 static Node ParseFuncCall(Parser* p) {
 	FuncCallNode ret;
 	ret.i    = INFO(NODE_FUNC_CALL);
-	ret.func = NewString(p->tokens[p->i].contents);
 
-	Advance(p);
 	Expect(p, TOKEN_LPAREN);
 
 	Advance(p);
@@ -717,8 +746,12 @@ 			}
 
 			Node ret = ParseBinary(p);
 
+			// this if statement is sickening
 			if (
-				((ret.i.type == NODE_BINARY_OP) && (ret.bin.op != TOKEN_ASSIGN)) ||
+				(
+					(ret.i.type == NODE_BINARY_OP) && (ret.bin.op != TOKEN_ASSIGN) &&
+					(ret.bin.op != TOKEN_LPAREN)
+				) ||
 				((ret.i.type != NODE_BINARY_OP) && (ret.i.type != NODE_FUNC_CALL))
 			) {
 				PrintError(p->tokens[p->i].err, "Unexpected %s", Parser_TypeStr(ret.i.type));
@@ -778,6 +811,7 @@ 				case TOKEN_LESS:     printf("<");  break;
 				case TOKEN_GREATER:  printf(">");  break;
 				case TOKEN_ASSIGN:   printf("=");  break;
 				case TOKEN_DOT:      printf(".");  break;
+				case TOKEN_LPAREN:   printf("");   break;
 				default:             assert(0);
 			}
 
@@ -819,13 +853,20 @@ 			puts("end");
 			break;
 		}
 		case NODE_DIM: {
-			printf("dim %s as ", node->dim.name);
+			printf("dim %s", node->dim.name);
+
+			if (node->dim.array) {
+				printf(" ");
+				Parser_PrintNode(node->dim.arrayLen);
+			}
+
+			printf(" as ");
 			Parser_PrintNode(node->dim.varType);
 			puts("");
 			break;
 		}
 		case NODE_FUNC_CALL: {
-			printf("%s(", node->funcCall.func);
+			printf("(");
 
 			for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) {
 				Parser_PrintNode(&node->funcCall.params[i]);
@@ -900,6 +941,13 @@ 			break;
 		}
 		case NODE_IMPORT: {
 			printf("import %s\n", node->import.name);
+			break;
+		}
+		case NODE_ARRAY: {
+			Parser_PrintNode(node->array.array);
+			putchar('[');
+			Parser_PrintNode(node->array.idx);
+			putchar(']');
 			break;
 		}
 		default: {
@@ -984,11 +1032,13 @@ 		case NODE_DIM: {
 			free(node->dim.name);
 			Parser_FreeNode(node->dim.varType);
 			free(node->dim.varType);
+
+			if (node->dim.array) {
+				Parser_FreeNode(node->dim.arrayLen);
+			}
 			break;
 		}
 		case NODE_FUNC_CALL: {
-			free(node->funcCall.func);
-
 			for (size_t i = 0; i < node->funcCall.paramsNum; ++ i) {
 				Parser_FreeNode(&node->funcCall.params[i]);
 			}
@@ -1033,6 +1083,11 @@ 			break;
 		}
 		case NODE_RETURN: {
 			Parser_FreeNode(node->ret.node);
+			break;
+		}
+		case NODE_ARRAY: {
+			Parser_FreeNode(node->array.array);
+			Parser_FreeNode(node->array.idx);
 			break;
 		}
 		default: return;




diff --git a/basic/source/parser.h b/basic/source/parser.h
index cd7ea068f2d262169b953c609cd28f97bdb95784..44d7f5966696bb6110814a2ea14725cbc7ff4b7d 100644
--- a/basic/source/parser.h
+++ b/basic/source/parser.h
@@ -23,7 +23,8 @@ 	NODE_TYPE_DEF,
 	NODE_TYPE_BLOCK,
 	NODE_PROGRAM,
 	NODE_IMPORT,
-	NODE_RETURN
+	NODE_RETURN,
+	NODE_ARRAY
 } NodeType;
 
 typedef struct {
@@ -89,11 +90,12 @@ typedef struct {
 	NodeInfo i;
 	char*    name;
 	Node*    varType;
+	bool     array;
+	Node*    arrayLen;
 } DimNode;
 
 typedef struct {
 	NodeInfo i;
-	char*    func;
 	Node*    params;
 	size_t   paramsNum;
 } FuncCallNode;
@@ -148,6 +150,12 @@ 	NodeInfo i;
 	Node*    node;
 } ReturnNode;
 
+typedef struct {
+	NodeInfo i;
+	Node*    array;
+	Node*    idx;
+} ArrayNode;
+
 union Node {
 	NodeInfo       i;
 	IntNode        integer;
@@ -166,6 +174,7 @@ 	TypeDefNode    typeDef;
 	TypeBlockNode  typeBlock;
 	ImportNode     import;
 	ReturnNode     ret;
+	ArrayNode      array;
 };
 
 typedef struct {




diff --git a/basic/source/semanticAnalysis.c b/basic/source/semanticAnalysis.c
index 1235acabde83d5a7bd24ee4802f0f4808b4c0974..1a382c2409465ec9bcad45e6b8db88e0ddc5e8d2 100644
--- a/basic/source/semanticAnalysis.c
+++ b/basic/source/semanticAnalysis.c
@@ -137,11 +137,67 @@ 	PrintError(node->i.err, "Type '%s' does not have member '%s'", leftType->name, member);
 	return GET_PRIM("unit", 0);
 }
 
+static UsedType EvalFuncCall(Node* node, UsedType left) {
+	Type* leftType = State_GetTypeFromUsed(left);
+
+	if (leftType->type != TYPE_FUNC) {
+		PrintError(node->i.err, "Type '%s' cannot be called", leftType->name);
+	}
+
+	assert(node->bin.right->i.type == NODE_FUNC_CALL);
+
+	Node*     call = node->bin.right;
+	Function* func = &leftType->func;
+
+	if (func->paramsLen != call->funcCall.paramsNum) {
+		PrintError(
+			call->i.err, "Expected %d parameters, got %d",
+			func->paramsLen, call->funcCall.paramsNum
+		);
+	}
+
+	for (size_t i = 0; i < func->paramsLen; ++ i) {
+		UsedType type      = SemanticAnalysis_EvalType(&call->funcCall.params[i]);
+		UsedType param     = func->params[i].type;
+		Type*    paramType = State_GetTypeFromUsed(param);
+		Type*    callType  = State_GetTypeFromUsed(type);
+
+		bool paramLit = strcmp(callType->name, "__lit") == 0;
+
+		if (!State_UsedTypeEq(type, param)) {
+			if (
+				(callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) &&
+				(callType->primType == paramType->primType) &&
+				(paramType->size >= callType->size)
+			) {
+				continue;
+			}
+
+			if (paramLit && (paramType->type == TYPE_PRIM)) continue;
+
+			PrintError(call->i.err,
+				"Expected %s for parameter %s, got %s",
+				paramType->name, func->params[i].name, callType->name
+			);
+		}
+	}
+
+	if (func->sub) {
+		return GET_PRIM("unit", 0);
+	}
+	else {
+		return func->ret;
+	}
+}
+
 static UsedType EvalBinOp(Node* node) {
 	UsedType left = SemanticAnalysis_EvalType(node->bin.left);
 
 	if (node->bin.op == TOKEN_DOT) {
 		return EvalDot(node, left);
+	}
+	if (node->bin.op == TOKEN_LPAREN) {
+		return EvalFuncCall(node, left);
 	}
 
 	UsedType right = SemanticAnalysis_EvalType(node->bin.right);
@@ -346,7 +402,22 @@ 				PrintError(node->i.err, "Nested function definitions are not allowed");
 			}
 
 			Function func = DecToFunc(node->funcDef.dec);
-			State_AddFunc(func);
+
+ 			// create type for this function
+ 			Type type;
+ 			type.type = TYPE_FUNC;
+ 			type.name = NULL;
+ 			type.size = (size_t) -1;
+ 			type.func = func;
+
+ 			size_t funcTypeIdx = State_AddType(type);
+
+ 			// create variable for this function
+ 			Var funcVar;
+ 			funcVar.type = (UsedType) {0, funcTypeIdx, 0};
+ 			funcVar.name = node->funcDef.dec.name;
+
+ 			State_AddVar(funcVar);
 
 			// now analyse the body
 			State_AddScope();
@@ -369,52 +440,6 @@ 			inFunc = false;
 			State_FreeScope();
 			return GET_PRIM("unit", 0);
 		}
-		case NODE_FUNC_CALL: {
-			Function* func = State_GetFunc(node->funcCall.func);
-			if (!func) {
-				PrintError(node->i.err, "Function %s does not exist", node->funcCall.func);
-			}
-
-			if (func->paramsLen != node->funcCall.paramsNum) {
-				PrintError(
-					node->i.err, "Expected %d parameters, got %d",
-					func->paramsLen, node->funcCall.paramsNum
-				);
-			}
-
-			for (size_t i = 0; i < func->paramsLen; ++ i) {
-				UsedType type      = SemanticAnalysis_EvalType(&node->funcCall.params[i]);
-				UsedType param     = func->params[i].type;
-				Type*    paramType = State_GetTypeFromUsed(param);
-				Type*    callType  = State_GetTypeFromUsed(type);
-
-				bool paramLit = strcmp(callType->name, "__lit") == 0;
-
-				if (!State_UsedTypeEq(type, param)) {
-					if (
-						(callType->type == TYPE_PRIM) && (paramType->type == TYPE_PRIM) &&
-						(callType->primType == paramType->primType) &&
-						(paramType->size >= callType->size)
-					) {
-						continue;
-					}
-
-					if (paramLit && (paramType->type == TYPE_PRIM)) continue;
-
-					PrintError(node->i.err,
-						"Expected %s for parameter %s, got %s",
-						paramType->name, func->params[i].name, callType->name
-					);
-				}
-			}
-
-			if (func->sub) {
-				return GET_PRIM("unit", 0);
-			}
-			else {
-				return func->ret;
-			}
-		}
 		case NODE_DIM: {
 			Var var;
 			var.type = SemanticAnalysis_NodeAsUsedType(node->dim.varType);
@@ -428,7 +453,23 @@ 				PrintError(node->i.err, "Nested function definitions are not allowed");
 			}
 
 			Function func = DecToFunc(node->funcDef.dec);
-			State_AddFunc(func);
+
+ 			// create type for this function
+ 			Type type;
+ 			type.type = TYPE_FUNC;
+ 			type.name = NULL;
+ 			type.size = (size_t) -1;
+ 			type.func = func;
+
+ 			size_t funcTypeIdx = State_AddType(type);
+
+ 			// create variable for this function
+ 			Var funcVar;
+ 			funcVar.type = (UsedType) {0, funcTypeIdx, 0};
+ 			funcVar.name = node->funcDef.dec.name;
+
+ 			State_AddVar(funcVar);
+
 			return GET_PRIM("unit", 0);
 		}
 		case NODE_IF: {




diff --git a/basic/source/state.c b/basic/source/state.c
index 216160a16844058fa5187d8339e8479fa6181406..5cdc7e708e75eeffb2abc3afebb589af987f5e59 100644
--- a/basic/source/state.c
+++ b/basic/source/state.c
@@ -14,14 +14,14 @@ 	state.typeNum      = 0;
 	state.scopes[0]    = NULL;
 	state.scopeSize[0] = 0;
 	state.scopeNum     = 1;
-	state.funcs        = NULL;
-	state.funcNum      = 0;
 }
 
-void State_AddType(Type type) {
+size_t State_AddType(Type type) {
 	++ state.typeNum;
 	state.types = SafeRealloc(state.types, state.typeNum * sizeof(Type));
 	state.types[state.typeNum - 1] = type;
+
+	return state.typeNum - 1;
 }
 
 void State_AddVar(Var var) {
@@ -43,12 +43,6 @@ 	state.scopes[state.scopeNum - 1]    = NULL;
 	return true;
 }
 
-void State_AddFunc(Function func) {
-	++ state.funcNum;
-	state.funcs = SafeRealloc(state.funcs, state.funcNum * sizeof(Function));
-	state.funcs[state.funcNum - 1] = func;
-}
-
 void State_FreeScope(void) {
 	Var*   scope    = state.scopes[state.scopeNum - 1];
 	size_t scopeNum = state.scopeSize[state.scopeNum - 1];
@@ -74,6 +68,8 @@ }
 
 Type* State_GetType(const char* name) {
 	for (size_t i = 0; i < state.typeNum; ++ i) {
+		if (!state.types[i].name) continue;
+
 		if (strcmp(state.types[i].name, name) == 0) {
 			return &state.types[i];
 		}
@@ -82,16 +78,6 @@
 	return NULL;
 }
 
-Function* State_GetFunc(const char* name) {
-	for (size_t i = 0; i < state.funcNum; ++ i) {
-		if (strcmp(state.funcs[i].name, name) == 0) {
-			return &state.funcs[i];
-		}
-	}
-
-	return NULL;
-}
-
 void State_MakePrimitive(const char* name, size_t size, int primType) {
 	Type type;
 	type.type     = TYPE_PRIM;
@@ -123,13 +109,6 @@ 	puts("GLOBALS");
 	puts("=======");
 	for (size_t i = 0; i < state.scopeSize[0]; ++ i) {
 		printf("- %s\n", state.scopes[0][i].name);
-	}
-	puts("\n");
-
-	puts("FUNCTIONS");
-	puts("=========");
-	for (size_t i = 0; i < state.funcNum; ++ i) {
-		printf("- %s\n", state.funcs[i].name);
 	}
 	puts("\n");
 }




diff --git a/basic/source/state.h b/basic/source/state.h
index decf9f57253ba9f349bcc40562a1dd26754b6492..d84934b50ebd589ab8c216db5de343191c424019 100644
--- a/basic/source/state.h
+++ b/basic/source/state.h
@@ -6,7 +6,8 @@
 enum {
 	TYPE_PRIM, // is this "primitive", or Primula the manul?
 	TYPE_STRUCT,
-	TYPE_UNIT
+	TYPE_UNIT,
+	TYPE_FUNC
 };
 
 enum {
@@ -22,6 +23,19 @@ 	size_t array; // 0 if not array, contains length if not array
 } UsedType;
 
 typedef struct {
+	UsedType type;
+	char*    name;
+} FuncParam;
+
+typedef struct {
+	bool       sub;
+	UsedType   ret;
+	FuncParam* params;
+	size_t     paramsLen;
+	char*      name;
+} Function;
+
+typedef struct {
 	char*    name;
 	UsedType type;
 } TypeField;
@@ -30,6 +44,8 @@ typedef struct {
 	int    type;
 	char*  name;
 	size_t size;
+
+	// TODO: put the stuff below into a union
 
 	// only for "struct" types
 	TypeField* structure;
@@ -37,6 +53,9 @@ 	size_t     structLen;
 
 	// only for "primitive" types
 	int primType;
+
+	// only for "function" types
+	Function func;
 } Type;
 
 typedef struct {
@@ -45,39 +64,22 @@ 	char*    name;
 } Var;
 
 typedef struct {
-	UsedType type;
-	char*    name;
-} FuncParam;
-
-typedef struct {
-	bool       sub;
-	UsedType   ret;
-	FuncParam* params;
-	size_t     paramsLen;
-	char*      name;
-} Function;
-
-typedef struct {
 	Type*     types;
 	size_t    typeNum;
 	Var*      scopes[16];
 	size_t    scopeSize[16];
 	size_t    scopeNum;
-	Function* funcs;
-	size_t    funcNum;
 } State;
 
 extern State state;
 
 void      State_Init(void);
-void      State_AddType(Type type);
+size_t    State_AddType(Type type);
 void      State_AddVar(Var var);
 bool      State_AddScope(void);
-void      State_AddFunc(Function func);
 void      State_FreeScope(void);
 Var*      State_GetVar(const char* name);
 Type*     State_GetType(const char* name);
-Function* State_GetFunc(const char* name);
 void      State_MakePrimitive(const char* name, size_t size, int primType);
 bool      State_UsedTypeEq(UsedType a, UsedType b);
 void      State_DumpInfo(void);




diff --git a/basic/test2.bas b/basic/test2.bas
index 08fb2be0209cd470a4560c6a56948753682be1e5..cda0b34274133fe1842785c47369fd4b40b13e5e 100644
--- a/basic/test2.bas
+++ b/basic/test2.bas
@@ -1 +1,3 @@
-print(1+2+3+4)
+'NITRON
+
+print("hello")




diff --git a/basic-std/std/io.bas b/basic-std/std/io.bas
index d751ab166b51048099aac4aa4d4f16ed1730d633..8d71472149b19410d55374414f249493717f056f 100644
--- a/basic-std/std/io.bas
+++ b/basic-std/std/io.bas
@@ -1,3 +1,5 @@
+'NITRON
+
 extern func puts(str as ptr(char)) i32
 extern func putchar(ch as char) i32