Add unsigned integer shifts

This commit is contained in:
Bruce Hill 2024-11-03 15:48:13 -05:00
parent 792743dff3
commit 3743913ce2
6 changed files with 64 additions and 13 deletions

4
ast.c
View File

@ -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",
};

2
ast.h
View File

@ -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,

View File

@ -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:

21
parse.c
View File

@ -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;

View File

@ -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

View File

@ -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))