/** * Eval a block diagram to an int. * * Eval a block diagram that represent an integer constant. This function first eval * a block diagram to its normal form, then check it represent a numerical value (a * block diagram of type : 0->1) then do a symbolic propagation and try to convert the * resulting signal to an int. * @param exp the expression to evaluate * @param globalDefEnv the global environment * @param visited list of visited definition to detect recursive definitions * @param localValEnv the local environment * @return a block diagram in normal form */ static int eval2int (Tree exp, Tree visited, Tree localValEnv) { Tree diagram = a2sb(eval(exp, visited, localValEnv)); // pour getBoxType() int numInputs, numOutputs; getBoxType(diagram, &numInputs, &numOutputs); if ( (numInputs > 0) || (numOutputs != 1) ) { evalerror(yyfilename, yylineno, "not a constant expression of type : (0->1)", exp); return 1; } else { Tree lsignals = boxPropagateSig(gGlobal->nil, diagram , makeSigInputList(numInputs) ); Tree val = simplify(hd(lsignals)); return tree2int(val); } }
/* Pop the the contents of the expression context stack into the globals describing the current expression context. */ static void popexp () { EXPR_CONTEXT *context; if (expr_depth == 0) evalerror ("recursion stack underflow"); context = expr_stack[--expr_depth]; expression = context->expression; RESTORETOK (context); free (context); }
/* Push and save away the contents of the globals describing the current expression context. */ static void pushexp () { EXPR_CONTEXT *context; if (expr_depth >= MAX_EXPR_RECURSION_LEVEL) evalerror ("expression recursion level exceeded"); if (expr_depth >= expr_stack_size) { expr_stack_size += EXPR_STACK_GROW_SIZE; expr_stack = (EXPR_CONTEXT **)xrealloc (expr_stack, expr_stack_size * sizeof (EXPR_CONTEXT *)); } context = (EXPR_CONTEXT *)xmalloc (sizeof (EXPR_CONTEXT)); context->expression = expression; SAVETOK(context); expr_stack[expr_depth++] = context; }
/** * Apply a function to a list of arguments. * Apply a function F to a list of arguments (a,b,c,...). * F can be either a closure over an abstraction, or a * pattern matcher. If it is not the case then we have : * F(a,b,c,...) ==> (a,b,c,...):F * * @param fun the function to apply * @param larg the list of arguments * @return the resulting expression in normal form */ static Tree applyList (Tree fun, Tree larg) { Tree abstr; Tree globalDefEnv; Tree visited; Tree localValEnv; Tree envList; Tree originalRules; Tree revParamList; Tree id; Tree body; Automaton* automat; int state; prim2 p2; //cerr << "applyList (" << *fun << ", " << *larg << ")" << endl; if (isNil(larg)) return fun; if (isBoxError(fun) || isBoxError(larg)) { return boxError(); } if (isBoxPatternMatcher(fun, automat, state, envList, originalRules, revParamList)) { Tree result; int state2; vector<Tree> envVect; list2vec(envList, envVect); //cerr << "applyList/apply_pattern_matcher(" << automat << "," << state << "," << *hd(larg) << ")" << endl; state2 = apply_pattern_matcher(automat, state, hd(larg), result, envVect); //cerr << "state2 = " << state2 << "; result = " << *result << endl; if (state2 >= 0 && isNil(result)) { // we need to continue the pattern matching return applyList( boxPatternMatcher(automat, state2, vec2list(envVect), originalRules, cons(hd(larg),revParamList)), tl(larg) ); } else if (state2 < 0) { stringstream error; error << "ERROR : pattern matching failed, no rule of " << boxpp(boxCase(originalRules)) << " matches argument list " << boxpp(reverse(cons(hd(larg), revParamList))) << endl; throw faustexception(error.str()); } else { // Pattern Matching was succesful // the result is a closure that we need to evaluate. if (isClosure(result, body, globalDefEnv, visited, localValEnv)) { // why ??? return simplifyPattern(eval(body, nil, localValEnv)); //return eval(body, nil, localValEnv); return applyList(eval(body, gGlobal->nil, localValEnv), tl(larg)); } else { cerr << "wrong result from pattern matching (not a closure) : " << boxpp(result) << endl; return boxError(); } } } if (!isClosure(fun, abstr, globalDefEnv, visited, localValEnv)) { // principle : f(a,b,c,...) ==> (a,b,c,...):f int ins, outs; // check arity of function Tree efun = a2sb(fun); //cerr << "TRACEPOINT 1 : " << boxpp(efun) << endl; if (!getBoxType(efun, &ins, &outs)) { // on laisse comme ca pour le moment // we can't determine the input arity of the expression // hope for the best return boxSeq(larg2par(larg), fun); } // check arity of arg list if (!boxlistOutputs(larg, &outs)) { // we don't know yet the output arity of larg. Therefore we can't // do any arity checking nor add _ to reach the required number of arguments // cerr << "warning : can't infere the type of : " << boxpp(larg) << endl; return boxSeq(larg2par(larg), fun); } if (outs > ins) { stringstream error; error << "too much arguments : " << outs << ", instead of : " << ins << endl; error << "when applying : " << boxpp(fun) << endl << "to : " << boxpp(larg) << endl; throw faustexception(error.str()); } if ((outs == 1) && (( isBoxPrim2(fun, &p2) && (p2 != sigPrefix)) || (getUserData(fun) && ((xtended*)getUserData(fun))->isSpecialInfix()))) { // special case : /(3) ==> _,3 : / Tree larg2 = concat(nwires(ins-outs), larg); return boxSeq(larg2par(larg2), fun); } else { Tree larg2 = concat(larg, nwires(ins-outs)); return boxSeq(larg2par(larg2), fun); } } if (isBoxEnvironment(abstr)) { evalerrorbox(yyfilename, -1, "an environment can't be used as a function", fun); } if (!isBoxAbstr(abstr, id, body)) { evalerror(yyfilename, -1, "(internal) not an abstraction inside closure", fun); } // try to synthetise a name from the function name and the argument name { Tree arg = eval(hd(larg), visited, localValEnv); Tree narg; if ( isBoxNumeric(arg,narg) ) { arg = narg; } Tree f = eval(body, visited, pushValueDef(id, arg, localValEnv)); Tree fname; if (getDefNameProperty(fun, fname)) { stringstream s; s << tree2str(fname); if (!gGlobal->gSimpleNames) s << "(" << boxpp(arg) << ")"; setDefNameProperty(f, s.str()); } return applyList(f, tl(larg)); } }
static Tree realeval (Tree exp, Tree visited, Tree localValEnv) { //Tree def; Tree fun; Tree arg; Tree var, num, body, ldef; Tree label; Tree cur, lo, hi, step; Tree e1, e2, exp2, notused, visited2, lenv2; Tree rules; Tree id; //cerr << "EVAL " << *exp << " (visited : " << *visited << ")" << endl; //cerr << "REALEVAL of " << *exp << endl; xtended* xt = (xtended*) getUserData(exp); // constants //----------- if ( xt || isBoxInt(exp) || isBoxReal(exp) || isBoxWire(exp) || isBoxCut(exp) || isBoxPrim0(exp) || isBoxPrim1(exp) || isBoxPrim2(exp) || isBoxPrim3(exp) || isBoxPrim4(exp) || isBoxPrim5(exp) || isBoxFFun(exp) || isBoxFConst(exp) || isBoxFVar(exp) || isBoxWaveform(exp)) { return exp; // block-diagram constructors //--------------------------- } else if (isBoxSeq(exp, e1, e2)) { return boxSeq(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxPar(exp, e1, e2)) { return boxPar(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxRec(exp, e1, e2)) { return boxRec(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxSplit(exp, e1, e2)) { return boxSplit(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); } else if (isBoxMerge(exp, e1, e2)) { return boxMerge(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv)); // Modules //-------- } else if (isBoxAccess(exp, body, var)) { Tree val = eval(body, visited, localValEnv); if (isClosure(val, exp2, notused, visited2, lenv2)) { // it is a closure, we have an environment to access return eval(closure(var,notused,visited2,lenv2), visited, localValEnv); } else { evalerror(getDefFileProp(exp), getDefLineProp(exp), "no environment to access", exp); } //////////////////////en chantier//////////////////////////// } else if (isBoxModifLocalDef(exp, body, ldef)) { Tree val = eval(body, visited, localValEnv); if (isClosure(val, exp2, notused, visited2, lenv2)) { // we rebuild the closure using a copy of the original environment // modified with some new definitions Tree lenv3 = copyEnvReplaceDefs(lenv2, ldef, visited2, localValEnv); return eval(closure(exp2,notused,visited2,lenv3), visited, localValEnv); } else { evalerror(getDefFileProp(exp), getDefLineProp(exp), "not a closure", val); evalerror(getDefFileProp(exp), getDefLineProp(exp), "no environment to access", exp); } /////////////////////////////////////////////////////////////////// } else if (isBoxComponent(exp, label)) { string fname = tree2str(label); Tree eqlst = gGlobal->gReader.expandlist(gGlobal->gReader.getlist(fname)); Tree res = closure(boxIdent("process"), gGlobal->nil, gGlobal->nil, pushMultiClosureDefs(eqlst, gGlobal->nil, gGlobal->nil)); setDefNameProperty(res, label); //cerr << "component is " << boxpp(res) << endl; return res; } else if (isBoxLibrary(exp, label)) { string fname = tree2str(label); Tree eqlst = gGlobal->gReader.expandlist(gGlobal->gReader.getlist(fname)); Tree res = closure(boxEnvironment(), gGlobal->nil, gGlobal->nil, pushMultiClosureDefs(eqlst, gGlobal->nil, gGlobal->nil)); setDefNameProperty(res, label); //cerr << "component is " << boxpp(res) << endl; return res; // user interface elements //------------------------ } else if (isBoxButton(exp, label)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); //cout << "button label : " << l1 << " become " << l2 << endl; return ((l1 == l2) ? exp : boxButton(tree(l2))); } else if (isBoxCheckbox(exp, label)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); //cout << "check box label : " << l1 << " become " << l2 << endl; return ((l1 == l2) ? exp : boxCheckbox(tree(l2))); } else if (isBoxVSlider(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return ( boxVSlider(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxHSlider(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return ( boxHSlider(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxNumEntry(exp, label, cur, lo, hi, step)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return (boxNumEntry(tree(l2), tree(eval2double(cur, visited, localValEnv)), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv)), tree(eval2double(step, visited, localValEnv)))); } else if (isBoxVGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxVGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxHGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxHGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxTGroup(exp, label, arg)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxTGroup(tree(l2), eval(arg, visited, localValEnv) ); } else if (isBoxHBargraph(exp, label, lo, hi)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxHBargraph(tree(l2), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv))); } else if (isBoxVBargraph(exp, label, lo, hi)) { const char* l1 = tree2str(label); const char* l2 = evalLabel(l1, visited, localValEnv); return boxVBargraph(tree(l2), tree(eval2double(lo, visited, localValEnv)), tree(eval2double(hi, visited, localValEnv))); // lambda calculus //---------------- } else if (isBoxIdent(exp)) { return evalIdDef(exp, visited, localValEnv); } else if (isBoxWithLocalDef(exp, body, ldef)) { return eval(body, visited, pushMultiClosureDefs(ldef, visited, localValEnv)); } else if (isBoxAppl(exp, fun, arg)) { return applyList( eval(fun, visited, localValEnv), revEvalList(arg, visited, localValEnv) ); } else if (isBoxAbstr(exp)) { // it is an abstraction : return a closure return closure(exp, gGlobal->nil, visited, localValEnv); } else if (isBoxEnvironment(exp)) { // environment : return also a closure return closure(exp, gGlobal->nil, visited, localValEnv); } else if (isClosure(exp, exp2, notused, visited2, lenv2)) { if (isBoxAbstr(exp2)) { // a 'real' closure return closure(exp2, gGlobal->nil, setUnion(visited,visited2), lenv2); } else if (isBoxEnvironment(exp2)) { // a 'real' closure return closure(exp2, gGlobal->nil, setUnion(visited,visited2), lenv2); } else { // it was a suspended evaluation return eval(exp2, setUnion(visited,visited2), lenv2); } // Algorithmic constructions //-------------------------- } else if (isBoxIPar(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iteratePar(var, n, body, visited, localValEnv); } else if (isBoxISeq(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateSeq(var, n, body, visited, localValEnv); } else if (isBoxISum(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateSum(var, n, body, visited, localValEnv); } else if (isBoxIProd(exp, var, num, body)) { int n = eval2int(num, visited, localValEnv); return iterateProd(var, n, body, visited, localValEnv); // static } else if (isBoxInputs(exp, body)) { int ins, outs; Tree b = a2sb(eval(body, visited, localValEnv)); if (getBoxType (b, &ins, &outs)) { return boxInt(ins); } else { stringstream error; error << "ERROR : can't evaluate ' : " << *exp << endl; throw faustexception(error.str()); } } else if (isBoxOutputs(exp, body)) { int ins, outs; Tree b = a2sb(eval(body, visited, localValEnv)); if (getBoxType (b, &ins, &outs)) { return boxInt(outs); } else { stringstream error; error << "ERROR : can't evaluate ' : " << *exp << endl; throw faustexception(error.str()); } } else if (isBoxSlot(exp)) { return exp; } else if (isBoxSymbolic(exp)) { return exp; // Pattern matching extension //--------------------------- } else if (isBoxCase(exp, rules)) { return evalCase(rules, localValEnv); } else if (isBoxPatternVar(exp, id)) { return exp; //return evalIdDef(id, visited, localValEnv); } else if (isBoxPatternMatcher(exp)) { return exp; } else { stringstream error; error << "ERROR : EVAL doesn't intercept : " << *exp << endl; throw faustexception(error.str()); } return NULL; }
static Tree real_a2sb(Tree exp) { Tree abstr, visited, unusedEnv, localValEnv, var, name, body; if (isClosure(exp, abstr, unusedEnv, visited, localValEnv)) { if (isBoxIdent(abstr)) { // special case introduced with access and components Tree result = a2sb(eval(abstr, visited, localValEnv)); // propagate definition name property when needed if (getDefNameProperty(exp, name)) setDefNameProperty(result, name); return result; } else if (isBoxAbstr(abstr, var, body)) { // Here we have remaining abstraction that we will try to // transform in a symbolic box by applying it to a slot Tree slot = boxSlot(++gGlobal->gBoxSlotNumber); stringstream s; s << boxpp(var); setDefNameProperty(slot, s.str() ); // ajout YO // Apply the abstraction to the slot Tree result = boxSymbolic(slot, a2sb(eval(body, visited, pushValueDef(var, slot, localValEnv)))); // propagate definition name property when needed if (getDefNameProperty(exp, name)) setDefNameProperty(result, name); return result; } else if (isBoxEnvironment(abstr)) { return abstr; } else { evalerror(yyfilename, -1, "a2sb : internal error : not an abstraction inside closure", exp); // Never reached... return 0; } } else if (isBoxPatternMatcher(exp)) { // Here we have remaining PM rules that we will try to // transform in a symbolic box by applying it to a slot Tree slot = boxSlot(++gGlobal->gBoxSlotNumber); stringstream s; s << "PM" << gGlobal->gBoxSlotNumber; setDefNameProperty(slot, s.str() ); // apply the PM rules to the slot and transfoms the result in a symbolic box Tree result = boxSymbolic(slot, a2sb(applyList(exp, cons(slot,gGlobal->nil)))); // propagate definition name property when needed if (getDefNameProperty(exp, name)) setDefNameProperty(result, name); return result; } else if (isBoxWaveform(exp)) { // A waveform is always in Normal Form, nothing to evaluate return exp; } else { // it is a constructor : transform each branches unsigned int ar = exp->arity(); tvec B(ar); bool modified = false; for (unsigned int i = 0; i < ar; i++) { Tree b = exp->branch(i); Tree m = a2sb(b); B[i] = m; if (b != m) modified=true; } Tree r = (modified) ? CTree::make(exp->node(), B) : exp; return r; } }