From 3743913ce2c5bc37f899d437c09b60cbb3bc6dea Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Sun, 3 Nov 2024 15:48:13 -0500 Subject: Add unsigned integer shifts --- ast.c | 4 +++- ast.h | 2 +- compile.c | 34 +++++++++++++++++++++++++++++++--- parse.c | 21 +++++++++++++++++---- test/integers.tm | 10 ++++++++++ typecheck.c | 6 ++---- 6 files changed, 64 insertions(+), 13 deletions(-) diff --git a/ast.c b/ast.c index 65a8f405..5087e91f 100644 --- a/ast.c +++ b/ast.c @@ -15,7 +15,8 @@ static const char *OP_NAMES[] = { [BINOP_UNKNOWN]="unknown", [BINOP_POWER]="^", [BINOP_MULT]="*", [BINOP_DIVIDE]="/", [BINOP_MOD]="mod", [BINOP_MOD1]="mod1", [BINOP_PLUS]="+", [BINOP_MINUS]="minus", - [BINOP_CONCAT]="++", [BINOP_LSHIFT]="<<", [BINOP_RSHIFT]=">>", [BINOP_MIN]="min", + [BINOP_CONCAT]="++", [BINOP_LSHIFT]="<<", [BINOP_ULSHIFT]="<<[u]", + [BINOP_RSHIFT]=">>", [BINOP_URSHIFT]=">>[u]", [BINOP_MIN]="min", [BINOP_MAX]="max", [BINOP_EQ]="==", [BINOP_NE]="!=", [BINOP_LT]="<", [BINOP_LE]="<=", [BINOP_GT]=">", [BINOP_GE]=">=", [BINOP_CMP]="<>", [BINOP_AND]="and", [BINOP_OR]="or", [BINOP_XOR]="xor", @@ -25,6 +26,7 @@ const char *binop_method_names[BINOP_XOR+1] = { [BINOP_POWER]="power", [BINOP_MULT]="times", [BINOP_DIVIDE]="divided_by", [BINOP_MOD]="modulo", [BINOP_MOD1]="modulo1", [BINOP_PLUS]="plus", [BINOP_MINUS]="minus", [BINOP_CONCAT]="concatenated_with", [BINOP_LSHIFT]="left_shifted", [BINOP_RSHIFT]="right_shifted", + [BINOP_ULSHIFT]="unsigned_left_shifted", [BINOP_URSHIFT]="unsigned_right_shifted", [BINOP_AND]="bit_and", [BINOP_OR]="bit_or", [BINOP_XOR]="bit_xor", }; diff --git a/ast.h b/ast.h index 6546dd2d..bae74e56 100644 --- a/ast.h +++ b/ast.h @@ -61,7 +61,7 @@ typedef struct when_clause_s { typedef enum { BINOP_UNKNOWN, BINOP_POWER=100, BINOP_MULT, BINOP_DIVIDE, BINOP_MOD, BINOP_MOD1, BINOP_PLUS, - BINOP_MINUS, BINOP_CONCAT, BINOP_LSHIFT, BINOP_RSHIFT, BINOP_MIN, + BINOP_MINUS, BINOP_CONCAT, BINOP_LSHIFT, BINOP_ULSHIFT, BINOP_RSHIFT, BINOP_URSHIFT, BINOP_MIN, BINOP_MAX, BINOP_EQ, BINOP_NE, BINOP_LT, BINOP_LE, BINOP_GT, BINOP_GE, BINOP_CMP, BINOP_AND, BINOP_OR, BINOP_XOR, diff --git a/compile.c b/compile.c index e226668f..383a4e03 100644 --- a/compile.c +++ b/compile.c @@ -28,6 +28,7 @@ static CORD compile_string(env_t *env, ast_t *ast, CORD color); static CORD compile_arguments(env_t *env, ast_t *call_ast, arg_t *spec_args, arg_ast_t *call_args); static CORD compile_maybe_incref(env_t *env, ast_t *ast); static CORD compile_int_to_type(env_t *env, ast_t *ast, type_t *target); +static CORD compile_unsigned_type(type_t *t); static CORD promote_to_optional(type_t *t, CORD code); static CORD compile_null(type_t *t); @@ -198,6 +199,19 @@ CORD compile_declaration(type_t *t, CORD name) } } +PUREFUNC CORD compile_unsigned_type(type_t *t) +{ + if (t->tag != IntType) + errx(1, "Not an int type, so unsigned doesn't make sense!"); + switch (Match(t, IntType)->bits) { + case TYPE_IBITS8: return "uint8_t"; + case TYPE_IBITS16: return "uint16_t"; + case TYPE_IBITS32: return "uint32_t"; + case TYPE_IBITS64: return "uint64_t"; + default: errx(1, "Invalid integer bit size"); + } +} + CORD compile_type(type_t *t) { if (t == THREAD_TYPE) return "Thread_t"; @@ -1772,7 +1786,7 @@ CORD compile_math_method(env_t *env, binop_e op, ast_t *lhs, ast_t *rhs, type_t } break; } - case BINOP_LSHIFT: case BINOP_RSHIFT: { + case BINOP_LSHIFT: case BINOP_RSHIFT: case BINOP_ULSHIFT: case BINOP_URSHIFT: { if (rhs_t->tag == IntType || rhs_t->tag == BigIntType) { binding_t *b = get_namespace_binding(env, lhs, binop_method_names[op]); if (binding_works(b, lhs_t, rhs_t, lhs_t)) @@ -2051,13 +2065,17 @@ CORD compile(env_t *env, ast_t *ast) CORD lhs = compile(env, binop->lhs); // Special case for bit shifting by an integer literal: - if (binop->op == BINOP_LSHIFT || binop->op == BINOP_RSHIFT) { + if (binop->op == BINOP_LSHIFT || binop->op == BINOP_RSHIFT || binop->op == BINOP_ULSHIFT || binop->op == BINOP_URSHIFT) { if (lhs_t->tag == IntType && rhs_t->tag == BigIntType && binop->rhs->tag == Int) { CORD shift_amount = compile_int_to_type(env, binop->rhs, lhs_t); if (binop->op == BINOP_LSHIFT) return CORD_all("(", lhs, " << ", shift_amount, ")"); - else + else if (binop->op == BINOP_ULSHIFT) + return CORD_all("(", compile_type(lhs_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", shift_amount, ")"); + else if (binop->op == BINOP_RSHIFT) return CORD_all("(", lhs, " >> ", shift_amount, ")"); + else if (binop->op == BINOP_URSHIFT) + return CORD_all("(", compile_type(lhs_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", shift_amount, ")"); } } @@ -2120,6 +2138,16 @@ CORD compile(env_t *env, ast_t *ast) code_err(ast, "Math operations are only supported for values of the same numeric type, not %T vs %T", lhs_t, rhs_t); return CORD_all("(", lhs, " >> ", rhs, ")"); } + case BINOP_ULSHIFT: { + if (operand_t->tag != IntType && operand_t->tag != NumType && operand_t->tag != ByteType) + code_err(ast, "Math operations are only supported for values of the same numeric type, not %T vs %T", lhs_t, rhs_t); + return CORD_all("(", compile_type(operand_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " << ", rhs, ")"); + } + case BINOP_URSHIFT: { + if (operand_t->tag != IntType && operand_t->tag != NumType && operand_t->tag != ByteType) + code_err(ast, "Math operations are only supported for values of the same numeric type, not %T vs %T", lhs_t, rhs_t); + return CORD_all("(", compile_type(operand_t), ")((", compile_unsigned_type(lhs_t), ")", lhs, " >> ", rhs, ")"); + } case BINOP_EQ: { switch (operand_t->tag) { case BigIntType: diff --git a/parse.c b/parse.c index 13c0a208..1e76f828 100644 --- a/parse.c +++ b/parse.c @@ -1704,13 +1704,26 @@ binop_e match_binary_operator(const char **pos) case '*': *pos += 1; return BINOP_MULT; case '/': *pos += 1; return BINOP_DIVIDE; case '^': *pos += 1; return BINOP_POWER; - case '<': + case '<': { *pos += 1; if (match(pos, "=")) return BINOP_LE; else if (match(pos, ">")) return BINOP_CMP; - else if (match(pos, "<")) return BINOP_LSHIFT; - else return BINOP_LT; - case '>': *pos += 1; return match(pos, "=") ? BINOP_GE : (match(pos, ">") ? BINOP_RSHIFT : BINOP_GT); + else if (match(pos, "<")) { + if (match(pos, "[u]")) + return BINOP_ULSHIFT; + return BINOP_LSHIFT; + } else return BINOP_LT; + } + case '>': { + *pos += 1; + if (match(pos, "=")) return BINOP_GE; + if (match(pos, ">")) { + if (match(pos, "[u]")) + return BINOP_URSHIFT; + return BINOP_RSHIFT; + } + return BINOP_GT; + } default: { if (match(pos, "!=")) return BINOP_NE; else if (match(pos, "==") && **pos != '=') return BINOP_EQ; diff --git a/test/integers.tm b/test/integers.tm index 8d34dfc0..225baab5 100644 --- a/test/integers.tm +++ b/test/integers.tm @@ -17,6 +17,16 @@ func main(): >> 1 << 10 = 1024 + !! Signed and unsigned bit shifting: + >> -2[64] << 1 + = -4[64] + >> -2[64] <<[u] 1 + = -4[64] + >> -2[64] >> 1 + = -1[64] + >> -2[64] >>[u] 1 + = 9223372036854775807[64] + >> 3 and 2 = 2 diff --git a/typecheck.c b/typecheck.c index 7cc081de..e5255959 100644 --- a/typecheck.c +++ b/typecheck.c @@ -927,10 +927,8 @@ type_t *get_type(env_t *env, ast_t *ast) return lhs_t; break; } - case BINOP_LSHIFT: case BINOP_RSHIFT: { - if (is_int_type(rhs_t) && binding_works(binop_method_names[binop->op], binop->lhs, lhs_t, rhs_t, lhs_t)) - return lhs_t; - break; + case BINOP_LSHIFT: case BINOP_RSHIFT: case BINOP_ULSHIFT: case BINOP_URSHIFT: { + return lhs_t; } case BINOP_POWER: { if (is_numeric_type(rhs_t) && binding_works(binop_method_names[binop->op], binop->lhs, lhs_t, rhs_t, lhs_t)) -- cgit v1.2.3