static Value* vecCompOp(const Vector* vector1, const Vector* vector2, const Context* ctx, BINTYPE bin) { unsigned count = vector1->vals->count; if(count != vector2->vals->count && vector2->vals->count > 1) { return ValErr(mathError("Cannot %s vectors of different sizes.", binop_verb[bin])); } ArgList* newv = ArgList_new(count); unsigned i; for(i = 0; i < count; i++) { /* Perform the specified operation on each matching component */ Value* val2; if(vector2->vals->count == 1) { val2 = vector2->vals->args[0]; } else { val2 = vector2->vals->args[i]; } BinOp* op = BinOp_new(bin, Value_copy(vector1->vals->args[i]), Value_copy(val2)); Value* result = BinOp_eval(op, ctx); BinOp_free(op); /* Error checking */ if(result->type == VAL_ERR) { ArgList_free(newv); return result; } /* Store result */ newv->args[i] = result; } return ValVec(Vector_new(newv)); }
static Value* eval_dot(Context* ctx, ArgList* arglist) { if(arglist->count != 2) { /* Two vectors are required for a dot product */ return ValErr(builtinArgs("dot", 2, arglist->count)); } Value* vector1 = Value_eval(arglist->args[0], ctx); if(vector1->type == VAL_ERR) { return vector1; } Value* vector2 = Value_eval(arglist->args[1], ctx); if(vector2->type == VAL_ERR) { Value_free(vector1); return vector2; } if(vector1->type != VAL_VEC || vector2->type != VAL_VEC) { /* Both values must be vectors */ return ValErr(typeError("Builtin dot expects two vectors.")); } unsigned count = vector1->vec->vals->count; if(count != vector2->vec->vals->count) { /* Both vectors must have the same number of values */ return ValErr(mathError("Vectors must have the same dimensions for dot product.")); } Value* total = ValInt(0); // store the total value of the dot product unsigned i; for(i = 0; i < count; i++) { /* Multiply v1[i] and v2[i] */ BinOp* mul = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[i]), Value_copy(vector2->vec->vals->args[i])); Value* part = BinOp_eval(mul, ctx); BinOp_free(mul); /* Accumulate the sum for all products */ BinOp* add = BinOp_new(BIN_ADD, part, total); total = BinOp_eval(add, ctx); BinOp_free(add); } return total; }
static Value* vecMagOp(const Vector* vec, const Value* scalar, const Context* ctx, BINTYPE bin) { /* Calculate old magnitude */ Value* mag = Vector_magnitude(vec, ctx); /* Calculate new magnitude */ BinOp* magOp = BinOp_new(bin, Value_copy(mag), Value_copy(scalar)); Value* newMag = BinOp_eval(magOp, ctx); BinOp_free(magOp); /* Calculate scalar factor */ BinOp* newDivOld = BinOp_new(BIN_DIV, newMag, mag); Value* scalFact = BinOp_eval(newDivOld, ctx); BinOp_free(newDivOld); /* Both newMag and mag are freed with newDivOld */ /* Calculate new vector */ return vecScalarOp(vec, scalFact, ctx, BIN_MUL); }
static void treeAddValue(BinOp** tree, BinOp** prev, BINTYPE op, Value* val) { BinOp* parent = *tree; BinOp* cur = *tree; BinOp* next; /* Descend down the right side of the tree until we find either an empty node or an operator with a higher precedence than the current one. */ while(cur->b && BinOp_cmp(cur->type, op) < 0) { parent = cur; cur = cur->b->expr; } if(BinOp_cmp(cur->type, op) >= 0) { /* Replace current node with new one */ if(cur == *tree) { /* At the tree's root */ next = BinOp_new(op, ValExpr(*tree), NULL); *tree = next; } else { /* Somewhere in the tree */ next = BinOp_new(op, parent->b, NULL); parent->b = ValExpr(next); } (*prev)->b = val; } else { /* New node is child of current node */ next = BinOp_new(op, val, NULL); (*prev)->b = ValExpr(next); } *prev = next; }
static Value* vecScalarOp(const Vector* vec, const Value* scalar, const Context* ctx, BINTYPE bin) { ArgList* newv = ArgList_new(vec->vals->count); unsigned i; for(i = 0; i < vec->vals->count; i++) { /* Perform operation */ BinOp* op = BinOp_new(bin, Value_copy(vec->vals->args[i]), Value_copy(scalar)); Value* result = BinOp_eval(op, ctx); BinOp_free(op); /* Error checking */ if(result->type == VAL_ERR) { ArgList_free(newv); return result; } /* Store result */ newv->args[i] = result; } return ValVec(Vector_new(newv)); }
static Value* eval_cross(Context* ctx, ArgList* arglist) { if(arglist->count != 2) { /* Two vectors are required for a cross product */ return ValErr(builtinArgs("cross", 2, arglist->count)); } Value* vector1 = Value_eval(arglist->args[0], ctx); if(vector1->type == VAL_ERR) { return vector1; } Value* vector2 = Value_eval(arglist->args[1], ctx); if(vector2->type == VAL_ERR) { Value_free(vector1); return vector2; } if(vector1->type != VAL_VEC || vector2->type != VAL_VEC) { /* Both values must be vectors */ return ValErr(typeError("Builtin dot expects two vectors.")); } if(vector1->vec->vals->count != 3) { /* Vectors must each have a size of 3 */ return ValErr(mathError("Vectors must each have a size of 3 for cross product.")); } /* First cross multiplication */ BinOp* i_pos_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[1]), Value_copy(vector2->vec->vals->args[2])); BinOp* i_neg_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[2]), Value_copy(vector2->vec->vals->args[1])); /* Evaluate multiplications */ Value* i_pos = BinOp_eval(i_pos_op, ctx); Value* i_neg = BinOp_eval(i_neg_op, ctx); BinOp_free(i_pos_op); BinOp_free(i_neg_op); /* Error checking */ if(i_pos->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(i_neg); return i_pos; } if(i_neg->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(i_pos); return i_neg; } /* Subtract products */ BinOp* i_op = BinOp_new(BIN_SUB, i_pos, i_neg); Value* i_val = BinOp_eval(i_op, ctx); BinOp_free(i_op); if(i_val->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); return i_val; } /* Part 2 */ BinOp* j_pos_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[0]), Value_copy(vector2->vec->vals->args[2])); BinOp* j_neg_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[2]), Value_copy(vector2->vec->vals->args[0])); Value* j_pos = BinOp_eval(j_pos_op, ctx); Value* j_neg = BinOp_eval(j_neg_op, ctx); BinOp_free(j_pos_op); BinOp_free(j_neg_op); if(j_pos->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(j_neg); return j_pos; } if(j_neg->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(j_pos); return j_neg; } BinOp* j_op = BinOp_new(BIN_SUB, j_pos, j_neg); Value* j_val = BinOp_eval(j_op, ctx); BinOp_free(j_op); if(j_val->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); return j_val; } /* Part 3 */ BinOp* k_pos_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[0]), Value_copy(vector2->vec->vals->args[1])); BinOp* k_neg_op = BinOp_new(BIN_MUL, Value_copy(vector1->vec->vals->args[1]), Value_copy(vector2->vec->vals->args[0])); Value* k_pos = BinOp_eval(k_pos_op, ctx); Value* k_neg = BinOp_eval(k_neg_op, ctx); BinOp_free(k_pos_op); BinOp_free(k_neg_op); if(k_pos->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(k_neg); return k_pos; } if(k_neg->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); Value_free(k_pos); return k_neg; } BinOp* k_op = BinOp_new(BIN_SUB, k_pos, k_neg); Value* k_val = BinOp_eval(k_op, ctx); BinOp_free(k_op); if(k_val->type == VAL_ERR) { Value_free(vector1); Value_free(vector2); return k_val; } ArgList* args = ArgList_create(3, i_val, j_val, k_val); return ValVec(Vector_new(args)); }
Value* Value_parse(const char** expr, char sep, char end, parser_cb* cb) { Value* val; BINTYPE op = BIN_UNK; BinOp* tree = NULL; BinOp* prev; while(1) { /* Get next value */ val = Value_next(expr, end, cb); /* Error parsing next value? */ if(val->type == VAL_ERR) { if(tree) { BinOp_free(tree); } return val; } /* End of input? */ if(val->type == VAL_END) { if(tree) { BinOp_free(tree); } return val; } /* Special case: negative value */ if(val->type == VAL_NEG) { Value_free(val); BinOp* cur = BinOp_new(BIN_MUL, ValInt(-1), NULL); if(tree) { prev->b = ValExpr(cur); } else { tree = cur; } prev = cur; continue; } /* Get next operator if it exists */ op = BinOp_nextType(expr, sep, end); /* Invalid operator? Return syntax error */ if(op == BIN_UNK) { /* Exit gracefully and return error */ if(tree) { BinOp_free(tree); } Value_free(val); return ValErr(badChar(**expr)); } /* End of the statement? */ else if(op == BIN_END) { /* Only skip end character if there's only one value to parse */ if(!sep && **expr && **expr == end) { (*expr)++; } /* If there was only one value, return it */ if(!tree) { return val; } /* Otherwise, place the final value into the tree and break out of the parse loop */ prev->b = val; break; } /* Tree not yet begun? Initialize it! */ if(tree == NULL) { tree = BinOp_new(op, val, NULL); prev = tree; } else { /* Tree already started, so add to it */ treeAddValue(&tree, &prev, op, val); } } return ValExpr(tree); }
Expression* Expression_parse(const char** expr) { Expression* ret = NULL; Variable* var; Value* val; const char* equals = strchr(*expr, '='); if(equals == NULL) { /* No assignment, just a plain expression. */ return parseExpr(expr); } /* There is an assignment */ /* First, parse the right side of the assignment */ equals++; val = Value_parse(&equals, 0, 0); if(val->type == VAL_ERR) { /* A parse error occurred */ var = VarErr(Error_copy(val->err)); Value_free(val); return Expression_new(var); } if(val->type == VAL_END) { /* Empty input */ Value_free(val); var = VarErr(earlyEnd()); return Expression_new(var); } /* Now parse the left side */ char* name = nextToken(expr); if(name == NULL) { Value_free(val); var = VarErr(syntaxError("No variable to assign to.")); return Expression_new(var); } trimSpaces(expr); if(**expr == '(') { /* Defining a function */ (*expr)++; /* Array of argument names */ unsigned size = 2; char** args = fmalloc(size * sizeof(*args)); unsigned len = 0; /* Add each argument name to the array */ char* arg = nextToken(expr); if(arg == NULL && **expr != ')') { /* Invalid character */ Value_free(val); free(args); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); if(arg == NULL) { /* Empty parameter list means function with no args */ free(args); args = NULL; len = 0; } else { /* Loop through each argument in the list */ while(**expr == ',' || **expr == ')') { args[len++] = arg; if(**expr == ')') break; (*expr)++; /* Expand argument array if it's too small */ if(len >= size) { size *= 2; args = frealloc(args, size * sizeof(*args)); } arg = nextToken(expr); if(arg == NULL) { /* Invalid character */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } trimSpaces(expr); } } if(**expr != ')') { /* Invalid character inside argument name list */ Value_free(val); free(name); /* Free argument names and return */ unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Skip closing parenthesis */ (*expr)++; trimSpaces(expr); if(**expr != '=') { Value_free(val); free(name); unsigned i; for(i = 0; i < len; i++) { free(args[i]); } free(args); var = VarErr(badChar(**expr)); return Expression_new(var); } /* Construct function and return it */ Function* func = Function_new(len, args, val); var = VarFunc(name, func); free(name); ret = Expression_new(var); } else { /* Defining a variable */ if(**expr != '=') { /* In-place manipulation */ BINTYPE bin = BinOp_nextType(expr, 0, 0); /* Still not an equals sign means invalid character */ if(**expr != '=') { Value_free(val); free(name); var = VarErr(badChar(**expr)); return Expression_new(var); } val = ValExpr(BinOp_new(bin, ValVar(name), val)); } var = VarValue(name, val); free(name); ret = Expression_new(var); } return ret; }