Check-in [b985f3bf91]
Not logged in
Overview
SHA1 Hash:b985f3bf912b784e838de05d6f794ae2b22f68c9
Date: 2010-11-08 23:59:30
User: kinaba
Comment:refactored parser to change AST to ML-like one.
Timelines: family | ancestors | descendants | both | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | manifest
Tags And Properties
Changes

Modified .poseidon from [0e48df10e4abff23] to [1c3854b81b30b626].

29 <projectFiles> 29 <projectFiles> 30 <source> 30 <source> 31 <name>d2stacktrace\dbghelp.d</name> 31 <name>d2stacktrace\dbghelp.d</name> 32 <name>d2stacktrace\stacktrace.d</name> 32 <name>d2stacktrace\stacktrace.d</name> 33 <name>main.d</name> 33 <name>main.d</name> 34 <name>polemy\_common.d</name> 34 <name>polemy\_common.d</name> 35 <name>polemy\ast.d</name> 35 <name>polemy\ast.d</name> 36 <name>polemy\eval.d</name> < 37 <name>polemy\lex.d</name> 36 <name>polemy\lex.d</name> 38 <name>polemy\parse.d</name> 37 <name>polemy\parse.d</name> 39 <name>polemy\tricks.d</name> 38 <name>polemy\tricks.d</name> 40 <name>polemy\value.d</name> < 41 </source> 39 </source> 42 <interface /> 40 <interface /> 43 <resource /> 41 <resource /> 44 <othersDMD /> 42 <othersDMD /> 45 <others> 43 <others> 46 <name>build.bat</name> 44 <name>build.bat</name> 47 <name>build.sh</name> 45 <name>build.sh</name>

Modified main.d from [e01d02a22ae40e90] to [e7185e89f4df4ae3].

