diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-01-06 01:05:21 +0200 | 
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-01-06 01:05:57 +0200 | 
| commit | 89bac537165bf262594cca343cb45e16a2167145 (patch) | |
| tree | f72a80f1624b12fa3b27c6dc6feedc3e06594e20 /src | |
| parent | aec19e55ca32f68536a550f100d3f058b8a93c02 (diff) | |
| download | fwd-89bac537165bf262594cca343cb45e16a2167145.tar.gz fwd-89bac537165bf262594cca343cb45e16a2167145.zip | |
implement move checking furthermvcheck
+ Enough that examples still compile, but missing references etc.
Diffstat (limited to 'src')
| -rw-r--r-- | src/analyze.c | 31 | ||||
| -rw-r--r-- | src/ast.c | 14 | ||||
| -rw-r--r-- | src/debug.c | 3 | ||||
| -rw-r--r-- | src/lexer.l | 1 | ||||
| -rw-r--r-- | src/move.c | 191 | ||||
| -rw-r--r-- | src/parser.y | 4 | 
6 files changed, 219 insertions, 25 deletions
| diff --git a/src/analyze.c b/src/analyze.c index 077e7d8..ab08f01 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -2,6 +2,7 @@  /* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */  #include <fwd/analyze.h> +#include <stdlib.h>  #include <string.h>  #include <assert.h> @@ -41,7 +42,17 @@ static int analyze_proc(struct state *state, struct scope *scope,  		return -1;  	} +	size_t group = 0;  	foreach_node(param, proc_params(node)) { +		if (param->ol == NULL && param->or == NULL) +			group++; /* no opt group */ + +		if (param->ol == NULL && param->or) +			group++; /* start of new group */ + +		/* otherwise same or ending group, don't increment */ + +		param->t->group = group;  		type_append(&callable->t0, clone_type(param->t));  	} @@ -113,6 +124,7 @@ static int analyze_comparison(struct state *state, struct scope *scope,  	node->t = tgen_id(tf, node->loc);  	if (!node->t) {  		internal_error("failed allocating comparison bool type"); +		free(tf);  		return -1;  	} @@ -132,7 +144,12 @@ static int analyze_block(struct state *state, struct scope *scope,  	if (analyze_list(state, block_scope, block_body(node)))  		return -1; -	node->t = ast_last(block_body(node))->t; +	struct ast *last = ast_last(block_body(node)); +	if (last) +		node->t = last->t; +	else +		node->t = tgen_void(node->loc); +  	return 0;  } @@ -179,7 +196,8 @@ static int analyze_init(struct state *state, struct scope *scope,  	/** @todo check that all parameters match, though that requires that the  	 * type is defined in fwd and not in C++, so this might have to wait a  	 * bit */ -	node->t = tgen_construct(init_id(node), init_args(node), node->loc); +	node->t = tgen_construct(strdup(init_id(node)), init_args(node), +	                         node->loc);  	if (!node->t) {  		internal_error("failed allocating type for construct");  		return -1; @@ -220,6 +238,8 @@ static int analyze_call(struct state *state, struct scope *scope,  			return -1;  		} +		/* clone group info */ +		arg->t->group = type->group;  		type = type->n;  	} @@ -305,6 +325,7 @@ static int analyze_int(struct state *state, struct scope *scope,  	node->t = tgen_id(i, node->loc);  	if (!node->t) {  		internal_error("failed allocating constant int type"); +		free(i);  		return -1;  	} @@ -324,6 +345,7 @@ static int analyze_str(struct state *state, struct scope *scope,  	struct type *ch = tgen_id(i, node->loc);  	if (!ch) {  		internal_error("failed allocating constant char type"); +		free(i);  		return -1;  	} @@ -417,6 +439,11 @@ static int analyze(struct state *state, struct scope *scope, struct ast *node)  		break;  	case AST_CONST_STR:     ret = analyze_str       (state, scope, node);  		break; + +	case AST_EMPTY: +		node->t = tgen_void(node->loc); +		ret = 0; +		break;  	default:  		internal_error("missing ast analysis for %s", ast_str(node->k));  		return -1; @@ -296,6 +296,8 @@ struct ast *clone_ast(struct ast *n)  	if (n->a3)  		new->a3 = clone_ast_list(n->a3); +	/** @todo rebuild opt group? */ +  	return new;  } @@ -331,6 +333,7 @@ struct type *clone_type(struct type *type)  	if (type->t0 && !(new->t0 = clone_type_list(type->t0)))  		return NULL; +	new->group = type->group;  	return new;  } @@ -542,7 +545,10 @@ void fix_closures(struct ast *root)  		}  		struct ast *next = root->n; -		struct ast *block = gen_block(next, next->loc); +		if (!next) +			next = gen_empty(root->loc); + +		struct ast *block = gen_block(next, root->loc);  		closure_body(arg) = block;  		root->n = NULL;  		root = next; @@ -648,3 +654,9 @@ const char *ast_str(enum ast_kind k)  	return "UNKNOWN";  } + +void opt_group(struct ast *a, struct ast *b) +{ +	a->or = b; +	b->ol = a; +} diff --git a/src/debug.c b/src/debug.c index f72fe9b..e65919b 100644 --- a/src/debug.c +++ b/src/debug.c @@ -154,6 +154,9 @@ static void _type_str(FILE *f, struct type *t);  static void _type_list_str(FILE *f, struct type *types)  { +	if (!types) +		return; +  	_type_str(f, types);  	foreach_type(type, types->n) { diff --git a/src/lexer.l b/src/lexer.l index a150798..ccae93e 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -110,6 +110,7 @@ STRING		\"(\\.|[^"\\])*\"  "'"		{return SQUOTE;}  "&"		{return AND;} +"|"		{return BAR;}  "~"		{return TILDE;}  "="		{return TO;} @@ -47,18 +47,23 @@ static void insert_move(struct state *state, struct ast *def, struct ast *use)  	moved_insert(&state->moved, pair);  } +static void merge(struct state *to, struct state *from) +{ +	if (moved_len(&from->moved) == 0) +		return; + +	foreach(moved, n, &from->moved) { +		moved_insert(&to->moved, *n); +	} +} +  static void push_up(struct state *state)  {  	struct state *parent = state->parent;  	if (!parent)  		return; -	if (moved_len(&state->moved) == 0) -		return; - -	foreach(moved, n, &state->moved) { -		moved_insert(&parent->moved, *n); -	} +	merge(parent, state);  }  static int mvcheck(struct state *state, struct ast *node); @@ -82,19 +87,42 @@ static int mvcheck_block(struct state *state, struct ast *node)  	return mvcheck_list(state, block_body(node));  } -static int mvcheck_list(struct state *state, struct ast *nodes) +static int mvcheck_call(struct state *state, struct ast *node)  { -	foreach_node(node, nodes) { -		if (mvcheck(state, node)) -			return -1; -	} +	if (mvcheck(state, call_expr(node))) +		return -1; -	return 0; -} +	struct ast *args = call_args(node); +	if (!args) +		return 0; -static int mvcheck_call(struct state *state, struct ast *node) -{ -	return mvcheck_list(state, call_args(node)); +	int ret = 0; +	long prev_group = args->t->group; +	struct state group_state = create_state(state); + +	foreach_node(arg, call_args(node)) { +		struct state arg_state = create_state(state); +		ret = mvcheck(&arg_state, arg); + +		long group = arg->t->group; +		if (prev_group != group) { +			/* previous group ended, push states up */ +			push_up(&group_state); + +			/* something like reset_state would maybe me more clear? */ +			destroy_state(&group_state); +			group_state = create_state(state); +		} + +		merge(&group_state, &arg_state); +		destroy_state(&arg_state); +		prev_group = group; +		if (ret) +			break; +	} + +	destroy_state(&group_state); +	return ret;  }  static int mvcheck_closure(struct state *state, struct ast *node) @@ -107,29 +135,148 @@ static int mvcheck_closure(struct state *state, struct ast *node)  	return ret;  } +static void opt_group_left(struct state *state, struct ast *def, +                           struct ast *node) +{ +	if (!def) +		return; + +	insert_move(state, def, node); +	opt_group_left(state, def->ol, node); +} + +static void opt_group_right(struct state *state, struct ast *def, +                            struct ast *node) +{ +	if (!def) +		return; + +	insert_move(state, def, node); +	opt_group_right(state, def->or, node); +} +  static int mvcheck_id(struct state *state, struct ast *node)  {  	struct ast *def = file_scope_find_symbol(node->scope, id_str(node));  	assert(def); +	/* moves only apply to variables, functions are 'eternal' */ +	if (def->k != AST_VAR_DEF) +		return 0; +  	struct ast_pair *prev = find_move(state, def);  	if (prev) { +		/* error messages for opt groups could be improved */  		move_error(node, prev->use);  		return -1;  	}  	insert_move(state, def, node); + +	if (def->or || def->ol) { +		/* we're part of an opt group, add all other members as if they +		 * were moved as well  */ +		opt_group_left(state, def->ol, node); +		opt_group_right(state, def->or, node); +	} + +	return 0; +} + +static int mvcheck_let(struct state *state, struct ast *node) +{ +	return mvcheck(state, let_expr(node)); +} + +static int mvcheck_init(struct state *state, struct ast *node) +{ +	return mvcheck_list(state, init_body(node)); +} + +static int mvcheck_if(struct state *state, struct ast *node) +{ +	if (mvcheck(state, if_cond(node))) +		return -1; + +	struct state body_state = create_state(state); +	struct state else_state = create_state(state); + +	if (mvcheck(&body_state, if_body(node))) { +		destroy_state(&body_state); +		destroy_state(&else_state); +		return -1; +	} + +	if (mvcheck(&else_state, if_else(node))) { +		destroy_state(&body_state); +		destroy_state(&else_state); +		return -1; +	} + +	push_up(&body_state); +	push_up(&else_state); + +	destroy_state(&body_state); +	destroy_state(&else_state); +	return 0; +} + +static int mvcheck_unop(struct state *state, struct ast *node) +{ +	return mvcheck(state, unop_expr(node)); +} + +static int mvcheck_binop(struct state *state, struct ast *node) +{ +	if (mvcheck(state, binop_left(node))) +		return -1; + +	return mvcheck(state, binop_right(node)); +} + +static int mvcheck_comparison(struct state *state, struct ast *node) +{ +	if (mvcheck(state, comparison_left(node))) +		return -1; + +	return mvcheck(state, comparison_right(node)); +} + +static int mvcheck_list(struct state *state, struct ast *nodes) +{ +	foreach_node(node, nodes) { +		if (mvcheck(state, node)) +			return -1; +	} +  	return 0;  }  static int mvcheck(struct state *state, struct ast *node)  { +	if (is_unop(node)) +		return mvcheck_unop(state, node); + +	if (is_binop(node)) +		return mvcheck_binop(state, node); + +	if (is_comparison(node)) +		return mvcheck_comparison(state, node); +  	switch (node->k) { -	case AST_PROC_DEF:	return mvcheck_proc	(state, node); -	case AST_BLOCK:		return mvcheck_block	(state, node); -	case AST_CALL:		return mvcheck_call	(state, node); -	case AST_CLOSURE:	return mvcheck_closure	(state, node); -	case AST_ID:		return mvcheck_id	(state, node); +	case AST_PROC_DEF:      return mvcheck_proc     (state, node); +	case AST_BLOCK:         return mvcheck_block    (state, node); +	case AST_CALL:          return mvcheck_call     (state, node); +	case AST_CLOSURE:       return mvcheck_closure  (state, node); +	case AST_LET:           return mvcheck_let      (state, node); +	case AST_ID:            return mvcheck_id       (state, node); +	case AST_INIT:          return mvcheck_init     (state, node); +	case AST_IF:            return mvcheck_if       (state, node); +	case AST_CONST_INT: +	case AST_CONST_STR: +	case AST_CONST_FLOAT: +	case AST_CONST_CHAR: +		return 0;  	default: break;  	} @@ -143,6 +290,8 @@ int mvcheck_root(struct ast *root)  		struct state state = create_state(NULL);  		if (mvcheck(&state, node))  			return -1; + +		destroy_state(&state);  	}  	return 0; diff --git a/src/parser.y b/src/parser.y index 9f532b9..dd177d0 100644 --- a/src/parser.y +++ b/src/parser.y @@ -53,6 +53,7 @@  %token PLUS "+"  %token XOR "^"  %token AND "&" +%token BAR "|"  %token TILDE "~"  %token LT "<"  %token GT ">" @@ -183,6 +184,7 @@ var  rev_vars  	: rev_vars "," var { $$ = $3; $$->n = $1; } +	| rev_vars "|" var { $$ = $3; $$->n = $1; opt_group($1, $3); }  	| var  vars @@ -230,7 +232,7 @@ type  	| "*" type { $$ = tgen_ptr($2, src_loc(@$)); }  rev_types -	: rev_types "," type { $$ = $3; $3->n = $$; } +	: rev_types "," type { $$ = $3; $$->n = $1; }  	| type  types | 
