FAUST compiler  0.9.9.6b8
eval.cpp
Go to the documentation of this file.
00001 /************************************************************************
00002  ************************************************************************
00003     FAUST compiler
00004     Copyright (C) 2003-2004 GRAME, Centre National de Creation Musicale
00005     ---------------------------------------------------------------------
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  ************************************************************************
00020  ************************************************************************/
00021  #define TRACE
00022 
00032 #include "eval.hh"
00033 #include <stdio.h>
00034 #include "errormsg.hh"
00035 #include "ppbox.hh"
00036 #include "simplify.hh"
00037 #include "propagate.hh"
00038 #include "patternmatcher.hh"
00039 #include "signals.hh"
00040 #include "xtended.hh"
00041 #include "loopDetector.hh"
00042 #include "property.hh"
00043 #include "names.hh"
00044 #include "compatibility.hh"
00045 
00046 
00047 #include <assert.h>
00048 extern SourceReader gReader;
00049 extern int  gMaxNameSize;
00050 extern bool gSimpleNames;
00051 extern bool gSimplifyDiagrams;
00052 // History
00053 // 23/05/2005 : New environment management
00054 
00055 
00056 //-------------- prototypes ---------------------------------------------------------
00057 static Tree     a2sb(Tree exp);
00058 static Tree     eval (Tree exp, Tree visited, Tree localValEnv);
00059 static Tree     realeval (Tree exp, Tree visited, Tree localValEnv);
00060 static Tree     revEvalList (Tree lexp, Tree visited, Tree localValEnv);
00061 static Tree     applyList (Tree fun, Tree larg);
00062 static Tree     iteratePar (Tree var, int num, Tree body, Tree visited, Tree localValEnv);
00063 static Tree     iterateSeq (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00064 static Tree     iterateSum (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00065 static Tree     iterateProd (Tree id, int num, Tree body, Tree visited, Tree localValEnv);
00066 static Tree     larg2par (Tree larg);
00067 static int      eval2int (Tree exp, Tree visited, Tree localValEnv);
00068 static double   eval2double (Tree exp, Tree visited, Tree localValEnv);
00069 static const char * evalLabel (const char* l, Tree visited, Tree localValEnv);
00070 
00071 static Tree     evalIdDef(Tree id, Tree visited, Tree env);
00072 
00073 
00074 
00075 static Tree     evalCase(Tree rules, Tree env);
00076 static Tree     evalRuleList(Tree rules, Tree env);
00077 static Tree     evalRule(Tree rule, Tree env);
00078 static Tree     evalPatternList(Tree patterns, Tree env);
00079 static Tree     evalPattern(Tree pattern, Tree env);
00080 
00081 static Tree     patternSimplification (Tree pattern);
00082 static bool     isBoxNumeric (Tree in, Tree& out);
00083 
00084 static Tree     vec2list(const vector<Tree>& v);
00085 static void     list2vec(Tree l, vector<Tree>& v);
00086 static Tree     listn (int n, Tree e);
00087 
00088 static Tree     boxSimplification(Tree box);
00089 
00090 // Public Interface
00091 //----------------------
00092 
00093 
00101 Tree evalprocess (Tree eqlist)
00102 {
00103     Tree b = a2sb(eval(boxIdent("process"), nil, pushMultiClosureDefs(eqlist, nil, nil)));
00104 
00105     if (gSimplifyDiagrams) {
00106         b = boxSimplification(b);
00107     }
00108 
00109     return b;
00110 }
00111 
00112 
00113 /* Eval a documentation expression. */
00114 
00115 Tree evaldocexpr (Tree docexpr, Tree eqlist)
00116 {
00117     return a2sb(eval(docexpr, nil, pushMultiClosureDefs(eqlist, nil, nil)));
00118 }
00119 
00120 
00121 
00122 // Private Implementation
00123 //------------------------
00124 
00132 property<Tree> gSymbolicBoxProperty;
00133 
00134 static Tree real_a2sb(Tree exp);
00135 
00136 static Tree a2sb(Tree exp)
00137 {
00138     Tree    result;
00139     Tree    id;
00140 
00141     if (gSymbolicBoxProperty.get(exp, result)) {
00142         return result;
00143     }
00144 
00145     result = real_a2sb(exp);
00146     if (result != exp && getDefNameProperty(exp, id)) {
00147         setDefNameProperty(result, id);     // propagate definition name property when needed
00148     }
00149     gSymbolicBoxProperty.set(exp, result);
00150     return result;
00151 }
00152 
00153 static int  gBoxSlotNumber = 0;     
00154 
00155 static Tree real_a2sb(Tree exp)
00156 {
00157     Tree abstr, visited, unusedEnv, localValEnv, var, name, body;
00158 
00159     if (isClosure(exp, abstr, unusedEnv, visited, localValEnv)) {
00160 
00161         if (isBoxIdent(abstr)) {
00162             // special case introduced with access and components
00163             Tree result = a2sb(eval(abstr, visited, localValEnv));
00164 
00165             // propagate definition name property when needed
00166             if (getDefNameProperty(exp, name))  setDefNameProperty(result, name);
00167             return result;
00168 
00169         } else if (isBoxAbstr(abstr, var, body)) {
00170             // Here we have remaining abstraction that we will try to 
00171             // transform in a symbolic box by applying it to a slot
00172 
00173             Tree slot = boxSlot(++gBoxSlotNumber); 
00174             stringstream s; s << boxpp(var);
00175             setDefNameProperty(slot, s.str() ); // ajout YO
00176             
00177             // Apply the abstraction to the slot
00178             Tree result = boxSymbolic(slot, a2sb(eval(body, visited, pushValueDef(var, slot, localValEnv))));
00179 
00180             // propagate definition name property when needed
00181             if (getDefNameProperty(exp, name)) setDefNameProperty(result, name);
00182             return result;
00183 
00184         } else if (isBoxEnvironment(abstr)) {
00185             return abstr;
00186     
00187         } else {
00188             evalerror(yyfilename, -1, " a2sb : internal error : not an abstraction inside closure ", exp);
00189             exit(1);
00190         }
00191         
00192     } else if (isBoxPatternMatcher(exp)) {
00193         // Here we have remaining PM rules that we will try to 
00194         // transform in a symbolic box by applying it to a slot
00195         
00196         Tree slot = boxSlot(++gBoxSlotNumber);          
00197         stringstream s; s << "PM" << gBoxSlotNumber;
00198         setDefNameProperty(slot, s.str() ); 
00199         
00200         // apply the PM rules to the slot and transfoms the result in a symbolic box
00201         Tree result = boxSymbolic(slot, a2sb(applyList(exp, cons(slot,nil))));
00202 
00203         // propagate definition name property when needed
00204         if (getDefNameProperty(exp, name)) setDefNameProperty(result, name);
00205         return result;
00206 
00207     } else {
00208         // it is a constructor : transform each branches
00209         unsigned int    ar = exp->arity();
00210         tvec            B(ar);
00211         bool            modified = false;
00212         for (unsigned int i = 0; i < ar; i++) {
00213             Tree b = exp->branch(i);
00214             Tree m = a2sb(b);
00215             B[i] = m;
00216             if (b != m) modified=true;
00217         }
00218         Tree r = (modified) ? CTree::make(exp->node(), B) : exp;
00219         return r;
00220     }
00221 }
00222 
00223 static bool autoName(Tree exp , Tree& id)
00224 {
00225     stringstream s; s << boxpp(exp);
00226     id = tree(s.str().c_str());
00227     return true;
00228 }
00229 
00230 bool getArgName(Tree t, Tree& id)
00231 {
00232     //return getDefNameProperty(t, id) || autoName(t, id) ;
00233     return autoName(t, id) ;
00234 }
00235 
00236 
00237 
00247 static loopDetector LD(1024, 512);
00248 
00249 
00250 static Node EVALPROPERTY(symbol("EvalProperty"));
00251 
00258 void setEvalProperty(Tree box, Tree env, Tree value)
00259 {
00260     setProperty(box, tree(EVALPROPERTY,env), value);
00261 }
00262 
00263 
00271 bool getEvalProperty(Tree box, Tree env, Tree& value)
00272 {
00273     return getProperty(box, tree(EVALPROPERTY,env), value);
00274 }
00275 
00276 
00277 static Tree eval (Tree exp, Tree visited, Tree localValEnv)
00278 {
00279     Tree    id;
00280     Tree    result;
00281     
00282     if (!getEvalProperty(exp, localValEnv, result)) {
00283         LD.detect(cons(exp,localValEnv));
00284         //cerr << "ENTER eval("<< *exp << ") with env " << *localValEnv << endl;
00285         result = realeval(exp, visited, localValEnv);
00286         setEvalProperty(exp, localValEnv, result);
00287         //cerr << "EXIT eval(" << *exp << ") IS " << *result << " with env " << *localValEnv << endl;
00288         if (getDefNameProperty(exp, id)) {
00289             setDefNameProperty(result, id);     // propagate definition name property 
00290         }
00291     }
00292     return result;
00293 }
00294 
00305 static Tree realeval (Tree exp, Tree visited, Tree localValEnv)
00306 {
00307     //Tree  def;
00308     Tree    fun;
00309     Tree    arg;
00310     Tree    var, num, body, ldef;
00311     Tree    label;
00312     Tree    cur, lo, hi, step;
00313     Tree    e1, e2, exp2, notused, visited2, lenv2;
00314     Tree    rules;
00315     Tree    id;
00316 
00317     //cerr << "EVAL " << *exp << " (visited : " << *visited << ")" << endl;
00318     //cerr << "REALEVAL of " << *exp << endl;
00319     
00320     xtended* xt = (xtended*) getUserData(exp);
00321 
00322 
00323     // constants
00324     //-----------
00325     
00326     if (    xt || 
00327             isBoxInt(exp) || isBoxReal(exp) || 
00328             isBoxWire(exp) || isBoxCut(exp) ||
00329             isBoxPrim0(exp) || isBoxPrim1(exp) || 
00330             isBoxPrim2(exp) || isBoxPrim3(exp) || 
00331             isBoxPrim4(exp) || isBoxPrim5(exp) ||
00332             isBoxFFun(exp) || isBoxFConst(exp) || isBoxFVar(exp) ) {
00333         return exp;
00334 
00335     // block-diagram constructors
00336     //---------------------------
00337     
00338     } else if ( isBoxSeq(exp, e1, e2) ) {
00339         return boxSeq(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00340 
00341     } else if ( isBoxPar(exp, e1, e2) ) {
00342         return boxPar(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00343 
00344     } else if ( isBoxRec(exp, e1, e2) ) {
00345         return boxRec(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00346 
00347     } else if ( isBoxSplit(exp, e1, e2) ) {
00348         return boxSplit(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00349 
00350     } else if ( isBoxMerge(exp, e1, e2) ) {
00351         return boxMerge(eval(e1, visited, localValEnv), eval(e2, visited, localValEnv));
00352         
00353     // Modules
00354     //--------
00355 
00356     } else if (isBoxAccess(exp, body, var)) {
00357         Tree val = eval(body, visited, localValEnv);
00358         if (isClosure(val, exp2, notused, visited2, lenv2)) {
00359             // it is a closure, we have an environment to access
00360             return eval(closure(var,notused,visited2,lenv2), visited, localValEnv);
00361         } else {
00362             evalerror(getDefFileProp(exp), getDefLineProp(exp), "No environment to access ", exp);
00363             exit(1);
00364         }
00365 
00367 
00368     } else if (isBoxModifLocalDef(exp, body, ldef)) {
00369         Tree val = eval(body, visited, localValEnv);
00370         if (isClosure(val, exp2, notused, visited2, lenv2)) {
00371             // we rebuild the closure using a copy of the original environment
00372             // modified with some new definitions
00373             Tree lenv3 = copyEnvReplaceDefs(lenv2, ldef, visited2, localValEnv);
00374             return eval(closure(exp2,notused,visited2,lenv3), visited, localValEnv);
00375         } else {
00376 
00377             evalerror(getDefFileProp(exp), getDefLineProp(exp), "not a closure ", val);
00378             evalerror(getDefFileProp(exp), getDefLineProp(exp), "No environment to access ", exp);
00379             exit(1);
00380         }
00381 
00383 
00384     } else if (isBoxComponent(exp, label)) {
00385         string  fname   = tree2str(label);
00386         Tree    eqlst   = gReader.expandlist(gReader.getlist(fname));
00387         Tree    res     = closure(boxIdent("process"), nil, nil, pushMultiClosureDefs(eqlst, nil, nil));
00388         setDefNameProperty(res, label);
00389         //cerr << "component is " << boxpp(res) << endl;
00390         return res;
00391 
00392     } else if (isBoxLibrary(exp, label)) {
00393         string  fname   = tree2str(label);
00394         Tree    eqlst   = gReader.expandlist(gReader.getlist(fname));
00395         Tree    res     = closure(boxEnvironment(), nil, nil, pushMultiClosureDefs(eqlst, nil, nil));
00396         setDefNameProperty(res, label);
00397         //cerr << "component is " << boxpp(res) << endl;
00398         return res;
00399 
00400 
00401     // user interface elements
00402     //------------------------
00403     
00404     } else if (isBoxButton(exp, label)) {
00405         const char* l1 = tree2str(label);
00406         const char* l2= evalLabel(l1, visited, localValEnv);
00407         //cout << "button label : " << l1 << " become " << l2 << endl;
00408         return ((l1 == l2) ? exp : boxButton(tree(l2)));
00409 
00410     } else if (isBoxCheckbox(exp, label)) {
00411         const char* l1 = tree2str(label);
00412         const char* l2= evalLabel(l1, visited, localValEnv);
00413         //cout << "check box label : " << l1 << " become " << l2 << endl;
00414         return ((l1 == l2) ? exp : boxCheckbox(tree(l2)));
00415 
00416     } else if (isBoxVSlider(exp, label, cur, lo, hi, step)) {
00417         const char* l1 = tree2str(label);
00418         const char* l2= evalLabel(l1, visited, localValEnv);
00419         return ( boxVSlider(tree(l2),
00420                     tree(eval2double(cur, visited, localValEnv)),
00421                     tree(eval2double(lo, visited, localValEnv)),
00422                     tree(eval2double(hi, visited, localValEnv)),
00423                     tree(eval2double(step, visited, localValEnv))));
00424 
00425     } else if (isBoxHSlider(exp, label, cur, lo, hi, step)) {
00426         const char* l1 = tree2str(label);
00427         const char* l2= evalLabel(l1, visited, localValEnv);
00428         return ( boxHSlider(tree(l2),
00429                     tree(eval2double(cur, visited, localValEnv)),
00430                     tree(eval2double(lo, visited, localValEnv)),
00431                     tree(eval2double(hi, visited, localValEnv)),
00432                     tree(eval2double(step, visited, localValEnv))));
00433 
00434     } else if (isBoxNumEntry(exp, label, cur, lo, hi, step)) {
00435         const char* l1 = tree2str(label);
00436         const char* l2= evalLabel(l1, visited, localValEnv);
00437         return (boxNumEntry(tree(l2),
00438                     tree(eval2double(cur, visited, localValEnv)),
00439                     tree(eval2double(lo, visited, localValEnv)),
00440                     tree(eval2double(hi, visited, localValEnv)),
00441                     tree(eval2double(step, visited, localValEnv))));
00442 
00443     } else if (isBoxVGroup(exp, label, arg)) {
00444         const char* l1 = tree2str(label);
00445         const char* l2= evalLabel(l1, visited, localValEnv);
00446         return boxVGroup(tree(l2),  eval(arg, visited, localValEnv) );
00447 
00448     } else if (isBoxHGroup(exp, label, arg)) {
00449         const char* l1 = tree2str(label);
00450         const char* l2= evalLabel(l1, visited, localValEnv);
00451         return boxHGroup(tree(l2),  eval(arg, visited, localValEnv) );
00452 
00453     } else if (isBoxTGroup(exp, label, arg)) {
00454         const char* l1 = tree2str(label);
00455         const char* l2= evalLabel(l1, visited, localValEnv);
00456         return boxTGroup(tree(l2),  eval(arg, visited, localValEnv) );
00457 
00458     } else if (isBoxHBargraph(exp, label, lo, hi)) {
00459         const char* l1 = tree2str(label);
00460         const char* l2= evalLabel(l1, visited, localValEnv);
00461         return boxHBargraph(tree(l2),
00462                     tree(eval2double(lo, visited, localValEnv)),
00463                     tree(eval2double(hi, visited, localValEnv)));
00464 
00465     } else if (isBoxVBargraph(exp, label, lo, hi)) {
00466         const char* l1 = tree2str(label);
00467         const char* l2= evalLabel(l1, visited, localValEnv);
00468         return boxVBargraph(tree(l2),
00469                     tree(eval2double(lo, visited, localValEnv)),
00470                     tree(eval2double(hi, visited, localValEnv)));
00471 
00472     // lambda calculus
00473     //----------------
00474         
00475     } else if (isBoxIdent(exp)) {
00476         return evalIdDef(exp, visited, localValEnv);
00477 
00478     } else if (isBoxWithLocalDef(exp, body, ldef)) {
00479         return eval(body, visited, pushMultiClosureDefs(ldef, visited, localValEnv));
00480     
00481     } else if (isBoxAppl(exp, fun, arg)) {
00482         return applyList( eval(fun, visited, localValEnv),
00483                           revEvalList(arg, visited, localValEnv) );
00484 
00485     } else if (isBoxAbstr(exp)) {
00486         // it is an abstraction : return a closure
00487         return closure(exp, nil, visited, localValEnv);
00488 
00489     } else if (isBoxEnvironment(exp)) {
00490         // environment : return also a closure
00491         return closure(exp, nil, visited, localValEnv);
00492 
00493     } else if (isClosure(exp, exp2, notused, visited2, lenv2)) {
00494 
00495         if (isBoxAbstr(exp2)) {
00496             // a 'real' closure
00497             return closure(exp2, nil, setUnion(visited,visited2), lenv2);
00498         } else if (isBoxEnvironment(exp2)) {
00499             // a 'real' closure
00500             return closure(exp2, nil, setUnion(visited,visited2), lenv2);
00501         } else {
00502             // it was a suspended evaluation
00503             return eval(exp2, setUnion(visited,visited2), lenv2);
00504         }
00505 
00506     // Algorithmic constructions
00507     //--------------------------
00508     
00509     } else if (isBoxIPar(exp, var, num, body)) {
00510         int n = eval2int(num, visited, localValEnv);
00511         return iteratePar(var, n, body, visited, localValEnv);
00512 
00513     } else if (isBoxISeq(exp, var, num, body)) {
00514         int n = eval2int(num, visited, localValEnv);
00515         return iterateSeq(var, n, body, visited, localValEnv);
00516 
00517     } else if (isBoxISum(exp, var, num, body)) {
00518         int n = eval2int(num, visited, localValEnv);
00519         return iterateSum(var, n, body, visited, localValEnv);
00520 
00521     } else if (isBoxIProd(exp, var, num, body)) {
00522         int n = eval2int(num, visited, localValEnv);
00523         return iterateProd(var, n, body, visited, localValEnv);
00524         
00525     } else if (isBoxSlot(exp))      { 
00526         return exp; 
00527     
00528     } else if (isBoxSymbolic(exp))  {
00529      
00530         return exp;
00531     
00532 
00533     // Pattern matching extension
00534     //---------------------------
00535     
00536     } else if (isBoxCase(exp, rules)) {
00537         return evalCase(rules, localValEnv);
00538 
00539     } else if (isBoxPatternVar(exp, id)) {
00540         return exp;
00541         //return evalIdDef(id, visited, localValEnv);
00542 
00543     } else if (isBoxPatternMatcher(exp)) {
00544         return exp;
00545 
00546     } else {
00547         cerr << "ERROR : EVAL don't intercept : " << *exp << endl;
00548         assert(false);
00549     }
00550 }
00551 
00552 /* Deconstruct a (BDA) op pattern (YO). */
00553 
00554 static inline bool isBoxPatternOp(Tree box, Node& n, Tree& t1, Tree& t2)
00555 {
00556     if (    isBoxPar(box, t1, t2) ||
00557             isBoxSeq(box, t1, t2) ||
00558             isBoxSplit(box, t1, t2) ||
00559             isBoxMerge(box, t1, t2) ||
00560             isBoxRec(box, t1, t2)    )
00561     {
00562         n = box->node();
00563         return true;
00564     } else {
00565         return false;
00566     }
00567 }
00568 
00569 
00570 Tree NUMERICPROPERTY = tree(symbol("NUMERICPROPERTY"));
00571 
00572 void setNumericProperty(Tree t, Tree num)
00573 {
00574     setProperty(t, NUMERICPROPERTY, num);
00575 }
00576 
00577 bool getNumericProperty(Tree t, Tree& num)
00578 {
00579     return getProperty(t, NUMERICPROPERTY, num);
00580 }
00581 
00588 /* uncomment for debugging output */
00589 //#define DEBUG
00590 Tree simplifyPattern (Tree value)
00591 {
00592     Tree num;
00593     if (!getNumericProperty(value,num)) {
00594         if (!isBoxNumeric(value,num)) {
00595             num = value;
00596         }
00597         setNumericProperty(value,num);
00598     }
00599     return num;
00600 }
00601 
00602 
00603 static bool isBoxNumeric (Tree in, Tree& out)
00604 {
00605     int     numInputs, numOutputs;
00606     double  x;
00607     int     i;
00608     Tree    v;
00609 
00610     if (isBoxInt(in, &i) || isBoxReal(in, &x)) {
00611         out = in;
00612         return true;
00613     } else {
00614         v = a2sb(in);
00615         if ( getBoxType(v, &numInputs, &numOutputs) && (numInputs == 0) && (numOutputs == 1) ) {
00616             // potential numerical expression
00617             Tree lsignals = boxPropagateSig(nil, v , makeSigInputList(numInputs) );
00618             Tree res = simplify(hd(lsignals));
00619             if (isSigReal(res, &x))     {
00620             out = boxReal(x);
00621             return true;
00622             }
00623             if (isSigInt(res, &i))      {
00624             out = boxInt(i);
00625             return true;
00626             }
00627         }
00628         return false;
00629     }
00630 }
00631 
00632 static Tree patternSimplification (Tree pattern)
00633 {   
00634     
00635     Node    n(0);
00636     Tree    v, t1, t2;
00637     
00638     if (isBoxNumeric(pattern, v)) {
00639         return v;
00640     } else if (isBoxPatternOp(pattern, n, t1, t2)) {
00641         return tree(n, patternSimplification(t1), patternSimplification(t2));
00642     } else {
00643         return pattern;
00644     }
00645 }
00646 
00647 
00648 
00662 static double eval2double (Tree exp, Tree visited, Tree localValEnv)
00663 {
00664     Tree diagram = a2sb(eval(exp, visited, localValEnv)); // pour getBoxType
00665     int numInputs, numOutputs;
00666     getBoxType(diagram, &numInputs, &numOutputs);
00667     if ( (numInputs > 0) || (numOutputs != 1) ) {
00668         evalerror (yyfilename, yylineno, "not a constant expression of type : (0->1)", exp);
00669         return 1;
00670     } else {
00671         Tree lsignals = boxPropagateSig(nil, diagram , makeSigInputList(numInputs) );
00672         Tree val = simplify(hd(lsignals));
00673         return tree2float(val);
00674     }
00675 }
00676 
00677 
00691 static int eval2int (Tree exp, Tree visited, Tree localValEnv)
00692 {
00693     Tree diagram = a2sb(eval(exp, visited, localValEnv));   // pour getBoxType()
00694     int numInputs, numOutputs;
00695     getBoxType(diagram, &numInputs, &numOutputs);
00696     if ( (numInputs > 0) || (numOutputs != 1) ) {
00697         evalerror (yyfilename, yylineno, "not a constant expression of type : (0->1)", exp);
00698         return 1;
00699     } else {
00700         Tree lsignals = boxPropagateSig(nil, diagram , makeSigInputList(numInputs) );
00701         Tree val = simplify(hd(lsignals));
00702         return tree2int(val);
00703     }
00704 }
00705 
00706 static bool isDigitChar(char c)
00707 {
00708     return (c >= '0') & (c <= '9');
00709 }
00710 
00711 static bool isIdentChar(char c)
00712 {
00713     return ((c >= 'a') & (c <= 'z')) || ((c >= 'A') & (c <= 'Z')) || ((c >= '0') & (c <= '9')) || (c == '_');
00714 }
00715 
00716 const char* Formats [] = {"%d", "%1d", "%2d", "%3d", "%4d"};
00717 
00718 static char* writeIdentValue(char* dst, int format, const char* ident, Tree visited, Tree localValEnv)
00719 {
00720     int n = eval2int(boxIdent(ident), visited, localValEnv);
00721     int i = min(4,max(format,0));
00722     
00723     return dst + sprintf(dst, Formats[i], n);
00724 }
00725 
00726 static const char * evalLabel (const char* label, Tree visited, Tree localValEnv)
00727 {
00728     char        res[2000];
00729     char        ident[64];
00730 
00731     const char* src = &label[0];
00732     char*       dst = &res[0];
00733     char*       id  = &ident[0];
00734 
00735     bool        parametric = false;
00736     int         state = 0; int format = 0;
00737     char        c;
00738 
00739     while ((c=*src++)) {
00740         if (state == 0) {
00741             // outside ident mode
00742             if (c == '%') {
00743                 // look ahead for next char
00744                 if (*src == '%') {
00745                     *dst++ = *src++;        // copy escape char and skip one char
00746                 } else {
00747                     state = 1;              // prepare ident mode
00748                     format = 0;
00749                     parametric = true;
00750                     id  = &ident[0];
00751                 }
00752             } else {
00753                 *dst++ = c;                 // copy char
00754             }
00755         } else if (state == 1) {
00756             // read the format 
00757             if (isDigitChar(c)) {
00758                 format = format*10 + (c-'0');
00759             } else {
00760                 state = 2;
00761                 --src; // unread !!!
00762             }
00763 
00764         } else {
00765             
00766             // within ident mode
00767             if (isIdentChar(c)) {
00768                 *id++ = c;
00769             } else {
00770                 *id = 0;
00771                 dst = writeIdentValue(dst, format, ident, visited, localValEnv);
00772                 state = 0;
00773                 src -= 1;
00774             }
00775         }
00776     }
00777 
00778     if (state == 2) {
00779         *id = 0;
00780         dst = writeIdentValue(dst, format, ident, visited, localValEnv);
00781     }
00782     *dst = 0;
00783     return (parametric) ? strdup(res) : label;
00784 }
00785 
00786 
00787 
00801 static Tree iteratePar (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00802 {
00803     assert (num>0);
00804 
00805     Tree res = eval(body, visited, pushValueDef(id, tree(num-1), localValEnv));
00806     for (int i = num-2; i >= 0; i--) {
00807         res = boxPar(eval(body, visited, pushValueDef(id, tree(i), localValEnv)), res);
00808     }
00809 
00810     return res;
00811 }
00812 
00813 
00814 
00827 static Tree iterateSeq (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00828 {
00829     assert (num>0);
00830 
00831     Tree res = eval(body, visited, pushValueDef(id, tree(num-1), localValEnv));
00832     for (int i = num-2; i >= 0; i--) {
00833         res = boxSeq(eval(body, visited, pushValueDef(id, tree(i), localValEnv)), res);
00834     }
00835 
00836     return res;
00837 }
00838 
00839 
00840 
00854 static Tree iterateSum (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00855 {
00856     assert (num>0);
00857 
00858     Tree res = eval(body, visited, pushValueDef(id, tree(0), localValEnv));
00859 
00860     for (int i = 1; i < num; i++) {
00861         res = boxSeq(boxPar(res, eval(body, visited, pushValueDef(id, tree(i), localValEnv))),boxPrim2(sigAdd)) ;
00862     }
00863 
00864     return res;
00865 }
00866 
00867 
00868 
00882 static Tree iterateProd (Tree id, int num, Tree body, Tree visited, Tree localValEnv)
00883 {
00884     assert (num>0);
00885 
00886     Tree res = eval(body, visited, pushValueDef(id, tree(0), localValEnv));
00887 
00888     for (int i = 1; i < num; i++) {
00889         res = boxSeq(boxPar(res, eval(body, visited, pushValueDef(id, tree(i), localValEnv))),boxPrim2(sigMul)) ;
00890     }
00891 
00892     return res;
00893 }
00894 
00903  #if 1
00904 static bool boxlistOutputs(Tree boxlist, int* outputs)
00905 {
00906     int ins, outs;
00907 
00908     *outputs = 0;
00909     while (!isNil(boxlist))
00910     {
00911         Tree b = a2sb(hd(boxlist)); // for getBoxType, suppose list of evaluated boxes
00912         if (getBoxType(b, &ins, &outs)) {
00913             *outputs += outs;
00914         } else {
00915             // arbitrary output arity set to 1
00916             // when can't be determined
00917             *outputs += 1;
00918         }
00919         boxlist = tl(boxlist);
00920     }
00921     return isNil(boxlist);
00922 }
00923 #else
00924 static bool boxlistOutputs(Tree boxlist, int* outputs)
00925 {
00926     int ins, outs;
00927 
00928     *outputs = 0;
00929     while (!isNil(boxlist) && getBoxType(hd(boxlist), &ins, &outs)) {
00930             *outputs += outs;
00931             boxlist = tl(boxlist);
00932     }
00933     return isNil(boxlist);
00934 }
00935 #endif
00936 
00940 static Tree nwires(int n)
00941 {
00942     Tree l = nil;
00943     while (n--) { l = cons(boxWire(), l); }
00944     return l;
00945 }
00946 
00947 
00959 static Tree applyList (Tree fun, Tree larg)
00960 {
00961     Tree abstr;
00962     Tree globalDefEnv;
00963     Tree visited;
00964     Tree localValEnv;
00965     Tree envList;
00966     Tree originalRules;
00967     Tree revParamList;
00968 
00969     Tree id;
00970     Tree body;
00971     
00972     Automaton*  automat;
00973     int         state;
00974 
00975     prim2   p2;
00976 
00977     //cerr << "applyList (" << *fun << ", " << *larg << ")" << endl;
00978 
00979     if (isNil(larg)) return fun;
00980 
00981     if (isBoxError(fun) || isBoxError(larg)) {
00982         return boxError();
00983     }
00984 
00985     if (isBoxPatternMatcher(fun, automat, state, envList, originalRules, revParamList)) {
00986         Tree            result;
00987         int             state2;
00988         vector<Tree>    envVect;
00989         
00990         list2vec(envList, envVect);
00991         //cerr << "applyList/apply_pattern_matcher(" << automat << "," << state << "," << *hd(larg) << ")" << endl;
00992         state2 = apply_pattern_matcher(automat, state, hd(larg), result, envVect);
00993         //cerr << "state2 = " << state2 << "; result = " << *result << endl;
00994         if (state2 >= 0 && isNil(result)) {
00995             // we need to continue the pattern matching
00996             return applyList(
00997                         boxPatternMatcher(automat, state2, vec2list(envVect), originalRules, cons(hd(larg),revParamList)),
00998                         tl(larg) );
00999         } else if (state2 < 0) {
01000             cerr << "ERROR : pattern matching failed, no rule of " << boxpp(boxCase(originalRules)) 
01001                  << " matches argument list " << boxpp(reverse(cons(hd(larg), revParamList))) << endl;
01002             exit(1);
01003         } else {
01004             // Pattern Matching was succesful
01005             // the result is a closure that we need to evaluate.
01006             if (isClosure(result, body, globalDefEnv, visited, localValEnv)) {
01007                 // why ??? return simplifyPattern(eval(body, nil, localValEnv));
01008                 //return eval(body, nil, localValEnv);
01009                 return applyList(eval(body, nil, localValEnv), tl(larg));
01010             } else {
01011                 cerr << "wrong result from pattern matching (not a closure) : " << boxpp(result) << endl;
01012                 return boxError();
01013             }
01014         }           
01015     }
01016     if (!isClosure(fun, abstr, globalDefEnv, visited, localValEnv)) {
01017         // principle : f(a,b,c,...) ==> (a,b,c,...):f
01018          int ins, outs;
01019          
01020          // check arity of function
01021          Tree efun = a2sb(fun);
01022          //cerr << "TRACEPOINT 1 : " << boxpp(efun) << endl;
01023          if (!getBoxType(efun, &ins, &outs)) { // on laisse comme ca pour le moment
01024             // we can't determine the input arity of the expression
01025             // hope for the best
01026             return boxSeq(larg2par(larg), fun);
01027          }
01028  
01029          // check arity of arg list
01030          if (!boxlistOutputs(larg,&outs)) {
01031             // we don't know yet the output arity of larg. Therefore we can't
01032             // do any arity checking nor add _ to reach the required number of arguments
01033             // cerr << "warning : can't infere the type of : " << boxpp(larg) << endl;
01034             return boxSeq(larg2par(larg), fun);
01035          }
01036         
01037         if (outs > ins) {
01038             cerr << "too much arguments : " << outs << ", instead of : " << ins << endl;
01039             cerr << "when applying : " << boxpp(fun) << endl
01040                  << "           to : " << boxpp(larg) << endl;
01041             assert(false);
01042         }
01043         
01044         if (    (outs == 1)
01045             &&
01046                 (  ( isBoxPrim2(fun, &p2) && (p2 != sigPrefix) )
01047                 || ( getUserData(fun) && ((xtended*)getUserData(fun))->isSpecialInfix() ) ) ) {
01048             // special case : /(3) ==> _,3 : /
01049             Tree larg2 = concat(nwires(ins-outs), larg);
01050             return boxSeq(larg2par(larg2), fun);
01051 
01052         } else {
01053 
01054             Tree larg2 = concat(larg, nwires(ins-outs));
01055             return boxSeq(larg2par(larg2), fun);
01056         }
01057     }
01058 
01059     if (isBoxEnvironment(abstr)) {
01060         evalerrorbox(yyfilename, -1, "an environment can't be used as a function", fun);
01061         exit(1);
01062     }
01063 
01064     if (!isBoxAbstr(abstr, id, body)) {
01065         evalerror(yyfilename, -1, "(internal) not an abstraction inside closure", fun);
01066         exit(1);
01067     }
01068 
01069     // try to synthetise a  name from the function name and the argument name
01070     {
01071         Tree arg = eval(hd(larg), visited, localValEnv);
01072         Tree narg; if ( isBoxNumeric(arg,narg) ) { arg =  narg; } 
01073         Tree f = eval(body, visited, pushValueDef(id, arg, localValEnv));
01074 
01075         Tree    fname;
01076         if (getDefNameProperty(fun, fname)) {
01077             stringstream s; s << tree2str(fname); if (!gSimpleNames) s << "(" << boxpp(arg) << ")";
01078             setDefNameProperty(f, s.str());
01079         }
01080         return applyList(f, tl(larg));
01081     }
01082 }
01083 
01084 
01085 
01097 static Tree revEvalList (Tree lexp, Tree visited, Tree localValEnv)
01098 {
01099     Tree result = nil;
01100     //Tree lexp_orig = lexp;
01101     //cerr << "ENTER revEvalList(" << *lexp_orig << ", env:" << *localValEnv << ")" << endl;
01102     while (!isNil(lexp)) {
01103         result = cons(eval(hd(lexp), visited, localValEnv), result);
01104         lexp = tl(lexp);
01105     }
01106 
01107     //cerr << "EXIT revEvalList(" << *lexp_orig << ", env:" << *localValEnv << ") -> " << *result << endl;
01108     return result;
01109 }
01110 
01111 
01112 
01119 static Tree larg2par (Tree larg)
01120 {
01121     if (isNil(larg)) {
01122         evalerror(yyfilename, -1, "empty list of arguments", larg);
01123         exit(1);
01124     }
01125     if (isNil(tl(larg))) {
01126         return hd(larg);
01127     }
01128     return boxPar(hd(larg), larg2par(tl(larg)));
01129 }
01130 
01131 
01132 
01133 
01144 static Tree evalIdDef(Tree id, Tree visited, Tree lenv)
01145 {
01146     Tree def, name;
01147 
01148     // search the environment env for a definition of symbol id
01149     while (!isNil(lenv) && !getProperty(lenv, id, def)) {
01150         lenv = lenv->branch(0);
01151     }
01152 
01153     // check that the definition exists
01154     if (isNil(lenv)) {
01155         cerr << "undefined symbol " << *id << endl;
01156         evalerror(getDefFileProp(id), getDefLineProp(id), "undefined symbol ", id);
01157         exit(1);
01158     }
01159 
01160     //cerr << "Id definition is " << *def << endl;
01161     // check that it is not a recursive definition
01162     Tree p = cons(id,lenv);
01163     // set the definition name property
01164     if (!getDefNameProperty(def, name)) {
01165         // if the definition has no name use the identifier
01166         stringstream s; s << boxpp(id);
01167         //XXXXXX setDefNameProperty(def, s.str());
01168     }
01169 
01170     // return the evaluated definition
01171     return eval(def, addElement(p,visited), nil);
01172 }
01173 
01174 
01182 static Tree listn (int n, Tree e)
01183 {
01184     return (n<= 0) ? nil : cons(e, listn(n-1,e));
01185 }
01186 
01192 static Node PMPROPERTYNODE(symbol("PMPROPERTY"));
01193 
01194 static void setPMProperty(Tree t, Tree env, Tree pm)
01195 {
01196     setProperty(t, tree(PMPROPERTYNODE, env), pm);
01197 }
01198 
01199 static bool getPMProperty(Tree t, Tree env, Tree& pm)
01200 {
01201     return getProperty(t, tree(PMPROPERTYNODE, env), pm);
01202 }
01203 
01213 static Tree evalCase(Tree rules, Tree env)
01214 {
01215     Tree pm;
01216     if (!getPMProperty(rules, env, pm)) {
01217         Automaton*  a = make_pattern_matcher(evalRuleList(rules, env));
01218         pm = boxPatternMatcher(a, 0, listn(len(rules), pushEnvBarrier(env)), rules, nil);
01219         setPMProperty(rules, env, pm);
01220     }
01221     return pm;
01222 }       
01223 
01224 
01228 static Tree evalRuleList(Tree rules, Tree env)
01229 {
01230     //cerr << "evalRuleList "<< *rules << " in " << *env << endl;
01231     if (isNil(rules)) return nil;
01232     else return cons(evalRule(hd(rules), env), evalRuleList(tl(rules), env));
01233 }
01234 
01235 
01239 static Tree evalRule(Tree rule, Tree env)
01240 {
01241     //cerr << "evalRule "<< *rule << " in " << *env << endl;
01242     return cons(evalPatternList(left(rule), env), right(rule));
01243 }
01244 
01245 
01249 static Tree evalPatternList(Tree patterns, Tree env)
01250 {
01251     if (isNil(patterns)) {
01252         return nil;
01253     } else {
01254         return cons(    evalPattern(hd(patterns), env), 
01255                         evalPatternList(tl(patterns), env)  );
01256     }
01257 }
01258 
01259 
01264 static Tree evalPattern(Tree pattern, Tree env)
01265 {
01266     Tree p = eval(pattern, nil, env);
01267     return patternSimplification(p);
01268 }
01269 
01270 
01271 static void list2vec(Tree l, vector<Tree>& v)
01272 {
01273     while (!isNil(l)) {
01274         v.push_back(hd(l));
01275         l = tl(l);
01276     }
01277 }
01278 
01279 
01280 static Tree vec2list(const vector<Tree>& v)
01281 {
01282     Tree l = nil;
01283     int  n = v.size();
01284     while (n--) { l = cons(v[n],l); }
01285     return l;
01286 }
01287 
01288 
01289 
01290 
01292 // further simplification : replace bloc-diagrams that denote constant number by this number
01294 
01295 static property<Tree> SimplifiedBoxProperty;
01296 static Tree numericBoxSimplification(Tree box);
01297 static Tree insideBoxSimplification (Tree box);
01298 
01303 Tree boxSimplification (Tree box)
01304 {
01305     Tree    simplified;
01306 
01307     if (SimplifiedBoxProperty.get(box,simplified)) {
01308 
01309         return simplified;
01310 
01311     } else {
01312 
01313         simplified = numericBoxSimplification(box);
01314 
01315         // transferts name property if any
01316         Tree name; if (getDefNameProperty(box, name)) setDefNameProperty(simplified, name);
01317 
01318         // attach simplified expression as a property of original box
01319         SimplifiedBoxProperty.set(box,simplified);
01320 
01321         return simplified;
01322     }
01323 }
01324 
01328 Tree numericBoxSimplification(Tree box)
01329 {
01330     int     ins, outs;
01331     Tree    result;
01332     int     i;
01333     double  x;
01334 
01335     if ( ! getBoxType(box, &ins, &outs)) {
01336         cout << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", Can't compute the box type of : " << *box << endl;
01337         exit(1);
01338     }
01339 
01340     if (ins==0 && outs==1) {
01341         // this box can potentially denote a number
01342         if (isBoxInt(box, &i) || isBoxReal(box, &x)) {
01343            result = box;
01344         } else {
01345             // propagate signals to discover if it simplifies to a number
01346             int     i;
01347             double  x;
01348             Tree    lsignals = boxPropagateSig(nil, box , makeSigInputList(0));
01349             Tree    s = simplify(hd(lsignals));
01350 
01351             if (isSigReal(s, &x))   {
01352                 result = boxReal(x);
01353             } else if (isSigInt(s, &i))     {
01354                 result = boxInt(i);
01355             } else {
01356                 result = insideBoxSimplification(box);
01357             }
01358         }
01359     } else {
01360         // this box can't denote a number
01361         result = insideBoxSimplification(box);
01362     }
01363     return result;
01364 }
01365 
01369 Tree insideBoxSimplification (Tree box)
01370 {
01371     int     i;
01372     double  r;
01373     prim0   p0;
01374     prim1   p1;
01375     prim2   p2;
01376     prim3   p3;
01377     prim4   p4;
01378     prim5   p5;
01379 
01380     Tree    t1, t2, ff, label, cur, min, max, step, type, name, file, slot, body;
01381 
01382 
01383     xtended* xt = (xtended*)getUserData(box);
01384 
01385     // Extended Primitives
01386 
01387     if (xt) {
01388         return box;
01389     }
01390 
01391     // Numbers and Constants
01392 
01393     else if (isBoxInt(box, &i))     {
01394         return box;
01395     }
01396     else if (isBoxReal(box, &r))    {
01397         return box;
01398     }
01399 
01400     else if (isBoxFConst(box, type, name, file))    {
01401         return box;
01402     }
01403 
01404     else if (isBoxFVar(box, type, name, file))    {
01405         return box;
01406     }
01407 
01408     // Wire and Cut
01409 
01410     else if (isBoxCut(box))                 {
01411         return box;
01412     }
01413 
01414     else if (isBoxWire(box))                {
01415         return box;
01416     }
01417 
01418     // Primitives
01419 
01420     else if (isBoxPrim0(box, &p0))          {
01421         return box;
01422     }
01423 
01424     else if (isBoxPrim1(box, &p1))          {
01425         return box;
01426     }
01427 
01428     else if (isBoxPrim2(box, &p2))              {
01429         return box;
01430     }
01431 
01432     else if (isBoxPrim3(box, &p3))              {
01433         return box;
01434     }
01435 
01436     else if (isBoxPrim4(box, &p4))              {
01437         return box;
01438     }
01439 
01440     else if (isBoxPrim5(box, &p5))              {
01441         return box;
01442     }
01443 
01444     else if (isBoxFFun(box, ff))                {
01445         return box;
01446     }
01447 
01448     // User Interface Widgets
01449 
01450     else if (isBoxButton(box, label))   {
01451         return box;
01452     }
01453 
01454     else if (isBoxCheckbox(box, label))     {
01455         return box;
01456     }
01457 
01458     else if (isBoxVSlider(box, label, cur, min, max, step))     {
01459         return box;
01460     }
01461 
01462     else if (isBoxHSlider(box, label, cur, min, max, step))     {
01463         return box;
01464     }
01465 
01466     else if (isBoxNumEntry(box, label, cur, min, max, step))    {
01467         return box;
01468     }
01469 
01470     else if (isBoxVBargraph(box, label, min, max))  {
01471         return box;
01472     }
01473 
01474     else if (isBoxHBargraph(box, label, min, max))  {
01475         return box;
01476     }
01477 
01478     // User Interface Groups
01479 
01480     else if (isBoxVGroup(box, label, t1))   {
01481         return boxVGroup(label, boxSimplification(t1));
01482     }
01483 
01484     else if (isBoxHGroup(box, label, t1))   {
01485         return boxHGroup(label, boxSimplification(t1));
01486     }
01487 
01488     else if (isBoxTGroup(box, label, t1))   {
01489         return boxTGroup(label, boxSimplification(t1));
01490     }
01491 
01492     // Slots and Symbolic Boxes
01493 
01494     else if (isBoxSlot(box))                {
01495         return box;;
01496     }
01497 
01498     else if (isBoxSymbolic(box, slot, body)){
01499 
01500         Tree b = boxSimplification(body);
01501         return boxSymbolic(slot,b);
01502     }
01503 
01504     // Block Diagram Composition Algebra
01505 
01506     else if (isBoxSeq(box, t1, t2))     {
01507         Tree s1 = boxSimplification(t1);
01508         Tree s2 = boxSimplification(t2);
01509         return boxSeq(s1,s2);
01510     }
01511 
01512     else if (isBoxPar(box, t1, t2))     {
01513         Tree s1 = boxSimplification(t1);
01514         Tree s2 = boxSimplification(t2);
01515         return boxPar(s1,s2);
01516     }
01517 
01518     else if (isBoxSplit(box, t1, t2))   {
01519         Tree s1 = boxSimplification(t1);
01520         Tree s2 = boxSimplification(t2);
01521         return boxSplit(s1,s2);
01522     }
01523 
01524     else if (isBoxMerge(box, t1, t2))   {
01525         Tree s1 = boxSimplification(t1);
01526         Tree s2 = boxSimplification(t2);
01527         return boxMerge(s1,s2);
01528     }
01529     else if (isBoxRec(box, t1, t2))     {
01530         Tree s1 = boxSimplification(t1);
01531         Tree s2 = boxSimplification(t2);
01532         return boxRec(s1,s2);
01533     }
01534 
01535     cout << "ERROR in file " << __FILE__ << ':' << __LINE__ << ", unrecognised box expression : " << *box << endl;
01536     exit(1);
01537     return 0;
01538 }