MBED port of https://github.com/ys1382/filagree . The only change is adding #define MBED

Dependents:   filagree_test

sys.c

Committer:
yusufx
Date:
2012-05-30
Revision:
0:1a89e28dea91

File content as of revision 0:1a89e28dea91:

#include "serial.h"
#include "sys.h"
#include "struct.h"
#include "variable.h"
#include "vm.h"
#include "util.h"
#include <stdio.h>
#include <string.h>

// system functions

void sys_callback2c(struct Context *context)
{
    stack_pop(context->rhs); // self
	context->callback2c(context);
}

void sys_print(struct Context *context)
{
    stack_pop(context->rhs); // self
    struct variable *v;
    while ((v = (struct variable*)stack_pop(context->rhs)))
        printf("%s\n", variable_value_str(context, v));
}

void sys_save(struct Context *context)
{
    stack_pop(context->rhs); // self
    struct variable *v = (struct variable*)stack_pop(context->rhs);
    struct variable *path = (struct variable*)stack_pop(context->rhs);
    variable_save(context, v, path);
}

void sys_load(struct Context *context)
{
    stack_pop(context->rhs); // self
    struct variable *path = (struct variable*)stack_pop(context->rhs);
    struct variable *v = variable_load(context, path);

    if (v)
        stack_push(context->operand_stack, v);
}

void sys_rm(struct Context *context)
{
    stack_pop(context->rhs); // self
    struct variable *path = (struct variable*)(struct variable*)stack_pop(context->rhs);
    remove(byte_array_to_string(path->str));
}

struct string_func builtin_funcs[] = {
	{"yield", (bridge*)&sys_callback2c},
    {"print", (bridge*)&sys_print},
    {"save", (bridge*)&sys_save},
    {"load", (bridge*)(bridge*)&sys_load},
    {"remove", (bridge*)&sys_rm},
};

struct variable *func_map(struct Context *context)
{
    struct map *map = map_new();
    for (int i=0; i<ARRAY_LEN(builtin_funcs); i++) {
        struct byte_array *name = byte_array_from_string(builtin_funcs[i].name);
        struct variable *value = variable_new_c(context, builtin_funcs[i].func);
        map_insert(map, name, value);
    }
    return variable_new_map(context, map);
}

// built-in member functions

#define FNC_STRING      "string"
#define FNC_LIST        "list"
#define FNC_TYPE        "type"
#define FNC_LENGTH      "length"
#define FNC_KEYS        "keys"
#define FNC_VALUES      "values"
#define FNC_SERIALIZE   "serialize"
#define FNC_DESERIALIZE "deserialize"
#define FNC_SORT        "sort"
#define FNC_FIND        "find"
#define FNC_REPLACE     "replace"
#define FNC_PART        "part"
#define FNC_REMOVE        "remove"
#define FNC_INSERT        "insert"

struct variable *comparator = NULL;

int (compar)(struct Context *context, const void *a, const void *b)
{
    struct variable *av = *(struct variable**)a;
    struct variable *bv = *(struct variable**)b;

    if (comparator) {

        assert_message(comparator->type == VAR_FNC, "non-function comparator");
        stack_push(context->rhs, av);
        stack_push(context->rhs, bv);
        byte_array_reset(comparator->str);
        stack_push(context->operand_stack, comparator);
        vm_call(context);

        struct variable *result = (struct variable*)stack_pop(context->rhs);
        assert_message(result->type == VAR_INT, "non-integer comparison result");
        return result->integer;

    } else {

        enum VarType at = av->type;
        enum VarType bt = bv->type;

        if (at == VAR_INT && bt == VAR_INT) {
            // DEBUGPRINT("compare %p:%d to %p:%d : %d\n", av, av->integer, bv, bv->integer, av->integer - bv->integer);
            return av->integer - bv->integer;
        } else
            DEBUGPRINT("can't compare %s to %s\n", var_type_str(at), var_type_str(bt));

        vm_exit_message(context, "incompatible types for comparison");
        return 0;
    }
}

int testarr[] = { 6, 5, 3, 1, 8, 7, 2, 4 };
//int testarr[] = { 2,1 };
int len = sizeof(testarr)/sizeof(testarr[0]);

void heapset(size_t width, void *base0, uint32_t index0, void *base1, uint32_t index1) {
    uint8_t *p0 = (uint8_t*)base0 + index0 * width;
    uint8_t *p1 = (uint8_t*)base1 + index1 * width;
    while (width--)
        *(p0 + width) = *(p1 + width);
}

int heapcmp(struct Context *context,
            int (*compar)(struct Context *, const void *, const void *),
            size_t width, void *base0, uint32_t index0, void *base1, uint32_t index1) {
    uint8_t *p0 = (uint8_t*)base0 + index0 * width;
    uint8_t *p1 = (uint8_t*)base1 + index1 * width;
    return compar(context, p0, p1);
}

