view src/ploki/pp.c @ 12292:d51f2100210c draft

<kspalaiologos> `` cat <<<"asmbf && bfi output.b" > /hackenv/ibin/asmbf
author HackEso <hackeso@esolangs.org>
date Thu, 02 Jan 2020 15:38:21 +0000
parents ac0403686959
children
line wrap: on
line source

#include "IO.h"
#include "Str.h"
#include "kork.h"
#include "list.h"
#include "main_io.h"
#include "main_opt.h"
#include "match.h"
#include "pp.h"
#include "re.h"
#include "run.h"
#include "val.h"
#include "xmalloc.h"

#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void pp_abs(struct val *v) {
	V_NUM(v);
	v_set_n(v, fabs(v->num));
}

void pp_acos(struct val *v) {
	V_NUM(v);
	v_set_n(v, acos(v->num));
}

void pp_asin(struct val *v) {
	V_NUM(v);
	v_set_n(v, asin(v->num));
}

void pp_atan(struct val *v) {
	V_NUM(v);
	v_set_n(v, atan(v->num));
}

void pp_atan2(struct val *v) {
	if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
		v_set_undef(v);
		#ifdef EINVAL
			errno = EINVAL;
		#endif
		return;
	} else {
		struct val *const a = li_at(v->magic.list, 0);
		struct val *const b = li_at(v->magic.list, 1);
		V_NUM(a);
		V_NUM(b);
		v_set_n(v, atan2(a->num, b->num));
	}
}

void pp_chr(struct val *v) {
	V_NUM(v);
	V_xxx_OFF(v);
	ko_cpy_c(v->ko, (unsigned char)(v->num + .5));
	v->type = V_STR_K;
}

void pp_cos(struct val *v) {
	V_NUM(v);
	v_set_n(v, cos(v->num));
}

void pp_defined(struct val *v) {
	if (v->type != V_UNDEF) {
		v_set_n(v, 1.0);
	}
}

void pp_eof(struct val *v) {
	if (!V_EXT_P(v)) {
		v_set_undef(v);
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}
	if (io_eof(v->magic.ext)) {
		v_set_n(v, 1.0);
	} else {
		v_set_m(v, "", 0);
	}
}

void pp_error(struct val *v) {
	if (!V_EXT_P(v)) {
		v_set_undef(v);
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}
	if (io_err(v->magic.ext)) {
		v_set_n(v, 1.0);
	} else {
		v_set_m(v, "", 0);
	}
}

void pp_escape(struct val *v) {
	String tmp;
	size_t i;

	V_STR(v);
	V_xxx_OFF(v);
	St_init(&tmp);
	St_cpy(&tmp, ko_str(v->ko));
	ko_zero(v->ko);
	for (i = St_len(&tmp); i; ) {
		--i;
		if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) {
			ko_cat_c(v->ko, '!');
		}
		ko_cat_c(v->ko, ST_INDEX(&tmp, i));
	}
	St_clear(&tmp);
	ko_reverse(v->ko);
	v->type = V_STR_K;
}

void pp_getc(struct val *v) {
	int c;

	if (!V_EXT_P(v)) {
		V_xxx_OFF(v);
		v->type = V_UNDEF;
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}
	c = io_getc(v->magic.ext);
	#if EOF != -1
		if (c == EOF) {
			c = -1;
		}
	#endif
	v_set_n(v, c);
}

void pp_getenv(struct val *v) {
	const char *const tmp = getenv(v_sptr(v, NULL));
	if (tmp) {
		v_set_m(v, tmp, strlen(tmp));
	} else {
		V_xxx_OFF(v);
		v->type = V_UNDEF;
	}
}

void pp_gets(struct val *v) {

	if (!V_EXT_P(v)) {
		V_xxx_OFF(v);
		v->type = V_UNDEF;
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}

	if (ko_getline(v->magic.ext, v->ko) + 1u) {
		V_xxx_OFF(v);
		v->type = V_STR_K;
	} else {
		V_xxx_OFF(v);
		v->type = V_UNDEF;
	}
}

void pp_int(struct val *v) {
	V_NUM(v);
	v_set_n(v, floor(v->num + .5));
}

void pp_io(struct val *v) {
	if (V_EXT_P(v)) {
		v_set_n(v, 1.0);
	} else {
		v_set_m(v, "", 0);
	}
}

void pp_length(struct val *v) {
	if (V_LIST_P(v)) {
		v_set_n(v, li_length(v->magic.list));
		return;
	}
	v_set_n(v, ko_length(v_kork(v)));
}

void pp_log(struct val *v) {
	V_NUM(v);
	v_set_n(v, log(v->num));
}

void pp_log10(struct val *v) {
	V_NUM(v);
	v_set_n(v, log10(v->num));
}

void pp_lower(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	ko_lower(v->ko);
}

void pp_moend(struct val *v) {
	size_t n;

	V_NUM(v);
	n = RINT(v->num);
	if (n < Interp.m_end.size) {
		v_set_n(v, Interp.m_end.index[n]);
	} else {
		v_set_undef(v);
	}
}

void pp_mostart(struct val *v) {
	size_t n;

	V_NUM(v);
	n = RINT(v->num);
	if (n < Interp.m_start.size) {
		v_set_n(v, Interp.m_start.index[n]);
	} else {
		v_set_undef(v);
	}
}

void pp_neg(struct val *v) {
	V_NUM(v);
	V_xxx_OFF(v);
	v->num = -v->num;
	v->type = V_NUM_K;
}

void pp_not(struct val *v) {
	if (v_true(v)) {
		v_set_m(v, "", 0);
	} else {
		v_set_n(v, 1.0);
	}
}

void pp_num(struct val *v) {
	V_NUM(v);
	V_xxx_OFF(v);
	v->type = V_NUM_K;
}

void pp_open(struct val *v) {
	IO *fh;
	struct val *name, *mode;
	enum io_flags flags;

	if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
		v_set_undef(v);
		#ifdef ENOENT
			errno = ENOENT;
		#endif
		return;
	}

	name = li_at(v->magic.list, 0);
	V_STR(name);
	if (ko_chr(name->ko, '\0') + 1u) {
		v_set_undef(v);
		#ifdef ENOENT
			errno = ENOENT;
		#endif
		return;
	}

	mode = li_at(v->magic.list, 1);
	flags = 0;
	V_STR(mode);

	if (ko_chr(mode->ko, 'A') + 1u) {
		flags |= IO_APPEND;
		if (ko_chr(mode->ko, '+') + 1u) {
			flags |= IO_READ;
		}
	} else if (ko_chr(mode->ko, 'W') + 1u) {
		flags |= IO_WRITE | IO_TRUNCATE;
		if (ko_chr(mode->ko, '+') + 1u) {
			flags |= IO_READ;
		}
	} else {
		flags |= IO_READ;
		if (ko_chr(mode->ko, '+') + 1u) {
			flags |= IO_WRITE;
		} else if (ko_chr(mode->ko, 'Z') + 1u) {
			flags |= IO_BUFFERED;
		}
	}

	if (ko_chr(mode->ko, 'B') + 1u) {
		flags |= IO_BINARY;
	}
	if ((flags & IO_WRITE || flags & IO_APPEND) && ko_chr(mode->ko, 'F') + 1u) {
		flags |= IO_AUTOFLUSH;
	}

	if (!(fh = io_open(ko_szp(name->ko), flags))) {
		v_set_undef(v);
		return;
	}

	v_set_io(v, fh);
}

void pp_openr(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	if (ko_chr(v->ko, '\0') + 1u) {
		v->type = V_UNDEF;
		#ifdef ENOENT
			errno = ENOENT;
		#endif
	} else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_READ | IO_BINARY))) {
		v->type = V_EXT_K;
	} else {
		v->type = V_UNDEF;
	}
}

void pp_openw(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	if (ko_chr(v->ko, '\0') + 1u) {
		v->type = V_UNDEF;
		#ifdef ENOENT
			errno = ENOENT;
		#endif
	} else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_WRITE | IO_TRUNCATE | IO_BINARY | IO_AUTOFLUSH))) {
		v->type = V_EXT_K;
	} else {
		v->type = V_UNDEF;
	}
}

void pp_ord(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	if (ko_length(v->ko)) {
		v->num = ko_at(v->ko, 0);
		v->type = V_NUM_K;
	} else {
		v->type = V_UNDEF;
	}
}

void pp_quote(struct val *v) {
	String tmp;
	size_t i;

	V_STR(v);
	V_xxx_OFF(v);
	St_init(&tmp);
	St_cpy_m(&tmp, ko_ptr(v->ko), ko_length(v->ko));
	ko_zero(v->ko);
	for (i = 0; i < St_len(&tmp); ++i) {
		if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) {
			ko_cat_c(v->ko, '\\');
		}
		ko_cat_c(v->ko, ST_INDEX(&tmp, i));
	}
	St_clear(&tmp);
	v->type = V_STR_K;
}

void pp_remove(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	if (ko_chr(v->ko, '\0') + 1u) {
		v->type = V_UNDEF;
		#ifdef ENOENT
			errno = ENOENT;
		#endif
		return;
	}

	if (remove(ko_szp(v->ko))) {
		v_set_m(v, "", 0);
	} else {
		v_set_n(v, 1.0);
	}
}

