~sircmpwn/harec unlisted

0cc65bddc822f5898b71cdd5a8d644b649ca1979 — Bor Grošelj Simić a month ago 5c4effb
implement &&=, ||= and ^^= operators

Signed-off-by: Bor Grošelj Simić <bor.groseljsimic@telemach.net>
5 files changed, 155 insertions(+), 55 deletions(-)

M include/lex.h
M src/gen.c
M src/lex.c
M src/parse.c
M tests/10-binarithms.ha
M include/lex.h => include/lex.h +5 -2
@@ 70,7 70,7 @@ enum lexical_token {
	T_LAST_KEYWORD = T_VOID,

	// Operators
	T_ANDEQ,
	T_BANDEQ,
	T_BAND,
	T_BNOT,
	T_BOR,


@@ 86,6 86,7 @@ enum lexical_token {
	T_GREATER,
	T_GREATEREQ,
	T_LAND,
	T_LANDEQ,
	T_LBRACE,
	T_LBRACKET,
	T_LEQUAL,


@@ 93,17 94,19 @@ enum lexical_token {
	T_LESSEQ,
	T_LNOT,
	T_LOR,
	T_LOREQ,
	T_LPAREN,
	T_LSHIFT,
	T_LSHIFTEQ,
	T_LXOR,
	T_LXOREQ,
	T_MINUS,
	T_MINUSEQ,
	T_MINUSMINUS,
	T_MODEQ,
	T_MODULO,
	T_NEQUAL,
	T_OREQ,
	T_BOREQ,
	T_PLUS,
	T_PLUSEQ,
	T_PLUSPLUS,

M src/gen.c => src/gen.c +27 -2
@@ 908,6 908,32 @@ gen_expr_assign(struct gen_context *ctx,
			qval_deref(&src);
		}
		gen_expression(ctx, value, &src);
	} else if (expr->assign.op == BIN_LAND || expr->assign.op == BIN_LOR) {
		struct qbe_statement rlabel = {0}, slabel = {0};
		struct qbe_value rbranch = {0}, sbranch = {0}, result = {0};
		rbranch.kind = QV_LABEL;
		rbranch.name = strdup(genl(&rlabel, &ctx->id, "value.%d"));
		sbranch.kind = QV_LABEL;
		sbranch.name = strdup(genl(&slabel, &ctx->id, "short_circuit.%d"));

		struct qbe_value load;
		gen_loadtemp(ctx, &load, &src, otype, type_is_signed(objtype));
		if (expr->binarithm.op == BIN_LAND) {
			pushi(ctx->current, NULL, Q_JNZ, &load, &rbranch,
				&sbranch, NULL);
		} else {
			pushi(ctx->current, NULL, Q_JNZ, &load, &sbranch,
				&rbranch, NULL);
		}

		push(&ctx->current->body, &rlabel);
		gen_temp(ctx, &result, otype, "assign.result.%d");
		gen_expression(ctx, value, &result);
		gen_store(ctx, &src, &result);
		if (!value->terminates) {
			pushi(ctx->current, NULL, Q_JMP, &sbranch, NULL);
		}
		push(&ctx->current->body, &slabel);
	} else {
		struct qbe_value v = {0};
		gen_temp(ctx, &v, vtype, "assign.value.%d");


@@ 917,8 943,7 @@ gen_expr_assign(struct gen_context *ctx,
		gen_temp(ctx, &result, otype, "assign.result.%d");

		struct qbe_value load;
		gen_loadtemp(ctx, &load, &src, otype,
			type_is_signed(objtype));
		gen_loadtemp(ctx, &load, &src, otype, type_is_signed(objtype));
		pushi(ctx->current, &result,
			binarithm_for_op(expr->assign.op, otype,
				type_is_signed(objtype)),

M src/lex.c => src/lex.c +74 -47
@@ 77,7 77,7 @@ static const char *tokens[] = {
	[T_VOID] = "void",

	// Operators
	[T_ANDEQ] = "&=",
	[T_BANDEQ] = "&=",
	[T_BAND] = "&",
	[T_BNOT] = "~",
	[T_BOR] = "|",


@@ 93,6 93,7 @@ static const char *tokens[] = {
	[T_GREATER] = ">",
	[T_GREATEREQ] = ">=",
	[T_LAND] = "&&",
	[T_LANDEQ] = "&&=",
	[T_LBRACE] = "{",
	[T_LBRACKET] = "[",
	[T_LEQUAL] = "==",


@@ 100,17 101,19 @@ static const char *tokens[] = {
	[T_LESSEQ] = "<=",
	[T_LNOT] = "!",
	[T_LOR] = "||",
	[T_LOREQ] = "||=",
	[T_LPAREN] = "(",
	[T_LSHIFT] = "<<",
	[T_LSHIFTEQ] = "<<=",
	[T_LXOR] = "^^",
	[T_LXOREQ] = "^^=",
	[T_MINUS] = "-",
	[T_MINUSEQ] = "-=",
	[T_MINUSMINUS] = "--",
	[T_MODEQ] = "%=",
	[T_MODULO] = "%",
	[T_NEQUAL] = "!=",
	[T_OREQ] = "|=",
	[T_BOREQ] = "|=",
	[T_PLUS] = "+",
	[T_PLUSEQ] = "+=",
	[T_PLUSPLUS] = "++",


@@ 653,6 656,72 @@ lex3(struct lexer *lexer, struct token *out, uint32_t c)
			break;
		}
		break;
	case '&':
		switch ((c = next(lexer, NULL, false))) {
		case '&':
			switch ((c = next(lexer, NULL, false))) {
			case '=':
				out->token = T_LANDEQ;
				break;
			default:
				push(lexer, c, false);
				out->token = T_LAND;
				break;
			}
			break;
		case '=':
			out->token = T_BANDEQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BAND;
			break;
		}
		break;
	case '|':
		switch ((c = next(lexer, NULL, false))) {
		case '|':
			switch ((c = next(lexer, NULL, false))) {
			case '=':
				out->token = T_LOREQ;
				break;
			default:
				push(lexer, c, false);
				out->token = T_LOR;
				break;
			}
			break;
		case '=':
			out->token = T_BOREQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BOR;
			break;
		}
		break;
	case '^':
		switch ((c = next(lexer, NULL, false))) {
		case '^':
			switch ((c = next(lexer, NULL, false))) {
			case '=':
				out->token = T_LXOREQ;
				break;
			default:
				push(lexer, c, false);
				out->token = T_LXOR;
				break;
			}
			break;
		case '=':
			out->token = T_BXOREQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BXOR;
			break;
		}
		break;
	default:
		assert(0); // Invariant
	}


@@ 684,20 753,6 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c)
	assert(c != UTF8_INVALID);

	switch (c) {
	case '^':
		switch ((c = next(lexer, NULL, false))) {
		case '^':
			out->token = T_LXOR;
			break;
		case '=':
			out->token = T_BXOREQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BXOR;
			break;
		}
		break;
	case '*':
		switch ((c = next(lexer, NULL, false))) {
		case '=':


@@ 793,34 848,6 @@ lex2(struct lexer *lexer, struct token *out, uint32_t c)
			break;
		}
		break;
	case '&':
		switch ((c = next(lexer, NULL, false))) {
		case '&':
			out->token = T_LAND;
			break;
		case '=':
			out->token = T_ANDEQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BAND;
			break;
		}
		break;
	case '|':
		switch ((c = next(lexer, NULL, false))) {
		case '|':
			out->token = T_LOR;
			break;
		case '=':
			out->token = T_OREQ;
			break;
		default:
			push(lexer, c, false);
			out->token = T_BOR;
			break;
		}
		break;
	case '=':
		switch ((c = next(lexer, NULL, false))) {
		case '=':


@@ 875,8 902,10 @@ _lex(struct lexer *lexer, struct token *out)
	case '.': // . .. ...
	case '<': // < << <= <<=
	case '>': // > >> >= >>=
	case '&': // & && &= &&=
	case '|': // | || |= ||=
	case '^': // ^ ^^ ^= ^^=
		return lex3(lexer, out, c);
	case '^': // ^ ^=
	case '*': // * *=
	case '%': // % %=
	case '/': // / /= //


@@ 884,8 913,6 @@ _lex(struct lexer *lexer, struct token *out)
	case '-': // - -=
	case ':': // : ::
	case '!': // ! !=
	case '&': // & && &=
	case '|': // | || |=
	case '=': // = == =>
		return lex2(lexer, out, c);
	case '~':

M src/parse.c => src/parse.c +8 -2
@@ 2180,8 2180,10 @@ parse_expression(struct lexer *lexer)
	switch (lex(lexer, &tok)) {
	case T_EQUAL:
		return parse_assignment(lexer, value, indirect, BIN_LEQUAL);
	case T_ANDEQ:
	case T_BANDEQ:
		return parse_assignment(lexer, value, indirect, BIN_BAND);
	case T_LANDEQ:
		return parse_assignment(lexer, value, indirect, BIN_LAND);
	case T_DIVEQ:
		return parse_assignment(lexer, value, indirect, BIN_DIV);
	case T_LSHIFTEQ:


@@ 2190,8 2192,10 @@ parse_expression(struct lexer *lexer)
		return parse_assignment(lexer, value, indirect, BIN_MINUS);
	case T_MODEQ:
		return parse_assignment(lexer, value, indirect, BIN_MODULO);
	case T_OREQ:
	case T_BOREQ:
		return parse_assignment(lexer, value, indirect, BIN_BOR);
	case T_LOREQ:
		return parse_assignment(lexer, value, indirect, BIN_LOR);
	case T_PLUSEQ:
		return parse_assignment(lexer, value, indirect, BIN_PLUS);
	case T_RSHIFTEQ:


@@ 2200,6 2204,8 @@ parse_expression(struct lexer *lexer)
		return parse_assignment(lexer, value, indirect, BIN_TIMES);
	case T_BXOREQ:
		return parse_assignment(lexer, value, indirect, BIN_BXOR);
	case T_LXOREQ:
		return parse_assignment(lexer, value, indirect, BIN_LXOR);
	default:
		unlex(lexer, &tok);
		if (indirect) {

M tests/10-binarithms.ha => tests/10-binarithms.ha +41 -2
@@ 8,7 8,7 @@ fn set(x: *int) bool = {
	return true;
};

fn andor() void = {
fn andorxor() void = {
	assert((false || false) == false);
	assert((false || true) == true);
	assert((true || false) == true);


@@ 18,6 18,18 @@ fn andor() void = {
	assert((false || set(&x)) == true);
	assert(x == 42);

	let x = 0;
	let f = false;
	f ||= false;
	assert(!f);
	f ||= set(&x);
	assert(x == 42);
	assert(f);
	f || error();
	assert(f);
	f ||= false;
	assert(f);

	assert((false && false) == false);
	assert((false && true) == false);
	assert((true && false) == false);


@@ 26,6 38,33 @@ fn andor() void = {
	x = 0;
	assert((true && set(&x)) == true);
	assert(x == 42);

	let x = 0;
	let f = true;
	f &&= true;
	f &&= set(&x);
	assert(x == 42);
	assert(f);
	f &&= false;
	assert(!f);
	f &&= error();
	f &&= true;
	assert(!f);

	assert((false ^^ false) == false);
	assert((false ^^ true) == true);
	assert((true ^^ false) == true);
	assert((true ^^ true) == false);

	let f = true;
	f ^^= true;
	assert(!f);
	f ^^= false;
	assert(!f);
	f ^^= true;
	assert(f);
	f ^^= false;
	assert(f);
};

fn sar_shr() void = {


@@ 52,6 91,6 @@ fn sar_shr() void = {

export fn main() void = {
	// TODO: other binarithms
	andor();
	andorxor();
	sar_shr();
};