From 6a0d55056254a87e4a2aaa22e30e4ff9a2a93ec4 Mon Sep 17 00:00:00 2001 From: Bob Nystrom Date: Wed, 4 Dec 2013 22:09:31 -0800 Subject: [PATCH] Bitwise ~ operator. --- src/wren_compiler.c | 11 ++++++++--- src/wren_core.c | 9 +++++++++ test/assignment/associativity.wren | 9 +++++++++ test/number/bitwise_not.wren | 23 +++++++++++++++++++++++ 4 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 test/assignment/associativity.wren create mode 100644 test/number/bitwise_not.wren diff --git a/src/wren_compiler.c b/src/wren_compiler.c index aa7e8a88..9150b383 100644 --- a/src/wren_compiler.c +++ b/src/wren_compiler.c @@ -56,6 +56,7 @@ typedef enum TOKEN_AMP, TOKEN_AMPAMP, TOKEN_BANG, + TOKEN_TILDE, TOKEN_EQ, TOKEN_LT, TOKEN_GT, @@ -481,6 +482,9 @@ static void readRawToken(Parser* parser) case '.': makeToken(parser, TOKEN_DOT); return; case ',': makeToken(parser, TOKEN_COMMA); return; case '*': makeToken(parser, TOKEN_STAR); return; + case '%': makeToken(parser, TOKEN_PERCENT); return; + case '+': makeToken(parser, TOKEN_PLUS); return; + case '~': makeToken(parser, TOKEN_TILDE); return; case '/': if (peekChar(parser) == '/') { @@ -497,8 +501,6 @@ static void readRawToken(Parser* parser) makeToken(parser, TOKEN_SLASH); return; - case '%': makeToken(parser, TOKEN_PERCENT); return; - case '+': makeToken(parser, TOKEN_PLUS); return; case '-': if (isDigit(peekChar(parser))) { @@ -614,6 +616,7 @@ static void nextToken(Parser* parser) case TOKEN_AMP: case TOKEN_AMPAMP: case TOKEN_BANG: + case TOKEN_TILDE: case TOKEN_EQ: case TOKEN_LT: case TOKEN_GT: @@ -1432,6 +1435,7 @@ void mixedSignature(Compiler* compiler, char* name, int* length) #define INFIX(prec, fn) { NULL, fn, NULL, prec, NULL } #define INFIX_OPERATOR(prec, name) { NULL, infixOp, infixSignature, prec, name } #define PREFIX_OPERATOR(name) { unaryOp, NULL, unarySignature, PREC_NONE, name } +#define OPERATOR(name) { unaryOp, infixOp, mixedSignature, PREC_TERM, name } GrammarRule rules[] = { @@ -1448,12 +1452,13 @@ GrammarRule rules[] = /* TOKEN_SLASH */ INFIX_OPERATOR(PREC_FACTOR, "/ "), /* TOKEN_PERCENT */ INFIX_OPERATOR(PREC_TERM, "% "), /* TOKEN_PLUS */ INFIX_OPERATOR(PREC_TERM, "+ "), - /* TOKEN_MINUS */ { unaryOp, infixOp, mixedSignature, PREC_TERM, "- " }, + /* TOKEN_MINUS */ OPERATOR("- "), /* TOKEN_PIPE */ UNUSED, /* TOKEN_PIPEPIPE */ INFIX(PREC_LOGIC, or), /* TOKEN_AMP */ UNUSED, /* TOKEN_AMPAMP */ INFIX(PREC_LOGIC, and), /* TOKEN_BANG */ PREFIX_OPERATOR("!"), + /* TOKEN_TILDE */ PREFIX_OPERATOR("~"), /* TOKEN_EQ */ UNUSED, /* TOKEN_LT */ INFIX_OPERATOR(PREC_COMPARISON, "< "), /* TOKEN_GT */ INFIX_OPERATOR(PREC_COMPARISON, "> "), diff --git a/src/wren_core.c b/src/wren_core.c index bed1b669..a5bee0f1 100644 --- a/src/wren_core.c +++ b/src/wren_core.c @@ -297,6 +297,13 @@ DEF_NATIVE(num_bangeq) return BOOL_VAL(AS_NUM(args[0]) != AS_NUM(args[1])); } +DEF_NATIVE(num_bitwiseNot) +{ + // Bitwise operators always work on 32-bit unsigned ints. + uint32_t value = (uint32_t)AS_NUM(args[0]); + return NUM_VAL(~value); +} + DEF_NATIVE(object_eqeq) { return BOOL_VAL(wrenValuesEqual(args[0], args[1])); @@ -478,6 +485,8 @@ void wrenInitializeCore(WrenVM* vm) NATIVE(vm->numClass, "> ", num_gt); NATIVE(vm->numClass, "<= ", num_lte); NATIVE(vm->numClass, ">= ", num_gte); + NATIVE(vm->numClass, "~", num_bitwiseNot); + // TODO(bob): The only reason there are here is so that 0 != -0. Is that what // we want? NATIVE(vm->numClass, "== ", num_eqeq); diff --git a/test/assignment/associativity.wren b/test/assignment/associativity.wren new file mode 100644 index 00000000..19dbc0e6 --- /dev/null +++ b/test/assignment/associativity.wren @@ -0,0 +1,9 @@ +var a = "a" +var b = "b" +var c = "c" + +// Assignment is right-associative. +a = b = c +io.write(a) // expect: c +io.write(b) // expect: c +io.write(c) // expect: c diff --git a/test/number/bitwise_not.wren b/test/number/bitwise_not.wren new file mode 100644 index 00000000..2e09245c --- /dev/null +++ b/test/number/bitwise_not.wren @@ -0,0 +1,23 @@ +io.write(~0) // expect: 4294967295 +io.write(~1) // expect: 4294967294 +io.write(~23) // expect: 4294967272 + +// Max u32 value. +io.write(~4294967295) // expect: 0 + +// Past max u32 value. +// TODO(bob): Is this right? +io.write(~4294967296) // expect: 4294967295 + +// Negative numbers. +io.write(~-1) // expect: 0 +io.write(~-123) // expect: 122 +io.write(~-4294967294) // expect: 4294967293 +io.write(~-4294967295) // expect: 4294967294 +io.write(~-4294967296) // expect: 4294967295 + +// Floating point values. +io.write(~1.23) // expect: 4294967294 +io.write(~0.00123) // expect: 4294967295 +io.write(~345.67) // expect: 4294966950 +io.write(~-12.34) // expect: 11