void pp_rename(struct val *v) {
	struct val *from, *to;

	if (!V_LIST_P(v) || li_length(v->magic.list) != 2) {
		v_set_undef(v);
		#ifdef ENOENT
			errno = ENOENT;
		#endif
		return;
	}

	from = li_at(v->magic.list, 0);
	V_STR(from);
	if (ko_chr(from->ko, '\0') + 1u) {
		v_set_undef(v);
		#ifdef ENOENT
			errno = ENOENT;
		#endif
		return;
	}

	to = li_at(v->magic.list, 1);
	V_STR(to);
	if (ko_chr(to->ko, '\0') + 1u) {
		v_set_undef(v);
		#ifdef EINVAL
			errno = EINVAL;
		#endif
		return;
	}

	if (rename(ko_szp(from->ko), ko_szp(to->ko))) {
		v_set_m(v, "", 0);
	} else {
		v_set_n(v, 1.0);
	}
}

void pp_reverse(struct val *v) {
	if (V_LIST_P(v)) {
		li_reverse(v->magic.list);
		v->type = V_LIST_K;
		return;
	}
	V_STR(v);
	V_xxx_OFF(v);
	ko_reverse(v->ko);
	v->type = V_STR_K;
}

void pp_seek(struct val *v) {
	struct val *fh, *tmp;
	long off;
	enum io_whence whence = IOS_START;

	if (!V_LIST_P(v) || li_length(v->magic.list) < 2 || li_length(v->magic.list) > 3) {
		v_set_undef(v);
		#ifdef EINVAL
			errno = EINVAL;
		#endif
		return;
	}

	fh = li_at(v->magic.list, 0);
	if (!V_EXT_P(fh)) {
		v_set_undef(v);
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}

	tmp = li_at(v->magic.list, 1);
	V_NUM(tmp);
	off = RINT(tmp->num);

	if ((tmp = li_at(v->magic.list, 2))) {
		V_NUM(tmp);
		switch ((long)RINT(tmp->num)) {
			case 0: whence = IOS_START; break;
			case 1: whence = IOS_CUR;   break;
			case 2: whence = IOS_END;   break;
			default:
				v_set_undef(v);
				#ifdef EINVAL
					errno = EINVAL;
				#endif
				return;
		}
	}

	v_set_n(v, io_seek(fh->magic.ext, off, whence));
}

void pp_sin(struct val *v) {
	V_NUM(v);
	v_set_n(v, sin(v->num));
}

void pp_sqrt(struct val *v) {
	V_NUM(v);
	V_xxx_OFF(v);
	v->num = sqrt(v->num);
	v->type = V_NUM_K;
}

void pp_str(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	v->type |= V_STR_K;
}

void pp_tan(struct val *v) {
	V_NUM(v);
	v_set_n(v, tan(v->num));
}

void pp_tell(struct val *v) {
	if (!V_EXT_P(v)) {
		v_set_undef(v);
		#ifdef EBADF
			errno = EBADF;
		#endif
		return;
	}
	v_set_n(v, io_tell(v->magic.ext));
}

void pp_typeof(struct val *v) {
	if (V_SUB_P(v)) {
		v_set_m(v, "stuff", 5);
	} else if (V_EXT_P(v)) {
		v_set_m(v, "stream", 6);
	} else if (V_LIST_P(v)) {
		v_set_m(v, "list", 4);
	} else if (V_NUM_P(v)) {
		v_set_m(v, "number", 6);
	} else if (V_STR_P(v)) {
		v_set_m(v, "string", 6);
	} else {
		v_set_m(v, "nothing", 7);
	}
}

void pp_upper(struct val *v) {
	V_STR(v);
	V_xxx_OFF(v);
	ko_upper(v->ko);
}

#define NUMB(expr)    \
do {                  \
	V_NUM(b);         \
	V_NUM(v);         \
	v_set_n(v, expr); \
} while (0)

#define ARITH(op) NUMB(v->num op b->num)

void pp_add(struct val *v, struct val *b) {
	ARITH(+);
}

#define LOGIC(init, cond)  \
do {                       \
	init;                  \
	if (cond) {            \
		v_set_n(v, 1.0);   \
	} else {               \
		v_set_m(v, "", 0); \
	}                      \
} while (0)

void pp_and(struct val *v, struct val *b) {
	LOGIC((void)0, v_true(v) && v_true(b));
}

void pp_comma(struct val *v, struct val *b) {
	v_set(v, b);
}

