Add unsigned integer shifts
This commit is contained in:
parent
792743dff3
commit
3743913ce2
4
ast.c
4
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",
|
||||
};
|
||||
|
||||
|
2
ast.h
2
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,
|
||||
|
34
compile.c
34
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:
|
||||
|
21
parse.c
21
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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user