Differences From Artifact [b119954d6ce43301]:
- File        
polemy/eval.d
- 2010-11-23 07:42:13 - part of checkin [6ac127ddd0] on branch trunk - new evaluator (user: kinaba) [annotate]
 
To Artifact [5a9949a1eb8839b1]:
- File        
polemy/eval.d
- 2010-11-23 09:36:27 - part of checkin [b97bd4f713] on branch trunk - automatic AST to table encoder (user: kinaba) [annotate]
 
     8      8   import polemy._common;
     9      9   import polemy.failure;
    10     10   import polemy.ast;
    11     11   import polemy.parse;
    12     12   import polemy.value;
    13     13   import polemy.layer;
    14     14   
           15  +/// Objects for maitaining global environment and evaluation of expression on it
    15     16   class Evaluator
    16     17   {
    17     18   public:
           19  + /// Initialize evaluator with empty context
    18     20    this() { theContext = new Table; }
    19     21   
           22  + /// Evaluate the AST
    20     23    Value evalAST(AST e)
    21     24    {
    22     25     return eval(e, ValueLayer, theContext, OverwriteCtx);
    23     26    }
    24     27   
           28  + /// Evaluate the string
    25     29    Value evalString(S,T...)(S str, T fn_ln_cn)
    26     30    {
    27     31     return evalAST(parseString(str,fn_ln_cn));
    28     32    }
    29     33   
           34  + /// Evaluate the file
    30     35    Value evalFile(S,T...)(S filename, T ln_cn)
    31     36    {
    32     37     return evalAST(parseFile(filename,ln_cn));
    33     38    }
    34     39   
           40  + /// Get the global context
    35     41    Table globalContext()
    36     42    {
    37     43     return theContext;
    38     44    }
    39     45   
    40     46   private:
    41     47    Table theContext;
    42     48   
    43         -private:
    44     49    enum : bool { CascadeCtx=false, OverwriteCtx=true };
    45         -
    46     50    Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
    47     51    {
    48     52     // dynamic-overload-resolution-pattern: modify here
    49     53     enum funName = "eval";
    50     54     alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
    51     55   
    52     56     // dynamic-overload-resolution-pattern: dispatch
................................................................................
    57     61      static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] )
    58     62       return __traits(getOverloads, this, funName)[i](_x, params[1..$]);
    59     63   
    60     64     // dynamic-overload-resolution-pattern: default behavior
    61     65     assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined"));
    62     66    }
    63     67   
    64         -private:
    65     68    Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
    66     69    {
    67         -  Value v = new StrValue(e.data);
    68         -  if( lay==RawMacroLayer || lay==MacroLayer )
    69         -  {
    70         -   auto ast = new Table;
    71         -   ast.set("pos",  ValueLayer, fromPos(e.pos));
    72         -   ast.set("is",   ValueLayer, new StrValue("str"));
    73         -   ast.set("data", ValueLayer, v);
    74         -   return ast;
    75         -  }
           70  +  if( isMacroishLayer(lay) )
           71  +   return ast2table(e, (AST e){return eval(e,lay,ctx);});
    76     72     if( lay==ValueLayer )
    77         -   return v;
    78         -  return lift(v, lay, ctx, e.pos);
           73  +   return new StrValue(e.data);
           74  +  return lift(new StrValue(e.data), lay, ctx, e.pos);
    79     75    }
    80     76   
    81     77    Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
    82     78    {
    83         -  Value v = new IntValue(e.data);
    84         -  if( lay==RawMacroLayer || lay==MacroLayer )
    85         -  {
    86         -   auto ast = new Table;
    87         -   ast.set("pos",  ValueLayer, fromPos(e.pos));
    88         -   ast.set("is",   ValueLayer, new StrValue("int"));
    89         -   ast.set("data", ValueLayer, v);
    90         -   return ast;
    91         -  }
           79  +  if( isMacroishLayer(lay) )
           80  +   return ast2table(e, (AST e){return eval(e,lay,ctx);});
    92     81     if( lay==ValueLayer )
    93         -   return v;
    94         -  return lift(v, lay, ctx, e.pos);
           82  +   return new IntValue(e.data);
           83  +  return lift(new IntValue(e.data), lay, ctx, e.pos);
    95     84    }
    96     85   
    97     86    Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
    98     87    {
    99         -  if( lay==RawMacroLayer || lay==MacroLayer )
   100         -  {
           88  +  if( isMacroishLayer(lay) )
   101     89      if( ctx.has(e.name,MacroLayer) )
   102     90       return ctx.get(e.name, MacroLayer, e.pos);
   103         -   auto ast = new Table;
   104         -   ast.set("pos",  ValueLayer, fromPos(e.pos));
   105         -   ast.set("is",   ValueLayer, new StrValue("var"));
   106         -   ast.set("name", ValueLayer, new StrValue(e.name));
   107         -   return ast;
   108         -  }
           91  +   else
           92  +    return ast2table(e, (AST e){return eval(e,lay,ctx);});
   109     93     if( lay==ValueLayer || ctx.has(e.name, lay) )
   110     94      return ctx.get(e.name, lay, e.pos);
   111     95     return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos);
   112     96    }
   113     97   
   114     98    Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
   115     99    {
   116    100     Value f = eval( e.fun, lay, ctx );
   117         -  if( lay==RawMacroLayer || lay==MacroLayer )
   118         -  {
          101  +  if( isMacroishLayer(lay) )
   119    102      if( auto ff = cast(FunValue)f )
   120    103       return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos);
   121         -   Table ast = new Table;
   122         -   ast.set("pos",  ValueLayer, fromPos(e.pos));
   123         -   ast.set("is",   ValueLayer, new StrValue("app"));
   124         -   ast.set("fun",  ValueLayer, f);
   125         -   Table args = new Table;
   126         -   foreach_reverse(a; e.args)
   127         -    args = makeCons(eval(a, lay, ctx), args);
   128         -   ast.set("args", ValueLayer, args);
   129         -   return ast;
   130         -  }
   131         -  else
   132         -  {
   133         -   return invokeFunction(f, e.args, lay, ctx, e.pos);
   134         -  }
          104  +   else
          105  +    return ast2table(e, (AST e){return eval(e,lay,ctx);});
          106  +  return invokeFunction(f, e.args, lay, ctx, e.pos);
   135    107    }
   136    108   
   137    109    Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
   138    110    {
   139         -  if( lay==RawMacroLayer || lay==MacroLayer )
   140         -  {
   141         -   Table t = new Table;
   142         -   t.set("pos",     ValueLayer, fromPos(e.pos));
   143         -   t.set("is",      ValueLayer, new StrValue("fun"));
   144         -   t.set("funbody", ValueLayer, eval(e.funbody,lay,ctx));
   145         -   Table params = new Table;
   146         -   foreach_reverse(p; e.params)
   147         -   {
   148         -    Table lays = new Table;
   149         -    foreach_reverse(l; p.layers)
   150         -     lays = makeCons(new StrValue(l), lays);
   151         -    Table kv = new Table;
   152         -    kv.set("name", ValueLayer, new StrValue(p.name));
   153         -    kv.set("layers", ValueLayer, lays);
   154         -    Table cons = new Table;
   155         -    params = makeCons(kv, params);
   156         -   }
   157         -   t.set("params", ValueLayer, params);
   158         -   return t;
   159         -  }
          111  +  if( isMacroishLayer(lay) )
          112  +   return ast2table(e, (AST e){return eval(e,lay,ctx);});
   160    113     else
   161         -  {
   162    114      return createNewFunction(e, ctx);
   163         -  }
   164    115    }
   165    116   
   166    117    Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
   167    118    {
   168         -  if( lay == RawMacroLayer )
   169         -  {
   170         -   Value r = eval(e.expr, lay, ctx);
   171         -   auto ast = new Table; // todo: pos
   172         -   ast.set("pos",   ValueLayer, fromPos(e.pos));
   173         -   ast.set("is",    ValueLayer, new StrValue("lay"));
   174         -   ast.set("layer", ValueLayer, new StrValue(e.layer));
   175         -   ast.set("expr",  ValueLayer, r);
   176         -   return ast;
   177         -  }
          119  +  if( isNoLayerChangeLayer(lay) )
          120  +   return ast2table(e, (AST e){return eval(e,lay,ctx);});
   178    121     else
   179    122      return eval(e.expr, e.layer, ctx);
   180    123    }
   181    124   
   182    125    Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
   183    126    {
   184    127     // todo @macro let
   185         -  if( lay==RawMacroLayer || lay==MacroLayer )
   186         -  {
   187         -   auto ast = new Table; // todo: pos
   188         -   ast.set("pos",   ValueLayer, fromPos(e.pos));
   189         -   ast.set("is",    ValueLayer, new StrValue("let"));
   190         -   ast.set("name",  ValueLayer, new StrValue(e.name));
   191         -   ast.set("layer", ValueLayer, new StrValue(e.layer));
   192         -   ast.set("init",  ValueLayer, eval(e.init, lay, ctx));
   193         -   ast.set("expr",  ValueLayer, eval(e.expr, lay, ctx));
   194         -   return ast;
   195         -  }
          128  +  if( isMacroishLayer(lay) )
          129  +   return ast2table(e, (AST e){return eval(e,lay,ctx);});
   196    130     else
   197    131     {
   198    132      if( !overwriteCtx )
   199    133       ctx = new Table(ctx, Table.Kind.NotPropagateSet);
   200    134      Value ri = eval(e.init, lay, ctx);
   201         -   string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer;
          135  +   string theLayer = e.layer.empty ? lay : e.layer; // neutral layer
   202    136      ctx.set(e.name, theLayer, ri);
   203    137      return eval(e.expr, lay, ctx, OverwriteCtx);
   204    138     }
   205    139    }
   206    140   
   207    141   private:
   208    142    Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null)
