Differences From Artifact [fafb5e120f10db35]:
- File
polemy/parse.d
- 2010-11-09 10:28:08 - part of checkin [dc93ad8cf6] on branch trunk - layered exec expression @lay(...) added (user: kinaba) [annotate]
To Artifact [a8c1fd55863166fb]:
- File
polemy/parse.d
- 2010-11-09 14:24:09 - part of checkin [2459e9a821] on branch trunk - refactored eof-driven REPL (user: kinaba) [annotate]
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 }