added not operator
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
- make it so that when a branch condition's and-ed sub-expression fails,
|
||||
the other sub-expressions aren't evaluated. Like this:
|
||||
|
||||
if type(A) == type({}) and A.name != none:
|
||||
.. do stuff ..
|
||||
|
||||
the second sub-expr. "A.name != none" raises an error if the first one
|
||||
"type(A) == type({})" isn't true, but doesn't need to be evaluated in
|
||||
that case.
|
||||
@@ -0,0 +1,131 @@
|
||||
|
||||
fun _count(elm)
|
||||
{
|
||||
if type(elm) == type({}):
|
||||
|
||||
if type(elm._count) == type(_count):
|
||||
|
||||
return elm._count(elm);
|
||||
|
||||
else if type(elm._count) == type(1):
|
||||
|
||||
return elm._count;
|
||||
|
||||
return count(elm);
|
||||
}
|
||||
|
||||
fun newTree()
|
||||
{
|
||||
return {root: none, _count: 0};
|
||||
}
|
||||
|
||||
fun locate(tree, index, path)
|
||||
{
|
||||
# This function walks the tree to find the
|
||||
# leaf that is referred to by the specified
|
||||
# index.
|
||||
# The traversed nodes are stored in the path
|
||||
# argument. The last one is the leaf.
|
||||
# The return value is the index relative to
|
||||
# the start of the leaf.
|
||||
assert(type(index) == type(1));
|
||||
|
||||
path = []; # List of traversed nodes (without the leaf).
|
||||
rindex = index; # index relative to the found leaf.
|
||||
cursor = tree; # Tree cursor. At the end it will refer to the leaf.
|
||||
|
||||
path[count(path)] = cursor;
|
||||
|
||||
while cursor.is_leaf == false:
|
||||
{
|
||||
if rindex < _count(cursor.left):
|
||||
cursor = cursor.left;
|
||||
else
|
||||
{
|
||||
rindex = rindex - _count(cursor.left);
|
||||
cursor = cursor.right;
|
||||
}
|
||||
|
||||
path[count(path)] = cursor;
|
||||
}
|
||||
return rindex;
|
||||
}
|
||||
|
||||
fun insert(tree, data, index)
|
||||
{
|
||||
if index == none:
|
||||
# Insert at the end.
|
||||
index = _count(tree);
|
||||
|
||||
path = [];
|
||||
rindex = locate(tree, index, path);
|
||||
assert(count(path) > 1);
|
||||
|
||||
leaf = path[count(path)-1];
|
||||
assert(type(leaf) == type(newBuffer(0)));
|
||||
|
||||
if rindex == 0:
|
||||
# Want to store the data before
|
||||
# the leaf buffer.
|
||||
{}
|
||||
else if rindex < leaf.used:
|
||||
# Want to store the data in the
|
||||
# middle of the leaf.
|
||||
{
|
||||
fun min(a, b)
|
||||
{
|
||||
if a < b:
|
||||
return a;
|
||||
return b;
|
||||
}
|
||||
|
||||
fun copy(dst, src, num)
|
||||
{
|
||||
i = 0;
|
||||
while i < num:
|
||||
{
|
||||
dst[i] = src[i];
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
# Insert in the current leaf what's
|
||||
# possible.
|
||||
|
||||
unused = count(leaf.buffer) - leaf.used;
|
||||
copied = min(unused, count(data));
|
||||
copy(leaf.buffer, data, copied);
|
||||
leaf.used = leaf.used + copied;
|
||||
|
||||
if copied == count(data):
|
||||
{
|
||||
# We're done. The unused portion of
|
||||
# the leaf was enough to store the
|
||||
# data.
|
||||
|
||||
# Update the path.
|
||||
i = count(path)-2;
|
||||
while i > 0:
|
||||
{
|
||||
if path[i] == path[i-1].left:
|
||||
path[i-1]._count = path[i-1]._count + copied;
|
||||
i = i - 1;
|
||||
}
|
||||
return none;
|
||||
}
|
||||
|
||||
# There's more data that needs to be
|
||||
# stored, but now we don't need to
|
||||
# insert in the middle of the leaf.
|
||||
|
||||
data = sliceBuffer(data, copying, count(data));
|
||||
}
|
||||
|
||||
if rindex == leaf.used:
|
||||
# Want to append data to the
|
||||
# end of the contents.
|
||||
{}
|
||||
}
|
||||
|
||||
print( count(newTree()), '\n');
|
||||
print(_count(newTree()), '\n');
|
||||
@@ -42,6 +42,7 @@ static const InstrInfo instr_table[] = {
|
||||
|
||||
[OPCODE_POS] = {"POS", 0, NULL},
|
||||
[OPCODE_NEG] = {"NEG", 0, NULL},
|
||||
[OPCODE_NOT] = {"NOT", 0, NULL},
|
||||
|
||||
[OPCODE_ADD] = {"ADD", 0, NULL},
|
||||
[OPCODE_SUB] = {"SUB", 0, NULL},
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef enum {
|
||||
OPCODE_NOPE,
|
||||
OPCODE_POS,
|
||||
OPCODE_NEG,
|
||||
OPCODE_NOT,
|
||||
OPCODE_ADD,
|
||||
OPCODE_SUB,
|
||||
OPCODE_MUL,
|
||||
|
||||
@@ -30,6 +30,8 @@ typedef enum {
|
||||
EXPR_GRT,
|
||||
EXPR_GEQ,
|
||||
|
||||
EXPR_NOT,
|
||||
|
||||
EXPR_ASS,
|
||||
EXPR_INT,
|
||||
EXPR_MAP,
|
||||
|
||||
@@ -27,6 +27,7 @@ static Opcode exprkind_to_opcode(ExprKind kind)
|
||||
{
|
||||
switch(kind)
|
||||
{
|
||||
case EXPR_NOT: return OPCODE_NOT;
|
||||
case EXPR_POS: return OPCODE_POS;
|
||||
case EXPR_NEG: return OPCODE_NEG;
|
||||
case EXPR_ADD: return OPCODE_ADD;
|
||||
@@ -56,6 +57,7 @@ static _Bool emit_instr_for_node(ExeBuilder *exeb, Node *node, Error *error)
|
||||
ExprNode *expr = (ExprNode*) node;
|
||||
switch(expr->kind)
|
||||
{
|
||||
case EXPR_NOT:
|
||||
case EXPR_POS:
|
||||
case EXPR_NEG:
|
||||
case EXPR_ADD:
|
||||
|
||||
+14
-1
@@ -58,6 +58,7 @@ typedef enum {
|
||||
|
||||
TKWIF,
|
||||
TKWFUN,
|
||||
TKWNOT,
|
||||
TKWELSE,
|
||||
TKWNONE,
|
||||
TKWTRUE,
|
||||
@@ -192,6 +193,10 @@ static Token *tokenize(Source *src, BPAlloc *alloc, Error *error)
|
||||
{
|
||||
tok->kind = TKWFUN;
|
||||
}
|
||||
else if(matchstr(str + tok->offset, tok->length, "not"))
|
||||
{
|
||||
tok->kind = TKWNOT;
|
||||
}
|
||||
else if(matchstr(str + tok->offset, tok->length, "else"))
|
||||
{
|
||||
tok->kind = TKWELSE;
|
||||
@@ -541,6 +546,7 @@ static Node *parse_statement(Context *ctx)
|
||||
case TFLOAT:
|
||||
case TSTRING:
|
||||
case TIDENT:
|
||||
case TKWNOT:
|
||||
case TKWNONE:
|
||||
case TKWTRUE:
|
||||
case TKWFALSE:
|
||||
@@ -1064,6 +1070,7 @@ static Node *parse_primary_expresion(Context *ctx)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case TKWNOT:
|
||||
{
|
||||
Token *unary_operator = current_token(ctx);
|
||||
|
||||
@@ -1083,9 +1090,15 @@ static Node *parse_primary_expresion(Context *ctx)
|
||||
temp->base.base.next = NULL;
|
||||
temp->base.base.offset = unary_operator->offset;
|
||||
temp->base.base.length = operand->offset + operand->length - unary_operator->offset;
|
||||
temp->base.kind = unary_operator->kind == '+' ? EXPR_POS : EXPR_NEG;
|
||||
temp->head = operand;
|
||||
temp->count = 1;
|
||||
|
||||
switch(unary_operator->kind)
|
||||
{
|
||||
case '+': temp->base.kind = EXPR_POS; break;
|
||||
case '-': temp->base.kind = EXPR_NEG; break;
|
||||
case TKWNOT: temp->base.kind = EXPR_NOT; break;
|
||||
}
|
||||
}
|
||||
return (Node*) temp;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ Object *Object_NewNetworkBuiltinsMap(Runtime *runtime, Heap *heap, Error *err);
|
||||
|
||||
static Object *select_(Object *self, Object *key, Heap *heap, Error *err);
|
||||
|
||||
static Object *bin_type (Runtime *runtime, Object **argv, unsigned int argc, Error *error);
|
||||
static Object *bin_print (Runtime *runtime, Object **argv, unsigned int argc, Error *error);
|
||||
static Object *bin_count (Runtime *runtime, Object **argv, unsigned int argc, Error *error);
|
||||
static Object *bin_assert(Runtime *runtime, Object **argv, unsigned int argc, Error *error);
|
||||
@@ -51,6 +52,13 @@ static Object *select_(Object *self, Object *key, Heap *heap, Error *err)
|
||||
|
||||
switch(PAIR(n, s[0]))
|
||||
{
|
||||
case PAIR(4, 't'):
|
||||
{
|
||||
if(!strcmp(s, "type"))
|
||||
return Object_FromNativeFunction(bm->runtime, bin_type, 1, heap, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
case PAIR(sizeof("count")-1, 'c'):
|
||||
{
|
||||
if(!strcmp(s, "count"))
|
||||
@@ -129,6 +137,14 @@ static Object *bin_print(Runtime *runtime, Object **argv, unsigned int argc, Err
|
||||
return Object_NewNone(Runtime_GetHeap(runtime), error);
|
||||
}
|
||||
|
||||
static Object *bin_type(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
(void) runtime;
|
||||
(void) error;
|
||||
return (Object*) argv[0]->type;
|
||||
}
|
||||
|
||||
static Object *bin_count(Runtime *runtime, Object **argv, unsigned int argc, Error *error)
|
||||
{
|
||||
assert(argc == 1);
|
||||
|
||||
@@ -2,12 +2,20 @@
|
||||
#include "../utils/defs.h"
|
||||
#include "objects.h"
|
||||
|
||||
static _Bool op_eql(Object *self, Object *other);
|
||||
|
||||
TypeObject t_type = {
|
||||
.base = (Object) { .type = &t_type, .flags = Object_STATIC },
|
||||
.name = "type",
|
||||
.size = sizeof (TypeObject),
|
||||
.op_eql = op_eql,
|
||||
};
|
||||
|
||||
static _Bool op_eql(Object *self, Object *other)
|
||||
{
|
||||
return self == other;
|
||||
}
|
||||
|
||||
const char *Object_GetName(const Object *obj)
|
||||
{
|
||||
assert(obj != NULL);
|
||||
|
||||
@@ -557,6 +557,38 @@ static _Bool step(Runtime *runtime, Error *error)
|
||||
Error_Report(error, 1, "NEG not implemented");
|
||||
return 0;
|
||||
|
||||
case OPCODE_NOT:
|
||||
{
|
||||
assert(opc == 0);
|
||||
|
||||
if(runtime->frame->used == 0)
|
||||
{
|
||||
Error_Report(error, 1, "Frame doesn't have enough items on the stack to execute NOT");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Object *top = Stack_Top(runtime->stack, 0);
|
||||
|
||||
if(!Runtime_Pop(runtime, error, 1))
|
||||
return 0;
|
||||
|
||||
assert(top != NULL);
|
||||
|
||||
_Bool v = Object_ToBool(top, error);
|
||||
|
||||
if(error->occurred)
|
||||
return 0;
|
||||
|
||||
Object *negated = Object_FromBool(!v, runtime->heap, error);
|
||||
|
||||
if(negated == NULL)
|
||||
return 0;
|
||||
|
||||
if(!Runtime_Push(runtime, error, negated))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
case OPCODE_ADD:
|
||||
case OPCODE_SUB:
|
||||
case OPCODE_MUL:
|
||||
|
||||
Reference in New Issue
Block a user