Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added bitwise NOT (~) #360

Merged
merged 2 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading