Diff
Not logged in

Differences From Artifact [fafb5e120f10db35]:

To Artifact [a8c1fd55863166fb]:


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