1
0
mirror of https://github.com/janet-lang/janet synced 2024-06-30 00:53:15 +00:00
janet/core/util.c
bakpakin 3efd400025 Huge number of changes. Still WIP. Refactoring and
changing C API model. This commit is not i a working state.
2017-09-09 14:39:51 -04:00

353 lines
9.2 KiB
C

/*
* Copyright (c) 2017 Calvin Rose
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "internal.h"
/****/
/* Parsing utils */
/****/
/* Get an integer power of 10 */
static double exp10(int power) {
if (power == 0) return 1;
if (power > 0) {
double result = 10;
int currentPower = 1;
while (currentPower * 2 <= power) {
result = result * result;
currentPower *= 2;
}
return result * exp10(power - currentPower);
} else {
return 1 / exp10(-power);
}
}
int dst_read_integer(const uint8_t *string, const uint8_t *end, int64_t *ret) {
int sign = 1, x = 0;
int64_t accum = 0;
if (*string == '-') {
sign = -1;
++string;
} else if (*string == '+') {
++string;
}
if (string >= end) return 0;
while (string < end) {
x = *string;
if (x < '0' || x > '9') return 0;
x -= '0';
accum = accum * 10 + x;
++string;
}
*ret = accum * sign;
return 1;
}
/* Read a real from a string. Returns if successfuly
* parsed a real from the enitre input string.
* If returned 1, output is int ret.*/
int dst_read_real(const uint8_t *string, const uint8_t *end, double *ret, int forceInt) {
int sign = 1, x = 0;
double accum = 0, exp = 1, place = 1;
/* Check the sign */
if (*string == '-') {
sign = -1;
++string;
} else if (*string == '+') {
++string;
}
if (string >= end) return 0;
while (string < end) {
if (*string == '.' && !forceInt) {
place = 0.1;
} else if (!forceInt && (*string == 'e' || *string == 'E')) {
/* Read the exponent */
++string;
if (string >= end) return 0;
if (!dst_read_real(string, end, &exp, 1))
return 0;
exp = exp10(exp);
break;
} else {
x = *string;
if (x < '0' || x > '9') return 0;
x -= '0';
if (place < 1) {
accum += x * place;
place *= 0.1;
} else {
accum *= 10;
accum += x;
}
}
++string;
}
*ret = accum * sign * exp;
return 1;
}
/* Utilities for manipulating different types with the same semantics */
/* Read both tuples and arrays as c pointers + uint32_t length. Return 1 if the
* view can be constructed, 0 if an invalid type. */
int dst_seq_view(DstValue seq, const DstValue **data, uint32_t *len) {
if (seq.type == DST_ARRAY) {
*data = seq.data.array->data;
*len = seq.data.array->count;
return 1;
} else if (seq.type == DST_TUPLE) {
*data = seq.data.st;
*len = dst_tuple_length(seq.data.st);
return 1;
}
return 0;
}
/* Read both strings and buffer as unsigned character array + uint32_t len.
* Returns 1 if the view can be constructed and 0 if the type is invalid. */
int dst_chararray_view(DstValue str, const uint8_t **data, uint32_t *len) {
if (str.type == DST_STRING || str.type == DST_SYMBOL) {
*data = str.data.string;
*len = dst_string_length(str.data.string);
return 1;
} else if (str.type == DST_BYTEBUFFER) {
*data = str.data.buffer->data;
*len = str.data.buffer->count;
return 1;
}
return 0;
}
/* Read both structs and tables as the entries of a hashtable with
* identical structure. Returns 1 if the view can be constructed and
* 0 if the type is invalid. */
int dst_hashtable_view(DstValue tab, const DstValue **data, uint32_t *cap) {
if (tab.type == DST_TABLE) {
*data = tab.data.table->data;
*cap = tab.data.table->capacity;
return 1;
} else if (tab.type == DST_STRUCT) {
*data = tab.data.st;
*cap = dst_struct_capacity(tab.data.st);
return 1;
}
return 0;
}
DstReal dst_integer_to_real(DstInteger x) {
return (DstReal) x;
}
DstInteger dst_real_to_integer(DstReal x) {
return (DstInteger) x;
}
uint32_t dst_startrange(DstInteger raw, uint32_t len) {
if (raw >= len)
return -1;
if (raw < 0)
return len + raw;
return raw;
}
uint32_t dst_endrange(DstInteger raw, uint32_t len) {
if (raw > len)
return -1;
if (raw < 0)
return len + raw + 1;
return raw;
}
static DstValue cfunction(DstCFunction fn) {
DstValue n;
n.type = DST_CFUNCTION;
n.data.cfunction = fn;
return n;
}
int dst_callc(Dst *vm, DstCFunction fn, int numargs, ...) {
int result, i;
va_list args;
DstValue *stack;
va_start(args, numargs);
stack = dst_thread_beginframe(vm, vm->thread, cfunction(fn), numargs);
for (i = 0; i < numargs; ++i) {
stack[i] = va_arg(args, DstValue);
}
va_end(args);
result = fn(vm);
dst_thread_popframe(vm, vm->thread);
return result;
}
/* Stack manipulation functions */
int dst_checkerr(Dst *vm) {
return !!vm->flags;
}
/* Get an argument from the stack */
DstValue dst_arg(Dst *vm, uint32_t index) {
DstValue *stack = dst_thread_stack(vm->thread);
uint32_t frameSize = dst_frame_size(stack);
if (frameSize <= index) {
DstValue ret;
ret.type = DST_NIL;
return ret;
}
return stack[index];
}
/* Put a value on the stack */
void dst_set_arg(Dst* vm, uint32_t index, DstValue x) {
DstValue *stack = dst_thread_stack(vm->thread);
uint32_t frameSize = dst_frame_size(stack);
if (frameSize <= index) return;
stack[index] = x;
}
/* Get the size of the VMStack */
uint32_t dst_args(Dst *vm) {
DstValue *stack = dst_thread_stack(vm->thread);
return dst_frame_size(stack);
}
void dst_addsize(Dst *vm, uint32_t n) {
dst_thread_pushnil(vm, vm->thread, n);
}
void dst_setsize(Dst *vm, uint32_t n) {
DstValue *stack = dst_thread_stack(vm->thread);
uint32_t frameSize = dst_frame_size(stack);
if (frameSize < n) {
dst_thread_ensure_extra(vm, vm->thread, n - frameSize);
}
dst_frame_size(stack) = n;
}
void dst_swap(Dst *vm, uint32_t x, uint32_t y) {
DstValue oldx = dst_arg(vm, x);
DstValue oldy = dst_arg(vm, y);
dst_set_arg(vm, x, oldy);
dst_set_arg(vm, y, oldx);
}
void dst_move(Dst *vm, uint32_t dest, uint32_t src) {
dst_set_arg(vm, dest, dst_arg(vm, src));
}
void dst_nil(Dst *vm, uint32_t dest) {
DstValue n;
n.type = DST_NIL;
dst_set_arg(vm, dest, n);
}
void dst_true(Dst *vm, uint32_t dest) {
dst_set_boolean(vm, dest, 1);
}
void dst_false(Dst *vm, uint32_t dest) {
dst_set_boolean(vm, dest, 0);
}
/* Boolean Functions */
void dst_set_boolean(Dst *vm, uint32_t dest, int val) {
DstValue n;
n.type = DST_BOOLEAN;
n.data.boolean = val;
dst_set_arg(vm, dest, n);
}
int dst_get_boolean(Dst *vm, uint32_t b) {
DstValue x = dst_arg(vm, b);
if (x.type != DST_BOOLEAN) {
return 0;
}
return x.data.boolean;
}
/* Integer functions */
void dst_set_integer(Dst *vm, uint32_t dest, int64_t val) {
DstValue n;
n.type = DST_INTEGER;
n.data.integer = val;
dst_set_arg(vm, dest, n);
}
int64_t dst_get_integer(Dst *vm, uint32_t i) {
DstValue x = dst_arg(vm, i);
if (x.type != DST_INTEGER) {
return 0;
}
return x.data.integer;
}
/* Real functions */
void dst_set_real(Dst *vm, uint32_t dest, double val) {
DstValue n;
n.type = DST_REAL;
n.data.real = val;
dst_set_arg(vm, dest, n);
}
double dst_get_real(Dst *vm, uint32_t r) {
DstValue x = dst_arg(vm, r);
if (x.type != DST_REAL) {
return 0.0;
}
return x.data.real;
}
/* CFunction functions */
void dst_set_cfunction(Dst *vm, uint32_t dest, DstCFunction cfn) {
DstValue n;
n.type = DST_CFUNCTION;
n.data.cfunction = cfn;
dst_set_arg(vm, dest, n);
}
DstCFunction dst_get_cfunction(Dst *vm, uint32_t cfn) {
DstValue x = dst_arg(vm, cfn);
if (x.type != DST_CFUNCTION) {
return NULL;
}
return x.data.cfunction;
}
void dst_return(Dst *vm, uint32_t index) {
vm->ret = dst_arg(vm, index);
}
void dst_throw(Dst *vm, uint32_t index) {
vm->flags = 1;
vm->ret = dst_arg(vm, index);
}
void dst_cerr(Dst *vm, const char *message) {
vm->flags = 1;
vm->ret = dst_string_cv(vm, message);
}
int dst_checktype(Dst *vm, uint32_t n, DstType type) {
return dst_arg(vm, n).type == type;
}