Index: main.d ================================================================== --- main.d +++ main.d @@ -3,16 +3,70 @@ * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ * * Entry point for Polemy interpreter. */ -import std.stdio; +import std.stdio; +import std.algorithm; +import polemy.value; +import polemy.lex; +import polemy.parse; +import polemy.ast; +import polemy.eval; -version(unittest) static ~this() +class REPL { - writeln( "(Press Enter to finish)" ); - readln(); + Table ctx; + string buf; + Value lastVal; + int lineno = 1; + int nextlineno = 1; + this() { ctx = createGlobalContext(); } + + bool tryRun( string s ) + { + nextlineno ++; + buf ~= s; + try { + AST a = parseString(buf, "", lineno); + buf = ""; + lineno = nextlineno; + lastVal = eval(a, ctx); + } catch( LexException ) { + // always EOF exception, so wait next + return false; + } catch( ParseException e ) { + if( find(e.msg, "EOF") ) // ultra ad-hoc + return false; + throw e; + } + return true; + } + + bool singleInteraction() + { + writef(">> ", lineno); + string line = readln(); + if( line.startsWith("exit") || line.startsWith("quit") ) + return false; + try { + if( tryRun(line) ) + writeln(lastVal); + } catch(Throwable e) { + writeln(e); + } + return true; + } } void main( string[] args ) { + if( args.length <= 1 ) + { + writeln("Welcome to Polemy 0.1.0"); + for(auto r = new REPL; r.singleInteraction();) {} + } + else + { + evalFile(args[1]); + } } Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -88,11 +88,11 @@ Tuple!(Value,"val",Table,"ctx") evalString(S,T...)(S str, T fn_ln_cn) { return eval( polemy.parse.parseString(str, fn_ln_cn) ); } -Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filenae, T ln_cn) +Tuple!(Value,"val",Table,"ctx") evalFile(S, T...)(S filename, T ln_cn) { return eval( polemy.parse.parseFile(filename, ln_cn) ); } Tuple!(Value,"val",Table,"ctx") eval(AST e) Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -13,12 +13,12 @@ class LexException : Exception { const LexPosition pos; - this( const LexPosition pos, string msg, string file="", int line=0 ) - { super(sprintf!"[%s] %s"(pos, msg), file, line); this.pos = pos; } + this( const LexPosition pos, string msg, string file="", int line=0, Throwable next=null ) + { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos = pos; } }; /// Represents a position in a source code class LexPosition @@ -36,23 +36,24 @@ } unittest { auto p = new LexPosition("hello.cpp", 123, 45); - auto q = new LexPosition("hello.cpp", 123, 46); assert_eq( p.filename, "hello.cpp" ); assert_eq( p.lineno, 123 ); assert_eq( p.column, 45 ); assert_eq( to!string(p), "hello.cpp:123:45" ); - assert_lt( p, q ); - assert_ne( p, q ); assert( !__traits(compiles, new LexPosition) ); assert( !__traits(compiles, p.filename="foo") ); assert( !__traits(compiles, p.lineno =789) ); assert( !__traits(compiles, p.column =222) ); + + auto q = new LexPosition("hello.cpp", 123, 46); + assert_lt( p, q ); + assert_ne( p, q ); } /// Represents a lexer token class Token @@ -159,11 +160,11 @@ string readQuoted(const LexPosition pos){char[] buf; return readQuoted(pos,buf);} string readQuoted(const LexPosition pos, ref char[] buf) { if( reader.empty ) - throw new LexException(pos, "EOF found while lexing a quoted-string"); + throw genex!LexException(pos, "EOF found while lexing a quoted-string"); dchar c = reader.front; reader.popFront; if( c == '"' ) return assumeUnique(buf); if( c == '\\' && !reader.empty ) { @@ -225,10 +226,11 @@ } unittest { assert( std.range.isForwardRange!(Lexer) ); + assert( is(ElementType!(Lexer) == Token) ); } unittest { auto lex = lexerFromString("this is a \t\r\n pen :-( @@; "); Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -13,12 +13,12 @@ class ParseException : Exception { const LexPosition pos; - private this( const LexPosition pos, string msg ) - { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; } + this( const LexPosition pos, string msg, string file="", int line=0, Throwable next=null ) + { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos = pos; } } private auto createException(Lexer)(Lexer lex, string msg) { return new ParseException(lex.empty?null:lex.front.pos, msg); } @@ -25,11 +25,11 @@ /// Entry points of this module auto parseString(S, T...)(S str, T fn_ln_cn) { return parserFromString(str, fn_ln_cn).parse(); } -auto parseFile(S, T...)(S filename,T ln_cn) +auto parseFile(S, T...)(S filename, T ln_cn) { return parserFromString(filename, ln_cn).parse(); } /// Named Constructor of Parser private auto parserFromLexer(Lexer)(Lexer lex) Index: tricks/tricks.d ================================================================== --- tricks/tricks.d +++ tricks/tricks.d @@ -19,12 +19,13 @@ return writer.data; } unittest { - assert( sprintf!"%s == %d"("1+2", 3) == "1+2 == 3" ); - assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" ); + assert_eq( sprintf!"%s == %04d"("1+2", 3), "1+2 == 0003" ); + assert_eq( sprintf!"%2$s == %1$s"("1+2", 5, 8), "5 == 1+2" ); + assert_throw!Error( sprintf!"%s%s"(1) ); } /// Create an exception with automatically completed filename and lineno information auto genex(ExceptionType, string fn=__FILE__, int ln=__LINE__, T...)(T params)