improve performance for integers
This commit is contained in:
@@ -40,6 +40,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t registerCount;
|
uint8_t registerCount;
|
||||||
|
uint8_t registerAssignment;
|
||||||
DArray *return_jumps;
|
DArray *return_jumps;
|
||||||
DArray bytecode;
|
DArray bytecode;
|
||||||
ConstantArena constants;
|
ConstantArena constants;
|
||||||
@@ -74,7 +75,13 @@ struct ArgonObject {
|
|||||||
struct hashmap_GC *dict;
|
struct hashmap_GC *dict;
|
||||||
bool as_bool;
|
bool as_bool;
|
||||||
union {
|
union {
|
||||||
mpq_t *as_number;
|
struct as_number {
|
||||||
|
bool is_int64;
|
||||||
|
union {
|
||||||
|
mpq_t *mpq;
|
||||||
|
int64_t i64;
|
||||||
|
} n;
|
||||||
|
}as_number;
|
||||||
struct string_struct as_str;
|
struct string_struct as_str;
|
||||||
native_fn native_fn;
|
native_fn native_fn;
|
||||||
struct argon_function_struct argon_fn;
|
struct argon_function_struct argon_fn;
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ Translated load_argon_file(char *path, ArErr *err) {
|
|||||||
}
|
}
|
||||||
hashmap_free(translated.constants.hashmap, NULL);
|
hashmap_free(translated.constants.hashmap, NULL);
|
||||||
Translated gc_translated = {
|
Translated gc_translated = {
|
||||||
translated.registerCount, NULL, {}, {}, translated.path};
|
translated.registerCount, translated.registerAssignment,NULL, {}, {}, translated.path};
|
||||||
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
|
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
|
||||||
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
memcpy(gc_translated.bytecode.data, translated.bytecode.data,
|
||||||
translated.bytecode.capacity);
|
translated.bytecode.capacity);
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ void free_parsed_while(void *ptr) {
|
|||||||
ParsedValue *parsedValue = ptr;
|
ParsedValue *parsedValue = ptr;
|
||||||
ParsedWhile *parsed_while = parsedValue->data;
|
ParsedWhile *parsed_while = parsedValue->data;
|
||||||
free_parsed(parsed_while->condition);
|
free_parsed(parsed_while->condition);
|
||||||
|
free(parsed_while->condition);
|
||||||
free_parsed(parsed_while->content);
|
free_parsed(parsed_while->content);
|
||||||
|
free(parsed_while->content);
|
||||||
free(parsed_while);
|
free(parsed_while);
|
||||||
}
|
}
|
||||||
@@ -134,6 +134,7 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
|
|||||||
}
|
}
|
||||||
StackFrame new_stackFrame = {
|
StackFrame new_stackFrame = {
|
||||||
{object->value.argon_fn.translated.registerCount,
|
{object->value.argon_fn.translated.registerCount,
|
||||||
|
object->value.argon_fn.translated.registerAssignment,
|
||||||
NULL,
|
NULL,
|
||||||
{object->value.argon_fn.bytecode, sizeof(uint8_t),
|
{object->value.argon_fn.bytecode, sizeof(uint8_t),
|
||||||
object->value.argon_fn.bytecode_length,
|
object->value.argon_fn.bytecode_length,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "number.h"
|
#include "number.h"
|
||||||
#include "../functions/functions.h"
|
#include "../functions/functions.h"
|
||||||
#include "../string/string.h"
|
#include "../string/string.h"
|
||||||
|
#include <gmp-x86_64.h>
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -72,8 +73,7 @@ ArgonObject *ARGON_NUMBER_TYPE___boolean__(size_t argc, ArgonObject **argv,
|
|||||||
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
return mpq_cmp_si(*argv[0]->value.as_number, 0, 1) == 0 ? ARGON_FALSE
|
return argv[0]->as_bool ? ARGON_FALSE : ARGON_TRUE;
|
||||||
: ARGON_TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
||||||
@@ -87,22 +87,60 @@ ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
|
|||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__add__ cannot perform addition between a number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__add__ cannot perform addition between a number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str.length, type_name->value.as_str.data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_t r;
|
if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) {
|
||||||
mpq_init(r);
|
int64_t a = argv[0]->value.as_number.n.i64;
|
||||||
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
int64_t b = argv[1]->value.as_number.n.i64;
|
||||||
ArgonObject *result = new_number_object(r);
|
bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
|
||||||
mpq_clear(r);
|
(a < 0 && b < 0 && a < INT64_MIN - b);
|
||||||
return result;
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_num_and_den(a + b, 1);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number.is_int64 &&
|
||||||
|
!argv[1]->value.as_number.is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_add(r, *argv[0]->value.as_number.n.mpq,
|
||||||
|
*argv[1]->value.as_number.n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number.is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
@@ -114,20 +152,61 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
|
|||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__subtract__ cannot perform subtraction between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__subtract__ cannot perform subtraction between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str.length, type_name->value.as_str.data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_sub(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) {
|
||||||
ArgonObject *result = new_number_object(r);
|
int64_t a = argv[0]->value.as_number.n.i64;
|
||||||
mpq_clear(r);
|
int64_t b = argv[1]->value.as_number.n.i64;
|
||||||
return result;
|
int64_t neg_a = -a;
|
||||||
|
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
|
||||||
|
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
return new_number_object_from_num_and_den(a - b, 1);
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
} else if (!argv[0]->value.as_number.is_int64 &&
|
||||||
|
!argv[1]->value.as_number.is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_sub(r, *argv[0]->value.as_number.n.mpq,
|
||||||
|
*argv[1]->value.as_number.n.mpq);
|
||||||
|
ArgonObject *result = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (argv[0]->value.as_number.is_int64) {
|
||||||
|
mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq);
|
||||||
|
mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
ArgonObject *result = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
@@ -139,20 +218,20 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
|
|||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__multiply__ cannot perform multiplication between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__multiply__ cannot perform multiplication between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str.length, type_name->value.as_str.data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_mul(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
mpq_mul(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq);
|
||||||
ArgonObject *result = new_number_object(r);
|
ArgonObject *result = new_number_object(r);
|
||||||
mpq_clear(r);
|
mpq_clear(r);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
(void)state;
|
(void)state;
|
||||||
if (argc != 2) {
|
if (argc != 2) {
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
@@ -164,13 +243,13 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
|
|||||||
if (argv[1]->type != TYPE_NUMBER) {
|
if (argv[1]->type != TYPE_NUMBER) {
|
||||||
ArgonObject *type_name = get_field_for_class(
|
ArgonObject *type_name = get_field_for_class(
|
||||||
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
|
||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(
|
||||||
"__division__ cannot perform division between number and %.*s",
|
0, 0, 0, "", "Runtime Error",
|
||||||
type_name->value.as_str.length,
|
"__division__ cannot perform division between number and %.*s",
|
||||||
type_name->value.as_str.data);
|
type_name->value.as_str.length, type_name->value.as_str.data);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
mpq_div(r, *argv[0]->value.as_number, *argv[1]->value.as_number);
|
mpq_div(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq);
|
||||||
ArgonObject *result = new_number_object(r);
|
ArgonObject *result = new_number_object(r);
|
||||||
mpq_clear(r);
|
mpq_clear(r);
|
||||||
return result;
|
return result;
|
||||||
@@ -185,7 +264,13 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
mpq_t *num = argv[0]->value.as_number;
|
if (argv[0]->value.as_number.is_int64) {
|
||||||
|
char buf[32];
|
||||||
|
snprintf(buf, sizeof(buf), "%" PRId64, argv[0]->value.as_number.n.i64);
|
||||||
|
return new_string_object_null_terminated(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
mpq_t *num = argv[0]->value.as_number.n.mpq;
|
||||||
|
|
||||||
/* If denominator == 1, print numerator as full integer */
|
/* If denominator == 1, print numerator as full integer */
|
||||||
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
|
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
|
||||||
@@ -327,6 +412,20 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArgonObject small_ints[UINT8_MAX * 2];
|
||||||
|
|
||||||
|
void init_small_ints() {
|
||||||
|
for (uint64_t i = 0; i < UINT8_MAX * 2; i++) {
|
||||||
|
small_ints[i].type = TYPE_NUMBER;
|
||||||
|
small_ints[i].dict = createHashmap_GC();
|
||||||
|
add_field(&small_ints[i], "__class__", ARGON_NUMBER_TYPE);
|
||||||
|
add_field(&small_ints[i], "__base__", BASE_CLASS);
|
||||||
|
small_ints[i].value.as_number.is_int64 = true;
|
||||||
|
small_ints[i].value.as_number.n.i64 = i;
|
||||||
|
small_ints[i].as_bool = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void create_ARGON_NUMBER_TYPE() {
|
void create_ARGON_NUMBER_TYPE() {
|
||||||
ARGON_NUMBER_TYPE = new_object();
|
ARGON_NUMBER_TYPE = new_object();
|
||||||
add_field(ARGON_NUMBER_TYPE, "__name__",
|
add_field(ARGON_NUMBER_TYPE, "__name__",
|
||||||
@@ -343,8 +442,7 @@ void create_ARGON_NUMBER_TYPE() {
|
|||||||
create_argon_native_function("__boolean__",
|
create_argon_native_function("__boolean__",
|
||||||
ARGON_NUMBER_TYPE___boolean__));
|
ARGON_NUMBER_TYPE___boolean__));
|
||||||
add_field(ARGON_NUMBER_TYPE, "__add__",
|
add_field(ARGON_NUMBER_TYPE, "__add__",
|
||||||
create_argon_native_function("__add__",
|
create_argon_native_function("__add__", ARGON_NUMBER_TYPE___add__));
|
||||||
ARGON_NUMBER_TYPE___add__));
|
|
||||||
add_field(ARGON_NUMBER_TYPE, "__subtract__",
|
add_field(ARGON_NUMBER_TYPE, "__subtract__",
|
||||||
create_argon_native_function("__subtract__",
|
create_argon_native_function("__subtract__",
|
||||||
ARGON_NUMBER_TYPE___subtract__));
|
ARGON_NUMBER_TYPE___subtract__));
|
||||||
@@ -354,6 +452,7 @@ void create_ARGON_NUMBER_TYPE() {
|
|||||||
add_field(ARGON_NUMBER_TYPE, "__division__",
|
add_field(ARGON_NUMBER_TYPE, "__division__",
|
||||||
create_argon_native_function("__division__",
|
create_argon_native_function("__division__",
|
||||||
ARGON_NUMBER_TYPE___division__));
|
ARGON_NUMBER_TYPE___division__));
|
||||||
|
init_small_ints();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
|
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
|
||||||
@@ -393,43 +492,116 @@ mpq_t *mpq_new_gc_from(const mpq_t src) {
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out) {
|
||||||
|
// Check denominator == 1
|
||||||
|
if (mpz_cmp_ui(mpq_denref(q), 1) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get numerator
|
||||||
|
mpz_t num;
|
||||||
|
mpz_init(num);
|
||||||
|
mpz_set(num, mpq_numref(q));
|
||||||
|
|
||||||
|
// Check bounds
|
||||||
|
if (mpz_cmp_si(num, INT64_MIN) < 0 || mpz_cmp_si(num, INT64_MAX) > 0) {
|
||||||
|
mpz_clear(num);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = mpz_get_si(num); // safe because we checked range
|
||||||
|
mpz_clear(num);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool double_to_int64(double x, int64_t *out) {
|
||||||
|
if (x < (double)INT64_MIN || x > (double)INT64_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t i = (int64_t)x;
|
||||||
|
if ((double)i == x) { // no fractional part
|
||||||
|
*out = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number) {
|
ArgonObject *new_number_object(mpq_t number) {
|
||||||
|
int64_t i64 = 0;
|
||||||
|
bool is_int64 = mpq_to_int64(number, &i64);
|
||||||
|
if (is_int64 && i64 >= INT8_MIN * 2 && i64 <= INT8_MAX * 2) {
|
||||||
|
return &small_ints[i64];
|
||||||
|
}
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_object();
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(number);
|
object->value.as_number.n.i64 = i64;
|
||||||
object->as_bool = mpq_cmp_si(number, 0, 1) != 0;
|
object->value.as_number.is_int64 = is_int64;
|
||||||
|
if (object->value.as_number.is_int64) {
|
||||||
|
object->as_bool = object->value.as_number.n.i64;
|
||||||
|
} else {
|
||||||
|
object->value.as_number.n.mpq = mpq_new_gc_from(number);
|
||||||
|
object->as_bool = mpq_cmp_si(number, 0, 1) != 0;
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d) {
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d) {
|
||||||
|
if (d == 1 && n >= INT8_MIN && n <= INT8_MAX) {
|
||||||
|
return &small_ints[(int8_t)n];
|
||||||
|
}
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_object();
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
||||||
mpq_t r;
|
|
||||||
mpq_init(r);
|
|
||||||
mpq_set_si(r, n, d);
|
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
if (d == 1) {
|
||||||
object->as_bool = n!=0;
|
object->value.as_number.is_int64 = true;
|
||||||
mpq_clear(r);
|
object->value.as_number.n.i64 = n;
|
||||||
|
object->as_bool = n;
|
||||||
|
} else {
|
||||||
|
object->value.as_number.is_int64 = false;
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_si(r, n, d);
|
||||||
|
object->value.as_number.n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = n != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d) {
|
ArgonObject *new_number_object_from_double(double d) {
|
||||||
|
int64_t i64 = 0;
|
||||||
|
bool is_int64 = double_to_int64(d, &i64);
|
||||||
|
if (is_int64 && i64 >= INT8_MIN && i64 <= INT8_MAX) {
|
||||||
|
return &small_ints[(int8_t)i64];
|
||||||
|
}
|
||||||
ArgonObject *object = new_object();
|
ArgonObject *object = new_object();
|
||||||
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
add_field(object, "__class__", ARGON_NUMBER_TYPE);
|
||||||
mpq_t r;
|
|
||||||
mpq_init(r);
|
|
||||||
mpq_set_d(r, d);
|
|
||||||
object->type = TYPE_NUMBER;
|
object->type = TYPE_NUMBER;
|
||||||
object->value.as_number = mpq_new_gc_from(r);
|
object->value.as_number.n.i64 = i64;
|
||||||
object->as_bool = d!=0;
|
object->value.as_number.is_int64 = is_int64;
|
||||||
mpq_clear(r);
|
if (object->value.as_number.is_int64) {
|
||||||
|
object->as_bool = object->value.as_number.n.i64;
|
||||||
|
} else {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_set_d(r, d);
|
||||||
|
object->value.as_number.n.mpq = mpq_new_gc_from(r);
|
||||||
|
object->as_bool = d != 0;
|
||||||
|
mpq_clear(r);
|
||||||
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state) {
|
void load_number(Translated *translated, RuntimeState *state) {
|
||||||
uint8_t to_register = pop_byte(translated, state);
|
uint8_t to_register = pop_byte(translated, state);
|
||||||
|
uint8_t is_int64 = pop_byte(translated, state);
|
||||||
|
if (is_int64) {
|
||||||
|
state->registers[to_register] =
|
||||||
|
new_number_object_from_num_and_den(pop_bytecode(translated, state), 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
size_t num_size = pop_bytecode(translated, state);
|
size_t num_size = pop_bytecode(translated, state);
|
||||||
size_t num_pos = pop_bytecode(translated, state);
|
size_t num_pos = pop_bytecode(translated, state);
|
||||||
mpq_t r;
|
mpq_t r;
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ void create_ARGON_NUMBER_TYPE();
|
|||||||
|
|
||||||
ArgonObject *new_number_object(mpq_t number);
|
ArgonObject *new_number_object(mpq_t number);
|
||||||
|
|
||||||
|
bool mpq_to_int64(mpq_t q, int64_t *out);
|
||||||
|
|
||||||
void load_number(Translated *translated, RuntimeState *state);
|
void load_number(Translated *translated, RuntimeState *state);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_double(double d);
|
ArgonObject *new_number_object_from_double(double d);
|
||||||
|
|
||||||
ArgonObject *new_number_object_from_long(long n, unsigned long d);
|
ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d);
|
||||||
|
|
||||||
#endif // RUNTIME_NUMBER_H
|
#endif // RUNTIME_NUMBER_H
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
ArgonObject *BASE_CLASS = NULL;
|
ArgonObject *BASE_CLASS = NULL;
|
||||||
|
|
||||||
|
|
||||||
ArgonObject *new_object() {
|
ArgonObject *new_object() {
|
||||||
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
|
ArgonObject *object = ar_alloc(sizeof(ArgonObject));
|
||||||
object->type = TYPE_OBJECT;
|
object->type = TYPE_OBJECT;
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ ArgonObject *ARGON_STRING_TYPE = NULL;
|
|||||||
ArgonObject *new_string_object(char*data, size_t length) {
|
ArgonObject *new_string_object(char*data, size_t length) {
|
||||||
ArgonObject * object = new_object();
|
ArgonObject * object = new_object();
|
||||||
add_field(object, "__class__", ARGON_STRING_TYPE);
|
add_field(object, "__class__", ARGON_STRING_TYPE);
|
||||||
add_field(object, "length", new_number_object_from_long(length, 1));
|
add_field(object, "length", new_number_object_from_num_and_den(length, 1));
|
||||||
object->type = TYPE_STRING;
|
object->type = TYPE_STRING;
|
||||||
object->value.as_str.data = ar_alloc_atomic(length);
|
object->value.as_str.data = ar_alloc_atomic(length);
|
||||||
memcpy(object->value.as_str.data, data, length);
|
memcpy(object->value.as_str.data, data, length);
|
||||||
|
|||||||
@@ -376,7 +376,7 @@ ArgonObject *ARGON_BOOL_TYPE___number__(size_t argc, ArgonObject **argv,
|
|||||||
"__number__ expects 1 arguments, got %" PRIu64, argc);
|
"__number__ expects 1 arguments, got %" PRIu64, argc);
|
||||||
return ARGON_NULL;
|
return ARGON_NULL;
|
||||||
}
|
}
|
||||||
return new_number_object_from_long(argv[0] == ARGON_TRUE, 1);
|
return new_number_object_from_num_and_den(argv[0] == ARGON_TRUE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv,
|
||||||
@@ -451,7 +451,7 @@ ArgonObject *ARGON_NULL_TYPE___number__(size_t argc, ArgonObject **argv,
|
|||||||
*err = create_err(0, 0, 0, "", "Runtime Error",
|
*err = create_err(0, 0, 0, "", "Runtime Error",
|
||||||
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
"__boolean__ expects 1 arguments, got %" PRIu64, argc);
|
||||||
}
|
}
|
||||||
return new_number_object_from_long(0, 1);
|
return new_number_object_from_num_and_den(0, 1);
|
||||||
}
|
}
|
||||||
ArgonObject *ARGON_NULL_TYPE___string__(size_t argc, ArgonObject **argv,
|
ArgonObject *ARGON_NULL_TYPE___string__(size_t argc, ArgonObject **argv,
|
||||||
ArErr *err, RuntimeState *state) {
|
ArErr *err, RuntimeState *state) {
|
||||||
@@ -655,29 +655,28 @@ static inline ArErr load_variable(Translated *translated, RuntimeState *state,
|
|||||||
|
|
||||||
static inline ArErr run_instruction(Translated *translated, RuntimeState *state,
|
static inline ArErr run_instruction(Translated *translated, RuntimeState *state,
|
||||||
struct Stack **stack) {
|
struct Stack **stack) {
|
||||||
static void *dispatch_table[] = {
|
static void *dispatch_table[] = {[OP_LOAD_STRING] = &&DO_LOAD_STRING,
|
||||||
[OP_LOAD_STRING] = &&DO_LOAD_STRING,
|
[OP_DECLARE] = &&DO_DECLARE,
|
||||||
[OP_DECLARE] = &&DO_DECLARE,
|
[OP_LOAD_NULL] = &&DO_LOAD_NULL,
|
||||||
[OP_LOAD_NULL] = &&DO_LOAD_NULL,
|
[OP_LOAD_FUNCTION] = &&DO_LOAD_FUNCTION,
|
||||||
[OP_LOAD_FUNCTION] = &&DO_LOAD_FUNCTION,
|
[OP_IDENTIFIER] = &&DO_IDENTIFIER,
|
||||||
[OP_IDENTIFIER] = &&DO_IDENTIFIER,
|
[OP_BOOL] = &&DO_BOOL,
|
||||||
[OP_BOOL] = &&DO_BOOL,
|
[OP_JUMP_IF_FALSE] = &&DO_JUMP_IF_FALSE,
|
||||||
[OP_JUMP_IF_FALSE] = &&DO_JUMP_IF_FALSE,
|
[OP_JUMP] = &&DO_JUMP,
|
||||||
[OP_JUMP] = &&DO_JUMP,
|
[OP_NEW_SCOPE] = &&DO_NEW_SCOPE,
|
||||||
[OP_NEW_SCOPE] = &&DO_NEW_SCOPE,
|
[OP_POP_SCOPE] = &&DO_POP_SCOPE,
|
||||||
[OP_POP_SCOPE] = &&DO_POP_SCOPE,
|
[OP_INIT_CALL] = &&DO_INIT_CALL,
|
||||||
[OP_INIT_CALL] = &&DO_INIT_CALL,
|
[OP_INSERT_ARG] = &&DO_INSERT_ARG,
|
||||||
[OP_INSERT_ARG] = &&DO_INSERT_ARG,
|
[OP_CALL] = &&DO_CALL,
|
||||||
[OP_CALL] = &&DO_CALL,
|
[OP_SOURCE_LOCATION] = &&DO_SOURCE_LOCATION,
|
||||||
[OP_SOURCE_LOCATION] = &&DO_SOURCE_LOCATION,
|
[OP_LOAD_BOOL] = &&DO_LOAD_BOOL,
|
||||||
[OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION,
|
[OP_LOAD_NUMBER] = &&DO_LOAD_NUMBER,
|
||||||
[OP_LOAD_BOOL] = &&DO_LOAD_BOOL,
|
[OP_ASSIGN] = &&DO_ASSIGN,
|
||||||
[OP_LOAD_NUMBER] = &&DO_LOAD_NUMBER,
|
[OP_COPY_TO_REGISTER] =
|
||||||
[OP_LOAD_ADDITION_FUNCTION] = &&DO_LOAD_ADDITION_FUNCTION,
|
&&DO_COPY_TO_REGISTER,
|
||||||
[OP_LOAD_SUBTRACTION_FUNCTION] = &&DO_LOAD_SUBTRACTION_FUNCTION,
|
[OP_ADDITION] = &&DO_ADDITION,
|
||||||
[OP_LOAD_MULTIPLY_FUNCTION] = &&DO_LOAD_MULTIPLY_FUNCTION,
|
[OP_SUBTRACTION] = &&DO_SUBTRACTION,
|
||||||
[OP_LOAD_DIVISION_FUNCTION] = &&DO_LOAD_DIVISION_FUNCTION,
|
[OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION};
|
||||||
[OP_ASSIGN] = &&DO_ASSIGN};
|
|
||||||
goto *dispatch_table[pop_byte(translated, state)];
|
goto *dispatch_table[pop_byte(translated, state)];
|
||||||
DO_LOAD_NULL:
|
DO_LOAD_NULL:
|
||||||
state->registers[pop_byte(translated, state)] = ARGON_NULL;
|
state->registers[pop_byte(translated, state)] = ARGON_NULL;
|
||||||
@@ -723,28 +722,7 @@ DO_JUMP:
|
|||||||
DO_NEW_SCOPE:
|
DO_NEW_SCOPE:
|
||||||
*stack = create_scope(*stack);
|
*stack = create_scope(*stack);
|
||||||
goto BREAK;
|
goto BREAK;
|
||||||
DO_POP_SCOPE:;
|
DO_POP_SCOPE:
|
||||||
// struct node_GC *array =
|
|
||||||
// checked_malloc(sizeof(struct node_GC) * (*stack)->scope->count);
|
|
||||||
// size_t j = 0;
|
|
||||||
// for (size_t i = 0; i < (*stack)->scope->size; i++) {
|
|
||||||
// struct node_GC *temp = (*stack)->scope->list[i];
|
|
||||||
// while (temp) {
|
|
||||||
// array[j++] = *temp;
|
|
||||||
// temp = temp->next;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// qsort(array, (*stack)->scope->count, sizeof(struct node_GC),
|
|
||||||
// compare_by_order);
|
|
||||||
// for (size_t i = 0; i < (*stack)->scope->count; i++) {
|
|
||||||
// struct node_GC temp = array[i];
|
|
||||||
// printf("%.*s = %.*s\n",
|
|
||||||
// (int)((ArgonObject *)temp.key)->value.as_str.length,
|
|
||||||
// ((ArgonObject *)temp.key)->value.as_str.data,
|
|
||||||
// (int)((ArgonObject *)temp.val)->value.as_str.length,
|
|
||||||
// ((ArgonObject *)temp.val)->value.as_str.data);
|
|
||||||
// }
|
|
||||||
// free(array);
|
|
||||||
*stack = (*stack)->prev;
|
*stack = (*stack)->prev;
|
||||||
goto BREAK;
|
goto BREAK;
|
||||||
DO_INIT_CALL: {
|
DO_INIT_CALL: {
|
||||||
@@ -758,7 +736,7 @@ DO_INIT_CALL: {
|
|||||||
}
|
}
|
||||||
DO_INSERT_ARG:;
|
DO_INSERT_ARG:;
|
||||||
size_t index = pop_bytecode(translated, state);
|
size_t index = pop_bytecode(translated, state);
|
||||||
(state->call_instance->args)[index] = state->registers[0];
|
state->call_instance->args[index] = state->registers[0];
|
||||||
goto BREAK;
|
goto BREAK;
|
||||||
DO_CALL: {
|
DO_CALL: {
|
||||||
ArErr err =
|
ArErr err =
|
||||||
@@ -766,25 +744,6 @@ DO_CALL: {
|
|||||||
state->call_instance->args, state, false);
|
state->call_instance->args, state, false);
|
||||||
state->call_instance = (*state->call_instance).previous;
|
state->call_instance = (*state->call_instance).previous;
|
||||||
return err;
|
return err;
|
||||||
// ArgonObject *object = state->registers[from_register];
|
|
||||||
// char *field = "__class__";
|
|
||||||
// uint64_t hash = siphash64_bytes(field, strlen(field), siphash_key);
|
|
||||||
// ArgonObject *class = hashmap_lookup_GC(object->dict, hash);
|
|
||||||
// field = "__name__";
|
|
||||||
// hash = siphash64_bytes(field, strlen(field), siphash_key);
|
|
||||||
// ArgonObject *class_name = hashmap_lookup_GC(class->dict, hash);
|
|
||||||
// hash = siphash64_bytes(field, strlen(field), siphash_key);
|
|
||||||
// ArgonObject *object_name = hashmap_lookup_GC(object->dict, hash);
|
|
||||||
// if (object_name) {
|
|
||||||
// printf("call <%.*s %.*s at %p>\n",
|
|
||||||
// (int)class_name->value.as_str.length,
|
|
||||||
// class_name->value.as_str.data,(int)object_name->value.as_str.length,
|
|
||||||
// object_name->value.as_str.data, object);
|
|
||||||
// } else {
|
|
||||||
// printf("call <%.*s object at %p>\n",
|
|
||||||
// (int)class_name->value.as_str.length, class_name->value.as_str.data,
|
|
||||||
// object);
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
DO_SOURCE_LOCATION:
|
DO_SOURCE_LOCATION:
|
||||||
state->source_location = (SourceLocation){pop_bytecode(translated, state),
|
state->source_location = (SourceLocation){pop_bytecode(translated, state),
|
||||||
@@ -797,18 +756,134 @@ DO_LOAD_BOOL:
|
|||||||
DO_LOAD_ACCESS_FUNCTION:
|
DO_LOAD_ACCESS_FUNCTION:
|
||||||
state->registers[0] = ACCESS_FUNCTION;
|
state->registers[0] = ACCESS_FUNCTION;
|
||||||
goto BREAK;
|
goto BREAK;
|
||||||
DO_LOAD_ADDITION_FUNCTION:
|
DO_COPY_TO_REGISTER: {
|
||||||
state->registers[0] = ADDITION_FUNCTION;
|
uint8_t from_register = pop_byte(translated, state);
|
||||||
goto BREAK;
|
uint64_t to_register = pop_byte(translated, state);
|
||||||
DO_LOAD_SUBTRACTION_FUNCTION:
|
state->registers[to_register] = state->registers[from_register];
|
||||||
state->registers[0] = SUBTRACTION_FUNCTION;
|
|
||||||
goto BREAK;
|
|
||||||
DO_LOAD_MULTIPLY_FUNCTION:
|
|
||||||
state->registers[0] = MULTIPLY_FUNCTION;
|
|
||||||
goto BREAK;
|
|
||||||
DO_LOAD_DIVISION_FUNCTION:
|
|
||||||
state->registers[0] = DIVISION_FUNCTION;
|
|
||||||
goto BREAK;
|
goto BREAK;
|
||||||
|
}
|
||||||
|
DO_ADDITION: {
|
||||||
|
uint8_t registerA = pop_byte(translated, state);
|
||||||
|
uint64_t registerB = pop_byte(translated, state);
|
||||||
|
uint64_t registerC = pop_byte(translated, state);
|
||||||
|
|
||||||
|
ArgonObject *valueA = state->registers[registerA];
|
||||||
|
ArgonObject *valueB = state->registers[registerB];
|
||||||
|
|
||||||
|
if (valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER) {
|
||||||
|
if (valueA->value.as_number.is_int64 && valueB->value.as_number.is_int64) {
|
||||||
|
int64_t a = valueA->value.as_number.n.i64;
|
||||||
|
int64_t b = valueB->value.as_number.n.i64;
|
||||||
|
bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
|
||||||
|
(a < 0 && b < 0 && a < INT64_MIN - b);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
state->registers[registerC] =
|
||||||
|
new_number_object_from_num_and_den(a + b, 1);
|
||||||
|
goto BREAK;
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
state->registers[registerC] = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
} else if (!valueA->value.as_number.is_int64 &&
|
||||||
|
!valueB->value.as_number.is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_add(r, *valueA->value.as_number.n.mpq,
|
||||||
|
*valueB->value.as_number.n.mpq);
|
||||||
|
state->registers[registerC] = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (valueA->value.as_number.is_int64) {
|
||||||
|
mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *valueB->value.as_number.n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *valueA->value.as_number.n.mpq);
|
||||||
|
mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_add(a_GMP, a_GMP, b_GMP);
|
||||||
|
state->registers[registerC] = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
}
|
||||||
|
goto BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArErr err = no_err;
|
||||||
|
ArgonObject *args[] = {valueA, valueB};
|
||||||
|
state->registers[registerC] = ARGON_ADDITION_FUNCTION(2, args, &err, state);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
DO_SUBTRACTION: {
|
||||||
|
uint8_t registerA = pop_byte(translated, state);
|
||||||
|
uint64_t registerB = pop_byte(translated, state);
|
||||||
|
uint64_t registerC = pop_byte(translated, state);
|
||||||
|
|
||||||
|
ArgonObject *valueA = state->registers[registerA];
|
||||||
|
ArgonObject *valueB = state->registers[registerB];
|
||||||
|
|
||||||
|
if (valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER) {
|
||||||
|
if (valueA->value.as_number.is_int64 && valueB->value.as_number.is_int64) {
|
||||||
|
int64_t a = valueA->value.as_number.n.i64;
|
||||||
|
int64_t b = valueB->value.as_number.n.i64;
|
||||||
|
int64_t neg_a = -a;
|
||||||
|
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
|
||||||
|
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
|
||||||
|
if (!gonna_overflow) {
|
||||||
|
state->registers[registerC] =
|
||||||
|
new_number_object_from_num_and_den(a - b, 1);
|
||||||
|
goto BREAK;
|
||||||
|
}
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
mpq_set_si(a_GMP, a, 1);
|
||||||
|
mpq_set_si(b_GMP, b, 1);
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
state->registers[registerC] = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
} else if (!valueA->value.as_number.is_int64 &&
|
||||||
|
!valueB->value.as_number.is_int64) {
|
||||||
|
mpq_t r;
|
||||||
|
mpq_init(r);
|
||||||
|
mpq_sub(r, *valueA->value.as_number.n.mpq,
|
||||||
|
*valueB->value.as_number.n.mpq);
|
||||||
|
state->registers[registerC] = new_number_object(r);
|
||||||
|
mpq_clear(r);
|
||||||
|
} else {
|
||||||
|
mpq_t a_GMP, b_GMP;
|
||||||
|
mpq_init(a_GMP);
|
||||||
|
mpq_init(b_GMP);
|
||||||
|
if (valueA->value.as_number.is_int64) {
|
||||||
|
mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1);
|
||||||
|
mpq_set(b_GMP, *valueB->value.as_number.n.mpq);
|
||||||
|
} else {
|
||||||
|
mpq_set(a_GMP, *valueA->value.as_number.n.mpq);
|
||||||
|
mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1);
|
||||||
|
}
|
||||||
|
mpq_sub(a_GMP, a_GMP, b_GMP);
|
||||||
|
state->registers[registerC] = new_number_object(a_GMP);
|
||||||
|
mpq_clear(a_GMP);
|
||||||
|
mpq_clear(b_GMP);
|
||||||
|
}
|
||||||
|
goto BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArErr err = no_err;
|
||||||
|
ArgonObject *args[] = {valueA, valueB};
|
||||||
|
state->registers[registerC] = ARGON_ADDITION_FUNCTION(2, args, &err, state);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
BREAK:
|
BREAK:
|
||||||
return no_err;
|
return no_err;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ int execute_code(FILE *stream, char *path, Stack *scope,
|
|||||||
|
|
||||||
hashmap_free(__translated.constants.hashmap, NULL);
|
hashmap_free(__translated.constants.hashmap, NULL);
|
||||||
Translated translated = {
|
Translated translated = {
|
||||||
__translated.registerCount, NULL, {}, {}, __translated.path};
|
__translated.registerCount, __translated.registerAssignment, NULL, {}, {}, __translated.path};
|
||||||
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
|
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
|
||||||
memcpy(translated.bytecode.data, __translated.bytecode.data,
|
memcpy(translated.bytecode.data, __translated.bytecode.data,
|
||||||
__translated.bytecode.capacity);
|
__translated.bytecode.capacity);
|
||||||
|
|||||||
@@ -131,27 +131,27 @@ loads a boolean into register 1
|
|||||||
|
|
||||||
## OP_LOAD_NUMBER
|
## OP_LOAD_NUMBER
|
||||||
|
|
||||||
loads a mpq_t number into memory
|
loads a mpq_t / int64 number into memory
|
||||||
|
|
||||||
1. the register to write to. (*)
|
1. the register to write to. (*)
|
||||||
|
1. is int64 (*)
|
||||||
1. the size of the numerator in the constant buffer.
|
1. the size of the numerator in the constant buffer.
|
||||||
1. the offset in the constant buffer of the numerator.
|
1. the offset in the constant buffer of the numerator.
|
||||||
1. is integer. (*)
|
1. is integer. (*)
|
||||||
1. the size of the denominator in the constant buffer.
|
1. the size of the denominator in the constant buffer.
|
||||||
1. the offset in the constant buffer of the denominator.
|
1. the offset in the constant buffer of the denominator.
|
||||||
|
|
||||||
## OP_LOAD_ADDITION_FUNCTION
|
## OP_COPY_TO_REGISTER
|
||||||
|
|
||||||
loads the addition function into register 1
|
copies the value from one register to another
|
||||||
|
|
||||||
## OP_LOAD_SUBTRACTION_FUNCTION
|
1. the register to copy from (*)
|
||||||
|
2. the register to write to (*)
|
||||||
|
|
||||||
loads the subtraction function into register 1
|
## OP_ADDITION
|
||||||
|
|
||||||
## OP_LOAD_MULTIPLY_FUNCTION
|
performs an addition between register A and register B, storing the result in register C
|
||||||
|
|
||||||
loads the multiply function into register 1
|
1. the register A (*)
|
||||||
|
2. the register B (*)
|
||||||
## OP_LOAD_DIVISION_FUNCTION
|
2. the register C (*)
|
||||||
|
|
||||||
loads the division function into register 1
|
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "number.h"
|
#include "number.h"
|
||||||
|
#include "../../runtime/objects/number/number.h"
|
||||||
#include "../translator.h"
|
#include "../translator.h"
|
||||||
#include <gmp.h>
|
#include <gmp.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -16,6 +17,13 @@ size_t translate_parsed_number(Translated *translated, mpq_t *number,
|
|||||||
set_registers(translated, to_register + 1);
|
set_registers(translated, to_register + 1);
|
||||||
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
|
||||||
push_instruction_byte(translated, to_register);
|
push_instruction_byte(translated, to_register);
|
||||||
|
int64_t i64;
|
||||||
|
uint8_t is_int64 = mpq_to_int64(*number, &i64);
|
||||||
|
push_instruction_byte(translated, is_int64);
|
||||||
|
if (is_int64) {
|
||||||
|
push_instruction_code(translated, i64);
|
||||||
|
return start;
|
||||||
|
}
|
||||||
size_t num_size;
|
size_t num_size;
|
||||||
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
|
||||||
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);
|
||||||
|
|||||||
@@ -6,42 +6,44 @@
|
|||||||
|
|
||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
size_t translate_operation(Translated *translated, ParsedOperation *operation,
|
||||||
ArErr *err) {
|
ArErr *err) {
|
||||||
set_registers(translated, 1);
|
uint8_t registerA = translated->registerAssignment++;
|
||||||
uint64_t first;
|
uint8_t registerB = translated->registerAssignment++;
|
||||||
switch (operation->operation) {
|
set_registers(translated, translated->registerAssignment);
|
||||||
case TOKEN_PLUS:;
|
uint64_t first = translate_parsed(translated, darray_get(&operation->to_operate_on, 0), err);
|
||||||
first = push_instruction_byte(translated, OP_LOAD_ADDITION_FUNCTION);
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
break;
|
push_instruction_byte(translated, 0);
|
||||||
case TOKEN_MINUS:
|
push_instruction_byte(translated, registerA);
|
||||||
first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION);
|
for (size_t i = 1; i < operation->to_operate_on.size; i++) {
|
||||||
break;
|
|
||||||
case TOKEN_STAR:
|
|
||||||
first = push_instruction_byte(translated, OP_LOAD_MULTIPLY_FUNCTION);
|
|
||||||
break;
|
|
||||||
case TOKEN_SLASH:
|
|
||||||
first = push_instruction_byte(translated, OP_LOAD_DIVISION_FUNCTION);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
*err = create_err(operation->line, operation->column, operation->length,
|
|
||||||
translated->path, "Syntax Error", "unknown operation");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
push_instruction_byte(translated, OP_INIT_CALL);
|
|
||||||
push_instruction_code(translated, operation->to_operate_on.size);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
|
|
||||||
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
|
||||||
push_instruction_byte(translated, OP_INSERT_ARG);
|
push_instruction_byte(translated, OP_COPY_TO_REGISTER);
|
||||||
push_instruction_code(translated, i);
|
push_instruction_byte(translated, 0);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
switch (operation->operation) {
|
||||||
|
case TOKEN_PLUS:;
|
||||||
|
push_instruction_byte(translated, OP_ADDITION);
|
||||||
|
break;
|
||||||
|
case TOKEN_MINUS:;
|
||||||
|
push_instruction_byte(translated, OP_SUBTRACTION);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
*err = create_err(operation->line, operation->column, operation->length,
|
||||||
|
translated->path, "Syntax Error", "unknown operation");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
push_instruction_byte(translated, registerA);
|
||||||
|
push_instruction_byte(translated, registerB);
|
||||||
|
push_instruction_byte(
|
||||||
|
translated, operation->to_operate_on.size - 1 == i ? 0 : registerA);
|
||||||
}
|
}
|
||||||
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_byte(translated, OP_SOURCE_LOCATION);
|
push_instruction_byte(translated, registerA);
|
||||||
push_instruction_code(translated, operation->line);
|
push_instruction_byte(translated, OP_LOAD_NULL);
|
||||||
push_instruction_code(translated, operation->column);
|
push_instruction_byte(translated, registerB);
|
||||||
push_instruction_code(translated, operation->length);
|
translated->registerAssignment -= 2;
|
||||||
push_instruction_byte(translated, OP_CALL);
|
|
||||||
return first;
|
return first;
|
||||||
}
|
}
|
||||||
@@ -86,6 +86,7 @@ Translated init_translator(char *path) {
|
|||||||
Translated translated;
|
Translated translated;
|
||||||
translated.path = path;
|
translated.path = path;
|
||||||
translated.registerCount = 1;
|
translated.registerCount = 1;
|
||||||
|
translated.registerAssignment = 1;
|
||||||
translated.return_jumps = NULL;
|
translated.return_jumps = NULL;
|
||||||
darray_init(&translated.bytecode, sizeof(uint8_t));
|
darray_init(&translated.bytecode, sizeof(uint8_t));
|
||||||
arena_init(&translated.constants);
|
arena_init(&translated.constants);
|
||||||
|
|||||||
@@ -29,14 +29,13 @@ typedef enum {
|
|||||||
OP_INSERT_ARG,
|
OP_INSERT_ARG,
|
||||||
OP_CALL,
|
OP_CALL,
|
||||||
OP_SOURCE_LOCATION,
|
OP_SOURCE_LOCATION,
|
||||||
OP_LOAD_ACCESS_FUNCTION,
|
|
||||||
OP_LOAD_BOOL,
|
OP_LOAD_BOOL,
|
||||||
OP_LOAD_NUMBER,
|
OP_LOAD_NUMBER,
|
||||||
OP_LOAD_ADDITION_FUNCTION,
|
OP_ASSIGN,
|
||||||
OP_LOAD_SUBTRACTION_FUNCTION,
|
OP_COPY_TO_REGISTER,
|
||||||
OP_LOAD_MULTIPLY_FUNCTION,
|
OP_ADDITION,
|
||||||
OP_LOAD_DIVISION_FUNCTION,
|
OP_SUBTRACTION,
|
||||||
OP_ASSIGN
|
OP_LOAD_ACCESS_FUNCTION
|
||||||
} OperationType;
|
} OperationType;
|
||||||
|
|
||||||
void arena_resize(ConstantArena *arena, size_t new_size);
|
void arena_resize(ConstantArena *arena, size_t new_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user