................................................................................
   212    146      Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
   213    147      foreach(i,p; f.params())
   214    148       if( p.layers.empty )
   215    149        newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx));
   216    150       else
   217    151        foreach(argLay; p.layers)
   218    152         newCtx.set(p.name, argLay, eval(args[i], argLay, ctx));
   219         -   return f.invoke(pos, lay, newCtx);
          153  +   return f.invoke(lay==RawMacroLayer ? MacroLayer : lay, newCtx, pos);
   220    154     }
   221    155     throw genex!RuntimeException(pos, text("tried to call non-function: ",_f));
   222    156    }
   223    157   
   224    158    Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null)
   225    159    {
          160  +  assert( !isMacroishLayer(lay), "lift to the @macro layer should not happen" );
          161  +
   226    162     // functions are automatically lifterd
   227    163     if( cast(FunValue) v )
   228    164      return v;
   229    165   
   230    166     // similar to invoke Function, but with only one argument bound to ValueLayer
   231    167     if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos))
   232    168     {
................................................................................
   233    169      Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
   234    170      auto ps = f.params();
   235    171      if( ps.length != 1 )
   236    172       throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
   237    173      if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
   238    174      {
   239    175       newCtx.set(ps[0].name, ValueLayer, v);
   240         -    return f.invoke(pos, ValueLayer, newCtx);
          176  +    return f.invoke(ValueLayer, newCtx, pos);
   241    177      }
   242    178      else
   243    179       throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
   244    180     }
   245    181     throw genex!RuntimeException(pos, "tried to call non-function");
   246    182    }
   247    183   
