From 966f97ad7c92f559ae54d0214db90c370e3b48eb Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Fri, 26 Apr 2024 21:08:13 +0300
Subject: add check against proc calls as statements

---
 src/check.c  | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++---------
 src/lower.c  |  9 +++++----
 src/parser.y | 36 ---------------------------------
 3 files changed, 61 insertions(+), 49 deletions(-)

(limited to 'src')

diff --git a/src/check.c b/src/check.c
index b4ea2b1..85e5459 100644
--- a/src/check.c
+++ b/src/check.c
@@ -35,6 +35,18 @@ static bool has_type(struct ast *n)
 	return n->t != 0;
 }
 
+static bool concrete_type(enum type_kind k)
+{
+	switch (k) {
+	case TYPE_VOID:
+	case TYPE_AUTO:
+		return false;
+	default: break;
+	}
+
+	return true;
+}
+
 static int analyze(struct state *state, struct scope *scope, struct ast *n);
 static int analyze_list(struct state *state, struct scope *scope, struct ast *l)
 {
@@ -46,6 +58,25 @@ static int analyze_list(struct state *state, struct scope *scope, struct ast *l)
 	return 0;
 }
 
+static int analyze_statement_list(struct state *state, struct scope *scope, struct ast *l)
+{
+	foreach_node(n, l) {
+		if (analyze(state, scope, n))
+			return -1;
+
+		if (n->k != AST_PROC_CALL)
+			continue;
+
+		if (n->t != TYPE_VOID) {
+			semantic_error(scope, n,
+					"non-void proc call not allowed as statement");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
 static struct ast *file_scope_find_analyzed(struct state *state,
                                             struct scope *scope, char *id)
 {
@@ -138,7 +169,7 @@ static int analyze_proc_def(struct state *state, struct scope *scope,
 	if (analyze_list(&proc_state, proc_scope, proc_vars(p)))
 		return -1;
 
-	if (analyze_list(&proc_state, proc_scope, proc_body(p)))
+	if (analyze_statement_list(&proc_state, proc_scope, proc_body(p)))
 		return -1;
 
 	struct ast *last = ast_last(proc_body(p));
@@ -168,6 +199,12 @@ static int analyze_var_def(struct state *state, struct scope *scope,
 	if (analyze(state, scope, expr))
 		return -1;
 
+	if (!concrete_type(expr->t)) {
+		semantic_error(scope, n, "illegal type in variable definition: %s",
+				type_str(expr->t));
+		return -1;
+	}
+
 	n->t = expr->t;
 	return 0;
 }
@@ -547,10 +584,22 @@ static int analyze_assign(struct state *state, struct scope *scope,
 	if (analyze(state, scope, l))
 		return -1;
 
+	if (!concrete_type(l->t)) {
+		semantic_error(scope, n, "illegal type for lefthand side: %s",
+				type_str(l->t));
+		return -1;
+	}
+
 	struct ast *r = assign_r(n);
 	if (analyze(state, scope, r))
 		return -1;
 
+	if (!concrete_type(r->t)) {
+		semantic_error(scope, n, "illegal type for righthand side: %s",
+				type_str(r->t));
+		return -1;
+	}
+
 	if (l->t != r->t) {
 		semantic_error(scope, n, "type mismatch: %s vs %s",
 		               type_str(l->t), type_str(r->t));
@@ -667,7 +716,7 @@ static int analyze_until(struct state *state, struct scope *scope,
 	scope_add_scope(scope, until_scope);
 
 	struct ast *body = until_body(n);
-	if (analyze_list(state, until_scope, body))
+	if (analyze_statement_list(state, until_scope, body))
 		return -1;
 
 	struct ast *cond = until_cond(n);
@@ -693,7 +742,7 @@ static int analyze_unless(struct state *state, struct scope *scope,
 	scope_add_scope(scope, otherwise_scope);
 
 	struct ast *body = unless_body(n);
-	if (analyze_list(state, unless_scope, body))
+	if (analyze_statement_list(state, unless_scope, body))
 		return -1;
 
 	struct ast *cond = unless_cond(n);
@@ -707,7 +756,7 @@ static int analyze_unless(struct state *state, struct scope *scope,
 	}
 
 	struct ast *otherwise = unless_otherwise(n);
-	if (otherwise && analyze_list(state, otherwise_scope, otherwise))
+	if (otherwise && analyze_statement_list(state, otherwise_scope, otherwise))
 		return -1;
 
 	n->t = TYPE_VOID;
@@ -824,11 +873,9 @@ int check(struct scope *scope, struct ast *root)
 	}
 
 	/* actually analyze all nodes */
-	foreach_node(n, root) {
-		struct state state = {0};
-		if (analyze(&state, scope, n))
-			return -1;
-	}
+	struct state state = {0};
+	if (analyze_statement_list(&state, scope, root))
+		return -1;
 
 #ifdef DEBUG
 	foreach_node(n, root) {
diff --git a/src/lower.c b/src/lower.c
index 7c5fdbd..1949bd5 100644
--- a/src/lower.c
+++ b/src/lower.c
@@ -299,11 +299,11 @@ static void lower_proc_call(struct fn *f, struct ast *c)
 	output_insn(f, CALL, null_loc(), null_loc(), null_loc(),
 	            loc_as_int(def->l));
 
+	f->sp -= count;
+
 	c->l = build_local_loc(f->sp);
 	if (c->t != TYPE_VOID)
 		output_insn(f, RETVAL, c->l, null_loc(), null_loc(), 0);
-
-	f->sp -= count;
 }
 
 static void lower_func_call(struct fn *f, struct ast *c)
@@ -322,11 +322,12 @@ static void lower_func_call(struct fn *f, struct ast *c)
 	struct ast *def = file_scope_find(c->scope, func_call_id(c));
 	output_insn(f, CALL, null_loc(), null_loc(), null_loc(),
 	            loc_as_int(def->l));
+
+	f->sp -= count;
+
 	c->l = build_local_loc(f->sp);
 	if (c->t != TYPE_VOID)
 		output_insn(f, RETVAL, c->l, null_loc(), null_loc(), 0);
-
-	f->sp -= count;
 }
 
 static void lower_eq(struct fn *f, struct ast *n)
diff --git a/src/parser.y b/src/parser.y
index 7aacd39..d053cce 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -9,42 +9,6 @@
 #include <posthaste/date.h>
 #include <posthaste/ast.h>
 
-#define FOREACH_TOKEN(M) \
-	M(LPAREN)	\
-	M(RPAREN)	\
-	M(LSQUARE)	\
-	M(RSQUARE)	\
-	M(LCURLY)	\
-	M(RCURLY)	\
-	M(APOSTROPHE)	\
-	M(AMPERSAND)	\
-	M(COMMA)	\
-	M(DOT)		\
-	M(EQ)		\
-	M(LT)		\
-	M(PLUS)		\
-	M(MINUS)	\
-	M(MULT)		\
-	M(DIV)		\
-	M(VAR)		\
-	M(IS)		\
-	M(UNLESS)	\
-	M(OTHERWISE)	\
-	M(UNTIL)	\
-	M(DO)		\
-	M(DONE)		\
-	M(PROCEDURE)	\
-	M(FUNCTION)	\
-	M(RETURN)	\
-	M(PRINT)	\
-	M(END)		\
-	M(STRING)	\
-	M(DATE_LITERAL)	\
-	M(INT_LITERAL)	\
-	M(IDENT)	\
-	M(FUNC_IDENT)	\
-	M(PROC_IDENT)
-
 %}
 
 %locations
-- 
cgit v1.2.3