Index: .poseidon ================================================================== --- .poseidon +++ .poseidon @@ -9,15 +9,15 @@ 0 main.d - -cov -D -Dddoc -g -unittest + -D -Dddoc -g -unittest - + doc\candydoc\candy.ddoc doc\candydoc\modules.ddoc 0 0 0 0 @@ -28,17 +28,16 @@ d2stacktrace\dbghelp.d d2stacktrace\stacktrace.d - doc\candydoc\candy.ddoc - doc\candydoc\modules.ddoc main.d polemy\_common.d polemy\ast.d polemy\eval.d polemy\failure.d + polemy\fresh.d polemy\layer.d polemy\lex.d polemy\parse.d polemy\value.d tricks\test.d @@ -48,13 +47,15 @@ build.bat build.sh + doc\candydoc\candy.ddoc + doc\candydoc\modules.ddoc readme.txt Index: d2stacktrace/stacktrace.d ================================================================== --- d2stacktrace/stacktrace.d +++ d2stacktrace/stacktrace.d @@ -246,12 +246,12 @@ return trace.GetCallstack(); } public: static this(){ -// Runtime.traceHandler(&TraceHandler); -// SetUnhandledExceptionFilter(&UnhandeledExceptionFilterHandler); + Runtime.traceHandler(&TraceHandler); + SetUnhandledExceptionFilter(&UnhandeledExceptionFilterHandler); } this(){ if(isInit) return; Index: doc/candydoc/modules.ddoc ================================================================== --- doc/candydoc/modules.ddoc +++ doc/candydoc/modules.ddoc @@ -3,10 +3,11 @@ $(MODULE tricks.tricks) $(MODULE tricks.test) $(MODULE polemy._common) $(MODULE polemy.failure) $(MODULE polemy.layer) + $(MODULE polemy.fresh) $(MODULE polemy.lex) $(MODULE polemy.parse) $(MODULE polemy.ast) $(MODULE polemy.eval) $(MODULE polemy.value) Index: polemy/ast.d ================================================================== --- polemy/ast.d +++ polemy/ast.d @@ -5,56 +5,58 @@ * Syntax tree for Polemy programming language. */ module polemy.ast; import polemy._common; import polemy.failure; +import polemy.layer; /// abstract class AST { LexPosition pos; mixin SimpleConstructor; mixin SimplePatternMatch; } +/// +class IntLiteral : AST +{ + BigInt data; + mixin SimpleClass; + this(LexPosition pos, int n) {super(pos); data = n;} + this(LexPosition pos, long n) {super(pos); data = n;} + this(LexPosition pos, BigInt n) {super(pos); data = n;} + this(LexPosition pos, string n) {super(pos); data = BigInt(n);} +} + /// class StrLiteral : AST { string data; mixin SimpleClass; } -/// -class IntLiteral : AST -{ - BigInt data; - mixin SimpleClass; - this(immutable LexPosition pos, long n) {super(pos); data = n;} - this(immutable LexPosition pos, BigInt n) {super(pos); data = n;} - this(immutable LexPosition pos, string n) {super(pos); data = BigInt(n);} -} - /// class VarExpression : AST { - string var; + string name; mixin SimpleClass; } /// -class LayeredExpression : AST +class LayExpression : AST { - string lay; - AST expr; + Layer layer; + AST expr; mixin SimpleClass; } /// class LetExpression : AST { - string var; - string layer; + string name; + Layer layer; AST init; AST expr; mixin SimpleClass; } @@ -61,20 +63,20 @@ /// class FuncallExpression : AST { AST fun; AST[] args; - this(immutable LexPosition pos, AST fun, AST[] args...) + this(LexPosition pos, AST fun, AST[] args...) { super(pos); this.fun=fun; this.args=args.dup; } mixin SimpleClass; } /// class Parameter { - string name; - string[] layers; + string name; + Layer[] layers; mixin SimpleClass; } /// class FunLiteral : AST @@ -97,10 +99,10 @@ alias genEast!IntLiteral 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!LayeredExpression lay; /// + alias genEast!LayExpression lay; /// alias genEast!LetExpression let; /// alias genEast!FuncallExpression call; /// auto param(string name, string[] lay...) { return new Parameter(name, lay); } /// } Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -31,14 +31,15 @@ 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(178)); + 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));} )); @@ -151,32 +152,32 @@ return lift(e.pos,v,lay,ctx); }, (VarExpression e) { if( lay == ValueLayer ) - return ctx.get(e.var, lay, e.pos); + return ctx.get(e.name, lay, e.pos); try { - return ctx.get(e.var, lay, e.pos); + return ctx.get(e.name, lay, e.pos); } catch( Throwable ) { // [TODO] more precise... - return lift(e.pos, ctx.get(e.var, ValueLayer, e.pos), lay, ctx); + return lift(e.pos, ctx.get(e.name, ValueLayer, e.pos), lay, ctx); } }, - (LayeredExpression e) + (LayExpression e) { - if( e.lay == MacroLayer ) + if( e.layer == MacroLayer ) return macroEval(e.expr, ctx, false); else - return eval(e.expr, ctx, true, e.lay); + 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) ctx = new Table(ctx, Table.Kind.NotPropagateSet); Value v = eval(e.init, ctx, true, lay); - ctx.set(e.var, (e.layer.length ? e.layer : lay), v, e.pos); + 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); @@ -193,21 +194,36 @@ delegate Value (AST e) { throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); } ); -} +} // [TODO] Optimization Value macroEval(AST e, Table ctx, bool AlwaysMacro) { Layer theLayer = ValueLayer; + + Table makeCons(Value a, Value d) + { + Table t = new Table; + t.set("car", theLayer, a); + t.set("cdr", theLayer, d); + return t; + } Table pos = new Table; - 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))); + 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); @@ -224,44 +240,44 @@ return t; }, (VarExpression e) { try { - return ctx.get(e.var, MacroLayer, e.pos); + return ctx.get(e.name, MacroLayer, e.pos); } catch( Throwable ) {// [TODO] more precies... Table t = new Table; t.set("pos", theLayer, pos); t.set("is", theLayer, new StrValue("var")); - t.set("name", theLayer, new StrValue(e.var)); + t.set("name", theLayer, new StrValue(e.name)); return cast(Value)t; } }, - (LayeredExpression e) + (LayExpression e) { if( AlwaysMacro ) { Table t = new Table; - t.set("pos", theLayer, pos); - t.set("is", theLayer, new StrValue("lay")); - t.set("layer", theLayer, new StrValue(e.lay)); - t.set("expr", theLayer, macroEval(e.expr,ctx,AlwaysMacro)); + 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; } else { - if( e.lay == MacroLayer ) + if( e.layer == MacroLayer ) return macroEval(e.expr, ctx, false); else - return eval(e.expr, ctx, true, e.lay); + return eval(e.expr, ctx, true, e.layer); } }, (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.var)); + 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) @@ -280,37 +296,32 @@ Table cons = new Table; cons.set("car",theLayer,macroEval(a,ctx,AlwaysMacro)); cons.set("cdr",theLayer,args); args = cons; } - t.set("arg", theLayer, args); + 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("body", theLayer, macroEval(e.funbody,ctx,AlwaysMacro)); - Table param = new Table; + t.set("funbody", theLayer, macroEval(e.funbody,ctx,AlwaysMacro)); + Table params = new Table; foreach_reverse(p; e.params) { - Table cons = new Table; + 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)); - foreach_reverse(lay; p.layers) - { - Table cons2 = new Table; - cons2.set("car", theLayer, new StrValue(lay)); - cons2.set("cdr", theLayer, kv); - kv = cons2; - } - cons.set("car", theLayer, kv); - cons.set("cdr", theLayer, param); - param = cons; + kv.set("layers", theLayer, lays); + Table cons = new Table; + params = makeCons(kv, params); } - t.set("param", theLayer, param); + t.set("params", theLayer, params); return t; }, delegate Value (AST e) { throw genex!RuntimeException(e.pos, sprintf!"Unknown Kind of Expression %s"(typeid(e))); @@ -344,11 +355,11 @@ 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); } @@ -381,5 +392,6 @@ assert_nothrow( evalString(`def foo() { def bar(y) { if(y<1) {0} else {bar(0)} }; bar(1) }; foo()`) ); } +*/ Index: polemy/failure.d ================================================================== --- polemy/failure.d +++ polemy/failure.d @@ -7,10 +7,14 @@ module polemy.failure; import polemy._common; /// Represents a position in source codes +alias immutable(LexPosition_t) LexPosition; + +/// Represents a position in source codes + class LexPosition_t { immutable string filename; /// name of the source file immutable int lineno; /// 1-origin immutable int column; /// 1-origin @@ -23,14 +27,10 @@ static LexPosition dummy; static this(){ dummy = new LexPosition("",0,0); } } -/// Represents a position in source codes - -alias immutable(LexPosition_t) LexPosition; - unittest { auto p = new LexPosition("hello.cpp", 123, 45); assert_eq( p.filename, "hello.cpp" ); ADDED polemy/fresh.d Index: polemy/fresh.d ================================================================== --- polemy/fresh.d +++ polemy/fresh.d @@ -0,0 +1,18 @@ +/** + * Authors: k.inaba + * License: NYSL 0.9982 http://www.kmonos.net/nysl/ + * + * Interpreter-wise fresh ID generator. + */ +module polemy.fresh; +import polemy._common; +import core.atomic; + +private shared int freshVarId = -1; + +/// Generate one fresh variable name + +string freshVarName() +{ + return text("$", atomicOp!("+=")(freshVarId, 1)); +} Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -111,11 +111,11 @@ public static { bool isSpace (dchar c) { return std.ctype.isspace(c)!=0; } bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.ctype.isalnum(c) && c!='_' && c!='\''; } - bool isSSymbol (dchar c) { return "()[]{};@".canFind(c); } + bool isSSymbol (dchar c) { return "()[]{};,@".canFind(c); } bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) && c!='"' && c!='#'; } bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } } string readQuoted(const LexPosition pos){char[] buf; return readQuoted(pos,buf);} Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -7,11 +7,12 @@ module polemy.parse; import polemy._common; import polemy.failure; import polemy.lex; import polemy.ast; -import polemy.layer; +import polemy.layer; +import polemy.fresh; /// Parse a string and return its AST AST parseString(S, T...)(S str, T fn_ln_cn) { @@ -102,11 +103,11 @@ : (eat("=", "after "~kwd), E(0)); // let var = ... if( moreDeclarationExists() ) return new LetExpression(pos, var, SystemLayer, e, Body()); else return new LetExpression(pos, var, SystemLayer, e, - new LayeredExpression(pos, SystemLayer, new VarExpression(pos, var)) + new LayExpression(pos, SystemLayer, new VarExpression(pos, var)) ); } else { string kwd = layer; @@ -143,11 +144,11 @@ return (tryEat(";") || tryEat("in")) && !closingBracket(); } private bool closingBracket() { - return lex.empty || !lex.front.quoted && ["}",")","]"].canFind(lex.front.str); + return lex.empty || !lex.front.quoted && ["}",")","]",","].canFind(lex.front.str); } // [TODO] make this customizable from program private static string[][] operator_perferences = [ ["||"], @@ -264,11 +265,11 @@ { auto lay = "@"~eatId("for layer ID"); eat("(", "for layered execution"); auto e = Body(); eat(")", "after "~lay~"(..."); - return new LayeredExpression(pos, lay, e); + return new LayExpression(pos, lay, e); } if( tryEat("(") ) { auto e = Body(); eat(")", "after parenthesized expression"); @@ -300,18 +301,182 @@ cond, new FunLiteral(thenPos, [], th), new FunLiteral(elsePos, [], el) ); } + if( tryEat("case") ) + { + return parsePatternMatch(pos); + } if( tryEat("fun") || tryEat("\u03BB") ) // lambda!! { eat("(", "after fun"); return parseLambdaAfterOpenParen(pos); } scope(exit) lex.popFront; return new VarExpression(pos, lex.front.str); } + + AST parsePatternMatch(LexPosition pos) + { + // case( pmExpr )cases + //==> + // let pmVar = pmExpr in (... let pmTryFirst = ... in pmTryFirst()) + eat("(", "after case"); + 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); + } + + AST parsePatternMatchCases(string pmVar, string tryThisBranchVar, AST thenDoThis) + { + // when( pat ) { cBody } + //==> + // ... let failBranchVar = ... in + // let tryThisBranchVar = fun(){ if(test){cBody}else{failBranchVar()} } in thenDoThis + if( tryEat("when") ) + { + auto pos = currentPosition(); + string failBranchVar = freshVarName(); + + 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)); + eat("}", "after pattern clause"); + return parsePatternMatchCases(pmVar, failBranchVar, + new LetExpression(pos, tryThisBranchVar, [], + new FunLiteral(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); + } + } + +// hageshiku tenuki + abstract class SinglePattern + { + string[] path; + mixin SimpleClass; + private AST access(string pmVar, string[] path) { + auto pos = currentPosition(); + AST e = new VarExpression(pos, pmVar); + foreach(p; path) + e = new FuncallExpression(pos, new VarExpression(pos, "."), e, new StrLiteral(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)) + ); + } + 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"), + a, + new FunLiteral(pos, [], b), + new FunLiteral(pos, [], new IntLiteral(pos, 0)) + ); + } + AST ppTest(string pmVar) { + AST c = null; + for(int i=0; i y ) { {} } + else { {car: x, cdr: fromTo(x+1,y)} } +}; + +def length(lst) +{ + case( lst ) + when( {car:_, cdr:x} ) { length(x)+1 } + when( _ ) { 0 } +}; + +def adjSum(lst) +{ + case( lst ) + when( {car:x, cdr:{car: y, cdr:z}} ) { {car: x+y, cdr: adjSum(z)} } + when( {car:x, cdr:{}} ) { {car: x, cdr: {}} } + when( {} ) { {} } +}; + +var xs = fromTo(1,11); + +print( xs ); +print( length(xs) ); +print( adjSum(xs) ); +print( length(adjSum(xs)) );