................................................................................
   273    209        if(auto i = this.ast.opCmp(rhs.ast))
   274    210         return i;
   275    211        return this.defCtx.opCmp(rhs.defCtx);
   276    212       }
   277    213       assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
   278    214      }
   279    215   
   280         -   override Value invoke(LexPosition pos, Layer lay, Table ctx)
          216  +   override Value invoke(Layer lay, Table ctx, LexPosition pos)
   281    217      {
   282    218       if( lay == MacroLayer )
   283    219        return eval(ast.funbody, lay, ctx);
   284         -    auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
   285         -    return eval(macroed, lay, ctx);
          220  +    if( afterMacroAST is null )
          221  +     afterMacroAST = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
          222  +    return eval(afterMacroAST, lay, ctx);
   286    223      }
          224  +
          225  +   AST afterMacroAST;
   287    226     }
   288    227     return new UserDefinedFunValue(e,ctx);
   289    228    }
   290    229   
   291    230   public:
   292         - /// TODO: move up
   293         - /// TDOO: to other layers?
   294         - void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg)
          231  + /// Add primitive function to the global context
          232  + void addPrimitive(R,T...)(string name, Layer defLay, R delegate (T) dg)
   295    233    {
   296    234     class NativeFunValue : FunValue
   297    235     {
   298         -   Parameter[] params_data;
   299         -   override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
   300    236      override const(Parameter[]) params() { return params_data; }
   301         -   override Table definitionContext() { return new Table; } // todo: cache
   302         -   this(){
          237  +   override Table definitionContext()   { return theContext; }
          238  +
          239  +   override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
          240  +   override int opCmp(Object rhs) {
          241  +    if(auto r = cast(NativeFunValue)rhs) return typeid(typeof(dg)).compare(&dg,&r.dg);
          242  +    if(auto r = cast(Value)rhs)          return typeid(this).opCmp(typeid(r));
          243  +    throw genex!RuntimeException(LexPosition.dummy, "comparison with value and somithing other");
          244  +   }
          245  +   mixin SimpleToHash;
          246  +
          247  +   R delegate(T) dg;
          248  +   Parameter[] params_data;
          249  +
          250  +   this(R delegate(T) dg)
          251  +   {
          252  +    this.dg = dg;
   303    253       foreach(i, Ti; T)
   304    254        params_data ~= new Parameter(text(i), []);
   305    255      }
   306         -   override Value invoke(LexPosition pos, Layer lay, Table ctx)
          256  +
          257  +   override Value invoke(Layer lay, Table ctx, LexPosition pos)
   307    258      {
   308         -    if( lay != ValueLayer )
   309         -     throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function");
          259  +    if( lay != defLay )
          260  +     throw genex!RuntimeException(pos, text("only ", defLay, " layer can call native function: ", name));
   310    261       T typed_args;
   311    262       foreach(i, Ti; T) {
   312         -     typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer);
          263  +     typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer, pos);
   313    264        if( typed_args[i] is null )
   314         -      throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1));
          265  +      throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d of native function: %s"(i+1,name));
   315    266       }
   316    267       try {
   317    268        return dg(typed_args);
   318    269       } catch( RuntimeException e ) {
   319    270        throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
   320    271       }
   321    272      }
   322    273     }
   323         -  theContext.set(name, lay, new NativeFunValue);
          274  +  theContext.set(name, defLay, new NativeFunValue(dg));
   324    275    }
   325    276   }
   326    277   
   327    278   version(unittest) import polemy.runtime;
   328    279   unittest
   329    280   {
   330    281    auto e = new Evaluator;