diff options
author | Tavian Barnes <tavianator@gmail.com> | 2011-05-15 16:10:51 -0600 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2011-05-15 16:10:51 -0600 |
commit | e5e88afdbf158e6df8f8c3328f308512819d9cf3 (patch) | |
tree | 2a011762c07c0087defcdc1f1022ffe32d532f49 /dimension/parse.c | |
parent | a5a6b94c038e01ebf1e2de0a0774a69b02fb8e1e (diff) | |
download | dimension-e5e88afdbf158e6df8f8c3328f308512819d9cf3.tar.xz |
Rip out old client.
Diffstat (limited to 'dimension/parse.c')
-rw-r--r-- | dimension/parse.c | 1679 |
1 files changed, 0 insertions, 1679 deletions
diff --git a/dimension/parse.c b/dimension/parse.c deleted file mode 100644 index 6651d41..0000000 --- a/dimension/parse.c +++ /dev/null @@ -1,1679 +0,0 @@ -/************************************************************************* - * Copyright (C) 2009-2011 Tavian Barnes <tavianator@tavianator.com> * - * * - * This file is part of Dimension. * - * * - * Dimension is free software; you can redistribute it and/or modify it * - * under the terms of the GNU General Public License as published by the * - * Free Software Foundation; either version 3 of the License, or (at * - * your option) any later version. * - * * - * Dimension is distributed in the hope that it will be useful, but * - * WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * - * General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *************************************************************************/ - -#include "parse.h" -#include "utility.h" -#include <errno.h> -#include <fenv.h> -#include <limits.h> -#include <math.h> -#include <stdint.h> -#include <stdlib.h> - -/* - * Symbol table - */ - -dmnsn_symbol_table * -dmnsn_new_symbol_table(void) -{ - dmnsn_symbol_table *symtable = dmnsn_new_array(sizeof(dmnsn_dictionary *)); - dmnsn_push_scope(symtable); - return symtable; -} - -void -dmnsn_delete_symbol_table(dmnsn_symbol_table *symtable) -{ - while (dmnsn_array_size(symtable) > 0) { - dmnsn_pop_scope(symtable); - } - dmnsn_delete_array(symtable); -} - -void -dmnsn_push_scope(dmnsn_symbol_table *symtable) -{ - dmnsn_dictionary *scope = dmnsn_new_dictionary(sizeof(dmnsn_astnode)); - dmnsn_array_push(symtable, &scope); -} - -static void -dmnsn_delete_symbol_table_entry(void *ptr) -{ - dmnsn_astnode *astnode = ptr; - dmnsn_delete_astnode(*astnode); -} - -void dmnsn_pop_scope(dmnsn_symbol_table *symtable) -{ - dmnsn_dictionary *scope; - dmnsn_array_pop(symtable, &scope); - dmnsn_dictionary_apply(scope, dmnsn_delete_symbol_table_entry); - dmnsn_delete_dictionary(scope); -} - -void dmnsn_local_symbol(dmnsn_symbol_table *symtable, - const char *id, dmnsn_astnode value) -{ - ++*value.refcount; - - dmnsn_dictionary *dict; - dmnsn_array_get(symtable, dmnsn_array_size(symtable) - 1, &dict); - dmnsn_astnode *node = dmnsn_dictionary_at(dict, id); - if (node) { - dmnsn_delete_astnode(*node); - *node = value; - } else { - dmnsn_dictionary_insert(dict, id, &value); - } -} - -void -dmnsn_declare_symbol(dmnsn_symbol_table *symtable, - const char *id, dmnsn_astnode value) -{ - ++*value.refcount; - - dmnsn_astnode *node = dmnsn_find_symbol(symtable, id); - if (node) { - /* Always update the most local symbol */ - dmnsn_delete_astnode(*node); - *node = value; - } else { - /* but create new ones at the least local scope */ - dmnsn_dictionary *dict; - dmnsn_array_get(symtable, 0, &dict); - - node = dmnsn_dictionary_at(dict, id); - if (node) { - dmnsn_delete_astnode(*node); - *node = value; - } else { - dmnsn_dictionary_insert(dict, id, &value); - } - } -} - -void -dmnsn_undef_symbol(dmnsn_symbol_table *symtable, const char *id) -{ - DMNSN_ARRAY_FOREACH (dmnsn_dictionary **, dict, symtable) { - dmnsn_astnode *node = dmnsn_dictionary_at(*dict, id); - if (node) { - dmnsn_delete_astnode(*node); - dmnsn_dictionary_remove(*dict, id); - break; - } - } -} - -dmnsn_astnode * -dmnsn_find_symbol(dmnsn_symbol_table *symtable, const char *id) -{ - dmnsn_astnode *symbol = NULL; - - DMNSN_ARRAY_FOREACH_REVERSE (dmnsn_dictionary **, dict, symtable) { - symbol = dmnsn_dictionary_at(*dict, id); - if (symbol) { - if (symbol->type == DMNSN_AST_IDENTIFIER) { - id = symbol->ptr; - } else { - break; - } - } - } - - return symbol; -} - -/* - * Abstract syntax tree - */ - -static dmnsn_astnode -dmnsn_new_astnode(dmnsn_astnode_type type) -{ - dmnsn_astnode astnode = { - .type = type, - .children = NULL, - .ptr = NULL, - .free_fn = NULL, - .refcount = dmnsn_malloc(sizeof(unsigned int)), - .location = { "<environment>", "<environment>", -1, -1, -1, -1, NULL } - }; - - *astnode.refcount = 0; - return astnode; -} - -dmnsn_astnode -dmnsn_new_ast_array(void) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_ARRAY); - astnode.children = dmnsn_new_array(sizeof(dmnsn_astnode)); - return astnode; -} - -static void -dmnsn_make_ast_integer(dmnsn_astnode *astnode, long value) -{ - astnode->type = DMNSN_AST_INTEGER; - astnode->ptr = dmnsn_malloc(sizeof(long)); - *(long *)astnode->ptr = value; -} - -dmnsn_astnode -dmnsn_new_ast_integer(long value) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_INTEGER); - dmnsn_make_ast_integer(&astnode, value); - return astnode; -} - -static void -dmnsn_make_ast_float(dmnsn_astnode *astnode, double value) -{ - astnode->type = DMNSN_AST_FLOAT; - astnode->ptr = dmnsn_malloc(sizeof(double)); - *(double *)astnode->ptr = value; -} - -dmnsn_astnode -dmnsn_new_ast_float(double value) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_FLOAT); - dmnsn_make_ast_float(&astnode, value); - return astnode; -} - -static void -dmnsn_make_ast_ivector(dmnsn_astnode *astnode, - long x, long y, long z, long f, long t) -{ - astnode->type = DMNSN_AST_VECTOR; - if (!astnode->children) - astnode->children = dmnsn_new_array(sizeof(dmnsn_astnode)); - - dmnsn_astnode comp; - - comp = dmnsn_new_ast_integer(x); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_integer(y); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_integer(z); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_integer(f); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_integer(t); - dmnsn_array_push(astnode->children, &comp); -} - -dmnsn_astnode -dmnsn_new_ast_ivector(long x, long y, long z, long f, long t) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_VECTOR); - dmnsn_make_ast_ivector(&astnode, x, y, z, f, t); - return astnode; -} - -static void -dmnsn_make_ast_vector(dmnsn_astnode *astnode, - double x, double y, double z, double f, double t) -{ - astnode->type = DMNSN_AST_VECTOR; - if (!astnode->children) - astnode->children = dmnsn_new_array(sizeof(dmnsn_astnode)); - - dmnsn_astnode comp; - - comp = dmnsn_new_ast_float(x); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_float(y); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_float(z); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_float(f); - dmnsn_array_push(astnode->children, &comp); - - comp = dmnsn_new_ast_float(t); - dmnsn_array_push(astnode->children, &comp); -} - -dmnsn_astnode -dmnsn_new_ast_vector(double x, double y, double z, double f, double t) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_VECTOR); - dmnsn_make_ast_vector(&astnode, x, y, z, f, t); - return astnode; -} - -dmnsn_astnode -dmnsn_new_ast_string(const char *value) -{ - dmnsn_astnode astnode = dmnsn_new_astnode(DMNSN_AST_STRING); - astnode.ptr = dmnsn_strdup(value); - return astnode; -} - -void -dmnsn_delete_astnode(dmnsn_astnode astnode) -{ - if (*astnode.refcount <= 1) { - dmnsn_delete_astree(astnode.children); - if (astnode.free_fn) { - astnode.free_fn(astnode.ptr); - } else { - dmnsn_free(astnode.ptr); - } - dmnsn_free(astnode.refcount); - } else { - --*astnode.refcount; - } -} - -void -dmnsn_delete_astree(dmnsn_astree *astree) -{ - if (astree) { - DMNSN_ARRAY_FOREACH (dmnsn_astnode *, node, astree) { - dmnsn_delete_astnode(*node); - } - dmnsn_delete_array(astree); - } -} - -static dmnsn_astnode -dmnsn_copy_astnode(dmnsn_astnode astnode) -{ - dmnsn_astnode copy = { - .type = astnode.type, - .children = dmnsn_new_array(sizeof(dmnsn_astnode)), - .ptr = NULL, - .refcount = dmnsn_malloc(sizeof(unsigned int)), - .location = astnode.location - }; - - *copy.refcount = 1; - return copy; -} - -static dmnsn_astnode -dmnsn_new_astnode2(dmnsn_astnode_type type, dmnsn_astnode loc, - dmnsn_astnode n1, dmnsn_astnode n2) -{ - dmnsn_astnode astnode = dmnsn_copy_astnode(loc); - astnode.type = type; - dmnsn_array_push(astnode.children, &n1); - dmnsn_array_push(astnode.children, &n2); - return astnode; -} - -/* 5-element vectors */ -#define DMNSN_VECTOR_NELEM 5 - -static dmnsn_astnode -dmnsn_vector_promote(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode promoted = dmnsn_copy_astnode(astnode); - - if (astnode.type == DMNSN_AST_VECTOR) { - dmnsn_astnode component; - DMNSN_ARRAY_FOREACH (dmnsn_astnode *, i, astnode.children) { - component = dmnsn_eval_scalar(*i, symtable); - - if (component.type == DMNSN_AST_NONE) { - dmnsn_delete_astnode(promoted); - return component; - } else { - dmnsn_array_push(promoted.children, &component); - } - } - - while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { - component = dmnsn_copy_astnode(component); - dmnsn_make_ast_integer(&component, 0); - dmnsn_array_push(promoted.children, &component); - } - } else { - dmnsn_astnode component = dmnsn_eval_scalar(astnode, symtable); - - if (component.type == DMNSN_AST_NONE) { - promoted.type = DMNSN_AST_NONE; - } else { - promoted.type = DMNSN_AST_VECTOR; - while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { - dmnsn_array_push(promoted.children, &component); - ++*component.refcount; - } - } - - dmnsn_delete_astnode(component); - } - - return promoted; -} - -static void -dmnsn_make_ast_maybe_integer(dmnsn_astnode *ret, double n) -{ - feclearexcept(FE_ALL_EXCEPT); - long l = lrint(n); - if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW)) { - dmnsn_make_ast_float(ret, n); - } else { - dmnsn_make_ast_integer(ret, l); - } -} - -static dmnsn_astnode -dmnsn_eval_zeroary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode ret = dmnsn_copy_astnode(astnode); - - switch (astnode.type) { - case DMNSN_AST_PI: - dmnsn_make_ast_float(&ret, 4.0*atan(1.0)); - break; - case DMNSN_AST_TRUE: - dmnsn_make_ast_integer(&ret, 1); - break; - case DMNSN_AST_FALSE: - dmnsn_make_ast_integer(&ret, 0); - break; - - case DMNSN_AST_X: - dmnsn_make_ast_ivector(&ret, 1, 0, 0, 0, 0); - break; - case DMNSN_AST_Y: - dmnsn_make_ast_ivector(&ret, 0, 1, 0, 0, 0); - break; - case DMNSN_AST_Z: - dmnsn_make_ast_ivector(&ret, 0, 0, 1, 0, 0); - break; - case DMNSN_AST_T: - dmnsn_make_ast_ivector(&ret, 0, 0, 0, 1, 0); - break; - - default: - dmnsn_diagnostic(astnode.location, "invalid constant '%s'", - dmnsn_astnode_string(astnode.type)); - ret.type = DMNSN_AST_NONE; - break; - } - - return ret; -} - -static dmnsn_astnode -dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode rhs; - dmnsn_array_get(astnode.children, 0, &rhs); - rhs = dmnsn_eval(rhs, symtable); - - dmnsn_astnode ret; - - if (rhs.type == DMNSN_AST_NONE) { - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - } else if (rhs.type == DMNSN_AST_VECTOR) { - switch (astnode.type) { - case DMNSN_AST_DOT_X: - dmnsn_array_get(rhs.children, 0, &ret); - ++*ret.refcount; - break; - case DMNSN_AST_DOT_Y: - dmnsn_array_get(rhs.children, 1, &ret); - ++*ret.refcount; - break; - case DMNSN_AST_DOT_Z: - dmnsn_array_get(rhs.children, 2, &ret); - ++*ret.refcount; - break; - case DMNSN_AST_DOT_T: - dmnsn_array_get(rhs.children, 3, &ret); - ++*ret.refcount; - break; - case DMNSN_AST_DOT_TRANSMIT: - dmnsn_array_get(rhs.children, 4, &ret); - ++*ret.refcount; - break; - - case DMNSN_AST_VLENGTH: - { - dmnsn_astnode dot = dmnsn_copy_astnode(astnode); - dot.type = DMNSN_AST_VDOT; - *rhs.refcount += 2; - dmnsn_array_push(dot.children, &rhs); - dmnsn_array_push(dot.children, &rhs); - - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_SQRT; - dmnsn_array_push(rewrite.children, &dot); - - ret = dmnsn_eval(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - case DMNSN_AST_VNORMALIZE: - { - dmnsn_astnode norm = dmnsn_copy_astnode(astnode); - norm.type = DMNSN_AST_VLENGTH; - ++*rhs.refcount; - dmnsn_array_push(norm.children, &rhs); - - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_DIV; - ++*rhs.refcount; - dmnsn_array_push(rewrite.children, &rhs); - dmnsn_array_push(rewrite.children, &norm); - - ret = dmnsn_eval(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - - default: - { - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_VECTOR; - - dmnsn_astnode op = dmnsn_copy_astnode(astnode); - dmnsn_array_resize(op.children, 1); - for (size_t i = 0; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 0)); - dmnsn_astnode temp = dmnsn_eval_unary(op, symtable); - dmnsn_array_set(ret.children, i, &temp); - } - - dmnsn_delete_array(op.children); - op.children = NULL; - dmnsn_delete_astnode(op); - break; - } - } - } else if (rhs.type == DMNSN_AST_INTEGER) { - long n = *(long *)rhs.ptr; - ret = dmnsn_copy_astnode(astnode); - - switch (astnode.type) { - case DMNSN_AST_DOT_X: - case DMNSN_AST_DOT_Y: - case DMNSN_AST_DOT_Z: - case DMNSN_AST_DOT_T: - case DMNSN_AST_DOT_TRANSMIT: - dmnsn_make_ast_integer(&ret, n); - break; - - case DMNSN_AST_NEGATE: - if ((n >= 0 && LONG_MIN + n <= 0) || (n < 0 && LONG_MAX + n >= 0)) { - dmnsn_make_ast_integer(&ret, -n); - } else { - dmnsn_make_ast_float(&ret, -(double)n); - } - break; - - case DMNSN_AST_NOT: - dmnsn_make_ast_integer(&ret, !n); - break; - - case DMNSN_AST_ABS: - if (n >= 0 || LONG_MAX + n >= 0) { - dmnsn_make_ast_integer(&ret, labs(n)); - } else { - dmnsn_make_ast_float(&ret, fabs(n)); - } - break; - case DMNSN_AST_ACOS: - dmnsn_make_ast_float(&ret, acos(n)); - break; - case DMNSN_AST_ACOSH: - dmnsn_make_ast_float(&ret, acosh(n)); - break; - case DMNSN_AST_ASIN: - dmnsn_make_ast_float(&ret, asin(n)); - break; - case DMNSN_AST_ASINH: - dmnsn_make_ast_float(&ret, asinh(n)); - break; - case DMNSN_AST_ATAN: - dmnsn_make_ast_float(&ret, atan(n)); - break; - case DMNSN_AST_ATANH: - dmnsn_make_ast_float(&ret, atanh(n)); - break; - case DMNSN_AST_CEIL: - dmnsn_make_ast_integer(&ret, n); - break; - case DMNSN_AST_COS: - dmnsn_make_ast_float(&ret, cos(n)); - break; - case DMNSN_AST_COSH: - dmnsn_make_ast_float(&ret, cosh(n)); - break; - case DMNSN_AST_DEGREES: - dmnsn_make_ast_float(&ret, dmnsn_degrees(n)); - break; - case DMNSN_AST_EXP: - dmnsn_make_ast_float(&ret, exp(n)); - break; - case DMNSN_AST_FLOOR: - dmnsn_make_ast_integer(&ret, n); - break; - case DMNSN_AST_INT: - dmnsn_make_ast_integer(&ret, n); - break; - case DMNSN_AST_LN: - dmnsn_make_ast_float(&ret, log(n)); - break; - case DMNSN_AST_LOG: - dmnsn_make_ast_float(&ret, log(n)/log(10.0)); - break; - case DMNSN_AST_RADIANS: - dmnsn_make_ast_float(&ret, dmnsn_radians(n)); - break; - case DMNSN_AST_SIN: - dmnsn_make_ast_float(&ret, sin(n)); - break; - case DMNSN_AST_SINH: - dmnsn_make_ast_float(&ret, sinh(n)); - break; - case DMNSN_AST_SQRT: - dmnsn_make_ast_float(&ret, sqrt(n)); - break; - case DMNSN_AST_TAN: - dmnsn_make_ast_float(&ret, tan(n)); - break; - case DMNSN_AST_TANH: - dmnsn_make_ast_float(&ret, tanh(n)); - break; - case DMNSN_AST_VLENGTH: - dmnsn_make_ast_float(&ret, sqrt(3.0*n*n)); - break; - case DMNSN_AST_VNORMALIZE: - { - double elem = 1.0/sqrt(DMNSN_VECTOR_NELEM); - dmnsn_make_ast_vector(&ret, elem, elem, elem, elem, elem); - break; - } - - default: - dmnsn_diagnostic(astnode.location, "invalid unary operator '%s' on %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } else if (rhs.type == DMNSN_AST_FLOAT) { - double n = *(double *)rhs.ptr; - ret = dmnsn_copy_astnode(astnode); - - switch (astnode.type) { - case DMNSN_AST_DOT_X: - case DMNSN_AST_DOT_Y: - case DMNSN_AST_DOT_Z: - case DMNSN_AST_DOT_T: - case DMNSN_AST_DOT_TRANSMIT: - dmnsn_make_ast_float(&ret, n); - break; - - case DMNSN_AST_NEGATE: - dmnsn_make_ast_float(&ret, -n); - break; - - case DMNSN_AST_NOT: - dmnsn_make_ast_integer(&ret, !n); - break; - - case DMNSN_AST_ABS: - dmnsn_make_ast_float(&ret, fabs(n)); - break; - case DMNSN_AST_ACOS: - dmnsn_make_ast_float(&ret, acos(n)); - break; - case DMNSN_AST_ACOSH: - dmnsn_make_ast_float(&ret, acosh(n)); - break; - case DMNSN_AST_ASIN: - dmnsn_make_ast_float(&ret, asin(n)); - break; - case DMNSN_AST_ASINH: - dmnsn_make_ast_float(&ret, asinh(n)); - break; - case DMNSN_AST_ATAN: - dmnsn_make_ast_float(&ret, atan(n)); - break; - case DMNSN_AST_ATANH: - dmnsn_make_ast_float(&ret, atanh(n)); - break; - case DMNSN_AST_CEIL: - dmnsn_make_ast_maybe_integer(&ret, ceil(n)); - break; - case DMNSN_AST_COS: - dmnsn_make_ast_float(&ret, cos(n)); - break; - case DMNSN_AST_COSH: - dmnsn_make_ast_float(&ret, cosh(n)); - break; - case DMNSN_AST_DEGREES: - dmnsn_make_ast_float(&ret, dmnsn_degrees(n)); - break; - case DMNSN_AST_EXP: - dmnsn_make_ast_float(&ret, exp(n)); - break; - case DMNSN_AST_FLOOR: - dmnsn_make_ast_maybe_integer(&ret, floor(n)); - break; - case DMNSN_AST_INT: - dmnsn_make_ast_maybe_integer(&ret, trunc(n)); - break; - case DMNSN_AST_LN: - dmnsn_make_ast_float(&ret, log(n)); - break; - case DMNSN_AST_LOG: - dmnsn_make_ast_float(&ret, log(n)/log(10.0)); - break; - case DMNSN_AST_RADIANS: - dmnsn_make_ast_float(&ret, dmnsn_radians(n)); - break; - case DMNSN_AST_SIN: - dmnsn_make_ast_float(&ret, sin(n)); - break; - case DMNSN_AST_SINH: - dmnsn_make_ast_float(&ret, sinh(n)); - break; - case DMNSN_AST_SQRT: - dmnsn_make_ast_float(&ret, sqrt(n)); - break; - case DMNSN_AST_TAN: - dmnsn_make_ast_float(&ret, tan(n)); - break; - case DMNSN_AST_TANH: - dmnsn_make_ast_float(&ret, tanh(n)); - break; - case DMNSN_AST_VLENGTH: - dmnsn_make_ast_float(&ret, sqrt(3.0*n*n)); - break; - case DMNSN_AST_VNORMALIZE: - { - double elem = 1.0/sqrt(DMNSN_VECTOR_NELEM); - dmnsn_make_ast_vector(&ret, elem, elem, elem, elem, elem); - break; - } - - default: - dmnsn_diagnostic(astnode.location, "invalid unary operator '%s' on %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } else if (rhs.type == DMNSN_AST_STRING) { - ret = dmnsn_copy_astnode(astnode); - - switch (astnode.type) { - case DMNSN_AST_ASC: - dmnsn_make_ast_integer(&ret, ((char *)rhs.ptr)[0]); - break; - case DMNSN_AST_STRLEN: - dmnsn_make_ast_integer(&ret, strlen(rhs.ptr)); - break; - case DMNSN_AST_VAL: - { - long l; - if (dmnsn_strtol(&l, rhs.ptr, 0)) { - dmnsn_make_ast_integer(&ret, l); - } else { - double d; - if (dmnsn_strtod(&d, rhs.ptr)) { - dmnsn_make_ast_float(&ret, d); - } else if (errno == ERANGE) { - dmnsn_diagnostic(astnode.location, "float value overflowed"); - ret.type = DMNSN_AST_NONE; - } else { - dmnsn_diagnostic(astnode.location, "invalid numeric string '%s'", - (const char *)rhs.ptr); - ret.type = DMNSN_AST_NONE; - } - } - break; - } - - default: - dmnsn_diagnostic(astnode.location, "invalid unary operator '%s' on %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } else { - dmnsn_diagnostic(rhs.location, "expected %s or %s or %s; found %s", - dmnsn_astnode_string(DMNSN_AST_INTEGER), - dmnsn_astnode_string(DMNSN_AST_FLOAT), - dmnsn_astnode_string(DMNSN_AST_STRING), - dmnsn_astnode_string(rhs.type)); - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - } - - dmnsn_delete_astnode(rhs); - return ret; -} - -static dmnsn_astnode -dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode lhs, rhs; - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - lhs = dmnsn_eval(lhs, symtable); - rhs = dmnsn_eval(rhs, symtable); - - dmnsn_astnode ret; - - if (lhs.type == DMNSN_AST_NONE || rhs.type == DMNSN_AST_NONE) { - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - } else if (lhs.type == DMNSN_AST_VECTOR || rhs.type == DMNSN_AST_VECTOR) { - dmnsn_astnode oldlhs = lhs, oldrhs = rhs; - lhs = dmnsn_vector_promote(lhs, symtable); - rhs = dmnsn_vector_promote(rhs, symtable); - dmnsn_delete_astnode(oldlhs); - dmnsn_delete_astnode(oldrhs); - - if (lhs.type == DMNSN_AST_NONE || rhs.type == DMNSN_AST_NONE) { - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - dmnsn_delete_astnode(lhs); - dmnsn_delete_astnode(rhs); - return ret; - } - - switch (astnode.type) { - case DMNSN_AST_EQUAL: - { - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - - dmnsn_astnode l, r; - dmnsn_array_get(lhs.children, 0, &l); - dmnsn_array_get(rhs.children, 0, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(rewrite.children, &l); - dmnsn_array_push(rewrite.children, &r); - - for (size_t i = 1; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_astnode temp = dmnsn_copy_astnode(astnode); - dmnsn_array_get(lhs.children, i, &l); - dmnsn_array_get(rhs.children, i, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(temp.children, &l); - dmnsn_array_push(temp.children, &r); - - dmnsn_astnode next = dmnsn_copy_astnode(astnode); - next.type = DMNSN_AST_AND; - dmnsn_array_push(next.children, &rewrite); - dmnsn_array_push(next.children, &temp); - rewrite = next; - } - - ret = dmnsn_eval_binary(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - - case DMNSN_AST_NOT_EQUAL: - { - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - - dmnsn_astnode l, r; - dmnsn_array_get(lhs.children, 0, &l); - dmnsn_array_get(rhs.children, 0, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(rewrite.children, &l); - dmnsn_array_push(rewrite.children, &r); - - for (size_t i = 1; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_astnode temp = dmnsn_copy_astnode(astnode); - dmnsn_array_get(lhs.children, i, &l); - dmnsn_array_get(rhs.children, i, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(temp.children, &l); - dmnsn_array_push(temp.children, &r); - - dmnsn_astnode next = dmnsn_copy_astnode(astnode); - next.type = DMNSN_AST_OR; - dmnsn_array_push(next.children, &rewrite); - dmnsn_array_push(next.children, &temp); - rewrite = next; - } - - ret = dmnsn_eval_binary(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - - case DMNSN_AST_AND: - { - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_OR; - - dmnsn_astnode l, r; - dmnsn_array_get(lhs.children, 0, &l); - dmnsn_array_get(rhs.children, 0, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(rewrite.children, &l); - dmnsn_array_push(rewrite.children, &r); - - for (size_t i = 1; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_astnode temp = dmnsn_copy_astnode(astnode); - temp.type = DMNSN_AST_OR; - dmnsn_array_get(lhs.children, i, &l); - dmnsn_array_get(rhs.children, i, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(temp.children, &l); - dmnsn_array_push(temp.children, &r); - - dmnsn_astnode next = dmnsn_copy_astnode(astnode); - next.type = DMNSN_AST_AND; - dmnsn_array_push(next.children, &rewrite); - dmnsn_array_push(next.children, &temp); - rewrite = next; - } - - ret = dmnsn_eval_binary(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - - case DMNSN_AST_OR: - { - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_OR; - - dmnsn_astnode l, r; - dmnsn_array_get(lhs.children, 0, &l); - dmnsn_array_get(rhs.children, 0, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(rewrite.children, &l); - dmnsn_array_push(rewrite.children, &r); - - for (size_t i = 1; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_astnode temp = dmnsn_copy_astnode(astnode); - temp.type = DMNSN_AST_OR; - dmnsn_array_get(lhs.children, i, &l); - dmnsn_array_get(rhs.children, i, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(temp.children, &l); - dmnsn_array_push(temp.children, &r); - - dmnsn_astnode next = dmnsn_copy_astnode(astnode); - next.type = DMNSN_AST_OR; - dmnsn_array_push(next.children, &rewrite); - dmnsn_array_push(next.children, &temp); - rewrite = next; - } - - ret = dmnsn_eval_binary(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - - case DMNSN_AST_LESS: - case DMNSN_AST_LESS_EQUAL: - case DMNSN_AST_GREATER: - case DMNSN_AST_GREATER_EQUAL: - dmnsn_diagnostic(astnode.location, - "invalid comparison operator '%s' between vectors", - dmnsn_astnode_string(astnode.type)); - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - break; - - case DMNSN_AST_VAXIS_ROTATE: - { - dmnsn_astnode rx, ry, rz; - dmnsn_array_get(lhs.children, 0, &rx); - dmnsn_array_get(lhs.children, 1, &ry); - dmnsn_array_get(lhs.children, 2, &rz); - dmnsn_astnode ax, ay, az; - dmnsn_array_get(rhs.children, 0, &ax); - dmnsn_array_get(rhs.children, 1, &ay); - dmnsn_array_get(rhs.children, 2, &az); - - dmnsn_vector r = dmnsn_new_vector( - rx.type == DMNSN_AST_INTEGER ? *(long *)rx.ptr : *(double *)rx.ptr, - ry.type == DMNSN_AST_INTEGER ? *(long *)ry.ptr : *(double *)ry.ptr, - rz.type == DMNSN_AST_INTEGER ? *(long *)rz.ptr : *(double *)rz.ptr - ); - dmnsn_vector axis = dmnsn_new_vector( - ax.type == DMNSN_AST_INTEGER ? *(long *)ax.ptr : *(double *)ax.ptr, - ay.type == DMNSN_AST_INTEGER ? *(long *)ay.ptr : *(double *)ay.ptr, - az.type == DMNSN_AST_INTEGER ? *(long *)az.ptr : *(double *)az.ptr - ); - - axis = dmnsn_vector_mul(dmnsn_radians(1.0), axis); - r = dmnsn_transform_vector(dmnsn_rotation_matrix(axis), r); - - ret = dmnsn_copy_astnode(astnode); - dmnsn_make_ast_vector(&ret, r.x, r.y, r.z, 0.0, 0.0); - break; - } - case DMNSN_AST_VCROSS: - { - dmnsn_astnode ux, uy, uz; - dmnsn_array_get(lhs.children, 0, &ux); - dmnsn_array_get(lhs.children, 1, &uy); - dmnsn_array_get(lhs.children, 2, &uz); - *ux.refcount += 2; - *uy.refcount += 2; - *uz.refcount += 2; - dmnsn_astnode vx, vy, vz; - dmnsn_array_get(rhs.children, 0, &vx); - dmnsn_array_get(rhs.children, 1, &vy); - dmnsn_array_get(rhs.children, 2, &vz); - *vx.refcount += 2; - *vy.refcount += 2; - *vz.refcount += 2; - - dmnsn_astnode uvx = dmnsn_new_astnode2( - DMNSN_AST_SUB, astnode, - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uy, vz), - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uz, vy) - ); - dmnsn_astnode uvy = dmnsn_new_astnode2( - DMNSN_AST_SUB, astnode, - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uz, vx), - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, ux, vz) - ); - dmnsn_astnode uvz = dmnsn_new_astnode2( - DMNSN_AST_SUB, astnode, - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, ux, vy), - dmnsn_new_astnode2(DMNSN_AST_MUL, astnode, uy, vx) - ); - - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_VECTOR; - dmnsn_array_push(rewrite.children, &uvx); - dmnsn_array_push(rewrite.children, &uvy); - dmnsn_array_push(rewrite.children, &uvz); - - ret = dmnsn_eval(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - case DMNSN_AST_VDOT: - { - dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); - rewrite.type = DMNSN_AST_MUL; - - dmnsn_astnode l, r; - dmnsn_array_get(lhs.children, 0, &l); - dmnsn_array_get(rhs.children, 0, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(rewrite.children, &l); - dmnsn_array_push(rewrite.children, &r); - - for (size_t i = 1; i < 3; ++i) { - dmnsn_astnode temp = dmnsn_copy_astnode(astnode); - temp.type = DMNSN_AST_MUL; - dmnsn_array_get(lhs.children, i, &l); - dmnsn_array_get(rhs.children, i, &r); - ++*l.refcount; - ++*r.refcount; - dmnsn_array_push(temp.children, &l); - dmnsn_array_push(temp.children, &r); - - dmnsn_astnode next = dmnsn_copy_astnode(astnode); - next.type = DMNSN_AST_ADD; - dmnsn_array_push(next.children, &rewrite); - dmnsn_array_push(next.children, &temp); - rewrite = next; - } - - ret = dmnsn_eval_binary(rewrite, symtable); - dmnsn_delete_astnode(rewrite); - break; - } - case DMNSN_AST_VROTATE: - { - dmnsn_astnode rx, ry, rz; - dmnsn_array_get(lhs.children, 0, &rx); - dmnsn_array_get(lhs.children, 1, &ry); - dmnsn_array_get(lhs.children, 2, &rz); - dmnsn_astnode ax, ay, az; - dmnsn_array_get(rhs.children, 0, &ax); - dmnsn_array_get(rhs.children, 1, &ay); - dmnsn_array_get(rhs.children, 2, &az); - - dmnsn_vector r = dmnsn_new_vector( - rx.type == DMNSN_AST_INTEGER ? *(long *)rx.ptr : *(double *)rx.ptr, - ry.type == DMNSN_AST_INTEGER ? *(long *)ry.ptr : *(double *)ry.ptr, - rz.type == DMNSN_AST_INTEGER ? *(long *)rz.ptr : *(double *)rz.ptr - ); - dmnsn_vector axis = dmnsn_new_vector( - ax.type == DMNSN_AST_INTEGER ? *(long *)ax.ptr : *(double *)ax.ptr, - ay.type == DMNSN_AST_INTEGER ? *(long *)ay.ptr : *(double *)ay.ptr, - az.type == DMNSN_AST_INTEGER ? *(long *)az.ptr : *(double *)az.ptr - ); - - axis = dmnsn_vector_mul(dmnsn_radians(1.0), axis); - - r = dmnsn_transform_vector( - dmnsn_rotation_matrix(dmnsn_new_vector(axis.x, 0.0, 0.0)), - r - ); - r = dmnsn_transform_vector( - dmnsn_rotation_matrix(dmnsn_new_vector(0.0, axis.y, 0.0)), - r - ); - r = dmnsn_transform_vector( - dmnsn_rotation_matrix(dmnsn_new_vector(0.0, 0.0, axis.z)), - r - ); - - ret = dmnsn_copy_astnode(astnode); - dmnsn_make_ast_vector(&ret, r.x, r.y, r.z, 0.0, 0.0); - break; - } - - default: - { - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_VECTOR; - - dmnsn_astnode op = dmnsn_copy_astnode(astnode); - dmnsn_array_resize(op.children, 2); - for (size_t i = 0; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_array_get(lhs.children, i, dmnsn_array_at(op.children, 0)); - dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 1)); - dmnsn_astnode temp = dmnsn_eval_binary(op, symtable); - dmnsn_array_set(ret.children, i, &temp); - } - - dmnsn_delete_array(op.children); - op.children = NULL; - dmnsn_delete_astnode(op); - break; - } - } - } else if (lhs.type == DMNSN_AST_STRING && rhs.type == DMNSN_AST_STRING) { - ret = dmnsn_copy_astnode(astnode); - - switch (astnode.type) { - case DMNSN_AST_STRCMP: - dmnsn_make_ast_integer(&ret, strcmp(lhs.ptr, rhs.ptr)); - break; - - default: - dmnsn_diagnostic(astnode.location, - "invalid binary operator '%s' on %s and %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(lhs.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } else if (lhs.type == DMNSN_AST_INTEGER && rhs.type == DMNSN_AST_INTEGER) { - ret = dmnsn_copy_astnode(astnode); - - long l, r; - l = *(long *)lhs.ptr; - r = *(long *)rhs.ptr; - - switch (astnode.type) { - case DMNSN_AST_ADD: - if ((r < 0 && LONG_MIN - r <= l) || (r >= 0 && LONG_MAX - r >= l)) { - dmnsn_make_ast_integer(&ret, l + r); - } else { - dmnsn_make_ast_float(&ret, (double)l + r); - } - break; - case DMNSN_AST_SUB: - if ((r >= 0 && LONG_MIN + r <= l) || (r < 0 && LONG_MAX + r >= l)) { - dmnsn_make_ast_integer(&ret, l - r); - } else { - dmnsn_make_ast_float(&ret, (double)l - r); - } - break; - case DMNSN_AST_MUL: - { -#if (ULONG_MAX > 4294967295) - __int128_t prod = l; -#else - int64_t prod = l; -#endif - prod *= r; - if (prod >= LONG_MIN && prod <= LONG_MAX) { - dmnsn_make_ast_integer(&ret, prod); - } else { - dmnsn_make_ast_float(&ret, prod); - } - break; - } - case DMNSN_AST_DIV: - if (r == -1 - && ((l >= 0 && LONG_MIN + l <= 0) || (l < 0 && LONG_MAX + l >= 0))) - { - dmnsn_make_ast_float(&ret, -(double)l); - } else if (r == 0) { - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_float(&ret, (double)l/0.0); - } else if (l%r == 0) { - dmnsn_make_ast_integer(&ret, l/r); - } else { - dmnsn_make_ast_float(&ret, (double)l/(double)r); - } - break; - - case DMNSN_AST_EQUAL: - dmnsn_make_ast_integer(&ret, l == r); - break; - case DMNSN_AST_NOT_EQUAL: - dmnsn_make_ast_integer(&ret, l != r); - break; - case DMNSN_AST_LESS: - dmnsn_make_ast_integer(&ret, l < r); - break; - case DMNSN_AST_LESS_EQUAL: - dmnsn_make_ast_integer(&ret, l <= r); - break; - case DMNSN_AST_GREATER: - dmnsn_make_ast_integer(&ret, l > r); - break; - case DMNSN_AST_GREATER_EQUAL: - dmnsn_make_ast_integer(&ret, l >= r); - break; - case DMNSN_AST_AND: - dmnsn_make_ast_integer(&ret, l && r); - break; - case DMNSN_AST_OR: - dmnsn_make_ast_integer(&ret, l || r); - break; - - case DMNSN_AST_ATAN2: - dmnsn_make_ast_float(&ret, atan2(l, r)); - break; - case DMNSN_AST_INT_DIV: - if (r == -1 - && ((l >= 0 && LONG_MIN + l <= 0) || (l < 0 && LONG_MAX + l >= 0))) - { - dmnsn_make_ast_float(&ret, -(double)l); - } else if (r == 0) { - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_float(&ret, (double)l/0.0); - } else { - dmnsn_make_ast_integer(&ret, l/r); - } - break; - case DMNSN_AST_MAX: - dmnsn_make_ast_integer(&ret, l > r ? l : r); - break; - case DMNSN_AST_MIN: - dmnsn_make_ast_integer(&ret, l < r ? l : r); - break; - case DMNSN_AST_MOD: - if (r == -1) { - /* LONG_MIN % -1 is potentially an overflow */ - dmnsn_make_ast_integer(&ret, 0); - } else if (r == 0) { - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_float(&ret, fmod(l, 0.0)); - } else { - dmnsn_make_ast_integer(&ret, l%r); - } - break; - case DMNSN_AST_POW: - dmnsn_make_ast_float(&ret, pow(l, r)); - break; - case DMNSN_AST_VCROSS: - dmnsn_make_ast_integer(&ret, 0); - break; - case DMNSN_AST_VDOT: - dmnsn_make_ast_integer(&ret, 3*l*r); - break; - case DMNSN_AST_VROTATE: - ret.type = DMNSN_AST_VECTOR; - *lhs.refcount += 3; - dmnsn_array_push(ret.children, &lhs); - dmnsn_array_push(ret.children, &lhs); - dmnsn_array_push(ret.children, &lhs); - break; - - default: - dmnsn_diagnostic(astnode.location, - "invalid binary operator '%s' on %s and %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(lhs.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } else { - ret = dmnsn_copy_astnode(astnode); - - double l, r; - - if (lhs.type == DMNSN_AST_INTEGER) { - l = *(long *)lhs.ptr; - } else if (lhs.type == DMNSN_AST_FLOAT) { - l = *(double *)lhs.ptr; - } else { - dmnsn_diagnostic(lhs.location, "expected %s or %s; found %s", - dmnsn_astnode_string(DMNSN_AST_INTEGER), - dmnsn_astnode_string(DMNSN_AST_FLOAT), - dmnsn_astnode_string(lhs.type)); - ret.type = DMNSN_AST_NONE; - dmnsn_delete_astnode(lhs); - dmnsn_delete_astnode(rhs); - return ret; - } - - if (rhs.type == DMNSN_AST_INTEGER) { - r = *(long *)rhs.ptr; - } else if (rhs.type == DMNSN_AST_FLOAT) { - r = *(double *)rhs.ptr; - } else { - dmnsn_diagnostic(rhs.location, "expected %s or %s; found %s", - dmnsn_astnode_string(DMNSN_AST_INTEGER), - dmnsn_astnode_string(DMNSN_AST_FLOAT), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - dmnsn_delete_astnode(lhs); - dmnsn_delete_astnode(rhs); - return ret; - } - - switch (astnode.type) { - case DMNSN_AST_ADD: - dmnsn_make_ast_float(&ret, l + r); - break; - case DMNSN_AST_SUB: - dmnsn_make_ast_float(&ret, l - r); - break; - case DMNSN_AST_MUL: - dmnsn_make_ast_float(&ret, l*r); - break; - case DMNSN_AST_DIV: - if (r == 0.0) - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_float(&ret, l/r); - break; - - case DMNSN_AST_EQUAL: - dmnsn_make_ast_integer(&ret, fabs(l - r) < dmnsn_epsilon); - break; - case DMNSN_AST_NOT_EQUAL: - dmnsn_make_ast_integer(&ret, fabs(l - r) >= dmnsn_epsilon); - break; - case DMNSN_AST_LESS: - dmnsn_make_ast_integer(&ret, l < r); - break; - case DMNSN_AST_LESS_EQUAL: - dmnsn_make_ast_integer(&ret, l <= r); - break; - case DMNSN_AST_GREATER: - dmnsn_make_ast_integer(&ret, l > r); - break; - case DMNSN_AST_GREATER_EQUAL: - dmnsn_make_ast_integer(&ret, l >= r); - break; - case DMNSN_AST_AND: - dmnsn_make_ast_integer(&ret, fabs(l) >= dmnsn_epsilon - && fabs(r) >= dmnsn_epsilon); - break; - case DMNSN_AST_OR: - dmnsn_make_ast_integer(&ret, fabs(l) >= dmnsn_epsilon - || fabs(r) >= dmnsn_epsilon); - break; - - case DMNSN_AST_ATAN2: - dmnsn_make_ast_float(&ret, atan2(l, r)); - break; - case DMNSN_AST_INT_DIV: - if (r == 0.0) - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_maybe_integer(&ret, trunc(l/r)); - break; - case DMNSN_AST_MAX: - if (l > r) { - if (lhs.type == DMNSN_AST_INTEGER) { - dmnsn_make_ast_maybe_integer(&ret, l); - } else { - dmnsn_make_ast_float(&ret, l); - } - } else { - if (rhs.type == DMNSN_AST_INTEGER) { - dmnsn_make_ast_maybe_integer(&ret, r); - } else { - dmnsn_make_ast_float(&ret, r); - } - } - break; - case DMNSN_AST_MIN: - if (l < r) { - if (lhs.type == DMNSN_AST_INTEGER) { - dmnsn_make_ast_maybe_integer(&ret, l); - } else { - dmnsn_make_ast_float(&ret, l); - } - } else { - if (rhs.type == DMNSN_AST_INTEGER) { - dmnsn_make_ast_maybe_integer(&ret, r); - } else { - dmnsn_make_ast_float(&ret, r); - } - } - break; - case DMNSN_AST_MOD: - if (r == 0.0) - dmnsn_diagnostic(astnode.location, "WARNING: division by zero"); - dmnsn_make_ast_float(&ret, fmod(l, r)); - break; - case DMNSN_AST_POW: - dmnsn_make_ast_float(&ret, pow(l, r)); - break; - case DMNSN_AST_VCROSS: - dmnsn_make_ast_integer(&ret, 0); - break; - case DMNSN_AST_VDOT: - dmnsn_make_ast_float(&ret, 3.0*l*r); - break; - case DMNSN_AST_VROTATE: - ret.type = DMNSN_AST_VECTOR; - *lhs.refcount += 3; - dmnsn_array_push(ret.children, &lhs); - dmnsn_array_push(ret.children, &lhs); - dmnsn_array_push(ret.children, &lhs); - break; - - default: - dmnsn_diagnostic(astnode.location, - "invalid binary operator '%s' on %s and %s", - dmnsn_astnode_string(astnode.type), - dmnsn_astnode_string(lhs.type), - dmnsn_astnode_string(rhs.type)); - ret.type = DMNSN_AST_NONE; - break; - } - } - - dmnsn_delete_astnode(lhs); - dmnsn_delete_astnode(rhs); - return ret; -} - -static dmnsn_astnode -dmnsn_eval_ternary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode test, iftrue, iffalse, ret; - dmnsn_array_get(astnode.children, 0, &test); - dmnsn_array_get(astnode.children, 1, &iftrue); - dmnsn_array_get(astnode.children, 2, &iffalse); - test = dmnsn_eval_scalar(test, symtable); - - switch (astnode.type) { - case DMNSN_AST_TERNARY: - dmnsn_assert(test.type == DMNSN_AST_INTEGER, - "Conditional expression evaluated to non-integer."); - ret = dmnsn_eval(*(long *)test.ptr ? iftrue : iffalse, symtable); - break; - - default: - dmnsn_diagnostic(astnode.location, "invalid ternary operator '%s'", - dmnsn_astnode_string(astnode.type)); - ret = dmnsn_copy_astnode(astnode); - ret.type = DMNSN_AST_NONE; - break; - } - - dmnsn_delete_astnode(test); - return ret; -} - -dmnsn_astnode -dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - switch (astnode.type) { - case DMNSN_AST_NONE: - case DMNSN_AST_INTEGER: - case DMNSN_AST_FLOAT: - case DMNSN_AST_STRING: - do { - ++*astnode.refcount; - } while (*astnode.refcount <= 1); - return astnode; - - case DMNSN_AST_VECTOR: - return dmnsn_vector_promote(astnode, symtable); - - case DMNSN_AST_IDENTIFIER: - { - dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, astnode.ptr); - if (symbol) { - dmnsn_astnode id = *symbol; - id.location = astnode.location; - return dmnsn_eval(id, symtable); - } else { - dmnsn_diagnostic(astnode.location, "unbound identifier '%s'", - (const char *)astnode.ptr); - dmnsn_astnode error = dmnsn_new_astnode(DMNSN_AST_NONE); - ++*error.refcount; - return error; - } - } - - case DMNSN_AST_PI: - case DMNSN_AST_TRUE: - case DMNSN_AST_FALSE: - case DMNSN_AST_X: - case DMNSN_AST_Y: - case DMNSN_AST_Z: - case DMNSN_AST_T: - return dmnsn_eval_zeroary(astnode, symtable); - - case DMNSN_AST_DOT_X: - case DMNSN_AST_DOT_Y: - case DMNSN_AST_DOT_Z: - case DMNSN_AST_DOT_T: - case DMNSN_AST_DOT_TRANSMIT: - case DMNSN_AST_NEGATE: - case DMNSN_AST_NOT: - case DMNSN_AST_ABS: - case DMNSN_AST_ACOS: - case DMNSN_AST_ACOSH: - case DMNSN_AST_ASC: - case DMNSN_AST_ASIN: - case DMNSN_AST_ASINH: - case DMNSN_AST_ATAN: - case DMNSN_AST_ATANH: - case DMNSN_AST_CEIL: - case DMNSN_AST_COS: - case DMNSN_AST_COSH: - case DMNSN_AST_DEGREES: - case DMNSN_AST_EXP: - case DMNSN_AST_FLOOR: - case DMNSN_AST_INT: - case DMNSN_AST_LN: - case DMNSN_AST_LOG: - case DMNSN_AST_RADIANS: - case DMNSN_AST_SIN: - case DMNSN_AST_SINH: - case DMNSN_AST_SQRT: - case DMNSN_AST_STRLEN: - case DMNSN_AST_TAN: - case DMNSN_AST_TANH: - case DMNSN_AST_VAL: - case DMNSN_AST_VLENGTH: - case DMNSN_AST_VNORMALIZE: - return dmnsn_eval_unary(astnode, symtable); - - case DMNSN_AST_ADD: - case DMNSN_AST_SUB: - case DMNSN_AST_MUL: - case DMNSN_AST_DIV: - case DMNSN_AST_EQUAL: - case DMNSN_AST_NOT_EQUAL: - case DMNSN_AST_LESS: - case DMNSN_AST_LESS_EQUAL: - case DMNSN_AST_GREATER: - case DMNSN_AST_GREATER_EQUAL: - case DMNSN_AST_AND: - case DMNSN_AST_OR: - case DMNSN_AST_ATAN2: - case DMNSN_AST_INT_DIV: - case DMNSN_AST_MAX: - case DMNSN_AST_MIN: - case DMNSN_AST_MOD: - case DMNSN_AST_POW: - case DMNSN_AST_STRCMP: - case DMNSN_AST_VAXIS_ROTATE: - case DMNSN_AST_VCROSS: - case DMNSN_AST_VDOT: - case DMNSN_AST_VROTATE: - return dmnsn_eval_binary(astnode, symtable); - - case DMNSN_AST_TERNARY: - return dmnsn_eval_ternary(astnode, symtable); - - default: - dmnsn_diagnostic(astnode.location, - "expected arithmetic expression; found %s", - dmnsn_astnode_string(astnode.type)); - dmnsn_astnode error = dmnsn_new_astnode(DMNSN_AST_NONE); - ++*error.refcount; - return error; - } - - return astnode; -} - -dmnsn_astnode -dmnsn_eval_scalar(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode ret = dmnsn_eval(astnode, symtable); - if (ret.type != DMNSN_AST_INTEGER && ret.type != DMNSN_AST_FLOAT - && ret.type != DMNSN_AST_NONE) - { - dmnsn_diagnostic(ret.location, "expected %s or %s; found %s", - dmnsn_astnode_string(DMNSN_AST_INTEGER), - dmnsn_astnode_string(DMNSN_AST_FLOAT), - dmnsn_astnode_string(ret.type)); - dmnsn_delete_astnode(ret); - ret = dmnsn_new_astnode(DMNSN_AST_NONE); - } - return ret; -} - -dmnsn_astnode -dmnsn_eval_vector(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode eval = dmnsn_eval(astnode, symtable); - dmnsn_astnode ret = dmnsn_vector_promote(eval, symtable); - dmnsn_delete_astnode(eval); - return ret; -} - -static void -dmnsn_print_astnode(FILE *file, dmnsn_astnode astnode) -{ - long ivalue; - double dvalue; - const char *svalue; - - switch (astnode.type) { - case DMNSN_AST_INTEGER: - ivalue = *(long *)astnode.ptr; - fprintf(file, "(%s %ld)", dmnsn_astnode_string(astnode.type), ivalue); - break; - - case DMNSN_AST_FLOAT: - dvalue = *(double *)astnode.ptr; - /* Don't print -0 */ - if (dvalue == 0.0) - fprintf(file, "(%s 0)", dmnsn_astnode_string(astnode.type)); - else - fprintf(file, "(%s %g)", dmnsn_astnode_string(astnode.type), dvalue); - break; - - case DMNSN_AST_STRING: - svalue = astnode.ptr; - fprintf(file, "(%s \"%s\")", dmnsn_astnode_string(astnode.type), svalue); - break; - - default: - fprintf(file, "%s", dmnsn_astnode_string(astnode.type)); - } -} - -static void -dmnsn_print_astree(FILE *file, dmnsn_astnode astnode) -{ - if (astnode.children && dmnsn_array_size(astnode.children) > 0) { - fprintf(file, "("); - dmnsn_print_astnode(file, astnode); - DMNSN_ARRAY_FOREACH (dmnsn_astnode *, child, astnode.children) { - fprintf(file, " "); - dmnsn_print_astree(file, *child); - } - fprintf(file, ")"); - } else { - dmnsn_print_astnode(file, astnode); - } -} - -void -dmnsn_print_astree_sexpr(FILE *file, const dmnsn_astree *astree) -{ - if (dmnsn_array_size(astree) == 0) { - fprintf(file, "()"); - } else { - fprintf(file, "("); - dmnsn_astnode *astnode = dmnsn_array_first(astree); - dmnsn_print_astree(file, *astnode); - - for (++astnode; - astnode <= (dmnsn_astnode *)dmnsn_array_last(astree); - ++astnode) - { - fprintf(file, " "); - dmnsn_print_astree(file, *astnode); - } - - fprintf(file, ")"); - } - - fprintf(file, "\n"); -} |