Diff
Not logged in

Differences From Artifact [fafb5e120f10db35]:

To Artifact [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 }