Skip to content

Commit

Permalink
Added bitwise NOT (~) (#360)
Browse files Browse the repository at this point in the history
* Added bitnot

* Fix message
  • Loading branch information
joente authored Feb 5, 2024
1 parent 10a31ef commit 301d4c2
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 25 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
_(This was marked as deprecated since v0.10.1)_
* Added set operators `<=`, `<`, `>=`, `>` for subset, proper subset, superset and proper superset checking.
* Added range `<..>` support for UTF8 type property definitions.
* Added bitwise NOT (`~`) operator.

# v1.4.16

Expand Down
2 changes: 1 addition & 1 deletion grammar/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class LangDef(Grammar):
x_function = Token('(')
x_index = Token('[')
x_parenthesis = Token('(')
x_preopr = Regex(r'(\s*!|\s*[\-+](?=[^0-9]))*')
x_preopr = Regex(r'(\s*~)*(\s*!|\s*[\-+](?=[^0-9]))*')
x_ternary = Token('?')
x_thing = Token('{')
x_template = Token('`')
Expand Down
4 changes: 2 additions & 2 deletions inc/langdef/langdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* should be used with the libcleri module.
*
* Source class: LangDef
* Created at: 2024-01-20 12:46:21
* Created at: 2024-02-04 14:13:28
*/
#ifndef CLERI_EXPORT_LANGDEF_H_
#define CLERI_EXPORT_LANGDEF_H_
Expand All @@ -15,7 +15,7 @@
cleri_grammar_t * compile_langdef(void);
cleri_grammar_t * compile_compat(void);

enum cleri_grammar_compat_ids {
enum cleri_grammar_ids {
CLERI_NONE, // used for objects with no name
CLERI_GID_ARRAY,
CLERI_GID_ASSIGN,
Expand Down
2 changes: 1 addition & 1 deletion inc/ti/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* "-rc0"
* ""
*/
#define TI_VERSION_PRE_RELEASE "-alpha12"
#define TI_VERSION_PRE_RELEASE "-alpha13"

#define TI_MAINTAINER \
"Jeroen van der Heijden <jeroen@cesbit.com>"
Expand Down
4 changes: 4 additions & 0 deletions itest/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,7 @@ def run_test(test: TestBase):
loop = asyncio.get_event_loop()
cleanup()
loop.run_until_complete(_run_test(test))


INT_MIN = -9223372036854775808
INT_MAX = 9223372036854775807
5 changes: 0 additions & 5 deletions itest/test_advanced.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
#!/usr/bin/env python
import asyncio
import pickle
import time
from lib import run_test
from lib import default_test_setup
from lib.testbase import TestBase
from lib.client import get_client
from thingsdb.exceptions import AssertionError
from thingsdb.exceptions import BadDataError
from thingsdb.exceptions import LookupError
from thingsdb.exceptions import MaxQuotaError
from thingsdb.exceptions import NumArgumentsError
Expand All @@ -16,7 +12,6 @@
from thingsdb.exceptions import SyntaxError
from thingsdb.exceptions import TypeError
from thingsdb.exceptions import ValueError
from thingsdb.exceptions import ZeroDivisionError


class TestAdvanced(TestBase):
Expand Down
77 changes: 70 additions & 7 deletions itest/test_operators.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
#!/usr/bin/env python
import asyncio
import pickle
import time
from lib import run_test
from lib import run_test, INT_MAX, INT_MIN
from lib import default_test_setup
from lib.testbase import TestBase
from lib.client import get_client
from thingsdb.exceptions import AssertionError
from thingsdb.exceptions import BadDataError
from thingsdb.exceptions import LookupError
from thingsdb.exceptions import TypeError
from thingsdb.exceptions import SyntaxError
from thingsdb.exceptions import OverflowError


Expand Down Expand Up @@ -301,6 +297,73 @@ async def test_preopr(self, client):
str(|| - !! +5);
'''), "|| -!!+5")

async def test_bit_operations(self, client):
res = await client.query(r"""//ti
[
~15,
~-15,
~~~---88,
~!6,
~!!-6,
~INT_MIN,
~INT_MAX,
~~INT_MIN,
~~INT_MAX,
];
""")
self.assertEqual(res, [
~15,
~-15,
~~~-88,
~0,
~1,
~INT_MIN,
~INT_MAX,
~~INT_MIN,
~~INT_MAX,
])

with self.assertRaisesRegex(
OverflowError,
r'integer overflow'):
await client.query(r"""//ti
~-INT_MIN;
""")

with self.assertRaisesRegex(
TypeError,
r'`-/\+` not supported by type `str`'):
await client.query(r"""//ti
+"test";
""")

with self.assertRaisesRegex(
TypeError,
r'`~` not supported by type `str`'):
await client.query(r"""//ti
~"test";
""")

with self.assertRaisesRegex(
TypeError,
r'~` not supported by type `float`'):
await client.query(r"""//ti
~~1.0;
""")

with self.assertRaisesRegex(
SyntaxError,
r'error at line 1, position 1, unexpected character `~`'):
await client.query(r"""//ti
+~1;
""")

with self.assertRaisesRegex(
SyntaxError,
r'error at line 1, position 1, unexpected character `~`'):
await client.query(r"""//ti
!~1;
""")

if __name__ == '__main__':
run_test(TestOperators())
8 changes: 4 additions & 4 deletions src/langdef/langdef.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* should be used with the libcleri module.
*
* Source class: LangDef
* Created at: 2024-01-20 12:46:21
* Created at: 2024-02-04 14:13:28
*/

#include <langdef/langdef.h>
Expand All @@ -27,7 +27,7 @@ cleri_grammar_t * compile_langdef(void)
cleri_t * x_function = cleri_token(CLERI_GID_X_FUNCTION, "(");
cleri_t * x_index = cleri_token(CLERI_GID_X_INDEX, "[");
cleri_t * x_parenthesis = cleri_token(CLERI_GID_X_PARENTHESIS, "(");
cleri_t * x_preopr = cleri_regex(CLERI_GID_X_PREOPR, "^(\\s*!|\\s*[\\-+](?=[^0-9]))*");
cleri_t * x_preopr = cleri_regex(CLERI_GID_X_PREOPR, "^(\\s*~)*(\\s*!|\\s*[\\-+](?=[^0-9]))*");
cleri_t * x_ternary = cleri_token(CLERI_GID_X_TERNARY, "?");
cleri_t * x_thing = cleri_token(CLERI_GID_X_THING, "{");
cleri_t * x_template = cleri_token(CLERI_GID_X_TEMPLATE, "`");
Expand Down Expand Up @@ -194,7 +194,7 @@ cleri_grammar_t * compile_langdef(void)
CLERI_GID_BLOCK,
3,
x_block,
cleri_list(CLERI_NONE, CLERI_THIS, cleri_repeat(CLERI_NONE, cleri_token(CLERI_NONE, ";"), 1, 0), 1, 0, 1),
cleri_list(CLERI_NONE, CLERI_THIS, cleri_repeat(CLERI_NONE, cleri_token(CLERI_NONE, ";"), 0, 0), 1, 0, 1),
cleri_token(CLERI_NONE, "}")
);
cleri_t * parenthesis = cleri_sequence(
Expand Down Expand Up @@ -286,7 +286,7 @@ cleri_grammar_t * compile_langdef(void)
),
operations
);
cleri_t * START = cleri_list(CLERI_GID_START, statement, cleri_repeat(CLERI_NONE, cleri_token(CLERI_NONE, ";"), 1, 0), 0, 0, 1);
cleri_t * START = cleri_list(CLERI_GID_START, statement, cleri_repeat(CLERI_NONE, cleri_token(CLERI_NONE, ";"), 0, 0), 0, 0, 1);
cleri_ref_set(chain, cleri_sequence(
CLERI_GID_CHAIN,
4,
Expand Down
64 changes: 59 additions & 5 deletions src/ti/preopr.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ enum
PO__NEGATIVE,
PO__AS_NUM,
PO__CHK_NUM,
PO__BIT_INV,
PO__BITWISE,
};

enum
Expand All @@ -26,13 +28,16 @@ enum
PO__FLAG_NEGATIVE =1<<PO__NEGATIVE,
PO__FLAG_AS_NUM =1<<PO__AS_NUM,
PO__FLAG_CHK_NUM =1<<PO__CHK_NUM,
PO__FLAG_BIT_INV =1<<PO__BIT_INV,
PO__FLAG_BITWISE =1<<PO__BITWISE,
};

int ti_preopr_bind(const char * s, size_t n)
{
register int preopr = 0;
register int negative = 0;
register int nots = 0;
register int inverts = 0;

if (!n)
return preopr; /* return 0 */
Expand All @@ -46,10 +51,14 @@ int ti_preopr_bind(const char * s, size_t n)
++negative;
/* fall through */
case '+':
preopr |= 1 << PO__AS_NUM;
preopr |= PO__FLAG_AS_NUM;
break;
case '!':
++nots;
break;
case '~':
++inverts;
preopr |= PO__FLAG_AS_NUM|PO__FLAG_BITWISE;
}

while (--n)
Expand All @@ -62,6 +71,9 @@ int ti_preopr_bind(const char * s, size_t n)
break;
case '!':
++nots;
break;
case '~':
++inverts;
}
}

Expand All @@ -72,7 +84,8 @@ int ti_preopr_bind(const char * s, size_t n)
((nots & 1) << PO__FALSE) |
((!!nots) << PO__BOOL) |
((negative & 1) << PO__NEGATIVE) |
((*s != '!') << PO__CHK_NUM)
((*s != '!') << PO__CHK_NUM) |
((inverts & 1) << PO__BIT_INV)
);

return preopr;
Expand All @@ -93,7 +106,8 @@ int ti_preopr_calc(int preopr, ti_val_t ** val, ex_t * e)
v->tp != TI_VAL_BOOL)
{
ex_set(e, EX_TYPE_ERROR,
"`-/+` not supported by type `%s`",
"`%s` not supported by type `%s`",
(preopr & PO__FLAG_BITWISE) ? "~" : "-/+",
ti_val_str(v));
return e->nr;
}
Expand All @@ -107,14 +121,54 @@ int ti_preopr_calc(int preopr, ti_val_t ** val, ex_t * e)
{
_Bool b = (preopr & PO__FLAG_FALSE) ^ ti_val_as_bool(v);
ti_val_unsafe_drop(v);
*val = preopr & PO__FLAG_AS_NUM
*val = (preopr & PO__FLAG_BIT_INV)
? (ti_val_t *) ti_vint_create(preopr & PO__FLAG_NEGATIVE ? ~((int) -b) : ~((int) b))
: (preopr & PO__FLAG_AS_NUM)
? (ti_val_t *) ti_vint_create(preopr & PO__FLAG_NEGATIVE ? -b : b)
: (ti_val_t *) ti_vbool_get(b);

return 0;
}

assert(preopr & PO__FLAG_AS_NUM);
if (preopr & PO__FLAG_BITWISE) switch(v->tp)
{
case TI_VAL_INT:
if (preopr & PO__FLAG_BIT_INV)
{
int64_t i = VINT(v);
if (preopr & PO__FLAG_NEGATIVE)
{
if (i == LLONG_MIN)
{
ex_set(e, EX_OVERFLOW, "integer overflow");
return e->nr;
}
i = -i;
}
ti_val_unsafe_drop(v);
*val = (ti_val_t *) ti_vint_create(~i);
if (!*val)
ex_set_mem(e);
return e->nr;
}
break;
case TI_VAL_FLOAT:
ex_set(e, EX_TYPE_ERROR,
"`~` not supported by type `%s`",
ti_val_str(v));
return e->nr;
case TI_VAL_BOOL:
if (preopr & PO__FLAG_BIT_INV)
{
_Bool b = VBOOL(v);
if (preopr & PO__FLAG_NEGATIVE)
b = -b;
ti_val_unsafe_drop(v);
*val = (ti_val_t *) ti_vint_create(~((int) b));
return e->nr;
}
break;
}

/*
* No ! is used in the sequence, so the number is unchanged, or the
Expand Down

0 comments on commit 301d4c2

Please sign in to comment.