<commit_before>#include "ops.h"

const char *str_expr_assign()
{
	return "assign";
}

int expr_is_lvalue(expr *e, enum lvalue_opts opts)
{
	/*
	 * valid lvaluess:
	 *
	 *   x              = 5;
	 *   *(expr)        = 5;
	 *   struct.member  = 5;
	 *   struct->member = 5;
	 * and so on
	 *
	 * also can't be const, checked in fold_assign (since we allow const inits)
	 */

	if(decl_is_array(e->tree_type))
		return opts & LVAL_ALLOW_ARRAY;

	if(expr_kind(e, identifier))
		return (opts & LVAL_ALLOW_FUNC) || !e->tree_type->func_code;

	if(expr_kind(e, op))
		switch(e->op){
			case op_deref:
			case op_struct_ptr:
			case op_struct_dot:
				return 1;
			default:
				break;
		}

	return 0;
}

void fold_expr_assign(expr *e, symtable *stab)
{
	int type_ok;

	fold_inc_writes_if_sym(e->lhs, stab);

	fold_expr(e->lhs, stab);
	fold_expr(e->rhs, stab);

	if(expr_kind(e->lhs, identifier))
		e->lhs->sym->nreads--; /* cancel the read that fold_ident thinks it got */

	fold_coerce_assign(e->lhs->tree_type, e->rhs, &type_ok);

	if(!expr_is_lvalue(e->lhs, LVAL_ALLOW_ARRAY)){
		/* only allow assignments to type[] if it's an init */
		DIE_AT(&e->lhs->where, "not an lvalue (%s%s%s)",
				e->lhs->f_str(),
				expr_kind(e->lhs, op) ? " - " : "",
				expr_kind(e->lhs, op) ? op_to_str(e->lhs->op) : ""
			);
	}

	if(decl_is_const(e->lhs->tree_type)){
		/* allow const init: */
		sym *const sym = e->lhs->sym;
		if(!sym || sym->decl->init != e->rhs)
			DIE_AT(&e->where, "can't modify const expression %s", e->lhs->f_str());
	}


	e->tree_type = decl_copy(e->lhs->tree_type);

	/* type check */
	if(!type_ok){
		fold_decl_equal(e->lhs->tree_type, e->rhs->tree_type,
				&e->where, WARN_ASSIGN_MISMATCH,
				"assignment type mismatch%s%s%s",
				e->lhs->spel ? " (" : "",
				e->lhs->spel ? e->lhs->spel : "",
				e->lhs->spel ? ")" : "");
	}

	/* do the typecheck after the equal-check, since the typecheck inserts casts */
	fold_insert_casts(e->lhs->tree_type, &e->rhs, stab, &e->where, "assignment");
}

void gen_expr_assign(expr *e, symtable *stab)
{
	if(e->assign_is_post){
		/* if this is the case, ->rhs->lhs is ->lhs, and ->rhs is an addition/subtraction of 1 * something */
		gen_expr(e->lhs, stab);
		out_comment("save previous for post assignment");
	}

	/*if(decl_is_struct_or_union(e->tree_type))*/
	fold_disallow_st_un(e, "copy (TODO)");

	UCC_ASSERT(e->lhs->f_store, "invalid store expression %s (no f_store())", e->lhs->f_str());

	/* store to the sym's home */
	e->lhs->f_store(e->lhs, stab);

	gen_expr(e->rhs, stab);

	out_store();

	/* if e->assign_is_post, the stack now just has the old value on */
}

void gen_expr_str_assign(expr *e, symtable *stab)
{
	(void)stab;
	idt_printf("%sassignment, expr:\n", e->assign_is_post ? "post-inc/dec " : "");
	idt_printf("assign to:\n");
	gen_str_indent++;
	print_expr(e->lhs);
	gen_str_indent--;
	idt_printf("assign from:\n");
	gen_str_indent++;
	print_expr(e->rhs);
	gen_str_indent--;
}

void mutate_expr_assign(expr *e)
{
	e->freestanding = 1;
}
<commit_msg>Fixed pre/post assignment stack repr<commit_after>#include "ops.h"

const char *str_expr_assign()
{
	return "assign";
}

