Index: .poseidon
==================================================================
--- .poseidon
+++ .poseidon
@@ -31,15 +31,13 @@
d2stacktrace\dbghelp.d
d2stacktrace\stacktrace.d
main.d
polemy\_common.d
polemy\ast.d
- polemy\eval.d
polemy\lex.d
polemy\parse.d
polemy\tricks.d
- polemy\value.d
Index: main.d
==================================================================
--- main.d
+++ main.d
@@ -4,11 +4,10 @@
*
* Entry point for Polemy interpreter.
*/
import std.stdio;
-import polemy.eval;
version(unittest) static ~this()
{
writeln( "***********************" );
writeln( "* All Tests Passed <3 *" );
Index: polemy/ast.d
==================================================================
--- polemy/ast.d
+++ polemy/ast.d
@@ -6,89 +6,71 @@
*/
module polemy.ast;
import polemy._common;
import polemy.lex;
-alias Statement[] Program;
-
-abstract class Statement
+abstract class AST
{
immutable LexPosition pos;
mixin SimpleConstructor;
}
-class DeclStatement : Statement
-{
- string var;
- Expression expr;
- mixin SimpleClass;
-}
-
-class ExprStatement : Statement
-{
- Expression expr;
- mixin SimpleClass;
-}
-
-abstract class Expression
-{
- immutable LexPosition pos;
- mixin SimpleConstructor;
-}
-
-class StrLiteralExpression : Expression
+class StrLiteral : AST
{
string data;
mixin SimpleClass;
}
-class IntLiteralExpression : Expression
+class IntLiteral : AST
{
- BigInt data;
+ BigInt data;
mixin SimpleClass;
+ this(immutable LexPosition pos, long n) {super(pos); data = n;}
+ this(immutable LexPosition pos, BigInt n) {super(pos); data = n;}
+ this(immutable LexPosition pos, string n) {super(pos); data = BigInt(n);}
}
-class VarExpression : Expression
+class VarExpression : AST
{
string var;
mixin SimpleClass;
}
-class AssignExpression : Expression
-{
- Expression lhs;
- Expression rhs;
+class LetExpression : AST
+{
+ string var;
+ AST init;
+ AST expr;
mixin SimpleClass;
-}
-
-class FuncallExpression : Expression
+}
+
+class FuncallExpression : AST
{
- Expression fun;
- Expression[] args;
- this(immutable LexPosition pos, Expression fun, Expression[] args...)
+ AST fun;
+ AST[] args;
+ this(immutable LexPosition pos, AST fun, AST[] args...)
{ super(pos); this.fun=fun; this.args=args.dup; }
mixin SimpleClass;
}
-
-class FunLiteralExpression : Expression
-{
- string[] params;
- Program funbody;
- mixin SimpleClass;
-}
+
+class FunLiteral : AST
+{
+ string[] params;
+ AST funbody;
+ mixin SimpleClass;
+}
/// Handy Generator for AST nodes. To use this, mixin EasyAst;
/*mixin*/
-template EasyAst()
+template EasyAST()
{
template genEast(T)
{ T genEast(P...)(P ps) { return new T(LexPosition.dummy, ps); } }
- alias genEast!DeclStatement decl;
- alias genEast!ExprStatement expr;
+ alias genEast!StrLiteral strl;
+ alias genEast!IntLiteral intl;
+ auto fun(string[] xs, AST ps) { return genEast!FunLiteral(xs,ps); }
alias genEast!VarExpression var;
- alias genEast!FuncallExpression funcall;
- alias genEast!IntLiteralExpression intl;
- alias genEast!StrLiteralExpression strl;
- alias genEast!FunLiteralExpression fun;
+ alias genEast!LetExpression let;
+ alias genEast!FuncallExpression call;
}
Index: polemy/lex.d
==================================================================
--- polemy/lex.d
+++ polemy/lex.d
@@ -11,22 +11,23 @@
/// Exception from this module
class LexException : Exception
{
- this( const LexPosition pos, string msg )
- { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
const LexPosition pos;
+
+ private this( const LexPosition pos, string msg )
+ { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
};
/// Represents a position in a source code
class LexPosition
{
immutable string filename; /// name of the source file
- immutable int lineno; /// line number, 1, 2, ...
- immutable int column; /// column, 1, 2, ...
+ immutable int lineno; /// 1-origin
+ immutable int column; /// 1-origin
override string toString() const
{ return sprintf!"%s:%d:%d"(filename, lineno, column); }
mixin SimpleConstructor;
@@ -85,27 +86,25 @@
assert( !__traits(compiles, t.pos=p) );
assert( !__traits(compiles, t.str=789) );
assert( !__traits(compiles, t.quoted=true) );
}
-/// Named Construtor for Lexer
+/// Named Construtors for Lexer
auto lexerFromFile(T...)( string filename, T rest )
{
return lexerFromString( std.file.readText(filename), filename, rest );
}
-/// Named Construtor for Lexer
-
auto lexerFromString(CharSeq)( CharSeq str, string filename="", int lineno=1, int column=1 )
{
return new LexerT!(PositionedReader!CharSeq)(
PositionedReader!CharSeq(str, filename, lineno, column)
);
}
-/// Standard Lexer Type (all users 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
Index: polemy/parse.d
==================================================================
--- polemy/parse.d
+++ polemy/parse.d
@@ -6,361 +6,301 @@
*/
module polemy.parse;
import polemy._common;
import polemy.lex;
import polemy.ast;
+
+/// Exception from this module
-/// Parsing Failure
-
-class ParserException : Exception
+class ParseException : Exception
{
-private:
- this(string msg) { super(msg); }
- static ParserException create(Lexer)(Lexer lex, string msg)
- {
- return new ParserException(sprintf!"[%s] %s"(
- lex.empty ? "EOF" : to!string(lex.front.pos), msg));
- }
+ const LexPosition pos;
+
+ private this( const LexPosition pos, string msg )
+ { super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
}
+
+private auto createException(Lexer)(Lexer lex, string msg)
+ { return new ParseException(lex.empty?null:lex.front.pos, msg); }
+/// Entry point of this module
+
+auto parseString(S, T...)(S str, T fn_ln_cn)
+ { return parserFromString(str, fn_ln_cn).parse(); }
+
+auto parseFile(S, T...)(S filename,T ln_cn)
+ { return parserFromString(filename, ln_cn).parse(); }
+
/// Named Constructor of Parser
+
+private auto parserFromLexer(Lexer)(Lexer lex)
+ { return new Parser!Lexer(lex); }
-auto parserFromLexer(Lexer)(Lexer lex)
-{
- return new Parser!Lexer(lex);
-}
+private auto parserFromString(T...)(T params)
+ { return parserFromLexer(polemy.lex.lexerFromString(params)); }
-/// Named Constructor of Parser (just fwd to lexerFromString)
-
-auto parserFromString(T...)(T params)
-{
- return parserFromLexer(polemy.lex.lexerFromString(params));
-}
-
-/// Named Constructor of Parser (just fwd to lexerFromFile)
-
-auto parserFromFile(T...)(T params)
-{
- return parserFromLexer(polemy.lex.lexerFromFile(params));
-}
-
+private auto parserFromFile(T...)(T params)
+ { return parserFromLexer(polemy.lex.lexerFromFile(params)); }
+
/// Parser
-class Parser(Lexer)
-{
- this(Lexer lex)
- {
- this.lex = lex;
- }
-
- Program parseProgram()
- {
- Program p = parseStatements();
- if( !lex.empty ) {
- auto e = ParserException.create(lex, "cannot reach eof");
- throw e;
- }
- return p;
- }
-
- Program parseStatements()
- {
- Program p;
- while( !lex.empty && (lex.front.quoted || lex.front.str!="}") )
- p ~= parseStatement();
- return p;
- }
-
- Statement parseStatement()
- {
- auto saved = lex.save;
- scope(failure) lex = saved;
-
- if( lex.empty )
- throw new ParserException("EOF during parsing a statement");
- auto pos = lex.front.pos;
+private class Parser(Lexer)
+ if( isForwardRange!(Lexer) && is(ElementType!(Lexer) == Token) )
+{
+ AST parse()
+ {
+ auto e = Body();
+ if( !lex.empty )
+ throw createException(lex, "input is not ended but parser came to the end");
+ return e;
+ }
+
+ AST Body()
+ {
+ if( lex.empty || !lex.front.quoted && lex.front.str=="}" )
+ return doNothingExpression();
+
+ auto pos = lex.front.pos;
+ if( tryEat("var") )
+ {
+ immutable LexPosition varpos = (lex.empty ? null : lex.front.pos);
+ string var = eatId("after var");
+ eat("=", "after var");
+ auto e = E(0);
+ if( tryEat(";") && !lex.empty && (lex.front.quoted || (lex.front.str!="}" && lex.front.str!=")")) )
+ return new LetExpression(pos, var, e, Body());
+ else
+ return new LetExpression(pos, var, e, new VarExpression(varpos, var));
+ }
+ else
+ {
+ auto e = E(0);
+ if( tryEat(";") && !lex.empty && (lex.front.quoted || (lex.front.str!="}" && lex.front.str!=")")) )
+ return new LetExpression(pos, "_", e, Body());
+ else
+ return e;
+ }
+ }
- if( !lex.front.quoted && lex.front.str=="var" )
- {
- // "var" Var "=" Expression ";"
- lex.popFront;
- string var = lex.front.str;
- lex.popFront;
- eat("=", "for variable declaration");
- auto parsed = new DeclStatement(pos, var, parseExpression());
- eat(";", "after variable declaration");
- return parsed;
- }
- else
- {
- // Expression ";"
- auto parsed = new ExprStatement(pos, parseExpression());
- eat(";", "after statement");
- return parsed;
- }
- }
-
- Expression parseExpression()
- {
- auto saved = lex.save;
- scope(failure) lex = saved;
- return parseE(0);
- }
-
- // [TODO] multi-char operators are not supported by the lexer...
+ // [TODO] make customizable from program
static immutable string[][] operator_perferences = [
- ["="],
- ["or"],
- ["and"],
+ ["||"],
+ ["&&"],
["!="],
["=="],
["<","<=",">",">="],
["|"],
["^"],
["&"],
["<<", ">>"],
- ["+","-"],
- ["*","/","%"]
+ ["+","-"],
+ ["~"],
+ ["*","/","%"],
+ ["^^"]
];
- Expression parseE(int level = 0)
+ AST E(int level)
{
if( operator_perferences.length <= level )
- return parseBaseExpression();
+ return Funcall();
else
{
auto ops = operator_perferences[level];
- auto e = parseE(level+1);
+ auto e = E(level+1);
seq:
while( !lex.empty )
{
auto pos = lex.front.pos;
foreach(op; ops)
if( tryEat(op) )
{
- if( op == "=" ) // right assoc
- return new AssignExpression(e.pos, e, parseE(level));
- else
- e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, parseE(level+1));
+ e = new FuncallExpression(e.pos, new VarExpression(pos, op), e, E(level+1));
continue seq;
}
break;
}
return e;
}
}
- Expression parseBaseExpression()
+ AST Funcall()
{
- if( lex.empty )
- throw new ParserException("EOF during parsing an expression");
- auto pos = lex.front.pos;
- Expression e = parseBaseBaseExpression();
- while( tryEat("(") ) // funcall
- {
- Expression[] args;
+ auto e = BaseExpression();
+ while( tryEat("(") )
+ {
+ AST[] args;
while( !tryEat(")") ) {
- if( lex.empty ) {
- auto ex = ParserException.create(lex,"Unexpected EOF");
- throw ex;
- }
- args ~= parseE();
+ if( lex.empty )
+ throw createException(lex,"Unexpected EOF");
+ args ~= E(0);
if( !tryEat(",") ) {
eat(")", "after function parameters");
break;
}
}
- e = new FuncallExpression(pos, e, args);
+ e = new FuncallExpression(e.pos, e, args);
}
return e;
}
- Expression parseBaseBaseExpression()
+ AST BaseExpression()
{
- if( lex.empty )
- throw new ParserException("EOF during parsing an expression");
+ if( lex.empty )
+ throw createException(lex, "Reached EOF when tried to parse an expression");
+
auto pos = lex.front.pos;
-
if( lex.front.quoted )
{
scope(exit) lex.popFront;
- return new StrLiteralExpression(pos, lex.front.str);
+ return new StrLiteral(pos, lex.front.str);
}
- if( isNumber(lex.front.str) ) // is_number
+ if( isNumber(lex.front.str) )
{
scope(exit) lex.popFront;
- return new IntLiteralExpression(pos, BigInt(cast(string)lex.front.str));
+ return new IntLiteral(pos, BigInt(cast(string)lex.front.str));
}
if( tryEat("(") )
{
- auto e = parseE();
+ auto e = Body();
eat(")", "after parenthesized expression");
return e;
}
if( tryEat("if") )
{
eat("(", "after if");
- auto cond = parseE();
+ auto cond = E(0);
eat(")", "after if condition");
auto thenPos = lex.front.pos;
eat("{", "after if condition");
- Statement[] th = parseStatements();
+ auto th = Body();
eat("}", "after if-then body");
- Statement[] el;
- auto elsePos = lex.front.pos;
+ auto el = doNothingExpression();
+ auto elsePos = (lex.empty ? LexPosition.dummy : lex.front.pos);
if( tryEat("else") ) {
eat("{", "after else");
- el = parseStatements();
+ el = Body();
eat("}", "after else body");
}
return new FuncallExpression(pos,
new VarExpression(pos, "if"),
cond,
- new FunLiteralExpression(thenPos, [], th),
- new FunLiteralExpression(elsePos, [], el)
+ new FunLiteral(thenPos, [], th),
+ new FunLiteral(elsePos, [], el)
);
}
-
if( tryEat("fun") )
{
eat("(", "after fun");
string[] params;
- while(!tryEat(")"))
+ while( !tryEat(")") )
{
- if( lex.empty ) {
- auto e = ParserException.create(lex,"Unexpected EOF");
- throw e;
- }
- if( lex.front.quoted ) {
- auto e = ParserException.create(lex,"Identifier Expected for parameters");
- throw e;
- }
- params ~= lex.front.str;
- lex.popFront;
+ params ~= eatId("for function parameter");
if( !tryEat(",") ) {
eat(")", "after function parameters");
break;
}
}
- eat("{", "after function parameters");
- Statement[] funbody;
- while(!tryEat("}")) {
- if( lex.empty ) {
- auto e = ParserException.create(lex,"Unexpected EOF");
- throw e;
- }
- funbody ~= parseStatement();
- }
- return new FunLiteralExpression(pos, params, funbody);
+ eat("{", "after function parameters");
+ auto funbody = Body();
+ eat("}", "after function body");
+ return new FunLiteral(pos, params, funbody);
}
scope(exit) lex.popFront;
return new VarExpression(pos, lex.front.str);
}
private:
- Lexer lex;
+ Lexer lex;
+ this(Lexer lex) { this.lex = lex; }
void eat(string kwd, lazy string msg)
{
if( !tryEat(kwd) )
- {
- auto e = ParserException.create(lex, "'"~kwd~"' is expected "~msg~" but '"
+ throw createException(lex, "'"~kwd~"' is expected "~msg~" but '"
~(lex.empty ? "EOF" : lex.front.str)~"' occured");
- throw e;
- }
}
bool tryEat(string kwd)
{
if( lex.empty || lex.front.quoted || lex.front.str!=kwd )
return false;
lex.popFront;
return true;
}
+
+ string eatId(lazy string msg)
+ {
+ if( lex.empty || lex.front.quoted )
+ throw createException(lex, "identifier is expected but not found "~msg);
+ string id = lex.front.str;
+ lex.popFront;
+ return id;
+ }
bool isNumber(string s)
{
return find!(`a<'0'||'9'