Check-in [2459e9a821]
Not logged in
Overview
SHA1 Hash:2459e9a8211a9a1182de150f2186c647cabf7453
Date: 2010-11-09 23:24:09
User: kinaba
Comment:refactored eof-driven REPL
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified main.d from [81cf3e2a44d63239] to [b29be17d733aa309].

20 Value lastVal; 20 Value lastVal; 21 int lineno = 1; 21 int lineno = 1; 22 int nextlineno = 1; 22 int nextlineno = 1; 23 this() { ctx = createGlobalContext(); } 23 this() { ctx = createGlobalContext(); } 24 24 25 bool tryRun( string s ) 25 bool tryRun( string s ) 26 { 26 { > 27 scope(failure) 27 nextlineno ++; | 28 { buf = ""; lineno = nextlineno; } > 29 28 buf ~= s; 30 buf ~= s; > 31 nextlineno ++; 29 try { | 32 try 30 AST a = parseString(buf, "<REPL>", lineno); | 33 { lastVal = eval(parseString(buf, "<REPL>", lineno), ctx 31 buf = ""; < 32 lineno = nextlineno; | 34 catch( UnexpectedEOF ) 33 lastVal = eval(a, ctx); < 34 } catch( LexException ) { < 35 // always EOF exception, so wait next < 36 return false; | 35 { return false; } // wait 37 } catch( ParseException e ) { < 38 if( find(e.msg, "EOF")!="" ) // ultra ad-hoc < 39 return false; < 40 buf = ""; | 36 buf = ""; 41 lineno = nextlineno; | 37 lineno = nextlineno; 42 throw e; < 43 } < 44 return true; 38 return true; 45 } 39 } 46 40 47 bool singleInteraction() 41 bool singleInteraction() 48 { 42 { 49 writef(">> ", lineno); 43 writef(">> ", lineno); 50 string line = readln(); 44 string line = readln();

Modified polemy/eval.d from [cdb82702a34f8def] to [62b3543f769fc9c9].

175 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 175 assert_eq( r.val, new IntValue(BigInt(21+21*21)) ); 176 assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21+21*21)) ); 176 assert_eq( r.ctx.get("x","@val"), new IntValue(BigInt(21+21*21)) ); 177 assert_nothrow( r.ctx.get("x","@val") ); 177 assert_nothrow( r.ctx.get("x","@val") ); 178 assert_throw!RuntimeException( r.ctx.get("y","@val") ); 178 assert_throw!RuntimeException( r.ctx.get("y","@val") ); 179 } 179 } 180 unittest 180 unittest 181 { 181 { 182 assert_nothrow( evalString(`print("Hello, world!");`) ); < 183 assert_nothrow( evalString(`print(fun(){});`) ); < 184 } < 185 unittest < 186 { < 187 assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(B 182 assert_eq( evalString(`let x=1; let y=(let x=2); x`).val, new IntValue(B 188 assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new 183 assert_eq( evalString(`let x=1; let y=(let x=2;fun(){x}); y()`).val, new 189 } 184 } 190 unittest 185 unittest 191 { 186 { 192 assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt( 187 assert_eq( evalString(`@a x=1; @b x=2; @a(x)`).val, new IntValue(BigInt( 193 assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt( 188 assert_eq( evalString(`@a x=1; @b x=2; @b(x)`).val, new IntValue(BigInt( 194 assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValu 189 assert_eq( evalString(`let x=1; let _ = (@a x=2;2); x`).val, new IntValu 195 assert_throw!Error( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) ); 190 assert_throw!Error( evalString(`let x=1; let _ = (@a x=2;2); @a(x)`) ); 196 } 191 } 197 192 198 unittest 193 unittest 199 { 194 { 200 assert_nothrow( evalString(`var fac = fun(x){ | 195 assert_eq( evalString(`var fac = fun(x){ 201 1; < 202 }; < 203 print(fac(3));`)); < 204 assert_nothrow( evalString(`var fac = fun(x){ < 205 if(x) 196 if(x) 206 { x*fac(x-1); } 197 { x*fac(x-1); } 207 else 198 else 208 { 1; }; 199 { 1; }; 209 }; 200 }; 210 print(fac(10));`)); | 201 fac(10);`).val, new IntValue(BigInt(10*9*8*5040))); 211 assert_nothrow( evalString(`var fib = fun(x){ | 202 assert_eq( evalString(`var fib = fun(x){ 212 if(x<2) 203 if(x<2) 213 { 1; } 204 { 1; } 214 else 205 else 215 { fib(x-1) + fib(x-2); }; 206 { fib(x-1) + fib(x-2); }; 216 }; 207 }; 217 print(fib(10));`)); | 208 fib(10);`).val, new IntValue(BigInt(89))); 218 } 209 }

Modified polemy/lex.d from [a96449f7398ef311] to [1725bdb3bf054565].

7 module polemy.lex; 7 module polemy.lex; 8 import polemy._common; 8 import polemy._common; 9 import std.file : readText; 9 import std.file : readText; 10 import std.ctype : isspace, isalnum; 10 import std.ctype : isspace, isalnum; 11 11 12 /// Exception from this module 12 /// Exception from this module 13 13 14 class LexException : Exception | 14 /*mixin*/ > 15 template ExceptionWithPosition() 15 { 16 { 16 const LexPosition pos; 17 const LexPosition pos; 17 < 18 this( const LexPosition pos, string msg, string file=null, size_t line=0 18 this( const LexPosition pos, string msg, string file=null, size_t line=0 19 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos 19 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos > 20 } > 21 > 22 class UnexpectedEOF : Exception > 23 { > 24 mixin ExceptionWithPosition; > 25 } > 26 > 27 class LexException : Exception > 28 { > 29 mixin ExceptionWithPosition; 20 }; 30 }; 21 31 22 /// Represents a position in a source code 32 /// Represents a position in a source code 23 33 24 class LexPosition 34 class LexPosition 25 { 35 { 26 immutable string filename; /// name of the source file 36 immutable string filename; /// name of the source file ................................................................................................................................................................................ 158 bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } 168 bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } 159 } 169 } 160 170 161 string readQuoted(const LexPosition pos){char[] buf; return readQuoted(p 171 string readQuoted(const LexPosition pos){char[] buf; return readQuoted(p 162 string readQuoted(const LexPosition pos, ref char[] buf) 172 string readQuoted(const LexPosition pos, ref char[] buf) 163 { 173 { 164 if( reader.empty ) 174 if( reader.empty ) 165 throw genex!LexException(pos, "EOF found while lexing a | 175 throw genex!UnexpectedEOF(pos, "Quoted string not termin 166 dchar c = reader.front; 176 dchar c = reader.front; 167 reader.popFront; 177 reader.popFront; 168 if( c == '"' ) 178 if( c == '"' ) 169 return assumeUnique(buf); 179 return assumeUnique(buf); 170 if( c == '\\' && !reader.empty ) { 180 if( c == '\\' && !reader.empty ) { 171 if( reader.front=='"' ) { 181 if( reader.front=='"' ) { 172 reader.popFront; 182 reader.popFront; ................................................................................................................................................................................ 289 assert_eq( lexf.front.str, "import" ); 299 assert_eq( lexf.front.str, "import" ); 290 assert_eq( lexf.front.pos.lineno, 8 ); 300 assert_eq( lexf.front.pos.lineno, 8 ); 291 assert_eq( lexf.front.pos.column, 1 ); 301 assert_eq( lexf.front.pos.column, 1 ); 292 } 302 } 293 303 294 unittest 304 unittest 295 { 305 { 296 assert_throw!LexException( lexerFromString(`"`) ); | 306 assert_throw!UnexpectedEOF( lexerFromString(`"`) ); 297 } 307 } 298 308 299 unittest 309 unittest 300 { 310 { 301 auto lex = lexerFromString(`my # comment should`~"\r\n"~`# hey!! 311 auto lex = lexerFromString(`my # comment should`~"\r\n"~`# hey!! 302 be ignored. 312 be ignored. 303 hahaha"hihihi""hu\\\"huhu"#123 aa 313 hahaha"hihihi""hu\\\"huhu"#123 aa

Modified polemy/parse.d from [fafb5e120f10db35] to [a8c1fd55863166fb].

9 import polemy.lex; 9 import polemy.lex; 10 import polemy.ast; 10 import polemy.ast; 11 11 12 /// Exception from this module 12 /// Exception from this module 13 13 14 class ParseException : Exception 14 class ParseException : Exception 15 { 15 { 16 const LexPosition pos; | 16 mixin ExceptionWithPosition; 17 < 18 this( const LexPosition pos, string msg, string file=null, size_t line=0 < 19 { super(sprintf!"[%s] %s"(pos, msg), file, line, next); this.pos < 20 } 17 } 21 18 22 private auto createException(Lexer)(Lexer lex, string msg) < 23 { return new ParseException(lex.empty?null:lex.front.pos, msg); } < 24 < 25 /// Entry points of this module 19 /// Entry points of this module 26 20 27 auto parseString(S, T...)(S str, T fn_ln_cn) 21 auto parseString(S, T...)(S str, T fn_ln_cn) 28 { return parserFromString(str, fn_ln_cn).parse(); } 22 { return parserFromString(str, fn_ln_cn).parse(); } 29 23 30 auto parseFile(S, T...)(S filename, T ln_cn) 24 auto parseFile(S, T...)(S filename, T ln_cn) 31 { return parserFromFile(filename, ln_cn).parse(); } 25 { return parserFromFile(filename, ln_cn).parse(); } ................................................................................................................................................................................ 46 private class Parser(Lexer) 40 private class Parser(Lexer) 47 if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) 41 if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) 48 { 42 { 49 AST parse() 43 AST parse() 50 { 44 { 51 auto e = Body(); 45 auto e = Body(); 52 if( !lex.empty ) 46 if( !lex.empty ) 53 throw createException(lex, "input is not ended but parse | 47 throw genex!ParseException(currentPosition(), "parsing e 54 return e; 48 return e; 55 } 49 } 56 50 57 AST Body() 51 AST Body() 58 { 52 { 59 if( lex.empty || !lex.front.quoted && lex.front.str=="}" ) | 53 if( lex.empty || !lex.front.quoted && ["}",")","]"].canFind(lex. 60 return doNothingExpression(); 54 return doNothingExpression(); 61 55 62 auto saved = lex.save; 56 auto saved = lex.save; 63 auto pos = lex.front.pos; 57 auto pos = lex.front.pos; 64 string kwd = lex.front.str; 58 string kwd = lex.front.str; 65 if( tryEat("let") || tryEat("var") || tryEat("def") || tryEat("@ 59 if( tryEat("let") || tryEat("var") || tryEat("def") || tryEat("@ 66 { 60 { 67 if( kwd == "@" ) { 61 if( kwd == "@" ) { 68 kwd ~= eatId("after @"); | 62 kwd ~= eatId("after @",true); 69 if( tryEat("(") ) { 63 if( tryEat("(") ) { 70 lex = saved; 64 lex = saved; 71 goto asExpression; 65 goto asExpression; 72 } 66 } 73 } 67 } 74 immutable LexPosition varpos = (lex.empty ? null : lex.f 68 immutable LexPosition varpos = (lex.empty ? null : lex.f 75 string var = eatId("after "~kwd); | 69 string var = eatId("after "~kwd,true); 76 eat("=", "after "~kwd); 70 eat("=", "after "~kwd); 77 kwd = (kwd[0]=='@' ? kwd : ""); // "let, var, def ==> ne 71 kwd = (kwd[0]=='@' ? kwd : ""); // "let, var, def ==> ne 78 auto e = E(0); 72 auto e = E(0); 79 if( tryEat(";") && !lex.empty && (lex.front.quoted || (l | 73 if( tryEat(";") && !lex.empty && (lex.front.quoted || ![ 80 return new LetExpression(pos, var, kwd, e, Body( 74 return new LetExpression(pos, var, kwd, e, Body( 81 else 75 else 82 return new LetExpression(pos, var, kwd, e, new V 76 return new LetExpression(pos, var, kwd, e, new V 83 } 77 } 84 else 78 else 85 { 79 { 86 asExpression: 80 asExpression: 87 auto e = E(0); 81 auto e = E(0); 88 if( tryEat(";") && !lex.empty && (lex.front.quoted || (l 82 if( tryEat(";") && !lex.empty && (lex.front.quoted || (l 89 return new LetExpression(pos, "_", "@val", e, Bo | 83 return new LetExpression(pos, "_", "", e, Body() 90 else 84 else 91 return e; 85 return e; 92 } 86 } 93 } 87 } 94 88 95 // [TODO] make customizable from program 89 // [TODO] make customizable from program 96 static immutable string[][] operator_perferences = [ 90 static immutable string[][] operator_perferences = [ ................................................................................................................................................................................ 134 } 128 } 135 129 136 AST Funcall() 130 AST Funcall() 137 { 131 { 138 auto e = BaseExpression(); 132 auto e = BaseExpression(); 139 while( tryEat("(") ) 133 while( tryEat("(") ) 140 { 134 { > 135 auto pos = currentPosition(); 141 AST[] args; 136 AST[] args; 142 while( !tryEat(")") ) { 137 while( !tryEat(")") ) { 143 if( lex.empty ) 138 if( lex.empty ) 144 throw createException(lex,"Unexpected EO | 139 throw genex!UnexpectedEOF(pos,"Closing ' 145 args ~= E(0); 140 args ~= E(0); 146 if( !tryEat(",") ) { 141 if( !tryEat(",") ) { 147 eat(")", "after function parameters"); 142 eat(")", "after function parameters"); 148 break; 143 break; 149 } 144 } 150 } 145 } 151 e = new FuncallExpression(e.pos, e, args); 146 e = new FuncallExpression(e.pos, e, args); ................................................................................................................................................................................ 152 } 147 } 153 return e; 148 return e; 154 } 149 } 155 150 156 AST BaseExpression() 151 AST BaseExpression() 157 { 152 { 158 if( lex.empty ) 153 if( lex.empty ) 159 throw createException(lex, "Reached EOF when tried to pa | 154 throw genex!UnexpectedEOF(currentPosition(), "Reached EO 160 155 161 auto pos = lex.front.pos; 156 auto pos = lex.front.pos; 162 if( lex.front.quoted ) 157 if( lex.front.quoted ) 163 { 158 { 164 scope(exit) lex.popFront; 159 scope(exit) lex.popFront; 165 return new StrLiteral(pos, lex.front.str); 160 return new StrLiteral(pos, lex.front.str); 166 } 161 } ................................................................................................................................................................................ 230 private: 225 private: 231 Lexer lex; 226 Lexer lex; 232 this(Lexer lex) { this.lex = lex; } 227 this(Lexer lex) { this.lex = lex; } 233 228 234 void eat(string kwd, lazy string msg) 229 void eat(string kwd, lazy string msg) 235 { 230 { 236 if( !tryEat(kwd) ) 231 if( !tryEat(kwd) ) 237 throw createException(lex, "'"~kwd~"' is expected "~msg~ | 232 if( lex.empty ) 238 ~(lex.empty ? "EOF" : lex.front.str)~"' occured" | 233 throw genex!UnexpectedEOF( > 234 currentPosition(), sprintf!"%s is expect > 235 else > 236 throw genex!ParseException( > 237 currentPosition(), sprintf!"%s is expect 239 } 238 } 240 239 241 bool tryEat(string kwd) 240 bool tryEat(string kwd) 242 { 241 { 243 if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) 242 if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) 244 return false; 243 return false; 245 lex.popFront; 244 lex.popFront; 246 return true; 245 return true; 247 } 246 } 248 247 249 string eatId(lazy string msg) | 248 string eatId(lazy string msg, bool allowQuoted=false) 250 { 249 { 251 if( lex.empty || lex.front.quoted ) | 250 if( lex.empty ) 252 throw createException(lex, "identifier is expected but n | 251 throw genex!UnexpectedEOF(currentPosition(), "identifier 253 string id = lex.front.str; | 252 if( !allowQuoted && lex.front.quoted ) > 253 throw genex!ParseException(currentPosition(), "identifie 254 lex.popFront; | 254 scope(exit) lex.popFront; 255 return id; | 255 return lex.front.str; 256 } 256 } 257 257 258 bool isNumber(string s) 258 bool isNumber(string s) 259 { 259 { 260 return find!(`a<'0'||'9'<a`)(s).empty; 260 return find!(`a<'0'||'9'<a`)(s).empty; 261 } 261 } 262 262 263 AST doNothingExpression() 263 AST doNothingExpression() 264 { 264 { 265 return new IntLiteral(lex.empty?null:lex.front.pos, BigInt(178)) | 265 return new IntLiteral(currentPosition(), BigInt(178)); > 266 } > 267 > 268 immutable(LexPosition) currentPosition() > 269 { > 270 return lex.empty ? null : lex.front.pos; 266 } 271 } 267 } 272 } 268 273 269 unittest 274 unittest 270 { 275 { 271 mixin EasyAST; 276 mixin EasyAST; 272 277 273 assert_eq(parseString(`123`), intl(123)); 278 assert_eq(parseString(`123`), intl(123)); 274 assert_eq(parseString(`"foo"`), strl("foo")); 279 assert_eq(parseString(`"foo"`), strl("foo")); 275 assert_eq(parseString(`fun(){1}`), fun([],intl(1))); 280 assert_eq(parseString(`fun(){1}`), fun([],intl(1))); 276 assert_eq(parseString(`fun(x){1}`), fun(["x"],intl(1))); 281 assert_eq(parseString(`fun(x){1}`), fun(["x"],intl(1))); 277 assert_eq(parseString("\u03BB(){1}"), fun([],intl(1))); 282 assert_eq(parseString("\u03BB(){1}"), fun([],intl(1))); 278 assert_eq(parseString("\u03BB(x){1}"), fun(["x"],intl(1))); 283 assert_eq(parseString("\u03BB(x){1}"), fun(["x"],intl(1))); 279 assert_eq(parseString(`1;2`), let("_","@val",intl(1),intl(2))); | 284 assert_eq(parseString(`1;2`), let("_","",intl(1),intl(2))); 280 assert_eq(parseString(`1;2;`), let("_","@val",intl(1),intl(2))); | 285 assert_eq(parseString(`1;2;`), let("_","",intl(1),intl(2))); 281 assert_eq(parseString(`let x=1;2`), let("x","",intl(1),intl(2))); 286 assert_eq(parseString(`let x=1;2`), let("x","",intl(1),intl(2))); 282 assert_eq(parseString(`var x=1;2;`), let("x","",intl(1),intl(2))); 287 assert_eq(parseString(`var x=1;2;`), let("x","",intl(1),intl(2))); 283 assert_eq(parseString(`def x=1`), let("x","",intl(1),var("x"))); 288 assert_eq(parseString(`def x=1`), let("x","",intl(1),var("x"))); 284 assert_eq(parseString(`@val x=1;`), let("x","@val",intl(1),var("x"))); 289 assert_eq(parseString(`@val x=1;`), let("x","@val",intl(1),var("x"))); 285 assert_eq(parseString(`@typ x="#int";`), let("x","@typ",strl("#int"),var 290 assert_eq(parseString(`@typ x="#int";`), let("x","@typ",strl("#int"),var 286 assert_eq(parseString(`f(1,2)`), call(var("f"),intl(1),intl(2))); 291 assert_eq(parseString(`f(1,2)`), call(var("f"),intl(1),intl(2))); 287 assert_eq(parseString(`if(1){2}`), call(var("if"),intl(1),fun([],intl(2) 292 assert_eq(parseString(`if(1){2}`), call(var("if"),intl(1),fun([],intl(2) ................................................................................................................................................................................ 315 call(var("fac"),intl(10)) 320 call(var("fac"),intl(10)) 316 ) 321 ) 317 ); 322 ); 318 } 323 } 319 324 320 unittest 325 unittest 321 { 326 { 322 assert_throw!ParseException(parseString(`1+`)); | 327 assert_throw!UnexpectedEOF(parseString(`1+`)); 323 assert_throw!ParseException(parseString(`1+2}`)); 328 assert_throw!ParseException(parseString(`1+2}`)); 324 assert_throw!ParseException(parseString(`let "x"`)); | 329 assert_throw!UnexpectedEOF(parseString(`let "x"`)); 325 assert_throw!ParseException(parseString(`var`)); | 330 assert_throw!UnexpectedEOF(parseString(`var`)); 326 assert_throw!ParseException(parseString(`@val x ==`)); 331 assert_throw!ParseException(parseString(`@val x ==`)); 327 assert_throw!ParseException(parseString(`if(){1}`)); 332 assert_throw!ParseException(parseString(`if(){1}`)); 328 assert_throw!ParseException(parseString(`f(`)); | 333 assert_throw!UnexpectedEOF(parseString(`f(`)); 329 } 334 }

Modified tricks/test.d from [314aad0104b85557] to [09cc57fcd7c969ca].

13 void assert_throw(ExceptionType, T, string fn=__FILE__, size_t ln=__LINE__)(lazy 13 void assert_throw(ExceptionType, T, string fn=__FILE__, size_t ln=__LINE__)(lazy 14 { 14 { 15 try 15 try 16 { t(); } 16 { t(); } 17 catch(ExceptionType) 17 catch(ExceptionType) 18 { return; } 18 { return; } 19 catch(Throwable e) 19 catch(Throwable e) 20 { onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.to | 20 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception\n > 21 onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption"); | 21 onAssertErrorMsg(fn, ln, msg.length ? msg : "not thrown"); 22 } 22 } 23 23 24 /// Unittest helper that asserts an expression must not throw anything 24 /// Unittest helper that asserts an expression must not throw anything 25 25 26 auto assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string 26 auto assert_nothrow(T, string fn=__FILE__, size_t ln=__LINE__)(lazy T t, string 27 { 27 { 28 try 28 try 29 { return t(); } 29 { return t(); } 30 catch(Throwable e) 30 catch(Throwable e) 31 { onAssertErrorMsg(fn, ln, msg.length ? msg : "exception ["~e.to | 31 { onAssertErrorMsg(fn, ln, msg.length ? msg : "bad exception\n > 32 assert(false); 32 assert(false); 33 } 33 } 34 34 35 unittest 35 unittest 36 { 36 { 37 auto error = {throw new Error("hello");}; 37 auto error = {throw new Error("hello");}; 38 auto nothing = (){}; 38 auto nothing = (){};