Index: .poseidon ================================================================== --- .poseidon +++ .poseidon @@ -32,10 +32,11 @@ d2stacktrace\stacktrace.d main.d polemy\_common.d polemy\ast.d polemy\eval.d + polemy\failure.d polemy\lex.d polemy\parse.d polemy\value.d tricks\test.d tricks\tricks.d Index: doc/candydoc/modules.ddoc ================================================================== --- doc/candydoc/modules.ddoc +++ doc/candydoc/modules.ddoc @@ -1,10 +1,11 @@ MODULES = $(MODULE main) $(MODULE tricks.tricks) $(MODULE tricks.test) $(MODULE polemy._common) + $(MODULE polemy.failure) $(MODULE polemy.lex) $(MODULE polemy.parse) $(MODULE polemy.ast) $(MODULE polemy.eval) $(MODULE polemy.value) Index: main.d ================================================================== --- main.d +++ main.d @@ -1,33 +1,75 @@ /** * Authors: k.inaba - * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ + * License: NYSL 0.9982 (http://www.kmonos.net/nysl/) * * Entry point for Polemy interpreter. */ - +module main; import std.stdio; import std.algorithm; +import std.array; import polemy.value; -import polemy.lex; +import polemy.failure; import polemy.parse; import polemy.ast; import polemy.eval; -/// Tenuki Read-Eval-Print-Loop +enum VersionNoMajor = 0; +enum VersionNoMinor = 1; +enum VersionNoRev = 0; + +/// Read-Eval-Print-Loop + class REPL { + /// Load the prelude environment + this() + { + ctx = createGlobalContext(); + } + + /// Print the version number etc. + void greet() + { + writefln("Welcome to Polemy %d.%d.%d", VersionNoMajor, VersionNoMinor, VersionNoRev); + } + + /// Run one file on the global scope + void runFile(string filename) + { + eval(parseFile(filename), ctx, false, "@v"); + } + + /// Repeat the singleInteraction + void replLoop() + { + while( singleInteraction() ) {} + } + + /// Read one line from stdin, and do some reaction + 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; + } + +private: Table ctx; string buf; Value lastVal; int lineno = 1; int nextlineno = 1; - this() { ctx = createGlobalContext(); } - this(string filename) { - ctx = createGlobalContext(); - eval(parseFile(filename), ctx, false, "@v"); - } bool tryRun( string s ) { scope(failure) { buf = ""; lineno = nextlineno; } @@ -40,50 +82,49 @@ { return false; } // wait buf = ""; lineno = nextlineno; return true; } +} + +/// Advance args[] to point the argument list fed to the script. +/// Returns the name of the source file to run, or returns "" if +/// no filename was given. Also, returns to libs[] the list of +/// library source to load. + +string parseArgv(ref string[] args, out string[] libs) +{ + args.popFront(); - bool singleInteraction() - { - writef(">> ", lineno); - string line = readln(); - if( line.startsWith("exit") || line.startsWith("quit") ) - return false; - try { - if( tryRun(line) ) - { - // for debugging. - //try { - // writeln(tableToAST("@v", cast(Table)lastVal)); - //} catch(Throwable e) { - // writeln(e); - //} - writeln(lastVal); - } - } catch(Throwable e) { - writeln(e); + while( !args.empty && args.front=="-l" ) { + args.popFront(); + if( !args.empty ) { + libs ~= args.front(); + args.popFront(); } - return true; + } + + if( args.empty ) + return ""; + else { + scope(exit) args.popFront; + return args.front; } } -/// Entry point. If args.length==1, invoke REPL. -/// If args.length==3 && args[1]=="-l" read args[2] and invoke REPL. -/// Otherwise interpret the argument as a filename. +/// Entry point. + void main( string[] args ) { - if( args.length <= 1 ) - { - writeln("Welcome to Polemy 0.1.0"); - for(auto r = new REPL; r.singleInteraction();) {} - } - else if( args.length>=3 && args[1]=="-l" ) - { - writeln("Welcome to Polemy 0.1.0"); - for(auto r = new REPL(args[2]); r.singleInteraction();) {} - } + string[] libs; + string src = parseArgv(args, libs); + + auto r = new REPL; + if( src.empty ) + r.greet(); + foreach(lb; libs) + r.runFile(lb); + if( src.empty ) + r.replLoop(); else - { - evalFile(args[1]); - } + r.runFile(src); } Index: polemy/_common.d ================================================================== --- polemy/_common.d +++ polemy/_common.d @@ -11,6 +11,6 @@ public import std.array; public import std.bigint; public import std.conv : text; public import std.exception; public import std.range; -public import std.stdio : writeln; // for debugging... +public import std.stdio : DBG = writeln; Index: polemy/ast.d ================================================================== --- polemy/ast.d +++ polemy/ast.d @@ -4,11 +4,11 @@ * * Syntax tree for Polemy programming language. */ module polemy.ast; import polemy._common; -import polemy.lex; +import polemy.failure; /// abstract class AST { immutable LexPosition pos; Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -4,15 +4,15 @@ * * Evaluator for Polemy programming language. */ module polemy.eval; import polemy._common; -import polemy.lex : LexPosition; +import polemy.failure; import polemy.ast; import polemy.parse; import polemy.value; -import std.typecons; +import std.typecons; import std.stdio; /// Table createGlobalContext() { ADDED polemy/failure.d Index: polemy/failure.d ================================================================== --- polemy/failure.d +++ polemy/failure.d @@ -0,0 +1,64 @@ +/** + * Authors: k.inaba + * License: NYSL 0.9982 http://www.kmonos.net/nysl/ + * + * Error Information for Polemy Programming Language + */ +module polemy.failure; +import polemy._common; + +/// Represents a position in source codes + +class LexPosition +{ + immutable string filename; /// name of the source file + immutable int lineno; /// 1-origin + immutable int column; /// 1-origin + + mixin SimpleClass; + override string toString() const + { + return sprintf!("%s:%d:%d")(filename, lineno, column); + } + + static immutable LexPosition dummy; + static this(){ dummy = new immutable(LexPosition)("",0,0); } +} + +unittest +{ + auto p = new LexPosition("hello.cpp", 123, 45); + + assert_eq( p.filename, "hello.cpp" ); + assert_eq( p.lineno, 123 ); + assert_eq( p.column, 45 ); + assert_eq( text(p), "hello.cpp:123:45" ); + + 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 ); +} + +/*mixin*/ +template ExceptionWithPosition() +{ + const LexPosition pos; + this( const LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null ) + { + if(pos is null) + super(sprintf!("[???????] %s")(msg), file, line, next); + else + super(sprintf!("[%s] %s")(pos, msg), file, line, next); + this.pos = pos; + } +} + +class UnexpectedEOF : Exception { mixin ExceptionWithPosition; } /// EOF during lexing/parsing +class LexException : Exception { mixin ExceptionWithPosition; } /// Lexer errors +class ParseException : Exception { mixin ExceptionWithPosition; } /// Parser errors +class RuntimeException : Exception { mixin ExceptionWithPosition; } /// Evaluator errors Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -3,77 +3,15 @@ * License: NYSL 0.9982 http://www.kmonos.net/nysl/ * * Lexer for Polemy programming language. */ module polemy.lex; -import polemy._common; +import polemy._common; +import polemy.failure; import std.file : readText; import std.ctype : isspace, isalnum; -/*mixin*/ -template ExceptionWithPosition() -{ - const LexPosition pos; - this( const LexPosition pos, string msg, string file=null, size_t line=0, Throwable next=null ) - { - if(pos is null) - super(sprintf!"[??] %s"(msg), file, line, next); - else - super(sprintf!"[%s] %s"(pos, msg), file, line, next); - this.pos = pos; - } -} - -/// Thrown when encountered an EOF in the middle of a lexical token - -class UnexpectedEOF : Exception -{ - mixin ExceptionWithPosition; -} - -/// Thrown when encountered a lexical error - -class LexException : Exception -{ - mixin ExceptionWithPosition; -}; - -/// Represents a position in source codes - -class LexPosition -{ - immutable string filename; /// name of the source file - immutable int lineno; /// 1-origin - immutable int column; /// 1-origin - - mixin SimpleClass; - override string toString() const - { return sprintf!"%s:%d:%d"(filename, lineno, column); } - - static immutable LexPosition dummy; - static this(){ dummy = new immutable(LexPosition)("",0,0); } -} - -unittest -{ - auto p = new LexPosition("hello.cpp", 123, 45); - - assert_eq( p.filename, "hello.cpp" ); - assert_eq( p.lineno, 123 ); - assert_eq( p.column, 45 ); - assert_eq( text(p), "hello.cpp:123:45" ); - - 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 { immutable LexPosition pos; /// Position where the token occurred in the source Index: polemy/parse.d ================================================================== --- polemy/parse.d +++ polemy/parse.d @@ -4,20 +4,14 @@ * * Parser for Polemy programming language */ module polemy.parse; import polemy._common; +import polemy.failure; import polemy.lex; import polemy.ast; -/// Thrown when encountered a syntax error - -class ParseException : Exception -{ - mixin ExceptionWithPosition; -} - /// Parse a string and return its AST /// Throws: ParseException, LexException, UnexpectedEOF AST parseString(S, T...)(S str, T fn_ln_cn) { Index: polemy/value.d ================================================================== --- polemy/value.d +++ polemy/value.d @@ -4,20 +4,13 @@ * * Runtime data structures for Polemy programming language. */ module polemy.value; import polemy._common; -import polemy.lex; +import polemy.failure; import polemy.ast; -/// Raised when something went wrong in runtime - -class RuntimeException : Exception -{ - mixin ExceptionWithPosition; -} - /// Runtime values of Polemy abstract class Value { } Index: readme.txt ================================================================== --- readme.txt +++ readme.txt @@ -48,10 +48,13 @@ executes foo.pmy > polemy -l foo.pmy after executing foo.pmy, starts REPL + > polemy -l foo.pmy -l bar.pmy buz.pmy + executes foo.pmy, bar.bmy, and then buz.pmy + <> Comment is "# ... \n"