int expr_is_lvalue(expr *e, enum lvalue_opts opts)
{
	/*
	 * valid lvaluess:
	 *
	 *   x              = 5;
	 *   *(expr)        = 5;
	 *   struct.member  = 5;
	 *   struct->member = 5;
	 * and so on
	 *
	 * also can't be const, checked in fold_assign (since we allow const inits)
	 */

	if(decl_is_array(e->tree_type))
		return opts & LVAL_ALLOW_ARRAY;

	if(expr_kind(e, identifier))
		return (opts & LVAL_ALLOW_FUNC) || !e->tree_type->func_code;

	if(expr_kind(e, op))
		switch(e->op){
			case op_deref:
			case op_struct_ptr:
			case op_struct_dot:
				return 1;
			default:
				break;
		}

	return 0;
}

void fold_expr_assign(expr *e, symtable *stab)
{
	int type_ok;

	fold_inc_writes_if_sym(e->lhs, stab);

	fold_expr(e->lhs, stab);
	fold_expr(e->rhs, stab);

	if(expr_kind(e->lhs, identifier))
		e->lhs->sym->nreads--; /* cancel the read that fold_ident thinks it got */

	fold_coerce_assign(e->lhs->tree_type, e->rhs, &type_ok);

	if(!expr_is_lvalue(e->lhs, LVAL_ALLOW_ARRAY)){
		/* only allow assignments to type[] if it's an init */
		DIE_AT(&e->lhs->where, "not an lvalue (%s%s%s)",
				e->lhs->f_str(),
				expr_kind(e->lhs, op) ? " - " : "",
				expr_kind(e->lhs, op) ? op_to_str(e->lhs->op) : ""
			);
	}

	if(decl_is_const(e->lhs->tree_type)){
		/* allow const init: */
		sym *const sym = e->lhs->sym;
		if(!sym || sym->decl->init != e->rhs)
			DIE_AT(&e->where, "can't modify const expression %s", e->lhs->f_str());
	}


	e->tree_type = decl_copy(e->lhs->tree_type);

	/* type check */
	if(!type_ok){
		fold_decl_equal(e->lhs->tree_type, e->rhs->tree_type,
				&e->where, WARN_ASSIGN_MISMATCH,
				"assignment type mismatch%s%s%s",
				e->lhs->spel ? " (" : "",
				e->lhs->spel ? e->lhs->spel : "",
				e->lhs->spel ? ")" : "");
	}

	/* do the typecheck after the equal-check, since the typecheck inserts casts */
	fold_insert_casts(e->lhs->tree_type, &e->rhs, stab, &e->where, "assignment");
}

void gen_expr_assign(expr *e, symtable *stab)
{
	if(e->assign_is_post){
		/* if this is the case, ->rhs->lhs is ->lhs, and ->rhs is an addition/subtraction of 1 * something */
		gen_expr(e->lhs, stab);
		out_comment("save previous for post assignment");
	}

	/*if(decl_is_struct_or_union(e->tree_type))*/
	fold_disallow_st_un(e, "copy (TODO)");

	UCC_ASSERT(e->lhs->f_store, "invalid store expression %s (no f_store())", e->lhs->f_str());

	/* store to the sym's home */
	e->lhs->f_store(e->lhs, stab);

	gen_expr(e->rhs, stab);

	out_store();

	if(e->assign_is_post){
		out_pop(); /* discard the new value, leave the old on */
		out_comment("pre-inc/dec value");
	}
}

void gen_expr_str_assign(expr *e, symtable *stab)
{
	(void)stab;
	idt_printf("%sassignment, expr:\n", e->assign_is_post ? "post-inc/dec " : "");
	idt_printf("assign to:\n");
	gen_str_indent++;
	print_expr(e->lhs);
	gen_str_indent--;
	idt_printf("assign from:\n");
	gen_str_indent++;
	print_expr(e->rhs);
	gen_str_indent--;
}

void mutate_expr_assign(expr *e)
{
	e->freestanding = 1;
}

{'fraction_non_alphanumeric': 0.18776648081338143, 'fraction_numerical': 0.0026238110856018366, 'mean_word_length': 3.6664116296863045, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 151, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1277169', 'n_tokens_mistral': 2736, 'n_tokens_neox': 2531, 'n_words': 503}