Index: .poseidon
==================================================================
--- .poseidon
+++ .poseidon
@@ -37,10 +37,11 @@
polemy\failure.d
polemy\fresh.d
polemy\layer.d
polemy\lex.d
polemy\parse.d
+ polemy\runtime.d
polemy\value.d
tricks\test.d
tricks\tricks.d
Index: doc/candydoc/modules.ddoc
==================================================================
--- doc/candydoc/modules.ddoc
+++ doc/candydoc/modules.ddoc
@@ -8,6 +8,7 @@
$(MODULE polemy.fresh)
$(MODULE polemy.lex)
$(MODULE polemy.parse)
$(MODULE polemy.ast)
$(MODULE polemy.eval)
+ $(MODULE polemy.runtime)
$(MODULE polemy.value)
Index: main.d
==================================================================
--- main.d
+++ main.d
@@ -8,27 +8,28 @@
import std.stdio;
import std.algorithm;
import std.array;
import polemy.value;
import polemy.failure;
+import polemy.layer;
import polemy.parse;
import polemy.ast;
import polemy.eval;
-import polemy.layer;
enum VersionNoMajor = 0;
enum VersionNoMinor = 1;
enum VersionNoRev = 0;
/// Read-Eval-Print-Loop
class REPL
{
+Evaluator ev;
/// Load the prelude environment
this()
{
- ctx = createGlobalContext();
+ ev = new Evaluator;
}
/// Print the version number etc.
void greet()
{
@@ -36,11 +37,11 @@
}
/// Run one file on the global scope
void runFile(string filename)
{
- eval(parseFile(filename), ctx, false, ValueLayer);
+ ev.evalFile(filename);
}
/// Repeat the singleInteraction
void replLoop()
{
@@ -76,11 +77,11 @@
{ buf = ""; lineno = nextlineno; }
buf ~= s;
nextlineno ++;
try
- { lastVal = eval(parseString(buf, "", lineno), ctx, false, ValueLayer); }
+ { lastVal = ev.evalString(buf, "", lineno); }
catch( UnexpectedEOF )
{ return false; } // wait
buf = "";
lineno = nextlineno;
return true;
Index: polemy/_common.d
==================================================================
--- polemy/_common.d
+++ polemy/_common.d
@@ -12,5 +12,7 @@
public import std.bigint;
public import std.conv : text;
public import std.exception;
public import std.range;
public import std.stdio : DBG = writeln;
+public import std.typecons;
+public import std.typetuple;
Index: polemy/ast.d
==================================================================
--- polemy/ast.d
+++ polemy/ast.d
@@ -16,11 +16,11 @@
mixin SimpleConstructor;
mixin SimplePatternMatch;
}
///
-class IntLiteral : AST
+class Int : AST
{
BigInt data;
mixin SimpleClass;
this(LexPosition pos, int n) {super(pos); data = n;}
this(LexPosition pos, long n) {super(pos); data = n;}
@@ -27,43 +27,43 @@
this(LexPosition pos, BigInt n) {super(pos); data = n;}
this(LexPosition pos, string n) {super(pos); data = BigInt(n);}
}
///
-class StrLiteral : AST
+class Str : AST
{
string data;
mixin SimpleClass;
}
///
-class VarExpression : AST
+class Var : AST
{
string name;
mixin SimpleClass;
}
///
-class LayExpression : AST
+class Lay : AST
{
Layer layer;
AST expr;
mixin SimpleClass;
}
///
-class LetExpression : AST
+class Let : AST
{
string name;
Layer layer;
AST init;
AST expr;
mixin SimpleClass;
}
///
-class FuncallExpression : AST
+class App : AST
{
AST fun;
AST[] args;
this(LexPosition pos, AST fun, AST[] args...)
{ super(pos); this.fun=fun; this.args=args.dup; }
@@ -77,11 +77,11 @@
Layer[] layers;
mixin SimpleClass;
}
///
-class FunLiteral : AST
+class Fun : AST
{
Parameter[] params;
AST funbody;
mixin SimpleClass;
}
@@ -93,16 +93,16 @@
{
///
template genEast(T)
{ T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } }
- alias genEast!StrLiteral strl; ///
- alias genEast!IntLiteral intl; ///
+ alias genEast!Str strl; ///
+ alias genEast!Int intl; ///
auto fun(string[] xs, AST ps) {
- return genEast!FunLiteral(array(map!((string x){return new Parameter(x,[]);})(xs)),ps); }
- auto funp(Parameter[] xs, AST ps) { return genEast!FunLiteral(xs,ps); } ///
- alias genEast!VarExpression var; ///
- alias genEast!LayExpression lay; ///
- alias genEast!LetExpression let; ///
- alias genEast!FuncallExpression call; ///
+ return genEast!Fun(array(map!((string x){return new Parameter(x,[]);})(xs)),ps); }
+ auto funp(Parameter[] xs, AST ps) { return genEast!Fun(xs,ps); } ///
+ alias genEast!Var var; ///
+ alias genEast!Lay lay; ///
+ alias genEast!Let let; ///
+ alias genEast!App call; ///
auto param(string name, string[] lay...) { return new Parameter(name, lay); } ///
}
Index: polemy/eval.d
==================================================================
--- polemy/eval.d
+++ polemy/eval.d
@@ -1,389 +1,425 @@
-/**
- * Authors: k.inaba
- * License: NYSL 0.9982 http://www.kmonos.net/nysl/
- *
- * Evaluator for Polemy programming language.
- */
-module polemy.eval;
-import polemy._common;
+/**
+ * Authors: k.inaba
+ * License: NYSL 0.9982 http://www.kmonos.net/nysl/
+ *
+ * Evaluator for Polemy programming language.
+ */
+module polemy.eval;
+import polemy._common;
import polemy.failure;
-import polemy.ast;
-import polemy.parse;
-import polemy.value;
+import polemy.ast;
+import polemy.parse;
+import polemy.value;
import polemy.layer;
-import std.typecons;
-import std.stdio;
-///
-Table createGlobalContext()
+class Evaluator
{
- auto ctx = new Table;
- ctx.set("+", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data + rhs.data);} ));
- ctx.set("-", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data - rhs.data);} ));
- ctx.set("*", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data * rhs.data);} ));
- ctx.set("/", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data / rhs.data);} ));
- ctx.set("%", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(lhs.data % rhs.data);} ));
- ctx.set("||", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) || (rhs.data!=0) ? 1:0));} ));
- ctx.set("&&", ValueLayer, native( (IntValue lhs, IntValue rhs){return new IntValue(BigInt((lhs.data!=0) && (rhs.data!=0) ? 1:0));} ));
- ctx.set("<", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs < rhs ? 1: 0));} ));
- ctx.set(">", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs > rhs ? 1: 0));} ));
- ctx.set("<=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs <= rhs ? 1: 0));} ));
- ctx.set(">=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs >= rhs ? 1: 0));} ));
- ctx.set("==", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs == rhs ? 1: 0));} ));
- ctx.set("!=", ValueLayer, native( (Value lhs, Value rhs){return new IntValue(BigInt(lhs != rhs ? 1: 0));} ));
- ctx.set("print", ValueLayer, native( (Value a){
- writeln(a);
- return new IntValue(BigInt(0));
- }));
- ctx.set("if", ValueLayer, native( (IntValue x, FunValue ft, FunValue fe){
- auto toRun = (x.data==0 ? fe : ft);
- // [TODO] fill positional information
- return toRun.invoke(null, ValueLayer, toRun.definitionContext());
-// return toRun.invoke(pos, lay, toRun.definitionContext());
- }));
- ctx.set("_isint", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(IntValue)v is null ? 0 : 1));} ));
- ctx.set("_isstr", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(StrValue)v is null ? 0 : 1));} ));
- ctx.set("_isfun", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(FunValue)v is null ? 0 : 1));} ));
- ctx.set("_isundefined", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(UndValue)v is null ? 0 : 1));} ));
- ctx.set("_istable", ValueLayer, native( (Value v){return new IntValue(BigInt(cast(Table)v is null ? 0 : 1));} ));
- ctx.set(".", ValueLayer, native( (Table t, StrValue s){
- return (t.has(s.data, ValueLayer) ? t.get(s.data, ValueLayer) : new UndValue);
- }) );
- ctx.set(".?", ValueLayer, native( (Table t, StrValue s){
- return new IntValue(BigInt(t.has(s.data, ValueLayer) ? 1 : 0));
- }) );
- ctx.set(".=", ValueLayer, native( (Table t, StrValue s, Value v){
- auto t2 = new Table(t, Table.Kind.NotPropagateSet);
- t2.set(s.data, ValueLayer, v);
- return t2;
- }) );
- ctx.set("{}", ValueLayer, native( (){
- return new Table;
- }) );
- return ctx;
-}
-
-/// Entry point of this module
-
-Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn)
-{
- return eval( polemy.parse.parseString(str, fn_ln_cn) );
-}
-
-/// Entry point of this module
-
-Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn)
-{
- return eval( polemy.parse.parseFile(filename, ln_cn) );
-}
-
-/// Entry point of this module
-
-Tuple!(Value,"val",Table,"ctx") eval(AST e)
-{
- Table ctx = createGlobalContext();
- return typeof(return)(eval(e, ctx, false, ValueLayer), ctx);
-}
-
-Value invokeFunction(in LexPosition pos, Value _f, AST[] args, Table callerCtx, Layer lay, bool AlwaysMacro=false)
-{
- if(auto f = cast(FunValue)_f)
+public:
+ this() { theContext = new Table; }
+
+ Value evalAST(AST e)
+ {
+ return eval(e, ValueLayer, theContext, OverwriteCtx);
+ }
+
+ Value evalString(S,T...)(S str, T fn_ln_cn)
+ {
+ return evalAST(parseString(str,fn_ln_cn));
+ }
+
+ Value evalFile(S,T...)(S filename, T ln_cn)
+ {
+ return evalAST(parseFile(filename,ln_cn));
+ }
+
+ Table globalContext()
+ {
+ return theContext;
+ }
+
+private:
+ Table theContext;
+
+private:
+ enum : bool { CascadeCtx=false, OverwriteCtx=true };
+
+ Value eval( AST e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ // dynamic-overload-resolution-pattern: modify here
+ enum funName = "eval";
+ alias TypeTuple!(e,lay,ctx,overwriteCtx) params;
+
+ // dynamic-overload-resolution-pattern: dispatch
+ alias typeof(__traits(getOverloads, this, funName)) ovTypes;
+ alias staticMap!(firstParam, ovTypes) fstTypes;
+ alias DerivedToFront!(fstTypes) fstTypes_sorted;
+ foreach(i, T; fstTypes_sorted)
+ static if( is(T == typeof(params[0])) ) {} else if( auto _x = cast(T)params[0] )
+ return __traits(getOverloads, this, funName)[i](_x, params[1..$]);
+
+ // dynamic-overload-resolution-pattern: default behavior
+ assert(false, text("eval() for ",typeid(e)," [",e.pos,"] is not defined"));
+ }
+
+private:
+ Value eval( Str e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ Value v = new StrValue(e.data);
+ if( lay==RawMacroLayer || lay==MacroLayer )
+ {
+ auto ast = new Table;
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("str"));
+ ast.set("data", ValueLayer, v);
+ return ast;
+ }
+ if( lay==ValueLayer )
+ return v;
+ return lift(v, lay, ctx, e.pos);
+ }
+
+ Value eval( Int e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ Value v = new IntValue(e.data);
+ if( lay==RawMacroLayer || lay==MacroLayer )
+ {
+ auto ast = new Table;
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("int"));
+ ast.set("data", ValueLayer, v);
+ return ast;
+ }
+ if( lay==ValueLayer )
+ return v;
+ return lift(v, lay, ctx, e.pos);
+ }
+
+ Value eval( Var e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ if( lay==RawMacroLayer || lay==MacroLayer )
+ {
+ if( ctx.has(e.name,MacroLayer) )
+ return ctx.get(e.name, MacroLayer, e.pos);
+ auto ast = new Table;
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("var"));
+ ast.set("name", ValueLayer, new StrValue(e.name));
+ return ast;
+ }
+ if( lay==ValueLayer || ctx.has(e.name, lay) )
+ return ctx.get(e.name, lay, e.pos);
+ return lift(ctx.get(e.name, ValueLayer, e.pos), lay, ctx, e.pos);
+ }
+
+ Value eval( App e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ Value f = eval( e.fun, lay, ctx );
+ if( lay==RawMacroLayer || lay==MacroLayer )
+ {
+ if( auto ff = cast(FunValue)f )
+ return invokeFunction(ff, e.args, MacroLayer, ctx, e.pos);
+ Table ast = new Table;
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("app"));
+ ast.set("fun", ValueLayer, f);
+ Table args = new Table;
+ foreach_reverse(a; e.args)
+ args = makeCons(eval(a, lay, ctx), args);
+ ast.set("args", ValueLayer, args);
+ return ast;
+ }
+ else
+ {
+ return invokeFunction(f, e.args, lay, ctx, e.pos);
+ }
+ }
+
+ Value eval( Fun e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
+ {
+ if( lay==RawMacroLayer || lay==MacroLayer )
+ {
+ Table t = new Table;
+ t.set("pos", ValueLayer, fromPos(e.pos));
+ t.set("is", ValueLayer, new StrValue("fun"));
+ t.set("funbody", ValueLayer, eval(e.funbody,lay,ctx));
+ Table params = new Table;
+ foreach_reverse(p; e.params)
+ {
+ Table lays = new Table;
+ foreach_reverse(l; p.layers)
+ lays = makeCons(new StrValue(l), lays);
+ Table kv = new Table;
+ kv.set("name", ValueLayer, new StrValue(p.name));
+ kv.set("layers", ValueLayer, lays);
+ Table cons = new Table;
+ params = makeCons(kv, params);
+ }
+ t.set("params", ValueLayer, params);
+ return t;
+ }
+ else
+ {
+ return createNewFunction(e, ctx);
+ }
+ }
+
+ Value eval( Lay e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
{
- Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
- foreach(i,p; f.params())
- if( p.layers.empty )
- if(lay==MacroLayer)
- ctx.set(p.name, lay, macroEval(args[i], callerCtx, AlwaysMacro));
- else
- ctx.set(p.name, lay, eval(args[i], callerCtx, true, lay));
- else
- foreach(argLay; p.layers)
- if(argLay==MacroLayer)
- ctx.set(p.name, argLay, macroEval(args[i], callerCtx, AlwaysMacro));
- else
- ctx.set(p.name, argLay, eval(args[i], callerCtx, true, argLay));
- return f.invoke(pos, lay, ctx);
+ if( lay == RawMacroLayer )
+ {
+ Value r = eval(e.expr, lay, ctx);
+ auto ast = new Table; // todo: pos
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("lay"));
+ ast.set("layer", ValueLayer, new StrValue(e.layer));
+ ast.set("expr", ValueLayer, r);
+ return ast;
+ }
+ else
+ return eval(e.expr, e.layer, ctx);
}
- throw genex!RuntimeException(pos, "tried to call non-function");
-}
-
-Value lift(in LexPosition pos, Value v, Layer lay, Table callerCtx)
-{
- // functions are automatically lifterd
- if( cast(FunValue) v )
- return v;
- // similar to invoke Function, but with only one argument bound to ValueLayer
- Value _f = callerCtx.get(lay, SystemLayer, pos);
- if(auto f = cast(FunValue)_f)
+ Value eval( Let e, Layer lay, Table ctx, bool overwriteCtx=CascadeCtx )
{
- Table ctx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
- auto ps = f.params();
- if( ps.length != 1 )
- throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
- if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
+ // todo @macro let
+ if( lay==RawMacroLayer || lay==MacroLayer )
{
- ctx.set(ps[0].name, ValueLayer, v);
- return f.invoke(pos, ValueLayer, ctx);
+ auto ast = new Table; // todo: pos
+ ast.set("pos", ValueLayer, fromPos(e.pos));
+ ast.set("is", ValueLayer, new StrValue("let"));
+ ast.set("name", ValueLayer, new StrValue(e.name));
+ ast.set("layer", ValueLayer, new StrValue(e.layer));
+ ast.set("init", ValueLayer, eval(e.init, lay, ctx));
+ ast.set("expr", ValueLayer, eval(e.expr, lay, ctx));
+ return ast;
}
else
- throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
- }
- throw genex!RuntimeException(pos, "tried to call non-function");
-}
-
-/// Entry point of this module
-/// If splitCtx = true, then inner variable declaration do not overwrite ctx.
-/// lay is the layer ID for evaluation (standard value semantics uses ValueLayer).
-
-Value eval(AST e, Table ctx, bool splitCtx, Layer lay)
-{
- return e.match(
- (StrLiteral e)
{
- Value v = new StrValue(e.data);
- if( lay == ValueLayer )
- return v;
- else
- return lift(e.pos,v,lay,ctx);
- },
- (IntLiteral e)
- {
- Value v = new IntValue(e.data);
- if( lay == ValueLayer )
- return v;
- else // rise
- return lift(e.pos,v,lay,ctx);
- },
- (VarExpression e)
- {
- if( lay == ValueLayer )
- return ctx.get(e.name, lay, e.pos);
- if( ctx.has(e.name, lay, e.pos) )
- return ctx.get(e.name, lay, e.pos);
- else
- return lift(e.pos, ctx.get(e.name, ValueLayer, e.pos), lay, ctx);
- },
- (LayExpression e)
- {
- if( e.layer == MacroLayer )
- return macroEval(e.expr, ctx, false);
- else
- return eval(e.expr, ctx, true, e.layer);
- },
- (LetExpression e)
- {
- // for letrec, we need this, but should avoid overwriting????
- // ctx.set(e.var, ValueLayer, new UndefinedValue, e.pos);
- if(splitCtx)
+ if( !overwriteCtx )
ctx = new Table(ctx, Table.Kind.NotPropagateSet);
- Value v = eval(e.init, ctx, true, lay);
- ctx.set(e.name, (e.layer.length ? e.layer : lay), v, e.pos);
- return eval(e.expr, ctx, false, lay);
- },
- (FuncallExpression e)
- {
- return invokeFunction(e.pos, eval(e.fun, ctx, true, lay), e.args, ctx, lay);
- },
- (FunLiteral e)
+ Value ri = eval(e.init, lay, ctx);
+ string theLayer = e.layer.empty ? (lay==RawMacroLayer ? MacroLayer : lay) : e.layer;
+ ctx.set(e.name, theLayer, ri);
+ return eval(e.expr, lay, ctx, OverwriteCtx);
+ }
+ }
+
+private:
+ Value invokeFunction(Value _f, AST[] args, Layer lay, Table ctx, LexPosition pos=null)
+ {
+ if(auto f = cast(FunValue)_f)
{
- return new UserDefinedFunValue(e, ctx);
- },
- delegate Value (AST e)
- {
- throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
+ Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
+ foreach(i,p; f.params())
+ if( p.layers.empty )
+ newCtx.set(p.name, (lay==RawMacroLayer ? MacroLayer : lay), eval(args[i], lay, ctx));
+ else
+ foreach(argLay; p.layers)
+ newCtx.set(p.name, argLay, eval(args[i], argLay, ctx));
+ return f.invoke(pos, lay, newCtx);
}
- );
-}
+ throw genex!RuntimeException(pos, text("tried to call non-function: ",_f));
+ }
-// [TODO] Optimization
-Value macroEval(AST e, Table ctx, bool AlwaysMacro)
-{
- Layer theLayer = ValueLayer;
-
- Table makeCons(Value a, Value d)
+ Value lift(Value v, Layer lay, Table ctx, LexPosition pos=null)
{
- Table t = new Table;
- t.set("car", theLayer, a);
- t.set("cdr", theLayer, d);
- return t;
+ // functions are automatically lifterd
+ if( cast(FunValue) v )
+ return v;
+
+ // similar to invoke Function, but with only one argument bound to ValueLayer
+ if(auto f = cast(FunValue)ctx.get(lay, SystemLayer, pos))
+ {
+ Table newCtx = new Table(f.definitionContext(), Table.Kind.NotPropagateSet);
+ auto ps = f.params();
+ if( ps.length != 1 )
+ throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
+ if( ps[0].layers.length==0 || ps[0].layers.length==1 && ps[0].layers[0]==ValueLayer )
+ {
+ newCtx.set(ps[0].name, ValueLayer, v);
+ return f.invoke(pos, ValueLayer, newCtx);
+ }
+ else
+ throw genex!RuntimeException(pos, "lift function must take exactly one argument at "~ValueLayer~" layer");
+ }
+ throw genex!RuntimeException(pos, "tried to call non-function");
}
- Table pos = new Table;
- if( e.pos !is null ) {
- pos.set("filename", theLayer, new StrValue(e.pos.filename));
- pos.set("lineno", theLayer, new IntValue(BigInt(e.pos.lineno)));
- pos.set("column", theLayer, new IntValue(BigInt(e.pos.column)));
- } else {
- pos.set("filename", theLayer, new StrValue("nullpos"));
- pos.set("lineno", theLayer, new IntValue(BigInt(0)));
- pos.set("column", theLayer, new IntValue(BigInt(0)));
- }
-
- return e.match(
- (StrLiteral e)
- {
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("str"));
- t.set("data", theLayer, new StrValue(e.data));
- return t;
- },
- (IntLiteral e)
+ Value createNewFunction(Fun e, Table ctx)
+ {
+ class UserDefinedFunValue : FunValue
{
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("int"));
- t.set("data", theLayer, new IntValue(e.data));
- return t;
- },
- (VarExpression e)
- {
- if( ctx.has(e.name, MacroLayer, e.pos) )
- return ctx.get(e.name, MacroLayer, e.pos);
- else {
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("var"));
- t.set("name", theLayer, new StrValue(e.name));
- return cast(Value)t;
+ Fun ast;
+ Table defCtx;
+ override const(Parameter[]) params() { return ast.params; }
+ override Table definitionContext() { return defCtx; }
+
+ this(Fun ast, Table defCtx) { this.ast=ast; this.defCtx=defCtx; }
+ override string toString() const { return sprintf!"(function:%x:%x)"(cast(void*)ast, cast(void*)defCtx); }
+ override bool opEquals(Object rhs_) const /// member-by-member equality
+ {
+ if( auto rhs = cast(typeof(this))rhs_ )
+ return this.ast==rhs.ast && this.defCtx==rhs.defCtx;
+ assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
+ }
+ override hash_t toHash() const /// member-by-member hash
+ {
+ return typeid(this.ast).getHash(&this.ast) + typeid(this.defCtx).getHash(&this.defCtx);
}
- },
- (LayExpression e)
- {
- if( AlwaysMacro )
+ override int opCmp(Object rhs_) /// member-by-member compare
{
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("lay"));
- t.set("layer", theLayer, new StrValue(e.layer));
- t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
- return cast(Value)t;
+ if( auto rhs = cast(typeof(this))rhs_ )
+ {
+ if(auto i = this.ast.opCmp(rhs.ast))
+ return i;
+ return this.defCtx.opCmp(rhs.defCtx);
+ }
+ assert(false, sprintf!"Cannot compare %s with %s"(typeid(this), typeid(rhs_)));
}
- else
+
+ override Value invoke(LexPosition pos, Layer lay, Table ctx)
{
- if( e.layer == MacroLayer )
- return macroEval(e.expr, ctx, false);
- else
- return eval(e.expr, ctx, true, e.layer);
+ if( lay == MacroLayer )
+ return eval(ast.funbody, lay, ctx);
+ auto macroed = tableToAST(ValueLayer, eval(e.funbody, RawMacroLayer, ctx));
+ return eval(macroed, lay, ctx);
}
- },
- (LetExpression e)
- {
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("let"));
- t.set("name", theLayer, new StrValue(e.name));
- t.set("init", theLayer, macroEval(e.init,ctx,AlwaysMacro));
- t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro));
- return t;
- },
- (FuncallExpression e)
+ }
+ return new UserDefinedFunValue(e,ctx);
+ }
+
+public:
+ /// TODO: move up
+ /// TDOO: to other layers?
+ void addPrimitive(R,T...)(string name, Layer lay, R delegate (T) dg)
+ {
+ class NativeFunValue : FunValue
{
- Value _f = macroEval(e.fun,ctx,AlwaysMacro);
-
- if( auto f = cast(FunValue)_f )
- return invokeFunction(e.pos, f, e.args, ctx, MacroLayer, AlwaysMacro);
-
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("app"));
- t.set("fun", theLayer, _f);
- Table args = new Table;
- foreach_reverse(a; e.args) {
- Table cons = new Table;
- cons.set("car",theLayer,macroEval(a,ctx,AlwaysMacro));
- cons.set("cdr",theLayer,args);
- args = cons;
+ Parameter[] params_data;
+ override string toString() { return sprintf!"(native:%x)"(dg.funcptr); }
+ override const(Parameter[]) params() { return params_data; }
+ override Table definitionContext() { return new Table; } // todo: cache
+ this(){
+ foreach(i, Ti; T)
+ params_data ~= new Parameter(text(i), []);
+ }
+ override Value invoke(LexPosition pos, Layer lay, Table ctx)
+ {
+ if( lay != ValueLayer )
+ throw genex!RuntimeException(pos, "only "~ValueLayer~" layer can call native function");
+ T typed_args;
+ foreach(i, Ti; T) {
+ typed_args[i] = cast(Ti) ctx.get(text(i), ValueLayer);
+ if( typed_args[i] is null )
+ throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1));
+ }
+ try {
+ return dg(typed_args);
+ } catch( RuntimeException e ) {
+ throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
+ }
}
- t.set("args", theLayer, args);
- return cast(Value)t;
- },
- (FunLiteral e)
- {
- Table t = new Table;
- t.set("pos", theLayer, pos);
- t.set("is", theLayer, new StrValue("fun"));
- t.set("funbody", theLayer, macroEval(e.funbody,ctx,AlwaysMacro));
- Table params = new Table;
- foreach_reverse(p; e.params)
- {
- Table lays = new Table;
- foreach_reverse(lay; p.layers)
- lays = makeCons(new StrValue(lay), lays);
- Table kv = new Table;
- kv.set("name", theLayer, new StrValue(p.name));
- kv.set("layers", theLayer, lays);
- Table cons = new Table;
- params = makeCons(kv, params);
- }
- t.set("params", theLayer, params);
- return t;
- },
- delegate Value (AST e)
- {
- throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e)));
}
- );
+ theContext.set(name, lay, new NativeFunValue);
+ }
+}
+
+version(unittest) import polemy.runtime;
+unittest
+{
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ auto r = assert_nothrow( e.evalString(`var x = 21; x + x*x;`) );
+ assert_eq( r, new IntValue(BigInt(21+21*21)) );
+ assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21)) );
+ assert_nothrow( e.globalContext.get("x",ValueLayer) );
+ assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
+}
+unittest
+{
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ auto r = assert_nothrow( e.evalString(`var x = 21; var x = x + x*x;`) );
+ assert_eq( r, new IntValue(BigInt(21+21*21)) );
+ assert_eq( e.globalContext.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
+ assert_nothrow( e.globalContext.get("x",ValueLayer) );
+ assert_throw!RuntimeException( e.globalContext.get("y",ValueLayer) );
+}
+unittest
+{
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ assert_eq( e.evalString(`let x=1; let y=(let x=2); x`), new IntValue(BigInt(1)) );
+ assert_eq( e.evalString(`let x=1; let y=(let x=2;fun(){x}); y()`), new IntValue(BigInt(2)) );
+}
+
+unittest
+{
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ assert_eq( e.evalString(`@a x=1; @b x=2; @a(x)`), new IntValue(BigInt(1)) );
+ assert_eq( e.evalString(`@a x=1; @b x=2; @b(x)`), new IntValue(BigInt(2)) );
+ assert_eq( e.evalString(`let x=1; let _ = (@a x=2;2); x`), new IntValue(BigInt(1)) );
+ e = new Evaluator;
+ assert_throw!Throwable( e.evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
+}
+
+unittest
+{
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ assert_eq( e.evalString(`
+ @@s(x){x};
+ @s "+" = fun(x, y) {@value(
+ @s(x) - @s(y)
+ )};
+ @s(1 + 2)
+ `), new IntValue(BigInt(-1)) );
}
-unittest
-{
- auto r = assert_nothrow( evalString(`var x = 21; x + x*x;`) );
- assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
- assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21)) );
- assert_nothrow( r.ctx.get("x",ValueLayer) );
- assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
-}
unittest
{
- auto r = assert_nothrow( evalString(`var x = 21; var x = x + x*x;`) );
- assert_eq( r.val, new IntValue(BigInt(21+21*21)) );
- assert_eq( r.ctx.get("x",ValueLayer), new IntValue(BigInt(21+21*21)) );
- assert_nothrow( r.ctx.get("x",ValueLayer) );
- assert_throw!RuntimeException( r.ctx.get("y",ValueLayer) );
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ assert_eq( e.evalString(`
+@@3(x){x};
+def incr(x) { x+1 };
+@ 3 incr(x) {@value( if(@ 3(x)+1< 3){@ 3(x)+1}else{0} )};
+def fb(n @value @3) { @3(n) };
+fb(incr(incr(incr(0))))
+ `), new IntValue(BigInt(0)) );
}
-unittest
-{
- assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(BigInt(1)) );
- assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new IntValue(BigInt(2)) );
-}
-unittest
-{
- assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt(1)) );
- assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt(2)) );
- assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValue(BigInt(1)) );
- assert_throw!Throwable( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) );
-}
-/*
-unittest
-{
- assert_eq( evalString(`var fac = fun(x){
- if(x)
- { x*fac(x-1); }
- else
- { 1; };
- };
- fac(10);`).val, new IntValue(BigInt(10*9*8*5040)));
- assert_eq( evalString(`var fib = fun(x){
- if(x<2)
- { 1; }
- else
- { fib(x-1) + fib(x-2); };
- };
- fib(5);`).val, new IntValue(BigInt(8)));
-}
unittest
{
- assert_throw!Throwable( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};@s(1+2)`) );
- assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){x-y};1+2`).val, new IntValue(BigInt(3)) );
- assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};1+2`).val, new IntValue(BigInt(3)) );
- assert_eq( evalString(`@@s(x){x}; @s "+"=fun(x,y){@value(@s(x)-@s(y))};@s(1+2)`).val, new IntValue(BigInt(-1)) );
+ auto e = new Evaluator;
+ enrollRuntimeLibrary(e);
+ assert_nothrow( e.evalString(`
+@macro twice(x) { x; x };
+def main() { twice(1) };
+main()
+ `) );
}
-
+/*
+unittest
+{
+ assert_eq( evalString(`var fac = fun(x){
+ if(x)
+ { x*fac(x-1); }
+ else
+ { 1; };
+ };
+ fac(10);`).val, new IntValue(BigInt(10*9*8*5040)));
+ assert_eq( evalString(`var fib = fun(x){
+ if(x<2)
+ { 1; }
+ else
+ { fib(x-1) + fib(x-2); };
+ };
+ fib(5);`).val, new IntValue(BigInt(8)));
+}
unittest
{
assert_eq( evalString(`@@t = fun(x){x+1}; @t(123)`).val, new IntValue(BigInt(124)) );
// there was a bug that declaration in the first line of function definition
// cannot be recursive
Index: polemy/layer.d
==================================================================
--- polemy/layer.d
+++ polemy/layer.d
@@ -12,9 +12,10 @@
alias string Layer;
enum : Layer
{
- SystemLayer = "(system)", /// Predefined layer for internal data
- ValueLayer = "@value", /// Predefined layer for normal run
- MacroLayer = "@macro", /// Predefined layer for macro run
+ SystemLayer = "(system)", /// Predefined layer for internal data
+ ValueLayer = "@value", /// Predefined layer for normal run
+ MacroLayer = "@macro", /// Predefined layer for macro run
+ RawMacroLayer = "(rawmacro)", /// Predefined layer for raw-macro run
}
Index: polemy/parse.d
==================================================================
--- polemy/parse.d
+++ polemy/parse.d
@@ -100,14 +100,14 @@
auto e = tryEat("(")
? parseLambdaAfterOpenParen(pos) // let var ( ...
: (eat("=", "after "~kwd), E(0)); // let var = ...
if( moreDeclarationExists() )
- return new LetExpression(pos, var, SystemLayer, e, Body());
+ return new Let(pos, var, SystemLayer, e, Body());
else
- return new LetExpression(pos, var, SystemLayer, e,
- new LayExpression(pos, SystemLayer, new VarExpression(pos, var))
+ return new Let(pos, var, SystemLayer, e,
+ new Lay(pos, SystemLayer, new Var(pos, var))
);
}
else
{
string kwd = layer;
@@ -119,13 +119,13 @@
auto e = tryEat("(")
? parseLambdaAfterOpenParen(varpos) // let var ( ...
: (eat("=", "after "~kwd), E(0)); // let var = ...
if( moreDeclarationExists() )
- return new LetExpression(pos, var, layer, e, Body());
+ return new Let(pos, var, layer, e, Body());
else
- return new LetExpression(pos, var, layer, e, new VarExpression(varpos, var));
+ return new Let(pos, var, layer, e, new Var(varpos, var));
}
}
AST TopLevelExpression()
{
@@ -132,11 +132,11 @@
/// TopLevelExpression ::= Expression ([";"|"in"] Body?)?
auto pos = currentPosition();
auto e = E(0);
if( moreDeclarationExists() )
- return new LetExpression(pos, "_", "", e, Body());
+ return new Let(pos, "_", "", e, Body());
else
return e;
}
private bool moreDeclarationExists()
@@ -179,14 +179,14 @@
auto pos = currentPosition();
foreach(op; operator_perferences[level])
if( tryEat(op) )
if( op[0]=='.' )
return rec(
- new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, parseId()));
+ new App(lhs.pos, new Var(pos, op), lhs, parseId()));
else
- return rec(
- new FuncallExpression(lhs.pos, new VarExpression(pos, op), lhs, E(level+1)));
+ return rec(
+ new App(lhs.pos, new Var(pos, op), lhs, E(level+1)));
return lhs;
}
if( operator_perferences.length <= level )
return Funcall();
@@ -211,11 +211,11 @@
if( !tryEat(",") ) {
eat(")", "after function parameters");
break;
}
}
- e = new FuncallExpression(e.pos, e, args);
+ e = new App(e.pos, e, args);
}
else if( tryEat("{") )
{
e = parseTableSetAfterBrace(e);
}
@@ -232,12 +232,12 @@
for(;;)
{
string key = eatId("for table key", AllowQuoted);
eat(":", "after table key");
AST val = E(0);
- e = new FuncallExpression(pos, new VarExpression(pos,".="),
- e, new StrLiteral(pos,key), val);
+ e = new App(pos, new Var(pos,".="),
+ e, new Str(pos,key), val);
if( !tryEat(",") )
{
eat("}", "for the end of table literal");
break;
}
@@ -252,34 +252,34 @@
auto pos = lex.front.pos;
if( lex.front.quoted )
{
scope(exit) lex.popFront;
- return new StrLiteral(pos, lex.front.str);
+ return new Str(pos, lex.front.str);
}
if( isNumber(lex.front.str) )
{
scope(exit) lex.popFront;
- return new IntLiteral(pos, BigInt(cast(string)lex.front.str));
+ return new Int(pos, BigInt(cast(string)lex.front.str));
}
if( tryEat("@") )
{
auto lay = "@"~eatId("for layer ID");
eat("(", "for layered execution");
auto e = Body();
eat(")", "after "~lay~"(...");
- return new LayExpression(pos, lay, e);
+ return new Lay(pos, lay, e);
}
if( tryEat("(") )
{
auto e = Body();
eat(")", "after parenthesized expression");
return e;
}
if( tryEat("{") )
{
- AST e = new FuncallExpression(pos, new VarExpression(pos,"{}"));
+ AST e = new App(pos, new Var(pos,"{}"));
return parseTableSetAfterBrace(e);
}
if( tryEat("if") )
{
eat("(", "after if");
@@ -294,15 +294,15 @@
if( tryEat("else") ) {
eat("{", "after else");
el = Body();
eat("}", "after else body");
}
- return new FuncallExpression(pos,
- new VarExpression(pos, "if"),
+ return new App(pos,
+ new Var(pos, "if"),
cond,
- new FunLiteral(thenPos, [], th),
- new FunLiteral(elsePos, [], el)
+ new Fun(thenPos, [], th),
+ new Fun(elsePos, [], el)
);
}
if( tryEat("case") )
{
return parsePatternMatch(pos);
@@ -311,11 +311,11 @@
{
eat("(", "after fun");
return parseLambdaAfterOpenParen(pos);
}
scope(exit) lex.popFront;
- return new VarExpression(pos, lex.front.str);
+ return new Var(pos, lex.front.str);
}
AST parsePatternMatch(LexPosition pos)
{
// case( pmExpr )cases
@@ -325,12 +325,12 @@
AST pmExpr = E(0);
eat(")", "after case");
string pmVar = freshVarName();
string pmTryFirst = freshVarName();
AST pmBody = parsePatternMatchCases(pmVar, pmTryFirst,
- new FuncallExpression(pos, new VarExpression(pos, pmTryFirst)));
- return new LetExpression(pos, pmVar, [], pmExpr, pmBody);
+ new App(pos, new Var(pos, pmTryFirst)));
+ return new Let(pos, pmVar, [], pmExpr, pmBody);
}
AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST thenDoThis)
{
// when( pat ) { cBody }
@@ -345,25 +345,25 @@
eat("(", "after when");
auto pr = parsePattern();
eat(")", "after when");
eat("{", "after pattern");
AST cBody = Body();
- AST judgement = new FuncallExpression(pos, new VarExpression(pos, "if"),
- ppTest(pmVar, pr), new FunLiteral(pos,[],ppBind(pmVar, pr, cBody)),
- new VarExpression(pos, failBranchVar));
+ AST judgement = new App(pos, new Var(pos, "if"),
+ ppTest(pmVar, pr), new Fun(pos,[],ppBind(pmVar, pr, cBody)),
+ new Var(pos, failBranchVar));
eat("}", "after pattern clause");
return parsePatternMatchCases(pmVar, failBranchVar,
- new LetExpression(pos, tryThisBranchVar, [],
- new FunLiteral(pos,[],judgement), thenDoThis)
+ new Let(pos, tryThisBranchVar, [],
+ new Fun(pos,[],judgement), thenDoThis)
);
}
else
{
auto pos = currentPosition();
- AST doNothing = new FunLiteral(pos,[],
- new StrLiteral(pos, sprintf!"(pattern match failure:%s)"(pos)));
- return new LetExpression(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis);
+ AST doNothing = new Fun(pos,[],
+ new Str(pos, sprintf!"(pattern match failure:%s)"(pos)));
+ return new Let(currentPosition(), tryThisBranchVar, [], doNothing, thenDoThis);
}
}
// hageshiku tenuki
abstract class SinglePattern
@@ -370,31 +370,31 @@
{
string[] path;
mixin SimpleClass;
private AST access(string pmVar, string[] path) {
auto pos = currentPosition();
- AST e = new VarExpression(pos, pmVar);
+ AST e = new Var(pos, pmVar);
foreach(p; path)
- e = new FuncallExpression(pos, new VarExpression(pos, "."), e, new StrLiteral(pos, p));
+ e = new App(pos, new Var(pos, "."), e, new Str(pos, p));
return e;
}
private AST has(AST e, string k) {
auto pos = currentPosition();
return opAndAnd(
- new FuncallExpression(pos, new VarExpression(pos, "_istable"), e),
- new FuncallExpression(pos, new VarExpression(pos, ".?"), e, new StrLiteral(pos, k))
+ new App(pos, new Var(pos, "_istable"), e),
+ new App(pos, new Var(pos, ".?"), e, new Str(pos, k))
);
}
private AST opAndAnd(AST a, AST b) {
if( a is null ) return b;
if( b is null ) return a;
auto pos = currentPosition();
- return new FuncallExpression(pos,
- new VarExpression(pos, "if"),
+ return new App(pos,
+ new Var(pos, "if"),
a,
- new FunLiteral(pos, [], b),
- new FunLiteral(pos, [], new IntLiteral(pos, 0))
+ new Fun(pos, [], b),
+ new Fun(pos, [], new Int(pos, 0))
);
}
AST ppTest(string pmVar) {
AST c = null;
for(int i=0; i