void pp_concat(struct val *v, struct val *b) {
	v_cat(v, b);
}

void pp_div(struct val *v, struct val *b) {
	ARITH(/);
}

#define CMP_LS(op) LOGIC((void)0, v_cmp_ls(v, b) op 0)

void pp_eq(struct val *v, struct val *b) {
	CMP_LS(==);
}

#define CMP_N(op) LOGIC(V_NUM(v); V_NUM(b), v->num op b->num)

void pp_eq_n(struct val *v, struct val *b) {
	if (V_EXT_P(v)) {
		if (V_EXT_P(b)) {
			LOGIC((void)0, v->magic.ext == b->magic.ext);
		} else if (V_SUB_P(b)) {
			goto false_cmp;
		} else {
			goto default_cmp;
		}
	} else if (V_SUB_P(v)) {
		if (V_SUB_P(b)) {
			LOGIC((void)0, v->magic.sub == b->magic.sub);
		} else if (V_EXT_P(b)) false_cmp: {
			LOGIC((void)0, 0);
		} else {
			goto default_cmp;
		}
	} else default_cmp: {
		CMP_N(==);
	}
}

static const char xdigits[] = "0123456789" "abcdefghijklmnopqrstuvwxyz";

void pp_frombase(struct val *v, struct val *b) {
	double p;
	size_t i;
	int base, sign;
	const char *tmp;

	V_NUM(b);
	V_STR(v);
	V_xxx_OFF(v);
	if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) {
		v->type = V_UNDEF;
		return;
	}
	base = floor(b->num + .5);
	ko_shiftws(v->ko);

	sign = 0;
	if (ko_at(v->ko, 0) == '-') {
		sign = 1;
		ko_shift(v->ko, 1);
	} else if (ko_at(v->ko, 0) == '+') {
		ko_shift(v->ko, 1);
	}

	p = 0.0;
	for (i = 0; i < ko_length(v->ko); ++i) {
		if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) &&
				tmp - xdigits < base) {
			p *= base;
			p += tmp - xdigits;
		} else {
			break;
		}
	}

	if (i < ko_length(v->ko)) {
		if (ko_at(v->ko, i) == '.') {
			double shift = 1.0;

			for (++i; i < ko_length(v->ko); ++i) {
				if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) &&
						tmp - xdigits < base) {
					shift *= base;
					p *= base;
					p += tmp - xdigits;
				} else {
					break;
				}
			}

			p /= shift;
		}
	}

	if (sign) {
		p = -p;
	}
	v_set_n(v, p);
}

void pp_gt(struct val *v, struct val *b) {
	CMP_LS(>);
}

void pp_gt_n(struct val *v, struct val *b) {
	CMP_N(>);
}

void pp_lt(struct val *v, struct val *b) {
	CMP_LS(<);
}

void pp_lt_n(struct val *v, struct val *b) {
	CMP_N(<);
}

void pp_match(struct val *v, struct val *b) {
	t_regex *re;

	V_STR(b);
	re = re_compile(ko_str(b->ko));
	do_match(v, re);
	re_free(re);
}

void pp_mod(struct val *v, struct val *b) {
	NUMB(fmod(v->num, b->num));
}

void pp_mult(struct val *v, struct val *b) {
	ARITH(*);
}

void pp_ne(struct val *v, struct val *b) {
	CMP_LS(!=);
}

void pp_ne_n(struct val *v, struct val *b) {
	if (V_EXT_P(v)) {
		if (V_EXT_P(b)) {
			LOGIC((void)0, v->magic.ext != b->magic.ext);
		} else if (V_SUB_P(b)) {
			goto true_cmp;
		} else {
			goto default_cmp;
		}
	} else if (V_SUB_P(v)) {
		if (V_SUB_P(b)) {
			LOGIC((void)0, v->magic.sub != b->magic.sub);
		} else if (V_EXT_P(b)) true_cmp: {
			LOGIC((void)0, 1);
		} else {
			goto default_cmp;
		}
	} else default_cmp: {
		CMP_N(!=);
	}
}

void pp_or(struct val *v, struct val *b) {
	LOGIC((void)0, v_true(v) || v_true(b));
}

void pp_pop(struct val *v, struct val *b) {
	long p;

	V_NUM(b);
	p = RINT(b->num);

	if (V_LIST_P(v)) {
		v->type = V_LIST_K;
		if (p < 0) {
			p += li_length(v->magic.list);
		}
		if (p < 0) {
			p = 0;
		}
		if ((size_t)p >= li_length(v->magic.list)) {
			return;
		}
		li_trunc(v->magic.list, p);
		return;
	}

	V_STR(v);
	V_xxx_OFF(v);
	v->type = V_STR_K;
	if (p < 0) {
		p += ko_length(v->ko);
	}
	if (p < 0) {
		p = 0;
	}
	if ((size_t)p >= ko_length(v->ko)) {
		return;
	}
	ko_trunc(v->ko, p);
}