int heapsortfg(struct Context *context,
               void *base, size_t nel, size_t width,
               int (*compar)(struct Context *, const void *, const void *))
{
    void *t = malloc(width); // the temporary value
    unsigned int n = nel, parent = nel/2, index, child; // heap indexes
    for (;;) { // loop until array is sorted
        if (parent > 0) { // first stage - Sorting the heap
            heapset(width, t, 0, base, --parent);
        } else { // second stage - Extracting elements in-place
            if (!--n) { // make the heap smaller
                free(t);
                return 0; // When the heap is empty, we are done
            }
            heapset(width, t, 0, base, n);
            heapset(width, base, n, base, 0);
        }
        // insert operation - pushing t down the heap to replace the parent
        index = parent; // start at the parent index
        child = index * 2 + 1; // get its left child index
        while (child < n) {
            if (child + 1 < n  && // choose the largest child
                heapcmp(context, compar, width, base, child+1, base, child) > 0) {
                child++; // right child exists and is bigger
            }
            // is the largest child larger than the entry?
            if (heapcmp(context, compar, width, base, child, t, 0) > 0) {
                heapset(width, base, index, base, child);
                index = child; // move index to the child
                child = index * 2 + 1; // get the left child and go around again
            } else
                break; // t's place is found
        }
        // store the temporary value at its new location
        heapset(width, base, index, t, 0);
    }
}

void cfnc_sort(struct Context *context)
{
    struct variable *self = (struct variable*)stack_pop(context->rhs);
    assert_message(self->type == VAR_LST, "sorting a non-list");
    comparator = (struct variable*)stack_pop(context->rhs);

    int num_items = self->list->length;

    int success = heapsortfg(context, self->list->data, num_items, sizeof(struct variable*), &compar);
    assert_message(!success, "error sorting");
}

struct variable *variable_part(struct Context *context, struct variable *self, uint32_t start, int32_t length)
{
    null_check(self);
    switch (self->type) {
        case VAR_STR: {
            struct byte_array *str = byte_array_part(self->str, start, length);
            return variable_new_str(context, str);
        }
        case VAR_LST: {
            struct array *list = array_part(self->list, start, length);
            return variable_new_list(context, list);
        }
        default:
            return (struct variable*)exit_message("bad part type");
    }
}

void variable_remove(struct variable *self, uint32_t start, int32_t length)
{
    null_check(self);
    switch (self->type) {
        case VAR_STR:
            byte_array_remove(self->str, start, length);
            break;
        case VAR_LST:
            array_remove(self->list, start, length);
            break;
        default:
            exit_message("bad remove type");
    }
}

struct variable *variable_concatenate(struct Context *context, int n, const struct variable* v, ...)
{
    struct variable* result = variable_copy(context, v);

    va_list argp;
    for(va_start(argp, v); --n;) {
        struct variable* parameter = va_arg(argp, struct variable* );
        if (!parameter)
            continue;
        else if (!result)
            result = variable_copy(context, parameter);
        else switch (result->type) {
            case VAR_STR: byte_array_append(result->str, parameter->str); break;
            case VAR_LST: array_append(result->list, parameter->list);    break;
            default: return (struct variable*)exit_message("bad concat type");
        }
    }

    va_end(argp);
    return result;
}

void cfnc_chop(struct Context *context, bool part)
{
    struct variable *self = (struct variable*)stack_pop(context->rhs);
    struct variable *start = (struct variable*)stack_pop(context->rhs);
    struct variable *length = (struct variable*)stack_pop(context->rhs);
    assert_message(start->type == VAR_INT, "non-integer index");
    assert_message(length->type == VAR_INT, "non-integer length");
    int32_t beginning = start->integer;
    int32_t foraslongas = length->integer;

    struct variable *result = variable_copy(context, self);
    if (part)
        result = variable_part(context, result, beginning, foraslongas);
    else
        variable_remove(result, beginning, foraslongas);
    stack_push(context->operand_stack, result);
}

static inline void cfnc_part(struct Context *context) {
    cfnc_chop(context, true);
}

static inline void cfnc_remove(struct Context *context) {
    cfnc_chop(context, false);
}

void cfnc_find(struct Context *context)
{
    struct variable *self = (struct variable*)stack_pop(context->rhs);
    struct variable *sought = (struct variable*)stack_pop(context->rhs);
    struct variable *start = (struct variable*)stack_pop(context->rhs);

    null_check(self);
    null_check(sought);
    assert_message(self->type == VAR_STR, "searching in a non-list");
    assert_message(sought->type == VAR_STR, "searching for a non-list");
    if (start) assert_message(start->type == VAR_INT, "non-integer index");

    int32_t beginning = start ? start->integer : 0;
    int32_t index = byte_array_find(self->str, sought->str, beginning);
    struct variable *result = variable_new_int(context, index);
    stack_push(context->operand_stack, result);
}

