aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2024-11-03 16:06:26 -0500
committerBruce Hill <bruce@bruce-hill.com>2024-11-03 16:06:26 -0500
commit39a58bc129fd9461d54b837bc1650c4c650aa333 (patch)
treed3a7e9b3be33856cc8343f6cb273f9a14c28effd
parent3743913ce2c5bc37f899d437c09b60cbb3bc6dea (diff)
Clean up behavior and syntax for unsigned bit shifts (<<<, >>>)
-rw-r--r--ast.c4
-rw-r--r--compile.c8
-rw-r--r--docs/integers.md5
-rw-r--r--docs/operators.md10
-rw-r--r--environment.c16
-rw-r--r--parse.c22
-rw-r--r--stdlib/integers.h4
-rw-r--r--test/integers.tm4
8 files changed, 45 insertions, 28 deletions
diff --git a/ast.c b/ast.c
index 5087e91f..a17e64a2 100644
--- a/ast.c
+++ b/ast.c
@@ -15,8 +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_ULSHIFT]="<<[u]",
- [BINOP_RSHIFT]=">>", [BINOP_URSHIFT]=">>[u]", [BINOP_MIN]="min",
+ [BINOP_CONCAT]="++", [BINOP_LSHIFT]="<<", [BINOP_ULSHIFT]="<<<",
+ [BINOP_RSHIFT]=">>", [BINOP_URSHIFT]=">>>", [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",
diff --git a/compile.c b/compile.c
index 383a4e03..1f67156a 100644
--- a/compile.c
+++ b/compile.c
@@ -725,6 +725,14 @@ CORD compile_statement(env_t *env, ast_t *ast)
if (lhs_t->tag != IntType && lhs_t->tag != ByteType)
code_err(ast, "I can't do a shift assignment with this operator between %T and %T", lhs_t, rhs_t);
return CORD_all(lhs, " >>= ", rhs, ";");
+ case BINOP_ULSHIFT:
+ if (lhs_t->tag != IntType && lhs_t->tag != ByteType)
+ code_err(ast, "I can't do a shift assignment with this operator between %T and %T", lhs_t, rhs_t);
+ return CORD_all("{ ", compile_unsigned_type(lhs_t), " *dest = (void*)&(", lhs, "); *dest <<= ", rhs, "; }");
+ case BINOP_URSHIFT:
+ if (lhs_t->tag != IntType && lhs_t->tag != ByteType)
+ code_err(ast, "I can't do a shift assignment with this operator between %T and %T", lhs_t, rhs_t);
+ return CORD_all("{ ", compile_unsigned_type(lhs_t), " *dest = (void*)&(", lhs, "); *dest >>= ", rhs, "; }");
case BINOP_AND: {
if (lhs_t->tag == BoolType)
return CORD_all("if (", lhs, ") ", lhs, " = ", rhs, ";");
diff --git a/docs/integers.md b/docs/integers.md
index ef30b74d..1c30aee0 100644
--- a/docs/integers.md
+++ b/docs/integers.md
@@ -21,8 +21,9 @@ truncated form of the input value.
Integers support the standard math operations (`x+y`, `x-y`, `x*y`, `x/y`) as
well as powers/exponentiation (`x^y`), modulus (`x mod y` and `x mod1 y`), and
-bitwise operations: `x and y`, `x or y`, `x xor y`, `x << y`, and `x >> y`. The
-operators `and`, `or`, and `xor` are _bitwise_, not logical operators.
+bitwise operations: `x and y`, `x or y`, `x xor y`, `x << y`, `x >> y`, `x >>>
+y` (unsigned right shift), and `x <<< y` (unsighted left shift). The operators
+`and`, `or`, and `xor` are _bitwise_, not logical operators.
# Integer Functions
diff --git a/docs/operators.md b/docs/operators.md
index 4afa3ad3..25f78689 100644
--- a/docs/operators.md
+++ b/docs/operators.md
@@ -10,6 +10,7 @@ Tomo supports a number of operators, both infix and prefix:
is particularly useful for doing wraparound behavior on 1-indexed arrays.
- `++`: concatenation (for text and arrays)
- `<<`, `>>`: bitwise left shift and right shift for integers
+- `<<<`, `>>>`: unsigned bitwise left shift and right shift for integers
- `_min_`/`_max_`: minimum and maximum (see below)
- `<`, `<=`, `>`, `>=`, `==`, `!=`: comparisons
- `<>`: the signed comparison operator (see below)
@@ -283,8 +284,10 @@ and will return a value of the same type.
#### Bit Operations
```
-func left_shift(T, Int)->T
-func right_shift(T, Int)->T
+func left_shifted(T, Int)->T
+func right_shifted(T, Int)->T
+func unsigned_left_shifted(T, Int)->T
+func unsigned_right_shifted(T, Int)->T
func bit_and(T, T)->T
func bit_or(T, T)->T
func bit_xor(T, T)->T
@@ -292,7 +295,8 @@ func bit_xor(T, T)->T
In a bit shifting expression, `a >> b` or `a << b`, if `a` has type `T` and `b`
is an `Int`, then the method `left_shift()` or `right_shift()` will be invoked.
-A value of type `T` will be returned.
+A value of type `T` will be returned. The same is true for `>>>`
+(`unsigned_right_shift()`) and `<<<` (`unsigned_left_shift`).
In a bitwise binary operation `a and b`, `a or b`, or `a xor b`, then the
method `bit_and()`, `bit_or()`, or `bit_xor()` will be invoked, assuming that
diff --git a/environment.c b/environment.c
index 2cd94f7e..7eb13685 100644
--- a/environment.c
+++ b/environment.c
@@ -138,8 +138,8 @@ env_t *new_compilation_unit(CORD libname)
{"modulo1", "Int64$modulo1", "func(x,y:Int64 -> Int64)"},
{"octal", "Int64$octal", "func(i:Int64, digits=0, prefix=yes -> Text)"},
{"to", "Int64$to", "func(from:Int64,to:Int64 -> Range)"},
- {"unsigned_left_shift", "Int64$unsigned_left_shift", "func(x:Int64,y:Int64 -> Int64)"},
- {"unsigned_right_shift", "Int64$unsigned_right_shift", "func(x:Int64,y:Int64 -> Int64)"},
+ {"unsigned_left_shifted", "Int64$unsigned_left_shifted", "func(x:Int64,y:Int64 -> Int64)"},
+ {"unsigned_right_shifted", "Int64$unsigned_right_shifted", "func(x:Int64,y:Int64 -> Int64)"},
{"wrapping_minus", "Int64$wrapping_minus", "func(x:Int64,y:Int64 -> Int64)"},
{"wrapping_plus", "Int64$wrapping_plus", "func(x:Int64,y:Int64 -> Int64)"},
// Must be defined after min/max:
@@ -159,8 +159,8 @@ env_t *new_compilation_unit(CORD libname)
{"modulo1", "Int32$modulo1", "func(x,y:Int32 -> Int32)"},
{"octal", "Int32$octal", "func(i:Int32, digits=0, prefix=yes -> Text)"},
{"to", "Int32$to", "func(from:Int32,to:Int32 -> Range)"},
- {"unsigned_left_shift", "Int32$unsigned_left_shift", "func(x:Int32,y:Int32 -> Int32)"},
- {"unsigned_right_shift", "Int32$unsigned_right_shift", "func(x:Int32,y:Int32 -> Int32)"},
+ {"unsigned_left_shifted", "Int32$unsigned_left_shifted", "func(x:Int32,y:Int32 -> Int32)"},
+ {"unsigned_right_shifted", "Int32$unsigned_right_shifted", "func(x:Int32,y:Int32 -> Int32)"},
{"wrapping_minus", "Int32$wrapping_minus", "func(x:Int32,y:Int32 -> Int32)"},
{"wrapping_plus", "Int32$wrapping_plus", "func(x:Int32,y:Int32 -> Int32)"},
// Must be defined after min/max:
@@ -180,8 +180,8 @@ env_t *new_compilation_unit(CORD libname)
{"modulo1", "Int16$modulo1", "func(x,y:Int16 -> Int16)"},
{"octal", "Int16$octal", "func(i:Int16, digits=0, prefix=yes -> Text)"},
{"to", "Int16$to", "func(from:Int16,to:Int16 -> Range)"},
- {"unsigned_left_shift", "Int16$unsigned_left_shift", "func(x:Int16,y:Int16 -> Int16)"},
- {"unsigned_right_shift", "Int16$unsigned_right_shift", "func(x:Int16,y:Int16 -> Int16)"},
+ {"unsigned_left_shifted", "Int16$unsigned_left_shifted", "func(x:Int16,y:Int16 -> Int16)"},
+ {"unsigned_right_shifted", "Int16$unsigned_right_shifted", "func(x:Int16,y:Int16 -> Int16)"},
{"wrapping_minus", "Int16$wrapping_minus", "func(x:Int16,y:Int16 -> Int16)"},
{"wrapping_plus", "Int16$wrapping_plus", "func(x:Int16,y:Int16 -> Int16)"},
// Must be defined after min/max:
@@ -201,8 +201,8 @@ env_t *new_compilation_unit(CORD libname)
{"modulo1", "Int8$modulo1", "func(x,y:Int8 -> Int8)"},
{"octal", "Int8$octal", "func(i:Int8, digits=0, prefix=yes -> Text)"},
{"to", "Int8$to", "func(from:Int8,to:Int8 -> Range)"},
- {"unsigned_left_shift", "Int8$unsigned_left_shift", "func(x:Int8,y:Int8 -> Int8)"},
- {"unsigned_right_shift", "Int8$unsigned_right_shift", "func(x:Int8,y:Int8 -> Int8)"},
+ {"unsigned_left_shifted", "Int8$unsigned_left_shifted", "func(x:Int8,y:Int8 -> Int8)"},
+ {"unsigned_right_shifted", "Int8$unsigned_right_shifted", "func(x:Int8,y:Int8 -> Int8)"},
{"wrapping_minus", "Int8$wrapping_minus", "func(x:Int8,y:Int8 -> Int8)"},
{"wrapping_plus", "Int8$wrapping_plus", "func(x:Int8,y:Int8 -> Int8)"},
// Must be defined after min/max:
diff --git a/parse.c b/parse.c
index 1e76f828..0130673a 100644
--- a/parse.c
+++ b/parse.c
@@ -1706,21 +1706,21 @@ binop_e match_binary_operator(const char **pos)
case '^': *pos += 1; return BINOP_POWER;
case '<': {
*pos += 1;
- if (match(pos, "=")) return BINOP_LE;
- else if (match(pos, ">")) return BINOP_CMP;
+ if (match(pos, "=")) return BINOP_LE; // "<="
+ else if (match(pos, ">")) return BINOP_CMP; // "<>"
else if (match(pos, "<")) {
- if (match(pos, "[u]"))
- return BINOP_ULSHIFT;
- return BINOP_LSHIFT;
+ if (match(pos, "<"))
+ return BINOP_ULSHIFT; // "<<<"
+ return BINOP_LSHIFT; // "<<"
} else return BINOP_LT;
}
case '>': {
*pos += 1;
- if (match(pos, "=")) return BINOP_GE;
+ if (match(pos, "=")) return BINOP_GE; // ">="
if (match(pos, ">")) {
- if (match(pos, "[u]"))
- return BINOP_URSHIFT;
- return BINOP_RSHIFT;
+ if (match(pos, ">"))
+ return BINOP_URSHIFT; // ">>>"
+ return BINOP_RSHIFT; // ">>"
}
return BINOP_GT;
}
@@ -1814,6 +1814,10 @@ PARSER(parse_update) {
else if (match(&pos, "*=")) op = BINOP_MULT;
else if (match(&pos, "/=")) op = BINOP_DIVIDE;
else if (match(&pos, "^=")) op = BINOP_POWER;
+ else if (match(&pos, "<<=")) op = BINOP_LSHIFT;
+ else if (match(&pos, "<<<=")) op = BINOP_ULSHIFT;
+ else if (match(&pos, ">>=")) op = BINOP_RSHIFT;
+ else if (match(&pos, ">>>=")) op = BINOP_URSHIFT;
else if (match(&pos, "and=")) op = BINOP_AND;
else if (match(&pos, "or=")) op = BINOP_OR;
else if (match(&pos, "xor=")) op = BINOP_XOR;
diff --git a/stdlib/integers.h b/stdlib/integers.h
index ea286202..e7b5b0e1 100644
--- a/stdlib/integers.h
+++ b/stdlib/integers.h
@@ -67,10 +67,10 @@
MACROLIKE PUREFUNC c_type type_name ## $wrapping_minus(c_type x, c_type y) { \
return (c_type)((u##c_type)x + (u##c_type)y); \
} \
- MACROLIKE PUREFUNC c_type type_name ## $unsigned_left_shift(c_type x, c_type y) { \
+ MACROLIKE PUREFUNC c_type type_name ## $unsigned_left_shifted(c_type x, c_type y) { \
return (c_type)((u##c_type)x << y); \
} \
- MACROLIKE PUREFUNC c_type type_name ## $unsigned_right_shift(c_type x, c_type y) { \
+ MACROLIKE PUREFUNC c_type type_name ## $unsigned_right_shifted(c_type x, c_type y) { \
return (c_type)((u##c_type)x >> y); \
}
diff --git a/test/integers.tm b/test/integers.tm
index 225baab5..9b5b6b4f 100644
--- a/test/integers.tm
+++ b/test/integers.tm
@@ -20,11 +20,11 @@ func main():
!! Signed and unsigned bit shifting:
>> -2[64] << 1
= -4[64]
- >> -2[64] <<[u] 1
+ >> -2[64] <<< 1
= -4[64]
>> -2[64] >> 1
= -1[64]
- >> -2[64] >>[u] 1
+ >> -2[64] >>> 1
= 9223372036854775807[64]
>> 3 and 2