void pp_pow(struct val *v, struct val *b) {
	NUMB(pow(v->num, b->num));
}

void pp_read(struct val *v, struct val *b) {
	long n;

	if (V_SUB_P(v)) {
		const size_t curdepth = depth_get();
		stack_store(&Interp.arg, b);
		eval_into(sub_expr(v->magic.sub), v);
		depth_restore(curdepth);
		return;
	}

	if (V_EXT_P(v)) {
		V_NUM(b);
		ko_read(v->magic.ext, v->ko, b->num < 0.0 ? (size_t)-1 : b->num + .5);
		V_xxx_OFF(v);
		v->type = V_STR_K;
		return;
	}

	if (V_LIST_P(v)) {
		struct val *ptr;
		V_NUM(b);
		n = RINT(b->num);
		if (n < 0) {
			n += li_length(v->magic.list);
		}

		if (n >= 0 && (ptr = li_at(v->magic.list, n))) {
			struct list *tmp = li_dup(v->magic.list);
			v_set(v, ptr);
			li_delete(tmp);
		} else {
			v_set_undef(v);
		}
		return;
	}

	V_STR(v);
	V_xxx_OFF(v);
	V_NUM(b);
	n = RINT(b->num);
	if (n < 0) {
		n += ko_length(v->ko);
	}
	if (n >= 0 && (size_t)n < ko_length(v->ko)) {
		ko_shift(v->ko, n);
		ko_trunc(v->ko, 1);
		v->type = V_STR_K;
	} else {
		v->type = V_UNDEF;
	}
}

void pp_shift(struct val *v, struct val *b) {
	long p;

	V_NUM(b);
	p = RINT(b->num);

	if (V_LIST_P(v)) {
		v->type = V_LIST_K;
		if (p < 0) {
			p += li_length(v->magic.list);
		}
		if (p <= 0) {
			return;
		}
		if ((size_t)p >= li_length(v->magic.list)) {
			li_zero(v->magic.list);
		} else {
			li_shift(v->magic.list, p);
		}
		return;
	}

	V_STR(v);
	V_xxx_OFF(v);
	v->type = V_STR_K;
	if (p < 0) {
		p += ko_length(v->ko);
	}
	if (p <= 0) {
		return;
	}
	if ((size_t)p >= ko_length(v->ko)) {
		ko_zero(v->ko);
	} else {
		ko_shift(v->ko, p);
	}
}

void pp_sub(struct val *v, struct val *b) {
	ARITH(-);
}

void pp_tobase(struct val *v, struct val *b) {
	double p;
	int base, sign;
	size_t i;

	V_NUM(b);
	V_NUM(v);
	V_xxx_OFF(v);

	if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) {
		v->type = V_UNDEF;
		return;
	}
	base = floor(b->num + .5);

	sign = 0;
	if (v->num < 0.) {
		v->num = -v->num;
		sign = 1;
	}

	p = v->num;
	ko_zero(v->ko);

	if (floor(p) < p) {
		double foo, bar;
		size_t rounds;

		foo = 1 + floor(log(pow(10, DBL_DIG)) / log(base));
		bar = p > 0. ? 1 + floor(log(p) / log(base)) : 0.;
		if (bar >= foo) {
			rounds = 0;
		} else {
			rounds = foo - bar;
		}

		for (i = 0; i < rounds; ++i) {
			p *= base;
			if (floor(p) >= p) {
				++i;
				break;
			}
		}

		p = floor(p);
		while (i--) {
			int c;
			c = fmod(p, base);
			p = floor(p / base);
			if (c >= 0) {
				ko_cat_c(v->ko, xdigits[c]);
			}
		}
	}

	while (ko_at(v->ko, 0) == '0') {
		ko_shift(v->ko, 1);
	}

	if (ko_length(v->ko)) {
		ko_cat_c(v->ko, '.');
	}

	while (p > 0.) {
		int c;
		c = fmod(p, base);
		p = floor(p / base);
		if (c >= 0) {
			ko_cat_c(v->ko, xdigits[c]);
		}
	}

	if (!ko_length(v->ko) || ko_lastchar(v->ko) == '.') {
		ko_cat_c(v->ko, '0');
	}
	if (sign) {
		ko_cat_c(v->ko, '-');
	}

	v->type = V_STR_K;
}