4198578702 2010-11-07 kinaba: /** 4198578702 2010-11-07 kinaba: * Authors: k.inaba 4198578702 2010-11-07 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ 4198578702 2010-11-07 kinaba: * 4198578702 2010-11-07 kinaba: * Lexer for Polemy programming language. 4198578702 2010-11-07 kinaba: */ 423f308350 2010-11-07 kinaba: module polemy.lex; 423f308350 2010-11-07 kinaba: import polemy._common; 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: import std.file : readText; 423f308350 2010-11-07 kinaba: import std.string : munch; 423f308350 2010-11-07 kinaba: import std.ctype; 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Represents a position in a source code 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: class LexPosition 423f308350 2010-11-07 kinaba: { 4198578702 2010-11-07 kinaba: immutable string filename; /// name of the source file 4198578702 2010-11-07 kinaba: immutable int lineno; /// line number, 1, 2, ... 4198578702 2010-11-07 kinaba: immutable int column; /// column, 1, 2, ... 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: override string toString() const 423f308350 2010-11-07 kinaba: { return sprintf!"%s:%d:%d"(filename, lineno, column); } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: mixin SimpleConstructor; 423f308350 2010-11-07 kinaba: mixin SimpleCompare; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto p = new LexPosition("hello.cpp", 123, 45); 423f308350 2010-11-07 kinaba: auto q = new LexPosition("hello.cpp", 123, 46); 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: assert_eq( p.filename, "hello.cpp" ); 61998c472a 2010-11-08 kinaba: assert_eq( p.lineno, 123 ); 61998c472a 2010-11-08 kinaba: assert_eq( p.column, 45 ); 61998c472a 2010-11-08 kinaba: assert_eq( to!string(p), "hello.cpp:123:45" ); 61998c472a 2010-11-08 kinaba: assert_lt( p, q ); 61998c472a 2010-11-08 kinaba: assert_ne( p, q ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, new LexPosition) ); 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, p.filename="foo") ); 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, p.lineno =789) ); 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, p.column =222) ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Represents a lexer token 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: class Token 423f308350 2010-11-07 kinaba: { 820e7198cc 2010-11-07 kinaba: /// currently we have three kinds of token 820e7198cc 2010-11-07 kinaba: enum Kind { 820e7198cc 2010-11-07 kinaba: identifier, /// anything other than others 820e7198cc 2010-11-07 kinaba: stringLiteral, /// "string literal" 820e7198cc 2010-11-07 kinaba: number /// 42 820e7198cc 2010-11-07 kinaba: }; 4198578702 2010-11-07 kinaba: immutable LexPosition pos; /// position where the token occurred in the source 4198578702 2010-11-07 kinaba: immutable string str; /// the token string itself 4198578702 2010-11-07 kinaba: immutable Kind kind; /// which kind of token? 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: mixin SimpleConstructor; 423f308350 2010-11-07 kinaba: mixin SimpleCompare; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto p = new immutable(LexPosition)("hello.cpp", 123, 45); 423f308350 2010-11-07 kinaba: auto t = new Token(p, "class", Token.Kind.identifier); 423f308350 2010-11-07 kinaba: 61998c472a 2010-11-08 kinaba: assert_eq( t.pos, p ); 61998c472a 2010-11-08 kinaba: assert_eq( t.str, "class" ); 61998c472a 2010-11-08 kinaba: assert_eq( t, new Token(p, "class", Token.Kind.identifier) ); 61998c472a 2010-11-08 kinaba: assert_lt( t, new Token(p, "struct", Token.Kind.identifier) ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, new Token) ); 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, t.pos=p) ); 423f308350 2010-11-07 kinaba: assert( !__traits(compiles, t.str=789) ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Named Construtor for Lexer 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: Lexer lexerFromFile(T...)( string filename, T rest ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return lexerFromString( std.file.readText(filename), filename, rest ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Named Construtor for Lexer 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: Lexer lexerFromString( string str, string filename="<unnamed>", int lineno=1, int column=1 ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return new Lexer(str, filename, lineno, column); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// Lexer is a forward range of Tokens 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: class Lexer 423f308350 2010-11-07 kinaba: { 4198578702 2010-11-07 kinaba: /// Range primitive 423f308350 2010-11-07 kinaba: bool empty() /*@property*/ 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return current is null; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 4198578702 2010-11-07 kinaba: /// Range primitive 423f308350 2010-11-07 kinaba: Token front() /*@property*/ 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return std.exception.enforce(current, "Lexer has already reached the end"); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 4198578702 2010-11-07 kinaba: /// Range primitive 423f308350 2010-11-07 kinaba: void popFront() /*@property*/ 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: std.exception.enforce(current, "Lexer has already reached the end"); 423f308350 2010-11-07 kinaba: current = readNext(); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 4198578702 2010-11-07 kinaba: /// Range primitive 423f308350 2010-11-07 kinaba: Lexer save() /*@property*/ 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return new Lexer(buffer, filename, lineno, column, current); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: private: // implementation 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: string buffer; 423f308350 2010-11-07 kinaba: string filename; 423f308350 2010-11-07 kinaba: int lineno; 423f308350 2010-11-07 kinaba: int column; 423f308350 2010-11-07 kinaba: Token current; 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: invariant() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: assert( buffer.empty || !std.ctype.isspace(buffer[0]) ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: this( string buffer, string filename, int lineno, int column, Token current=null ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: this.buffer = buffer; 423f308350 2010-11-07 kinaba: this.filename = filename; 423f308350 2010-11-07 kinaba: this.lineno = lineno; 423f308350 2010-11-07 kinaba: this.column = column; 423f308350 2010-11-07 kinaba: skipws(); 423f308350 2010-11-07 kinaba: this.current = (current is null ? readNext() : current); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: void skipws() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: bool progress = false; 423f308350 2010-11-07 kinaba: do 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: string ws = buffer.munch(" \t"); 423f308350 2010-11-07 kinaba: column += ws.length; 423f308350 2010-11-07 kinaba: progress = !ws.empty; 423f308350 2010-11-07 kinaba: while( !buffer.empty && (buffer[0]=='\r' || buffer[0]=='\n') ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: progress = true; 423f308350 2010-11-07 kinaba: if( buffer[0] == '\n' ) 423f308350 2010-11-07 kinaba: buffer = buffer[1..$]; 423f308350 2010-11-07 kinaba: else // if( buffer.front == '\r' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: buffer = buffer[1..$]; 423f308350 2010-11-07 kinaba: if( !buffer.empty && buffer[0]=='\n' ) 423f308350 2010-11-07 kinaba: buffer = buffer[1..$]; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: lineno ++; 423f308350 2010-11-07 kinaba: column = 1; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: }while( progress ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: char readChar() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: scope(exit) { 423f308350 2010-11-07 kinaba: buffer = buffer[1..$]; 423f308350 2010-11-07 kinaba: column ++; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: return buffer[0]; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: /// This is the main lexing routine 423f308350 2010-11-07 kinaba: Token readNext() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( buffer.empty ) 423f308350 2010-11-07 kinaba: return null; 423f308350 2010-11-07 kinaba: scope(exit) 423f308350 2010-11-07 kinaba: skipws(); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: if( isSymbol(buffer[0]) ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( buffer[0] == '#' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: // skip comment 423f308350 2010-11-07 kinaba: while( !buffer.empty && (buffer[0]!='\n' && buffer[0]!='\r') ) 423f308350 2010-11-07 kinaba: readChar(); 423f308350 2010-11-07 kinaba: skipws(); 423f308350 2010-11-07 kinaba: return readNext(); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else if( buffer[0] == '"' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: // string literal 423f308350 2010-11-07 kinaba: auto pos = currentPosition(); 423f308350 2010-11-07 kinaba: string lit; 423f308350 2010-11-07 kinaba: readChar(); 423f308350 2010-11-07 kinaba: while( !buffer.empty && buffer[0]!='"' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: // read one char 423f308350 2010-11-07 kinaba: char c = readChar(); 423f308350 2010-11-07 kinaba: if( c == '\\' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( !buffer.empty && (buffer[0]=='\\' || buffer[0]=='"') ) 423f308350 2010-11-07 kinaba: lit ~= readChar(); 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: lit ~= c; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else if( c == '\n' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: lit ~= c; 423f308350 2010-11-07 kinaba: lineno++; 423f308350 2010-11-07 kinaba: column = 1; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else if( c == '\r' ) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: if( !buffer.empty && buffer[0]=='\n' ) 423f308350 2010-11-07 kinaba: readChar(); 423f308350 2010-11-07 kinaba: lit ~= '\n'; 423f308350 2010-11-07 kinaba: lineno++; 423f308350 2010-11-07 kinaba: column = 1; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: lit ~= c; 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: if( !buffer.empty ) 423f308350 2010-11-07 kinaba: readChar(); 423f308350 2010-11-07 kinaba: return new Token(pos, lit, Token.Kind.stringLiteral); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: // normal symbol 423f308350 2010-11-07 kinaba: auto pos = currentPosition(); 423f308350 2010-11-07 kinaba: auto str = ""~readChar(); 423f308350 2010-11-07 kinaba: return new Token(pos, str, Token.Kind.identifier); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: else 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto pos = currentPosition(); 423f308350 2010-11-07 kinaba: int i = 0; 423f308350 2010-11-07 kinaba: while( i<buffer.length && !std.ctype.isspace(buffer[i]) && !isSymbol(buffer[i]) ) 423f308350 2010-11-07 kinaba: ++i; 423f308350 2010-11-07 kinaba: auto str = buffer[0 .. i]; 423f308350 2010-11-07 kinaba: buffer = buffer[i .. $]; 423f308350 2010-11-07 kinaba: column += i; 423f308350 2010-11-07 kinaba: bool isNumber = find!(`a<'0' || '9'<a`)(str).empty; 423f308350 2010-11-07 kinaba: return new Token(pos, str, isNumber ? Token.Kind.number : Token.Kind.identifier); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: bool isSymbol(char c) 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return (0x21<=c && c<=0x7f && !std.ctype.isalnum(c) && c!='_'); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: immutable(LexPosition) currentPosition() 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: return new immutable(LexPosition)(filename, lineno, column); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: assert( std.range.isForwardRange!(Lexer) ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto lex = lexerFromString("this is a \t\n pen :-( "); 423f308350 2010-11-07 kinaba: Token[] ts = std.array.array(lex); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[0].pos.lineno == 1 ); 423f308350 2010-11-07 kinaba: assert( ts[0].pos.column == 1 ); 423f308350 2010-11-07 kinaba: assert( ts[0].kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( ts[0].str == "this" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[1].pos.lineno == 1 ); 423f308350 2010-11-07 kinaba: assert( ts[1].pos.column == 6 ); 423f308350 2010-11-07 kinaba: assert( ts[1].kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( ts[1].str == "is" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[2].pos.lineno == 1 ); 423f308350 2010-11-07 kinaba: assert( ts[2].pos.column == 9 ); 423f308350 2010-11-07 kinaba: assert( ts[2].kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( ts[2].str == "a" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[3].pos.lineno == 2 ); 423f308350 2010-11-07 kinaba: assert( ts[3].pos.column == 2 ); 423f308350 2010-11-07 kinaba: assert( ts[3].kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( ts[3].str == "pen" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: // consecutive symbols are always separated 423f308350 2010-11-07 kinaba: // hence, no "++" or "<<" or ... 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[4].pos.lineno == 2 ); 423f308350 2010-11-07 kinaba: assert( ts[4].pos.column == 6 ); 423f308350 2010-11-07 kinaba: assert( ts[4].str == ":" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[5].pos.lineno == 2 ); 423f308350 2010-11-07 kinaba: assert( ts[5].pos.column == 7 ); 423f308350 2010-11-07 kinaba: assert( ts[5].str == "-" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts[6].pos.lineno == 2 ); 423f308350 2010-11-07 kinaba: assert( ts[6].pos.column == 8 ); 423f308350 2010-11-07 kinaba: assert( ts[6].str == "(" ); 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: assert( ts.length == 7 ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto lex2 = lexerFromString(" a12\n3a 5 "); 423f308350 2010-11-07 kinaba: assert( lex2.front.str == "a12" ); 423f308350 2010-11-07 kinaba: assert( lex2.front.kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: lex2.popFront; 423f308350 2010-11-07 kinaba: auto lex3 = lex2.save; 423f308350 2010-11-07 kinaba: assert( lex2.front.str == "3a" ); 423f308350 2010-11-07 kinaba: assert( lex2.front.kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: lex2.popFront; 423f308350 2010-11-07 kinaba: assert( lex3.front.str == "3a" ); 423f308350 2010-11-07 kinaba: assert( lex3.front.kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( lex2.front.str == "5" ); 423f308350 2010-11-07 kinaba: assert( lex2.front.kind == Token.Kind.number ); 423f308350 2010-11-07 kinaba: lex2.popFront; 423f308350 2010-11-07 kinaba: lex3.popFront; 423f308350 2010-11-07 kinaba: assert( lex2.empty ); 423f308350 2010-11-07 kinaba: assert( !lex3.empty ); 423f308350 2010-11-07 kinaba: assert( lex3.front.str == "5" ); 423f308350 2010-11-07 kinaba: assert( lex3.front.kind == Token.Kind.number ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: //!! be sure to run the unittest on the root of the source directory 423f308350 2010-11-07 kinaba: auto lexf = lexerFromFile("polemy/lex.d"); 4198578702 2010-11-07 kinaba: lexf = find!`a.str == "module"`(lexf); 423f308350 2010-11-07 kinaba: assert( lexf.front.str == "module", lexf.front.str ); 423f308350 2010-11-07 kinaba: assert( lexf.front.pos.filename == "polemy/lex.d" ); 4198578702 2010-11-07 kinaba: assert( lexf.front.pos.lineno == 7 ); 423f308350 2010-11-07 kinaba: assert( lexf.front.pos.column == 1 ); 423f308350 2010-11-07 kinaba: lexf.popFront; 423f308350 2010-11-07 kinaba: assert( lexf.front.str == "polemy" ); 4198578702 2010-11-07 kinaba: assert( lexf.front.pos.lineno == 7 ); 423f308350 2010-11-07 kinaba: assert( lexf.front.pos.column == 8 ); 423f308350 2010-11-07 kinaba: lexf.popFront; 423f308350 2010-11-07 kinaba: assert( lexf.front.str == "." ); 423f308350 2010-11-07 kinaba: lexf.popFront; 423f308350 2010-11-07 kinaba: assert( lexf.front.str == "lex" ); 423f308350 2010-11-07 kinaba: lexf.popFront; 423f308350 2010-11-07 kinaba: assert( lexf.front.str == ";" ); 423f308350 2010-11-07 kinaba: lexf.popFront; 423f308350 2010-11-07 kinaba: assert( lexf.front.str == "import" ); 4198578702 2010-11-07 kinaba: assert( lexf.front.pos.lineno == 8 ); 423f308350 2010-11-07 kinaba: assert( lexf.front.pos.column == 1 ); 423f308350 2010-11-07 kinaba: } 423f308350 2010-11-07 kinaba: 423f308350 2010-11-07 kinaba: unittest 423f308350 2010-11-07 kinaba: { 423f308350 2010-11-07 kinaba: auto lex = lexerFromString(`my # comment should 423f308350 2010-11-07 kinaba: # hey!! 423f308350 2010-11-07 kinaba: be ignored. 423f308350 2010-11-07 kinaba: hahaha"hihihi""hu\\\"huhu"#123 aa 423f308350 2010-11-07 kinaba: 123 aa "aaa 423f308350 2010-11-07 kinaba: bbb # 123 423f308350 2010-11-07 kinaba: eee" 423f308350 2010-11-07 kinaba: zzz 423f308350 2010-11-07 kinaba: `); 423f308350 2010-11-07 kinaba: Token[] ts = std.array.array(lex); 423f308350 2010-11-07 kinaba: assert( ts[0].str == "my" ); 423f308350 2010-11-07 kinaba: assert( ts[0].pos.lineno == 1 ); 423f308350 2010-11-07 kinaba: assert( ts[1].str == "be" ); 423f308350 2010-11-07 kinaba: assert( ts[1].pos.lineno == 3 ); 423f308350 2010-11-07 kinaba: assert( ts[2].str == "ignored" ); 423f308350 2010-11-07 kinaba: assert( ts[3].str == "." ); 423f308350 2010-11-07 kinaba: assert( ts[4].str == "hahaha" ); 423f308350 2010-11-07 kinaba: assert( ts[4].pos.lineno == 4 ); 423f308350 2010-11-07 kinaba: assert( ts[4].kind == Token.Kind.identifier ); 423f308350 2010-11-07 kinaba: assert( ts[5].str == "hihihi" ); 423f308350 2010-11-07 kinaba: assert( ts[5].pos.lineno == 4 ); 423f308350 2010-11-07 kinaba: assert( ts[5].kind == Token.Kind.stringLiteral ); 423f308350 2010-11-07 kinaba: assert( ts[6].str == `hu\"huhu` ); 423f308350 2010-11-07 kinaba: assert( ts[6].kind == Token.Kind.stringLiteral ); 423f308350 2010-11-07 kinaba: assert( ts[6].pos.lineno == 4 ); 423f308350 2010-11-07 kinaba: assert( ts[7].str == "123" ); 423f308350 2010-11-07 kinaba: assert( ts[7].pos.lineno == 5 ); 423f308350 2010-11-07 kinaba: assert( ts[7].kind == Token.Kind.number ); 423f308350 2010-11-07 kinaba: assert( ts[8].str == "aa" ); 423f308350 2010-11-07 kinaba: assert( ts[9].pos.lineno == 5 ); 423f308350 2010-11-07 kinaba: assert( ts[9].str == "aaa\nbbb # 123\neee" ); 423f308350 2010-11-07 kinaba: assert( ts[9].kind == Token.Kind.stringLiteral ); 423f308350 2010-11-07 kinaba: assert( ts[10].pos.lineno == 8 ); 423f308350 2010-11-07 kinaba: assert( ts.length == 11 ); 423f308350 2010-11-07 kinaba: }