Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -419,11 +419,11 @@ return (*p)[0]; } else { Value v; - try { v = evlay.lift(new BottomValue, ctx, pos); } catch { v = new BottomValue; } + try { v = evlay.lift(new BottomValue, ctx, pos); } catch { return nonMemoizedRun(); } memo[memokey] = tuple(v, 0); } Value r = nonMemoizedRun(); memo[memokey] = tuple(r, 9999); Index: polemy/lex.d ================================================================== --- polemy/lex.d +++ polemy/lex.d @@ -3,15 +3,15 @@ * License: NYSL 0.9982 http://www.kmonos.net/nysl/ * * Lexer for Polemy programming language. */ module polemy.lex; -import polemy._common; +import polemy._common; import polemy.failure; import std.file : readText; -import std.ctype : isspace, isalnum; - +import std.ctype : isspace, isalnum; + /// Represents a lexer token class Token { immutable LexPosition pos; /// Position where the token occurred in the source @@ -35,11 +35,11 @@ assert_ne( t, u ); assert( u.quoted ); assert( !__traits(compiles, new Token) ); assert( !__traits(compiles, t.pos=p) ); - assert( !__traits(compiles, t.str=789) ); + assert( !__traits(compiles, t.str="789") ); assert( !__traits(compiles, t.quoted=true) ); } /// Named Construtors for Lexer @@ -46,27 +46,27 @@ Lexer lexerFromFile(T...)( string filename, T ln_cn ) { return lexerFromString( std.file.readText(filename), filename, ln_cn ); } -/// Named Construtor for Lexer - -LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzilla:2581 */ +/// Named Construtor for Lexer + +LexerT!(PositionedReader!CharSeq) /* ddoc doesn't recognize auto return... bugzilla:2581 */ lexerFromString(CharSeq)( CharSeq str, string filename="", int lineno=1, int column=1 ) { - return new LexerT!(PositionedReader!CharSeq)( - PositionedReader!CharSeq(str, filename, lineno, column) + return new LexerT!(PositionedReader!CharSeq)( + PositionedReader!CharSeq(str, filename, lineno, column) ); } -/// Standard Lexer Type (all you have to know is that this is a forward range of Tokens!) - +/// Standard Lexer Type (all you have to know is that this is a forward range of Tokens!) + alias LexerT!(PositionedReader!string) Lexer; -/// Lexer Implementation - -class LexerT(Reader) +/// Lexer Implementation + +class LexerT(Reader) if( isForwardRange!(Reader) && is(ElementType!(Reader)==dchar) ) { /// Range primitive bool empty() /*@property*/ { @@ -98,99 +98,99 @@ Token current; invariant() { assert( reader.empty || !isSpace(reader.front) ); - } - - this( Reader reader, Token current = null ) - { - this.reader = reader; - readWhile!isSpace(); - this.current = (current is null ? readNext() : current); - } - - public static + } + + this( Reader reader, Token current = null ) + { + this.reader = reader; + readWhile!isSpace(); + this.current = (current is null ? readNext() : current); + } + + public static { bool isSpace (dchar c) { return std.ctype.isspace(c)!=0; } - bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.ctype.isalnum(c) && c!='_' && c!='\''; } - bool isSSymbol (dchar c) { return "()[]{};,@".canFind(c); } - bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) && c!='"' && c!='#'; } - bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } - } - - string readQuoted(const LexPosition pos){char[] buf; return readQuoted(pos,buf);} - string readQuoted(const LexPosition pos, ref char[] buf) - { - if( reader.empty ) - throw genex!UnexpectedEOF(pos, "Quoted string not terminated"); - dchar c = reader.front; - reader.popFront; - if( c == '"' ) - return assumeUnique(buf); - if( c == '\\' && !reader.empty ) { - if( reader.front=='"' ) { - reader.popFront; - return readQuoted(pos,buf ~= '\"'); - } - if( reader.front=='\\' ) { - reader.popFront; - return readQuoted(pos,buf ~= '\\'); - } - } - return readQuoted(pos,buf ~= c); - } - - string readWhile(alias fn)() - { - char[] buf; - for(; !reader.empty && fn(reader.front); reader.popFront) - buf ~= reader.front; - return assumeUnique(buf); + bool isSymbol (dchar c) { return 0x21<=c && c<=0x7f && !std.ctype.isalnum(c) && c!='_' && c!='\''; } + bool isSSymbol (dchar c) { return "()[]{};,@".canFind(c); } + bool isMSymbol (dchar c) { return isSymbol(c) && !isSSymbol(c) && c!='"' && c!='#'; } + bool isLetter (dchar c) { return !isSpace(c) && !isSymbol(c); } + } + + string readQuoted(const LexPosition pos){char[] buf; return readQuoted(pos,buf);} + string readQuoted(const LexPosition pos, ref char[] buf) + { + if( reader.empty ) + throw genex!UnexpectedEOF(pos, "Quoted string not terminated"); + dchar c = reader.front; + reader.popFront; + if( c == '"' ) + return assumeUnique(buf); + if( c == '\\' && !reader.empty ) { + if( reader.front=='"' ) { + reader.popFront; + return readQuoted(pos,buf ~= '\"'); + } + if( reader.front=='\\' ) { + reader.popFront; + return readQuoted(pos,buf ~= '\\'); + } + } + return readQuoted(pos,buf ~= c); + } + + string readWhile(alias fn)() + { + char[] buf; + for(; !reader.empty && fn(reader.front); reader.popFront) + buf ~= reader.front; + return assumeUnique(buf); } Token readNext() { if( reader.empty ) - return null; - scope(success) - readWhile!isSpace(); - if( reader.front == '#' ) // comment - { - reader = find(reader, '\n'); - readWhile!isSpace(); - return readNext(); + return null; + scope(success) + readWhile!isSpace(); + if( reader.front == '#' ) // comment + { + reader = find(reader, '\n'); + readWhile!isSpace(); + return readNext(); + } + else if( reader.front == '"' ) // quoted + { + auto pos = reader.currentPosition(); + reader.popFront; + return new Token(pos, readQuoted(pos), true); + } + else if( isSSymbol(reader.front) ) // paren + { + auto pos = reader.currentPosition(); + string s; s~=reader.front; reader.popFront; + return new Token(pos, s, false); } - else if( reader.front == '"' ) // quoted - { - auto pos = reader.currentPosition(); - reader.popFront; - return new Token(pos, readQuoted(pos), true); - } - else if( isSSymbol(reader.front) ) // paren - { - auto pos = reader.currentPosition(); - string s; s~=reader.front; reader.popFront; - return new Token(pos, s, false); - } - else if( isMSymbol(reader.front) ) // symbol + else if( isMSymbol(reader.front) ) // symbol { auto pos = reader.currentPosition(); return new Token(pos, readWhile!isMSymbol(), false); } else { - auto pos = reader.currentPosition(); - return new Token(pos, readWhile!isLetter(), false); + auto pos = reader.currentPosition(); + return new Token(pos, readWhile!isLetter(), false); } } } unittest { assert( std.range.isForwardRange!(Lexer) ); - assert( is(ElementType!(Lexer) == Token) ); + assert( is(ElementType!(Lexer) == Token) ); } unittest { auto lex = lexerFromString("this is a \t\r\n pen :-( @@; "); @@ -218,17 +218,17 @@ assert_eq( ts[4].pos.lineno, 2 ); assert_eq( ts[4].pos.column, 6 ); assert_eq( ts[4].str, ":-" ); - assert_eq( ts[5].pos.lineno, 2 ); - assert_eq( ts[5].pos.column, 8 ); - assert_eq( ts[5].str, "(" ); - assert_eq( ts[6].str, "@" ); - assert_eq( ts[7].str, "@" ); - assert_eq( ts[8].str, ";" ); // paren and simicolons, atmarks are split - + assert_eq( ts[5].pos.lineno, 2 ); + assert_eq( ts[5].pos.column, 8 ); + assert_eq( ts[5].str, "(" ); + assert_eq( ts[6].str, "@" ); + assert_eq( ts[7].str, "@" ); + assert_eq( ts[8].str, ";" ); // paren and simicolons, atmarks are split + assert_eq( ts.length, 9 ); } unittest { @@ -249,15 +249,15 @@ lexf.popFront; assert_eq( lexf.front.str, "import" ); assert_eq( lexf.front.pos.lineno, 8 ); assert_eq( lexf.front.pos.column, 1 ); } - -unittest -{ - assert_throw!UnexpectedEOF( lexerFromString(`"`) ); -} + +unittest +{ + assert_throw!UnexpectedEOF( lexerFromString(`"`) ); +} unittest { auto lex = lexerFromString(`my # comment should`~"\r\n"~`# hey!! be ignored. @@ -293,106 +293,106 @@ assert( ts[9].quoted ); assert_eq( ts[10].pos.lineno, 8 ); assert( !ts[10].quoted ); assert_eq( ts.length, 11 ); } - -unittest -{ - auto lex2 = lexerFromString(" a12\n3a 5 "); - assert_eq( lex2.front.str, "a12" ); - lex2.popFront; - auto lex3 = lex2.save; - assert_eq( lex2.front.str, "3a" ); - lex2.popFront; - assert_eq( lex3.front.str, "3a" ); - assert_eq( lex2.front.str, "5" ); - lex2.popFront; - lex3.popFront; - assert( lex2.empty ); - assert( !lex3.empty ); - assert_eq( lex3.front.str, "5" ); -} - -unittest -{ - auto lex = lexerFromString(`=""`); - assert_eq(lex.front.str, "="); lex.popFront; - assert_eq(lex.front.str, ""); lex.popFront; - assert( lex.empty ); - assert_eq( lexerFromString(`-@`).front.str, "-" ); -} - -/// Forward range for reader character by character, -/// keeping track of position information and caring \r\n -> \n conversion. - -struct PositionedReader(CharSeq) - if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq)==dchar) ) -{ - CharSeq buffer; - string filename; - int lineno; - int column; - - /// Range primitive - bool empty() /*@property*/ - { - return buffer.empty; - } - - /// Range primitive - dchar front() /*@property*/ - { - dchar c = buffer.front; - return (c=='\r' ? '\n' : c); - } - - /// Range primitive - void popFront() /*@property*/ - { - dchar c = buffer.front; - buffer.popFront; - if( c=='\r' ) - { - if( !buffer.empty && buffer.front=='\n' ) - buffer.popFront; - c = '\n'; - } - if( c=='\n' ) - { - lineno ++; - column = 1; - } - else - column ++; - } - - /// Range primitive - typeof(this) save() /*@property*/ - { - return this; - } - - /// Get the current position - LexPosition currentPosition() const - { - return new LexPosition(filename, lineno, column); - } -} - -unittest -{ - assert( isForwardRange!(PositionedReader!string) ); - assert( is(ElementType!(PositionedReader!string) == dchar) ); - { - auto pr = PositionedReader!string("abc","",1,1); - assert_eq(pr.currentPosition().column, 1); pr.popFront; - assert_eq(pr.currentPosition().column, 2); pr.popFront; - assert_eq(pr.currentPosition().column, 3); pr.popFront; - } - { - auto pr = PositionedReader!string("\n\r\n\n","",1,1); - assert_eq(pr.currentPosition().lineno, 1); pr.popFront; - assert_eq(pr.currentPosition().lineno, 2); pr.popFront; - assert_eq(pr.currentPosition().lineno, 3); pr.popFront; - } -} + +unittest +{ + auto lex2 = lexerFromString(" a12\n3a 5 "); + assert_eq( lex2.front.str, "a12" ); + lex2.popFront; + auto lex3 = lex2.save; + assert_eq( lex2.front.str, "3a" ); + lex2.popFront; + assert_eq( lex3.front.str, "3a" ); + assert_eq( lex2.front.str, "5" ); + lex2.popFront; + lex3.popFront; + assert( lex2.empty ); + assert( !lex3.empty ); + assert_eq( lex3.front.str, "5" ); +} + +unittest +{ + auto lex = lexerFromString(`=""`); + assert_eq(lex.front.str, "="); lex.popFront; + assert_eq(lex.front.str, ""); lex.popFront; + assert( lex.empty ); + assert_eq( lexerFromString(`-@`).front.str, "-" ); +} + +/// Forward range for reader character by character, +/// keeping track of position information and caring \r\n -> \n conversion. + +struct PositionedReader(CharSeq) + if( isForwardRange!(CharSeq) && is(ElementType!(CharSeq)==dchar) ) +{ + CharSeq buffer; + string filename; + int lineno; + int column; + + /// Range primitive + bool empty() /*@property*/ + { + return buffer.empty; + } + + /// Range primitive + dchar front() /*@property*/ + { + dchar c = buffer.front; + return (c=='\r' ? '\n' : c); + } + + /// Range primitive + void popFront() /*@property*/ + { + dchar c = buffer.front; + buffer.popFront; + if( c=='\r' ) + { + if( !buffer.empty && buffer.front=='\n' ) + buffer.popFront; + c = '\n'; + } + if( c=='\n' ) + { + lineno ++; + column = 1; + } + else + column ++; + } + + /// Range primitive + typeof(this) save() /*@property*/ + { + return this; + } + + /// Get the current position + LexPosition currentPosition() const + { + return new LexPosition(filename, lineno, column); + } +} + +unittest +{ + assert( isForwardRange!(PositionedReader!string) ); + assert( is(ElementType!(PositionedReader!string) == dchar) ); + { + auto pr = PositionedReader!string("abc","",1,1); + assert_eq(pr.currentPosition().column, 1); pr.popFront; + assert_eq(pr.currentPosition().column, 2); pr.popFront; + assert_eq(pr.currentPosition().column, 3); pr.popFront; + } + { + auto pr = PositionedReader!string("\n\r\n\n","",1,1); + assert_eq(pr.currentPosition().lineno, 1); pr.popFront; + assert_eq(pr.currentPosition().lineno, 2); pr.popFront; + assert_eq(pr.currentPosition().lineno, 3); pr.popFront; + } +} Index: sample/type.pmy ================================================================== --- sample/type.pmy +++ sample/type.pmy @@ -165,8 +165,18 @@ when {car: x, cdr: xs}: revi(xs, cons(x,ys)) when {}: ys }; revi(xs, {}) }; + +def str_app(xs, ys) { + case xs + when {car: x, cdr: xs}: cons(""~x, str_app(xs, ys)) + when {}: ys +}; var xs = cons(1, cons(2, cons(3, nil))); +var ys = cons("four", cons("five", cons("six", nil))); print( @type( rev(xs) ) ); +print( @type( rev(ys) ) ); +print( @type( str_app(xs,ys) ) ); +print( @type( str_app(xs,xs) ) );