2 * Authors: k.inaba 2 * Authors: k.inaba 3 * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ 3 * License: NYSL 0.9982 (http://www.kmonos.net/nysl/ 4 * 4 * 5 * Entry point for Polemy interpreter. 5 * Entry point for Polemy interpreter. 6 */ 6 */ 7 7 8 import std.stdio; 8 import std.stdio; 9 import polemy.eval; < 10 9 11 version(unittest) static ~this() 10 version(unittest) static ~this() 12 { 11 { 13 writeln( "***********************" ); 12 writeln( "***********************" ); 14 writeln( "* All Tests Passed <3 *" ); 13 writeln( "* All Tests Passed <3 *" ); 15 writeln( "*********************** (Press Enter to finish)" ); 14 writeln( "*********************** (Press Enter to finish)" ); 16 readln(); 15 readln(); 17 } 16 } 18 17 19 void main( string[] args ) 18 void main( string[] args ) 20 { 19 { 21 } 20 }

Modified polemy/ast.d from [f03af1208bc8c434] to [4e37845b6ce5021a].

4 * 4 * 5 * Syntax tree for Polemy programming language. 5 * Syntax tree for Polemy programming language. 6 */ 6 */ 7 module polemy.ast; 7 module polemy.ast; 8 import polemy._common; 8 import polemy._common; 9 import polemy.lex; 9 import polemy.lex; 10 10 11 alias Statement[] Program; < 12 < 13 abstract class Statement | 11 abstract class AST 14 { 12 { 15 immutable LexPosition pos; 13 immutable LexPosition pos; 16 mixin SimpleConstructor; 14 mixin SimpleConstructor; 17 } 15 } 18 16 19 class DeclStatement : Statement < 20 { < 21 string var; < 22 Expression expr; < 23 mixin SimpleClass; < 24 } < 25 < 26 class ExprStatement : Statement < 27 { < 28 Expression expr; < 29 mixin SimpleClass; < 30 } < 31 < 32 abstract class Expression < 33 { < 34 immutable LexPosition pos; < 35 mixin SimpleConstructor; < 36 } < 37 < 38 class StrLiteralExpression : Expression | 17 class StrLiteral : AST 39 { 18 { 40 string data; 19 string data; 41 mixin SimpleClass; 20 mixin SimpleClass; 42 } 21 } 43 22 44 class IntLiteralExpression : Expression | 23 class IntLiteral : AST 45 { 24 { 46 BigInt data; 25 BigInt data; 47 mixin SimpleClass; 26 mixin SimpleClass; > 27 this(immutable LexPosition pos, long n) {super(pos); data = n;} > 28 this(immutable LexPosition pos, BigInt n) {super(pos); data = n;} > 29 this(immutable LexPosition pos, string n) {super(pos); data = BigInt(n); 48 } 30 } 49 31 50 class VarExpression : Expression | 32 class VarExpression : AST 51 { 33 { 52 string var; 34 string var; 53 mixin SimpleClass; 35 mixin SimpleClass; 54 } 36 } 55 37 56 class AssignExpression : Expression | 38 class LetExpression : AST 57 { 39 { 58 Expression lhs; | 40 string var; 59 Expression rhs; | 41 AST init; > 42 AST expr; 60 mixin SimpleClass; 43 mixin SimpleClass; 61 } 44 } 62 45 63 class FuncallExpression : Expression | 46 class FuncallExpression : AST 64 { 47 { 65 Expression fun; | 48 AST fun; 66 Expression[] args; | 49 AST[] args; 67 this(immutable LexPosition pos, Expression fun, Expression[] args...) | 50 this(immutable LexPosition pos, AST fun, AST[] args...) 68 { super(pos); this.fun=fun; this.args=args.dup; } 51 { super(pos); this.fun=fun; this.args=args.dup; } 69 mixin SimpleClass; 52 mixin SimpleClass; 70 } 53 } 71 54 72 class FunLiteralExpression : Expression | 55 class FunLiteral : AST 73 { 56 { 74 string[] params; 57 string[] params; 75 Program funbody; | 58 AST funbody; 76 mixin SimpleClass; 59 mixin SimpleClass; 77 } 60 } 78 61 79 /// Handy Generator for AST nodes. To use this, mixin EasyAst; 62 /// Handy Generator for AST nodes. To use this, mixin EasyAst; 80 63 81 /*mixin*/ 64 /*mixin*/ 82 template EasyAst() | 65 template EasyAST() 83 { 66 { 84 template genEast(T) 67 template genEast(T) 85 { T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } 68 { T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } 86 69 87 alias genEast!DeclStatement decl; | 70 alias genEast!StrLiteral strl; 88 alias genEast!ExprStatement expr; | 71 alias genEast!IntLiteral intl; > 72 auto fun(string[] xs, AST ps) { return genEast!FunLiteral(xs,ps); } 89 alias genEast!VarExpression var; 73 alias genEast!VarExpression var; > 74 alias genEast!LetExpression let; 90 alias genEast!FuncallExpression funcall; | 75 alias genEast!FuncallExpression call; 91 alias genEast!IntLiteralExpression intl; < 92 alias genEast!StrLiteralExpression strl; < 93 alias genEast!FunLiteralExpression fun; < 94 } 76 }

Modified polemy/lex.d from [bee9af8d0f8f7348] to [50586221a28fd499].

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 class LexException : Exception 15 { 15 { 16 this( const LexPosition pos, string msg ) < 17 { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; } < 18 const LexPosition pos; 16 const LexPosition pos; > 17 > 18 private this( const LexPosition pos, string msg ) > 19 { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; } 19 }; 20 }; 20 21 21 /// Represents a position in a source code 22 /// Represents a position in a source code 22 23 23 class LexPosition 24 class LexPosition 24 { 25 { 25 immutable string filename; /// name of the source file 26 immutable string filename; /// name of the source file 26 immutable int lineno; /// line number, 1, 2, ... | 27 immutable int lineno; /// 1-origin 27 immutable int column; /// column, 1, 2, ... | 28 immutable int column; /// 1-origin 28 29 29 override string toString() const 30 override string toString() const 30 { return sprintf!"%s:%d:%d"(filename, lineno, column); } 31 { return sprintf!"%s:%d:%d"(filename, lineno, column); } 31 32 32 mixin SimpleConstructor; 33 mixin SimpleConstructor; 33 mixin SimpleCompare; 34 mixin SimpleCompare; 34 35 ................................................................................................................................................................................ 83 84 84 assert( !__traits(compiles, new Token) ); 85 assert( !__traits(compiles, new Token) ); 85 assert( !__traits(compiles, t.pos=p) ); 86 assert( !__traits(compiles, t.pos=p) ); 86 assert( !__traits(compiles, t.str=789) ); 87 assert( !__traits(compiles, t.str=789) ); 87 assert( !__traits(compiles, t.quoted=true) ); 88 assert( !__traits(compiles, t.quoted=true) ); 88 } 89 } 89 90 90 /// Named Construtor for Lexer | 91 /// Named Construtors for Lexer 91 92 92 auto lexerFromFile(T...)( string filename, T rest ) 93 auto lexerFromFile(T...)( string filename, T rest ) 93 { 94 { 94 return lexerFromString( std.file.readText(filename), filename, rest ); 95 return lexerFromString( std.file.readText(filename), filename, rest ); 95 } 96 } 96 97 97 /// Named Construtor for Lexer < 98 < 99 auto lexerFromString(CharSeq)( CharSeq str, string filename="<unnamed>", int lin 98 auto lexerFromString(CharSeq)( CharSeq str, string filename="<unnamed>", int lin 100 { 99 { 101 return new LexerT!(PositionedReader!CharSeq)( 100 return new LexerT!(PositionedReader!CharSeq)( 102 PositionedReader!CharSeq(str, filename, lineno, column) 101 PositionedReader!CharSeq(str, filename, lineno, column) 103 ); 102 ); 104 } 103 } 105 104 106 /// Standard Lexer Type (all users have to know is that this is a forward range | 105 /// Standard Lexer Type (all you have to know is that this is a forward range of 107 106 108 alias LexerT!(PositionedReader!string) Lexer; 107 alias LexerT!(PositionedReader!string) Lexer; 109 108 110 /// Lexer Implementation 109 /// Lexer Implementation 111 110 112 class LexerT(Reader) 111 class LexerT(Reader) 113 if( isForwardRange!(Reader) && is(ElementType!(Reader) == dchar) ) 112 if( isForwardRange!(Reader) && is(ElementType!(Reader) == dchar) )

Modified polemy/parse.d from [51dd3bd106fd9ecb] to [10baa46251b8a0b6].

5 * Parser for Polemy programming language 5 * Parser for Polemy programming language 6 */ 6 */ 7 module polemy.parse; 7 module polemy.parse; 8 import polemy._common; 8 import polemy._common; 9 import polemy.lex; 9 import polemy.lex; 10 import polemy.ast; 10 import polemy.ast; 11 11 12 /// Parsing Failure | 12 /// Exception from this module 13 13 14 class ParserException : Exception | 14 class ParseException : Exception 15 { 15 { 16 private: | 16 const LexPosition pos; 17 this(string msg) { super(msg); } < 18 static ParserException create(Lexer)(Lexer lex, string msg) < 19 { | 17 20 return new ParserException(sprintf!"[%s] %s"( < 21 lex.empty ? "EOF" : to!string(lex.front.pos), msg)); < 22 } < > 18 private this( const LexPosition pos, string msg ) > 19 { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; } 23 } 20 } > 21 > 22 private auto createException(Lexer)(Lexer lex, string msg) > 23 { return new ParseException(lex.empty?null:lex.front.pos, msg); } > 24 > 25 /// Entry point of this module > 26 > 27 auto parseString(S, T...)(S str, T fn_ln_cn) > 28 { return parserFromString(str, fn_ln_cn).parse(); } > 29 > 30 auto parseFile(S, T...)(S filename,T ln_cn) > 31 { return parserFromString(filename, ln_cn).parse(); } 24 32 25 /// Named Constructor of Parser 33 /// Named Constructor of Parser 26 34 27 auto parserFromLexer(Lexer)(Lexer lex) | 35 private auto parserFromLexer(Lexer)(Lexer lex) 28 { < 29 return new Parser!Lexer(lex); | 36 { return new Parser!Lexer(lex); } 30 } < 31 37 32 /// Named Constructor of Parser (just fwd to lexerFromString) | 38 private auto parserFromString(T...)(T params) > 39 { return parserFromLexer(polemy.lex.lexerFromString(params)); } 33 40 34 auto parserFromString(T...)(T params) < 35 { < 36 return parserFromLexer(polemy.lex.lexerFromString(params)); < 37 } < 38 < 39 /// Named Constructor of Parser (just fwd to lexerFromFile) < 40 < 41 auto parserFromFile(T...)(T params) | 41 private auto parserFromFile(T...)(T params) 42 { < 43 return parserFromLexer(polemy.lex.lexerFromFile(params)); | 42 { return parserFromLexer(polemy.lex.lexerFromFile(params)); } 44 } < 45 43 46 /// Parser 44 /// Parser 47 45 48 class Parser(Lexer) | 46 private class Parser(Lexer) > 47 if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) ) 49 { 48 { 50 this(Lexer lex) | 49 AST parse() 51 { 50 { 52 this.lex = lex; | 51 auto e = Body(); 53 } < 54 < 55 Program parseProgram() < 56 { < 57 Program p = parseStatements(); < 58 if( !lex.empty ) { | 52 if( !lex.empty ) 59 auto e = ParserException.create(lex, "cannot reach eof") < 60 throw e; < 61 } < > 53 throw createException(lex, "input is not ended but parse 62 return p; | 54 return e; 63 } 55 } 64 56 65 Program parseStatements() | 57 AST Body() 66 { 58 { 67 Program p; | 59 if( lex.empty || !lex.front.quoted && lex.front.str=="}" ) 68 while( !lex.empty && (lex.front.quoted || lex.front.str!="}") ) < 69 p ~= parseStatement(); < 70 return p; | 60 return doNothingExpression(); 71 } < 72 61 73 Statement parseStatement() < 74 { < 75 auto saved = lex.save; < 76 scope(failure) lex = saved; < 77 < 78 if( lex.empty ) < 79 throw new ParserException("EOF during parsing a statemen < 80 auto pos = lex.front.pos; 62 auto pos = lex.front.pos; 81 < 82 if( !lex.front.quoted && lex.front.str=="var" ) < > 63 if( tryEat("var") ) 83 { 64 { 84 // "var" Var "=" Expression ";" | 65 immutable LexPosition varpos = (lex.empty ? null : lex.f 85 lex.popFront; < 86 string var = lex.front.str; | 66 string var = eatId("after var"); 87 lex.popFront; < 88 eat("=", "for variable declaration"); | 67 eat("=", "after var"); > 68 auto e = E(0); > 69 if( tryEat(";") && !lex.empty && (lex.front.quoted || (l 89 auto parsed = new DeclStatement(pos, var, parseExpressio | 70 return new LetExpression(pos, var, e, Body()); 90 eat(";", "after variable declaration"); | 71 else 91 return parsed; | 72 return new LetExpression(pos, var, e, new VarExp 92 } 73 } 93 else 74 else 94 { 75 { 95 // Expression ";" | 76 auto e = E(0); 96 auto parsed = new ExprStatement(pos, parseExpression()); | 77 if( tryEat(";") && !lex.empty && (lex.front.quoted || (l 97 eat(";", "after statement"); | 78 return new LetExpression(pos, "_", e, Body()); > 79 else 98 return parsed; | 80 return e; 99 } 81 } 100 } 82 } 101 83 102 Expression parseExpression() | 84 // [TODO] make customizable from program 103 { < 104 auto saved = lex.save; < 105 scope(failure) lex = saved; < 106 return parseE(0); < 107 } < 108 < 109 // [TODO] multi-char operators are not supported by the lexer... < 110 static immutable string[][] operator_perferences = [ 85 static immutable string[][] operator_perferences = [ 111 ["="], | 86 ["||"], 112 ["or"], | 87 ["&&"], 113 ["and"], < 114 ["!="], 88 ["!="], 115 ["=="], 89 ["=="], 116 ["<","<=",">",">="], 90 ["<","<=",">",">="], 117 ["|"], 91 ["|"], 118 ["^"], 92 ["^"], 119 ["&"], 93 ["&"], 120 ["<<", ">>"], 94 ["<<", ">>"], 121 ["+","-"], 95 ["+","-"], > 96 ["~"], 122 ["*","/","%"] | 97 ["*","/","%"], > 98 ["^^"] 123 ]; 99 ]; 124 100 125 Expression parseE(int level = 0) | 101 AST E(int level) 126 { 102 { 127 if( operator_perferences.length <= level ) 103 if( operator_perferences.length <= level ) 128 return parseBaseExpression(); | 104 return Funcall(); 129 else 105 else 130 { 106 { 131 auto ops = operator_perferences[level]; 107 auto ops = operator_perferences[level]; 132 auto e = parseE(level+1); | 108 auto e = E(level+1); 133 seq: 109 seq: 134 while( !lex.empty ) 110 while( !lex.empty ) 135 { 111 { 136 auto pos = lex.front.pos; 112 auto pos = lex.front.pos; 137 foreach(op; ops) 113 foreach(op; ops) 138 if( tryEat(op) ) 114 if( tryEat(op) ) 139 { 115 { 140 if( op == "=" ) // right assoc < 141 return new AssignExpress < 142 else < 143 e = new FuncallExpressio | 116 e = new FuncallExpression(e.pos, 144 continue seq; 117 continue seq; 145 } 118 } 146 break; 119 break; 147 } 120 } 148 return e; 121 return e; 149 } 122 } 150 } 123 } 151 124 152 Expression parseBaseExpression() | 125 AST Funcall() 153 { 126 { 154 if( lex.empty ) < 155 throw new ParserException("EOF during parsing an express < 156 auto pos = lex.front.pos; < 157 Expression e = parseBaseBaseExpression(); | 127 auto e = BaseExpression(); 158 while( tryEat("(") ) // funcall | 128 while( tryEat("(") ) 159 { 129 { 160 Expression[] args; | 130 AST[] args; 161 while( !tryEat(")") ) { 131 while( !tryEat(")") ) { 162 if( lex.empty ) { | 132 if( lex.empty ) 163 auto ex = ParserException.create(lex,"Un | 133 throw createException(lex,"Unexpected EO 164 throw ex; < 165 } < 166 args ~= parseE(); | 134 args ~= E(0); 167 if( !tryEat(",") ) { 135 if( !tryEat(",") ) { 168 eat(")", "after function parameters"); 136 eat(")", "after function parameters"); 169 break; 137 break; 170 } 138 } 171 } 139 } 172 e = new FuncallExpression(pos, e, args); | 140 e = new FuncallExpression(e.pos, e, args); 173 } 141 } 174 return e; 142 return e; 175 } 143 } 176 144 177 Expression parseBaseBaseExpression() | 145 AST BaseExpression() 178 { 146 { 179 if( lex.empty ) 147 if( lex.empty ) 180 throw new ParserException("EOF during parsing an express | 148 throw createException(lex, "Reached EOF when tried to pa > 149 181 auto pos = lex.front.pos; 150 auto pos = lex.front.pos; 182 < 183 if( lex.front.quoted ) 151 if( lex.front.quoted ) 184 { 152 { 185 scope(exit) lex.popFront; 153 scope(exit) lex.popFront; 186 return new StrLiteralExpression(pos, lex.front.str); | 154 return new StrLiteral(pos, lex.front.str); 187 } 155 } 188 if( isNumber(lex.front.str) ) // is_number | 156 if( isNumber(lex.front.str) ) 189 { 157 { 190 scope(exit) lex.popFront; 158 scope(exit) lex.popFront; 191 return new IntLiteralExpression(pos, BigInt(cast(string) | 159 return new IntLiteral(pos, BigInt(cast(string)lex.front. 192 } 160 } 193 if( tryEat("(") ) 161 if( tryEat("(") ) 194 { 162 { 195 auto e = parseE(); | 163 auto e = Body(); 196 eat(")", "after parenthesized expression"); 164 eat(")", "after parenthesized expression"); 197 return e; 165 return e; 198 } 166 } 199 if( tryEat("if") ) 167 if( tryEat("if") ) 200 { 168 { 201 eat("(", "after if"); 169 eat("(", "after if"); 202 auto cond = parseE(); | 170 auto cond = E(0); 203 eat(")", "after if condition"); 171 eat(")", "after if condition"); 204 auto thenPos = lex.front.pos; 172 auto thenPos = lex.front.pos; 205 eat("{", "after if condition"); 173 eat("{", "after if condition"); 206 Statement[] th = parseStatements(); | 174 auto th = Body(); 207 eat("}", "after if-then body"); 175 eat("}", "after if-then body"); 208 Statement[] el; | 176 auto el = doNothingExpression(); 209 auto elsePos = lex.front.pos; | 177 auto elsePos = (lex.empty ? LexPosition.dummy : lex.fron 210 if( tryEat("else") ) { 178 if( tryEat("else") ) { 211 eat("{", "after else"); 179 eat("{", "after else"); 212 el = parseStatements(); | 180 el = Body(); 213 eat("}", "after else body"); 181 eat("}", "after else body"); 214 } 182 } 215 return new FuncallExpression(pos, 183 return new FuncallExpression(pos, 216 new VarExpression(pos, "if"), 184 new VarExpression(pos, "if"), 217 cond, 185 cond, 218 new FunLiteralExpression(thenPos, [], th), | 186 new FunLiteral(thenPos, [], th), 219 new FunLiteralExpression(elsePos, [], el) | 187 new FunLiteral(elsePos, [], el) 220 ); 188 ); 221 } 189 } 222 < 223 if( tryEat("fun") ) 190 if( tryEat("fun") ) 224 { 191 { 225 eat("(", "after fun"); 192 eat("(", "after fun"); 226 string[] params; 193 string[] params; 227 while(!tryEat(")")) | 194 while( !tryEat(")") ) 228 { 195 { 229 if( lex.empty ) { | 196 params ~= eatId("for function parameter"); 230 auto e = ParserException.create(lex,"Une < 231 throw e; < 232 } < 233 if( lex.front.quoted ) { < 234 auto e = ParserException.create(lex,"Ide < 235 throw e; < 236 } < 237 params ~= lex.front.str; < 238 lex.popFront; < 239 if( !tryEat(",") ) { 197 if( !tryEat(",") ) { 240 eat(")", "after function parameters"); 198 eat(")", "after function parameters"); 241 break; 199 break; 242 } 200 } 243 } 201 } 244 eat("{", "after function parameters"); 202 eat("{", "after function parameters"); 245 Statement[] funbody; | 203 auto funbody = Body(); 246 while(!tryEat("}")) { | 204 eat("}", "after function body"); 247 if( lex.empty ) { < 248 auto e = ParserException.create(lex,"Une < 249 throw e; < 250 } < 251 funbody ~= parseStatement(); < 252 } < 253 return new FunLiteralExpression(pos, params, funbody); | 205 return new FunLiteral(pos, params, funbody); 254 } 206 } 255 scope(exit) lex.popFront; 207 scope(exit) lex.popFront; 256 return new VarExpression(pos, lex.front.str); 208 return new VarExpression(pos, lex.front.str); 257 } 209 } 258 210 259 private: 211 private: 260 Lexer lex; 212 Lexer lex; > 213 this(Lexer lex) { this.lex = lex; } 261 214 262 void eat(string kwd, lazy string msg) 215 void eat(string kwd, lazy string msg) 263 { 216 { 264 if( !tryEat(kwd) ) 217 if( !tryEat(kwd) ) 265 { < 266 auto e = ParserException.create(lex, "'"~kwd~"' is expec | 218 throw createException(lex, "'"~kwd~"' is expected "~msg~ 267 ~(lex.empty ? "EOF" : lex.front.str)~"' occured" 219 ~(lex.empty ? "EOF" : lex.front.str)~"' occured" 268 throw e; < 269 } < 270 } 220 } 271 221 272 bool tryEat(string kwd) 222 bool tryEat(string kwd) 273 { 223 { 274 if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) 224 if( lex.empty || lex.front.quoted || lex.front.str!=kwd ) 275 return false; 225 return false; 276 lex.popFront; 226 lex.popFront; 277 return true; 227 return true; 278 } 228 } > 229 > 230 string eatId(lazy string msg) > 231 { > 232 if( lex.empty || lex.front.quoted ) > 233 throw createException(lex, "identifier is expected but n > 234 string id = lex.front.str; > 235 lex.popFront; > 236 return id; > 237 } 279 238 280 bool isNumber(string s) 239 bool isNumber(string s) 281 { 240 { 282 return find!(`a<'0'||'9'<a`)(s).empty; 241 return find!(`a<'0'||'9'<a`)(s).empty; 283 } 242 } 284 } < 285 243 286 unittest | 244 AST doNothingExpression() 287 { | 245 { 288 auto p = parserFromString(` | 246 return new IntLiteral(lex.empty?null:lex.front.pos, BigInt(178)) 289 var x = 100; < 290 var y = 200; < 291 `); < 292 Program prog = p.parseProgram(); < 293 assert( prog.length == 2 ); < 294 auto p0 = cast(DeclStatement)prog[0]; < 295 auto p1 = cast(DeclStatement)prog[1]; < 296 assert( p0.var == "x" ); < 297 assert( p1.var == "y" ); < 298 assert( (cast(IntLiteralExpression)p0.expr).data == 100 ); < 299 assert( (cast(IntLiteralExpression)p1.expr).data == 200 ); < > 247 } 300 } 248 } 301 249 302 unittest 250 unittest 303 { 251 { 304 auto p = parserFromString(` | 252 mixin EasyAST; 305 var zzz = 100; # comment < > 253 306 zzz = zzz + zzz * "fo\no"; # comment | 254 assert_eq(parseString(`123`), intl(123)); 307 42; < > 255 assert_eq(parseString(`"foo"`), strl("foo")); 308 `); | 256 assert_eq(parseString(`fun(){1}`), fun([],intl(1))); > 257 assert_eq(parseString(`fun(x){1}`), fun(["x"],intl(1))); > 258 assert_eq(parseString(`1;2`), let("_",intl(1),intl(2))); > 259 assert_eq(parseString(`1;2;`), let("_",intl(1),intl(2))); > 260 assert_eq(parseString(`var x=1;2`), let("x",intl(1),intl(2))); > 261 assert_eq(parseString(`var x=1;2;`), let("x",intl(1),intl(2))); > 262 assert_eq(parseString(`var x=1`), let("x",intl(1),var("x"))); > 263 assert_eq(parseString(`var x=1;`), let("x",intl(1),var("x"))); > 264 assert_eq(parseString(`f(1,2)`), call(var("f"),intl(1),intl(2))); > 265 assert_eq(parseString(`if(1){2}`), call(var("if"),intl(1),fun([],intl(2) > 266 assert_eq(parseString(`if(1){2}else{3}`), call(var("if"),intl(1),fun([], > 267 assert_eq(parseString(`if(1){}else{3}()()`), > 268 call(call(call(var("if"),intl(1),fun([],intl(178)),fun([],intl(3 > 269 assert_eq(parseString(`1+2*3`), call(var("+"),intl(1),call(var("*"),intl > 270 assert_eq(parseString(`(1+2)*3`), call(var("*"),call(var("+"),intl(1),in > 271 assert_eq(parseString(`1*(2+3)`), call(var("*"),intl(1),call(var("+"),in > 272 assert_eq(parseString(`1*2+3`), call(var("+"),call(var("*"),intl(1),intl 309 273 310 mixin EasyAst; | 274 assert_eq(parseString(` 311 auto s0 = decl("zzz", intl(BigInt(100))); | 275 var x = 100; #comment 312 auto s1 = expr( new AssignExpression(null, | 276 var y = 200; #comment!!!!! 313 new VarExpression(null, "zzz"), | 277 x+y 314 new FuncallExpression(null, new VarExpression(null,"+"), | 278 `), 315 new VarExpression(null, "zzz"), | 279 let("x", intl(100), let("y", intl(200), call(var("+"), var("x"), 316 new FuncallExpression(null, new VarExpression(null,"*"), | 280 ); 317 new VarExpression(null, "zzz"), < 318 new StrLiteralExpression(null, "fo\\no") < 319 )))); < 320 auto s2 = new ExprStatement(null, new IntLiteralExpression(null, BigInt( < 321 281 322 Program prog = p.parseProgram(); | 282 assert_eq(parseString(` 323 assert( prog.length == 3 ); | 283 var fac = fun(x){ if(x <= 1) {1} else {x*fac(x-1)} }; 324 assert( prog[0] == s0 ); | 284 fac(10) 325 assert( prog[1] == s1 ); | 285 `), 326 assert( prog[2] == s2 ); | 286 let("fac", fun(["x"], > 287 call(var("if"), > 288 call(var("<="), var("x"), intl(1)), > 289 fun([], intl(1)), > 290 fun([], call(var("*"), var("x"), call(var("fac") > 291 )), > 292 call(var("fac"),intl(10)) > 293 ) > 294 ); 327 } 295 } 328 296 329 unittest 297 unittest 330 { 298 { 331 auto p = parserFromString(` | 299 assert_throw!ParseException(parseString(`1+`)); 332 var f = fun(x,y){x+y;}; | 300 assert_throw!ParseException(parseString(`1+2}`)); 333 f(1,fun(abc){}(4)); | 301 assert_throw!ParseException(parseString(`var "x"`)); 334 `); | 302 assert_throw!ParseException(parseString(`var`)); 335 mixin EasyAst; | 303 assert_throw!ParseException(parseString(`var x ==`)); 336 Program prog = p.parseProgram(); | 304 assert_throw!ParseException(parseString(`if(){1}`)); 337 assert( prog.length == 2 ); | 305 assert_throw!ParseException(parseString(`f(`)); 338 assert( prog[0] == decl("f", fun( < 339 ["x","y"], [expr(funcall(var("+"), var("x"), var("y")))] < 340 ))); < 341 assert( prog[1] == expr(funcall(var("f"), < 342 intl(BigInt(1)), < 343 funcall( < 344 fun(["abc"], cast(Statement[])[]), < 345 intl(BigInt(4)) < 346 )))); < 347 } < 348 < 349 unittest < 350 { < 351 auto p = parserFromString(`var x = 1; var f = fun(){x=x+1;}; f(); f(); x < 352 Program prog = p.parseProgram(); < 353 } < 354 < 355 unittest < 356 { < 357 auto p = parserFromString(`if(x<2){1;}else{x;};`); < 358 Program prog = p.parseProgram(); < 359 assert( prog[0] == new ExprStatement(null, new FuncallExpression(null, < 360 new VarExpression(null, "if"), < 361 new FuncallExpression(null, new VarExpression(null,"<"), new Var < 362 new IntLiteralExpression(null, BigInt(2))), < 363 new FunLiteralExpression(null, [], [new ExprStatement(null, new < 364 new FunLiteralExpression(null, [], [new ExprStatement(null, new < 365 ))); < 366 } 306 }