void cfnc_insert(struct Context *context)
{
    struct variable *self = (struct variable*)stack_pop(context->rhs);
    struct variable *start = (struct variable*)stack_pop(context->rhs);
    struct variable *insertion = (struct variable*)stack_pop(context->rhs);
    assert_message(start->type == VAR_INT, "non-integer index");
    assert_message(insertion && insertion->type == self->type, "insertion doesn't match destination");

    int32_t position = start->integer;
    struct variable *first = variable_part(context, variable_copy(context, self), 0, position);
    struct variable *second = variable_part(context, variable_copy(context, self), position, -1);
    struct variable *joined = variable_concatenate(context, 3, first, self, second);
    stack_push(context->operand_stack, joined);
}

//    a                b        c
// <sought> <replacement> [<start>]
// <start> <length> <replacement>
void replace(struct Context *context)
{
    struct variable *self = (struct variable*)stack_pop(context->rhs);
    struct variable *a = (struct variable*)stack_pop(context->rhs);
    struct variable *b = (struct variable*)stack_pop(context->rhs);
    struct variable *c = (struct variable*)stack_pop(context->rhs);
    
    null_check(self);
    null_check(b);
    assert_message(self->type == VAR_STR, "searching in a non-string");
    
    int32_t where = 0;
    struct byte_array *replaced = self->str;
    
    if (a->type == VAR_STR) { // find a, replace with b
        
        assert_message(b->type == VAR_STR, "non-string replacement");
        
        if (c) { // replace first match after index b
            
            assert_message(c->type == VAR_INT, "non-integer index");
            uint32_t found = byte_array_find(self->str, a->str, c->integer);
            replaced = byte_array_replace(self->str, b->str, found, b->str->length);
            
        } else for(;;) { // replace all
            
            if ((where = byte_array_find(self->str, a->str, where)) < 0)
                break;
            replaced = byte_array_replace(replaced, b->str, where++, a->str->length);            
        }
        
    } else if (a->type == VAR_INT ) { // replace at index a, length b, insert c
        
        assert_message(a || a->type == VAR_INT, "non-integer count");
        assert_message(b || b->type == VAR_INT, "non-integer start");
        replaced = byte_array_replace(self->str, c->str, a->integer, b->integer);
        
    } else exit_message("replacement is not a string");
    
    null_check(replaced);
    struct variable *result = variable_new_str(context, replaced);
    stack_push(context->operand_stack, result);
}


struct variable *builtin_method(struct Context *context, 
                                struct variable *indexable,
                                const struct variable *index)
{
    enum VarType it = indexable->type;
    const char *idxstr = byte_array_to_string(index->str);

    if (!strcmp(idxstr, FNC_LENGTH))
        return variable_new_int(context, indexable->list->length);
    if (!strcmp(idxstr, FNC_TYPE)) {
        const char *typestr = var_type_str(it);
        return variable_new_str(context, byte_array_from_string(typestr));
    }

    if (!strcmp(idxstr, FNC_STRING))
        return variable_new_str(context, variable_value(context, indexable));

    if (!strcmp(idxstr, FNC_LIST))
        return variable_new_list(context, indexable->list);

    if (!strcmp(idxstr, FNC_KEYS)) {
        assert_message(it == VAR_LST || it == VAR_MAP, "keys are only for map or list");

        struct variable *v = variable_new_list(context, array_new());
        if (indexable->map) {
            const struct array *a = map_keys(indexable->map);
            for (int i=0; i<a->length; i++) {
                struct variable *u = variable_new_str(context, (struct byte_array*)array_get(a, i));
                array_add(v->list, u);
            }
        }
        return v;
    }

    if (!strcmp(idxstr, FNC_VALUES)) {
        assert_message(it == VAR_LST || it == VAR_MAP, "values are only for map or list");
        if (!indexable->map)
            return variable_new_list(context, array_new());
        else
            return variable_new_list(context, (struct array*)map_values(indexable->map));
    }

    if (!strcmp(idxstr, FNC_SERIALIZE)) {
        struct byte_array *bits = variable_serialize(context, 0, indexable);
        return variable_new_str(context, bits);
    }

    if (!strcmp(idxstr, FNC_DESERIALIZE)) {
        struct byte_array *bits = indexable->str;
        byte_array_reset(bits);
        struct variable *d = variable_deserialize(context, bits);
        return d;
    }

    if (!strcmp(idxstr, FNC_SORT)) {
        assert_message(indexable->type == VAR_LST, "sorting non-list");
        return variable_new_c(context, &cfnc_sort);
    }

    if (!strcmp(idxstr, FNC_FIND)) {
        assert_message(indexable->type == VAR_STR, "searching in non-string");
        return variable_new_c(context, &cfnc_find);
    }

    if (!strcmp(idxstr, FNC_PART))
        return variable_new_c(context, &cfnc_part);

    if (!strcmp(idxstr, FNC_REMOVE))
        return variable_new_c(context, &cfnc_remove);

    if (!strcmp(idxstr, FNC_INSERT))
        return variable_new_c(context, &cfnc_insert);

    if (!strcmp(idxstr, FNC_REPLACE))
        return variable_new_c(context, &replace);

    return NULL;
}