Mercurial > projects > dmdscript-tango
view dmdscript_tango/statement.d @ 3:8363a4bf6a8f
rename package: dmdscript to dmdscript_tango
author | saaadel |
---|---|
date | Sun, 24 Jan 2010 18:33:05 +0200 |
parents | 55c2951c07be |
children |
line wrap: on
line source
/* Digital Mars DMDScript source code. * Copyright (c) 2000-2002 by Chromium Communications * D version Copyright (c) 2004-2007 by Digital Mars * All Rights Reserved * written by Walter Bright * www.digitalmars.com * Use at your own risk. There is no warranty, express or implied. * License for redistribution is by the GNU General Public License in gpl.txt. * * A binary, non-exclusive license for commercial use can be * purchased from www.digitalmars.com/dscript/buy.html. * * DMDScript is implemented in the D Programming Language, * www.digitalmars.com/d/ * * For a C++ implementation of DMDScript, including COM support, * see www.digitalmars.com/dscript/cppscript.html. */ module dmdscript_tango.statement; import std.stdio; import std.string; import std.math; import dmdscript_tango.script; import dmdscript_tango.value; import dmdscript_tango.scopex; import dmdscript_tango.expression; import dmdscript_tango.irstate; import dmdscript_tango.symbol; import dmdscript_tango.identifier; import dmdscript_tango.ir; import dmdscript_tango.lexer; import dmdscript_tango.textgen.errmsgs; import dmdscript_tango.functiondefinition; import dmdscript_tango.opcodes; enum { TOPSTATEMENT, FUNCTIONDEFINITION, EXPSTATEMENT, VARSTATEMENT, } /******************************** TopStatement ***************************/ class TopStatement { const uint TOPSTATEMENT_SIGNATURE = 0xBA3FE1F3; uint signature = TOPSTATEMENT_SIGNATURE; Loc loc; int done; // 0: parsed // 1: semantic // 2: toIR int st; this(Loc loc) { this.loc = loc; this.done = 0; this.st = TOPSTATEMENT; } invariant { assert(signature == TOPSTATEMENT_SIGNATURE); } void toBuffer(inout tchar[] buf) { buf ~= "TopStatement.toBuffer()\n"; } Statement semantic(Scope *sc) { writefln("TopStatement.semantic(%p)", this); return null; } void toIR(IRstate *irs) { writefln("TopStatement.toIR(%p)", this); } void error(Scope *sc, int msgnum) { error(sc, errmsgtbl[msgnum]); } void error(Scope *sc, ...) { tchar[] buf; tchar[] sourcename; if (sc.funcdef) { if (sc.funcdef.isanonymous) sourcename = "anonymous"; else if (sc.funcdef.name) sourcename ~= sc.funcdef.name.toString(); } buf = std.string.format("%s(%d) : Error: ", sourcename, loc); void putc(dchar c) { std.utf.encode(buf, c); } std.format.doFormat(&putc, _arguments, _argptr); if (!sc.errinfo.message) { sc.errinfo.message = buf; sc.errinfo.linnum = loc; sc.errinfo.srcline = Lexer.locToSrcline(sc.getSource().ptr, loc); } } TopStatement ImpliedReturn() { return this; } } /******************************** Statement ***************************/ class Statement : TopStatement { LabelSymbol *label; this(Loc loc) { super(loc); this.loc = loc; } void toBuffer(inout tchar[] buf) { buf ~= "Statement.toBuffer()\n"; } Statement semantic(Scope *sc) { writef("Statement.semantic(%p)\n", this); return this; } void toIR(IRstate *irs) { writef("Statement.toIR(%p)\n", this); } uint getBreak() { assert(0); return 0; } uint getContinue() { assert(0); return 0; } uint getGoto() { assert(0); return 0; } uint getTarget() { assert(0); return 0; } ScopeStatement getScope() { return null; } } /******************************** EmptyStatement ***************************/ class EmptyStatement : Statement { this(Loc loc) { super(loc); this.loc = loc; } void toBuffer(inout tchar[] buf) { buf ~= ";\n"; } Statement semantic(Scope *sc) { //writef("EmptyStatement.semantic(%p)\n", this); return this; } void toIR(IRstate *irs) { } } /******************************** ExpStatement ***************************/ class ExpStatement : Statement { Expression exp; this(Loc loc, Expression exp) { //writef("ExpStatement.ExpStatement(this = %x, exp = %x)\n", this, exp); super(loc); st = EXPSTATEMENT; this.exp = exp; } void toBuffer(inout tchar[] buf) { if (exp) exp.toBuffer(buf); buf ~= ";\n"; } Statement semantic(Scope *sc) { //writef("exp = '%s'\n", exp.toString()); //writef("ExpStatement.semantic(this = %x, exp = %x, exp.vptr = %x, %x, %x)\n", this, exp, ((uint *)exp)[0], /*(*(uint **)exp)[12],*/ *(uint *)(*(uint **)exp)[12]); if (exp) exp = exp.semantic(sc); //writef("-semantic()\n"); return this; } TopStatement ImpliedReturn() { return new ImpliedReturnStatement(loc, exp); } void toIR(IRstate *irs) { //writef("ExpStatement.toIR(%p)\n", exp); if (exp) { uint marksave = irs.mark(); assert(exp); exp.toIR(irs, 0); irs.release(marksave); exp = null; // release to garbage collector } } } /****************************** VarDeclaration ******************************/ class VarDeclaration { Loc loc; Identifier *name; Expression init; this(Loc loc, Identifier *name, Expression init) { this.loc = loc; this.init = init; this.name = name; } } /******************************** VarStatement ***************************/ class VarStatement : Statement { VarDeclaration[] vardecls; this(Loc loc) { super(loc); st = VARSTATEMENT; } Statement semantic(Scope *sc) { FunctionDefinition fd; uint i; // Collect all the Var statements in order in the function // declaration, this is so it is easy to instantiate them fd = sc.funcdef; //fd.varnames.reserve(vardecls.length); for (i = 0; i < vardecls.length; i++) { VarDeclaration vd; vd = vardecls[i]; if (vd.init) vd.init = vd.init.semantic(sc); fd.varnames ~= vd.name; } return this; } void toBuffer(inout tchar[] buf) { uint i; if (vardecls.length) { buf ~= "var "; for (i = 0; i < vardecls.length; i++) { VarDeclaration vd; vd = vardecls[i]; buf ~= vd.name.toString(); if (vd.init) { buf ~= " = "; vd.init.toBuffer(buf); } } buf ~= ";\n"; } } void toIR(IRstate *irs) { uint i; uint ret; if (vardecls.length) { uint marksave; marksave = irs.mark(); ret = irs.alloc(1); for (i = 0; i < vardecls.length; i++) { VarDeclaration vd; vd = vardecls[i]; // This works like assignment statements: // name = init; IR property; if (vd.init) { vd.init.toIR(irs, ret); property.id = Identifier.build(vd.name.toString()); irs.gen2(loc, IRputthis, ret, property.index); } } irs.release(marksave); vardecls[] = null; // help gc } } } /******************************** BlockStatement ***************************/ class BlockStatement : Statement { Statement[] statements; this(Loc loc) { super(loc); } Statement semantic(Scope *sc) { uint i; //writefln("BlockStatement.semantic()"); for (i = 0; i < statements.length; i++) { Statement s; s = statements[i]; assert(s); statements[i] = s.semantic(sc); } return this; } TopStatement ImpliedReturn() { uint i = statements.length; if (i) { TopStatement ts = statements[i - 1]; ts = ts.ImpliedReturn(); statements[i - 1] = cast(Statement)ts; } return this; } void toBuffer(inout tchar[] buf) { buf ~= "{\n"; foreach (Statement s; statements) { s.toBuffer(buf); } buf ~= "}\n"; } void toIR(IRstate *irs) { foreach (Statement s; statements) { s.toIR(irs); } // Release to garbage collector statements[] = null; statements = null; } } /******************************** LabelStatement ***************************/ class LabelStatement : Statement { Identifier* ident; Statement statement; uint gotoIP; uint breakIP; ScopeStatement scopeContext; this(Loc loc, Identifier *ident, Statement statement) { //writef("LabelStatement.LabelStatement(%p, '%s', %p)\n", this, ident.toChars(), statement); super(loc); this.ident = ident; this.statement = statement; gotoIP = ~0u; breakIP = ~0u; scopeContext = null; } Statement semantic(Scope *sc) { LabelSymbol ls; //writef("LabelStatement.semantic('%ls')\n", ident.toString()); scopeContext = sc.scopeContext; ls = sc.searchLabel(ident); if (ls) { // Ignore multiple definition errors //if (ls.statement) //error(sc, "label '%s' is already defined", ident.toString()); ls.statement = this; } else { ls = new LabelSymbol(loc, ident, this); sc.insertLabel(ls); } if (statement) statement = statement.semantic(sc); return this; } TopStatement ImpliedReturn() { if (statement) statement = cast(Statement)statement.ImpliedReturn(); return this; } void toBuffer(inout tchar[] buf) { buf ~= ident.toString(); buf ~= ": "; if (statement) statement.toBuffer(buf); else buf ~= '\n'; } void toIR(IRstate *irs) { gotoIP = irs.getIP(); statement.toIR(irs); breakIP = irs.getIP(); } uint getGoto() { return gotoIP; } uint getBreak() { return breakIP; } uint getContinue() { return statement.getContinue(); } ScopeStatement getScope() { return scopeContext; } } /******************************** IfStatement ***************************/ class IfStatement : Statement { Expression condition; Statement ifbody; Statement elsebody; this(Loc loc, Expression condition, Statement ifbody, Statement elsebody) { super(loc); this.condition = condition; this.ifbody = ifbody; this.elsebody = elsebody; } Statement semantic(Scope *sc) { //writef("IfStatement.semantic(%p)\n", sc); assert(condition); condition = condition.semantic(sc); ifbody = ifbody.semantic(sc); if (elsebody) elsebody = elsebody.semantic(sc); return this; } TopStatement ImpliedReturn() { assert(condition); ifbody = cast(Statement)ifbody.ImpliedReturn(); if (elsebody) elsebody = cast(Statement)elsebody.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint c; uint u1; uint u2; assert(condition); c = irs.alloc(1); condition.toIR(irs, c); u1 = irs.getIP(); irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c); irs.release(c, 1); ifbody.toIR(irs); if (elsebody) { u2 = irs.getIP(); irs.gen1(loc, IRjmp, 0); irs.patchJmp(u1, irs.getIP()); elsebody.toIR(irs); irs.patchJmp(u2, irs.getIP()); } else { irs.patchJmp(u1, irs.getIP()); } // Help GC condition = null; ifbody = null; elsebody = null; } } /******************************** SwitchStatement ***************************/ class SwitchStatement : Statement { Expression condition; Statement bdy; uint breakIP; ScopeStatement scopeContext; DefaultStatement swdefault; CaseStatement[] cases; this(Loc loc, Expression c, Statement b) { super(loc); condition = c; bdy = b; breakIP = ~0u; scopeContext = null; swdefault = null; cases = null; } Statement semantic(Scope *sc) { condition = condition.semantic(sc); SwitchStatement switchSave = sc.switchTarget; Statement breakSave = sc.breakTarget; scopeContext = sc.scopeContext; sc.switchTarget = this; sc.breakTarget = this; bdy = bdy.semantic(sc); sc.switchTarget = switchSave; sc.breakTarget = breakSave; return this; } void toIR(IRstate *irs) { uint c; uint udefault; uint marksave; //writef("SwitchStatement.toIR()\n"); marksave = irs.mark(); c = irs.alloc(1); condition.toIR(irs, c); // Generate a sequence of cmp-jt // Not the most efficient, but we await a more formal // specification of switch before we attempt to optimize if (cases.length) { uint x; x = irs.alloc(1); for (uint i = 0; i < cases.length; i++) { CaseStatement cs; x = irs.alloc(1); cs = cases[i]; cs.exp.toIR(irs, x); irs.gen3(loc, IRcid, x, c, x); cs.patchIP = irs.getIP(); irs.gen2(loc, IRjt, 0, x); } } udefault = irs.getIP(); irs.gen1(loc, IRjmp, 0); Statement breakSave = irs.breakTarget; irs.breakTarget = this; bdy.toIR(irs); irs.breakTarget = breakSave; breakIP = irs.getIP(); // Patch jump addresses if (cases.length) { for (uint i = 0; i < cases.length; i++) { CaseStatement cs; cs = cases[i]; irs.patchJmp(cs.patchIP, cs.caseIP); } } if (swdefault) irs.patchJmp(udefault, swdefault.defaultIP); else irs.patchJmp(udefault, breakIP); irs.release(marksave); // Help gc condition = null; bdy = null; } uint getBreak() { return breakIP; } ScopeStatement getScope() { return scopeContext; } } /******************************** CaseStatement ***************************/ class CaseStatement : Statement { Expression exp; uint caseIP; uint patchIP; this(Loc loc, Expression exp) { super(loc); this.exp = exp; caseIP = ~0u; patchIP = ~0u; } Statement semantic(Scope *sc) { //writef("CaseStatement.semantic(%p)\n", sc); exp = exp.semantic(sc); if (sc.switchTarget) { SwitchStatement sw = sc.switchTarget; uint i; // Look for duplicate for (i = 0; i < sw.cases.length; i++) { CaseStatement cs = sw.cases[i]; if (exp == cs.exp) { error(sc, errmsgtbl[ERR_SWITCH_REDUNDANT_CASE], exp.toString()); return null; } } sw.cases ~= this; } else { error(sc, errmsgtbl[ERR_MISPLACED_SWITCH_CASE], exp.toString()); return null; } return this; } void toIR(IRstate *irs) { caseIP = irs.getIP(); } } /******************************** DefaultStatement ***************************/ class DefaultStatement : Statement { uint defaultIP; this(Loc loc) { super(loc); defaultIP = ~0u; } Statement semantic(Scope *sc) { if (sc.switchTarget) { SwitchStatement sw = sc.switchTarget; if (sw.swdefault) { error(sc, ERR_SWITCH_REDUNDANT_DEFAULT); return null; } sw.swdefault = this; } else { error(sc, ERR_MISPLACED_SWITCH_DEFAULT); return null; } return this; } void toIR(IRstate *irs) { defaultIP = irs.getIP(); } } /******************************** DoStatement ***************************/ class DoStatement : Statement { Statement bdy; Expression condition; uint breakIP; uint continueIP; ScopeStatement scopeContext; this(Loc loc, Statement b, Expression c) { super(loc); bdy = b; condition = c; breakIP = ~0u; continueIP = ~0u; scopeContext = null; } Statement semantic(Scope *sc) { Statement continueSave = sc.continueTarget; Statement breakSave = sc.breakTarget; scopeContext = sc.scopeContext; sc.continueTarget = this; sc.breakTarget = this; bdy = bdy.semantic(sc); condition = condition.semantic(sc); sc.continueTarget = continueSave; sc.breakTarget = breakSave; return this; } TopStatement ImpliedReturn() { if (bdy) bdy = cast(Statement)bdy.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint c; uint u1; Statement continueSave = irs.continueTarget; Statement breakSave = irs.breakTarget; uint marksave; irs.continueTarget = this; irs.breakTarget = this; marksave = irs.mark(); u1 = irs.getIP(); bdy.toIR(irs); c = irs.alloc(1); continueIP = irs.getIP(); condition.toIR(irs, c); irs.gen2(loc, (condition.isBooleanResult() ? IRjtb : IRjt), u1 - irs.getIP(), c); breakIP = irs.getIP(); irs.release(marksave); irs.continueTarget = continueSave; irs.breakTarget = breakSave; // Help GC condition = null; bdy = null; } uint getBreak() { return breakIP; } uint getContinue() { return continueIP; } ScopeStatement getScope() { return scopeContext; } } /******************************** WhileStatement ***************************/ class WhileStatement : Statement { Expression condition; Statement bdy; uint breakIP; uint continueIP; ScopeStatement scopeContext; this(Loc loc, Expression c, Statement b) { super(loc); condition = c; bdy = b; breakIP = ~0u; continueIP = ~0u; scopeContext = null; } Statement semantic(Scope *sc) { Statement continueSave = sc.continueTarget; Statement breakSave = sc.breakTarget; scopeContext = sc.scopeContext; sc.continueTarget = this; sc.breakTarget = this; condition = condition.semantic(sc); bdy = bdy.semantic(sc); sc.continueTarget = continueSave; sc.breakTarget = breakSave; return this; } TopStatement ImpliedReturn() { if (bdy) bdy = cast(Statement)bdy.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint c; uint u1; uint u2; Statement continueSave = irs.continueTarget; Statement breakSave = irs.breakTarget; uint marksave = irs.mark(); irs.continueTarget = this; irs.breakTarget = this; u1 = irs.getIP(); continueIP = u1; c = irs.alloc(1); condition.toIR(irs, c); u2 = irs.getIP(); irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c); bdy.toIR(irs); irs.gen1(loc, IRjmp, u1 - irs.getIP()); irs.patchJmp(u2, irs.getIP()); breakIP = irs.getIP(); irs.release(marksave); irs.continueTarget = continueSave; irs.breakTarget = breakSave; // Help GC condition = null; bdy = null; } uint getBreak() { return breakIP; } uint getContinue() { return continueIP; } ScopeStatement getScope() { return scopeContext; } } /******************************** ForStatement ***************************/ class ForStatement : Statement { Statement init; Expression condition; Expression increment; Statement bdy; uint breakIP; uint continueIP; ScopeStatement scopeContext; this(Loc loc, Statement init, Expression condition, Expression increment, Statement bdy) { super(loc); this.init = init; this.condition = condition; this.increment = increment; this.bdy = bdy; breakIP = ~0u; continueIP = ~0u; scopeContext = null; } Statement semantic(Scope *sc) { Statement continueSave = sc.continueTarget; Statement breakSave = sc.breakTarget; if (init) init = init.semantic(sc); if (condition) condition = condition.semantic(sc); if (increment) increment = increment.semantic(sc); scopeContext = sc.scopeContext; sc.continueTarget = this; sc.breakTarget = this; bdy = bdy.semantic(sc); sc.continueTarget = continueSave; sc.breakTarget = breakSave; return this; } TopStatement ImpliedReturn() { if (bdy) bdy = cast(Statement)bdy.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint u1; uint u2 = 0; // unneeded initialization keeps lint happy Statement continueSave = irs.continueTarget; Statement breakSave = irs.breakTarget; uint marksave = irs.mark(); irs.continueTarget = this; irs.breakTarget = this; if (init) init.toIR(irs); u1 = irs.getIP(); if (condition) { if (condition.op == TOKless || condition.op == TOKlessequal) { BinExp be = cast(BinExp)condition; RealExpression re; uint b; uint c; b = irs.alloc(1); be.e1.toIR(irs, b); re = cast(RealExpression )be.e2; if (be.e2.op == TOKreal && !isnan(re.value)) { u2 = irs.getIP(); irs.gen(loc, (condition.op == TOKless) ? IRjltc : IRjlec, 4, 0, b, re.value); } else { c = irs.alloc(1); be.e2.toIR(irs, c); u2 = irs.getIP(); irs.gen3(loc, (condition.op == TOKless) ? IRjlt : IRjle, 0, b, c); } } else { uint c; c = irs.alloc(1); condition.toIR(irs, c); u2 = irs.getIP(); irs.gen2(loc, (condition.isBooleanResult() ? IRjfb : IRjf), 0, c); } } bdy.toIR(irs); continueIP = irs.getIP(); if (increment) increment.toIR(irs, 0); irs.gen1(loc, IRjmp, u1 - irs.getIP()); if (condition) irs.patchJmp(u2, irs.getIP()); breakIP = irs.getIP(); irs.release(marksave); irs.continueTarget = continueSave; irs.breakTarget = breakSave; // Help GC init = null; condition = null; bdy = null; increment = null; } uint getBreak() { return breakIP; } uint getContinue() { return continueIP; } ScopeStatement getScope() { return scopeContext; } } /******************************** ForInStatement ***************************/ class ForInStatement : Statement { Statement init; Expression inexp; Statement bdy; uint breakIP; uint continueIP; ScopeStatement scopeContext; this(Loc loc, Statement init, Expression inexp, Statement bdy) { super(loc); this.init = init; this.inexp = inexp; this.bdy = bdy; breakIP = ~0u; continueIP = ~0u; scopeContext = null; } Statement semantic(Scope *sc) { Statement continueSave = sc.continueTarget; Statement breakSave = sc.breakTarget; init = init.semantic(sc); if (init.st == EXPSTATEMENT) { ExpStatement es; es = cast(ExpStatement)(init); es.exp.checkLvalue(sc); } else if (init.st == VARSTATEMENT) { } else { error(sc, ERR_INIT_NOT_EXPRESSION); return null; } inexp = inexp.semantic(sc); scopeContext = sc.scopeContext; sc.continueTarget = this; sc.breakTarget = this; bdy = bdy.semantic(sc); sc.continueTarget = continueSave; sc.breakTarget = breakSave; return this; } TopStatement ImpliedReturn() { bdy = cast(Statement)bdy.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint e; uint iter; ExpStatement es; VarStatement vs; uint base; IR property; int opoff; uint marksave = irs.mark(); e = irs.alloc(1); inexp.toIR(irs, e); iter = irs.alloc(1); irs.gen2(loc, IRiter, iter, e); Statement continueSave = irs.continueTarget; Statement breakSave = irs.breakTarget; irs.continueTarget = this; irs.breakTarget = this; if (init.st == EXPSTATEMENT) { es = cast(ExpStatement)(init); es.exp.toLvalue(irs, base, &property, opoff); } else if (init.st == VARSTATEMENT) { VarDeclaration vd; vs = cast(VarStatement)(init); assert(vs.vardecls.length == 1); vd = vs.vardecls[0]; property.id = Identifier.build(vd.name.toString()); opoff = 2; base = ~0u; } else { // Error already reported by semantic() return; } continueIP = irs.getIP(); if (opoff == 2) irs.gen3(loc, IRnextscope, 0, property.index, iter); else irs.gen(loc, IRnext + opoff, 4, 0, base, property.index, iter); bdy.toIR(irs); irs.gen1(loc, IRjmp, continueIP - irs.getIP()); irs.patchJmp(continueIP, irs.getIP()); breakIP = irs.getIP(); irs.continueTarget = continueSave; irs.breakTarget = breakSave; irs.release(marksave); // Help GC init = null; inexp = null; bdy = null; } uint getBreak() { return breakIP; } uint getContinue() { return continueIP; } ScopeStatement getScope() { return scopeContext; } } /******************************** ScopeStatement ***************************/ class ScopeStatement : Statement { ScopeStatement enclosingScope; int depth; // syntactical nesting level of ScopeStatement's int npops; // how many items added to scope chain this(Loc loc) { super(loc); enclosingScope = null; depth = 1; npops = 1; } } /******************************** WithStatement ***************************/ class WithStatement : ScopeStatement { Expression exp; Statement bdy; this(Loc loc, Expression exp, Statement bdy) { super(loc); this.exp = exp; this.bdy = bdy; } Statement semantic(Scope *sc) { exp = exp.semantic(sc); enclosingScope = sc.scopeContext; sc.scopeContext = this; // So enclosing FunctionDeclaration knows how deep the With's // can nest if (enclosingScope) depth = enclosingScope.depth + 1; if (depth > sc.funcdef.withdepth) sc.funcdef.withdepth = depth; sc.nestDepth++; bdy = bdy.semantic(sc); sc.nestDepth--; sc.scopeContext = enclosingScope; return this; } TopStatement ImpliedReturn() { bdy = cast(Statement)bdy.ImpliedReturn(); return this; } void toIR(IRstate *irs) { uint c; uint marksave = irs.mark(); irs.scopeContext = this; c = irs.alloc(1); exp.toIR(irs, c); irs.gen1(loc, IRpush, c); bdy.toIR(irs); irs.gen0(loc, IRpop); irs.scopeContext = enclosingScope; irs.release(marksave); // Help GC exp = null; bdy = null; } } /******************************** ContinueStatement ***************************/ class ContinueStatement : Statement { Identifier *ident; Statement target; this(Loc loc, Identifier *ident) { super(loc); this.ident = ident; target = null; } Statement semantic(Scope *sc) { if (ident == null) { target = sc.continueTarget; if (!target) { error(sc, ERR_MISPLACED_CONTINUE); return null; } } else { LabelSymbol ls; ls = sc.searchLabel(ident); if (!ls || !ls.statement) { error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString()); return null; } else target = ls.statement; } return this; } void toIR(IRstate *irs) { ScopeStatement w; ScopeStatement tw; tw = target.getScope(); for (w = irs.scopeContext; !(w is tw); w = w.enclosingScope) { assert(w); irs.pops(w.npops); } irs.addFixup(irs.getIP()); irs.gen1(loc, IRjmp, cast(uint)cast(void*)this); } uint getTarget() { assert(target); return target.getContinue(); } } /******************************** BreakStatement ***************************/ class BreakStatement : Statement { Identifier *ident; Statement target; this(Loc loc, Identifier *ident) { super(loc); this.ident = ident; target = null; } Statement semantic(Scope *sc) { //writef("BreakStatement.semantic(%p)\n", sc); if (ident == null) { target = sc.breakTarget; if (!target) { error(sc, ERR_MISPLACED_BREAK); return null; } } else { LabelSymbol ls; ls = sc.searchLabel(ident); if (!ls || !ls.statement) { error(sc, errmsgtbl[ERR_UNDEFINED_STATEMENT_LABEL], ident.toString()); return null; } else target = ls.statement; } return this; } void toIR(IRstate *irs) { ScopeStatement w; ScopeStatement tw; assert(target); tw = target.getScope(); for (w = irs.scopeContext; !(w is tw); w = w.enclosingScope) { assert(w); irs.pops(w.npops); } irs.addFixup(irs.getIP()); irs.gen1(loc, IRjmp, cast(uint)cast(void*)this); } uint getTarget() { assert(target); return target.getBreak(); } } /******************************** GotoStatement ***************************/ class GotoStatement : Statement { Identifier *ident; LabelSymbol label; this(Loc loc, Identifier *ident) { super(loc); this.ident = ident; label = null; } Statement semantic(Scope *sc) { LabelSymbol ls; ls = sc.searchLabel(ident); if (!ls) { ls = new LabelSymbol(loc, ident, null); sc.insertLabel(ls); } label = ls; return this; } void toIR(IRstate *irs) { assert(label); // Determine how many with pops we need to do for (ScopeStatement w = irs.scopeContext; ; w = w.enclosingScope) { if (!w) { if (label.statement.scopeContext) { assert(0); // BUG: should do next statement instead //script.error(errmsgtbl[ERR_GOTO_INTO_WITH]); } break; } if (w is label.statement.scopeContext) break; irs.pops(w.npops); } irs.addFixup(irs.getIP()); irs.gen1(loc, IRjmp, cast(uint)cast(void*)this); } uint getTarget() { return label.statement.getGoto(); } } /******************************** ReturnStatement ***************************/ class ReturnStatement : Statement { Expression exp; this(Loc loc, Expression exp) { super(loc); this.exp = exp; } Statement semantic(Scope *sc) { if (exp) exp = exp.semantic(sc); // Don't allow return from eval functions or global function if (sc.funcdef.iseval || sc.funcdef.isglobal) error(sc, ERR_MISPLACED_RETURN); return this; } void toBuffer(inout tchar[] buf) { //writef("ReturnStatement.toBuffer()\n"); buf ~= "return "; if (exp) exp.toBuffer(buf); buf ~= ";\n"; } void toIR(IRstate *irs) { ScopeStatement w; int npops; npops = 0; for (w = irs.scopeContext; w; w = w.enclosingScope) npops += w.npops; if (exp) { uint e; e = irs.alloc(1); exp.toIR(irs, e); if (npops) { irs.gen1(loc, IRimpret, e); irs.pops(npops); irs.gen0(loc, IRret); } else irs.gen1(loc, IRretexp, e); irs.release(e, 1); } else { if (npops) irs.pops(npops); irs.gen0(loc, IRret); } // Help GC exp = null; } } /******************************** ImpliedReturnStatement ***************************/ // Same as ReturnStatement, except that the return value is set but the // function does not actually return. Useful for setting the return // value for loop bodies. class ImpliedReturnStatement : Statement { Expression exp; this(Loc loc, Expression exp) { super(loc); this.exp = exp; } Statement semantic(Scope *sc) { if (exp) exp = exp.semantic(sc); return this; } void toBuffer(inout tchar[] buf) { if (exp) exp.toBuffer(buf); buf ~= ";\n"; } void toIR(IRstate *irs) { if (exp) { uint e; e = irs.alloc(1); exp.toIR(irs, e); irs.gen1(loc, IRimpret, e); irs.release(e, 1); // Help GC exp = null; } } } /******************************** ThrowStatement ***************************/ class ThrowStatement : Statement { Expression exp; this(Loc loc, Expression exp) { super(loc); this.exp = exp; } Statement semantic(Scope *sc) { if (exp) exp = exp.semantic(sc); else { error(sc, ERR_NO_THROW_EXPRESSION); return new EmptyStatement(loc); } return this; } void toBuffer(inout tchar[] buf) { buf ~= "throw "; if (exp) exp.toBuffer(buf); buf ~= ";\n"; } void toIR(IRstate *irs) { uint e; assert(exp); e = irs.alloc(1); exp.toIR(irs, e); irs.gen1(loc, IRthrow, e); irs.release(e, 1); // Help GC exp = null; } } /******************************** TryStatement ***************************/ class TryStatement : ScopeStatement { Statement bdy; Identifier* catchident; Statement catchbdy; Statement finalbdy; this(Loc loc, Statement bdy, Identifier *catchident, Statement catchbdy, Statement finalbdy) { super(loc); this.bdy = bdy; this.catchident = catchident; this.catchbdy = catchbdy; this.finalbdy = finalbdy; if (catchbdy && finalbdy) npops = 2; // 2 items in scope chain } Statement semantic(Scope *sc) { enclosingScope = sc.scopeContext; sc.scopeContext = this; // So enclosing FunctionDeclaration knows how deep the With's // can nest if (enclosingScope) depth = enclosingScope.depth + 1; if (depth > sc.funcdef.withdepth) sc.funcdef.withdepth = depth; bdy.semantic(sc); if (catchbdy) catchbdy.semantic(sc); if (finalbdy) finalbdy.semantic(sc); sc.scopeContext = enclosingScope; return this; } void toBuffer(inout tchar[] buf) { buf ~= "try\n"; bdy.toBuffer(buf); if (catchident) { buf ~= "catch (" ~ catchident.toString() ~ ")\n"; } if (catchbdy) catchbdy.toBuffer(buf); if (finalbdy) { buf ~= "finally\n"; finalbdy.toBuffer(buf); } } void toIR(IRstate *irs) { uint f; uint c; uint e; uint e2; uint marksave = irs.mark(); irs.scopeContext = this; if (finalbdy) { f = irs.getIP(); irs.gen1(loc, IRtryfinally, 0); if (catchbdy) { c = irs.getIP(); irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString())); bdy.toIR(irs); irs.gen0(loc, IRpop); // remove catch clause irs.gen0(loc, IRpop); // call finalbdy e = irs.getIP(); irs.gen1(loc, IRjmp, 0); irs.patchJmp(c, irs.getIP()); catchbdy.toIR(irs); irs.gen0(loc, IRpop); // remove catch object irs.gen0(loc, IRpop); // call finalbdy code e2 = irs.getIP(); irs.gen1(loc, IRjmp, 0); // jmp past finalbdy irs.patchJmp(f, irs.getIP()); irs.scopeContext = enclosingScope; finalbdy.toIR(irs); irs.gen0(loc, IRfinallyret); irs.patchJmp(e, irs.getIP()); irs.patchJmp(e2, irs.getIP()); } else // finalbdy only { bdy.toIR(irs); irs.gen0(loc, IRpop); e = irs.getIP(); irs.gen1(loc, IRjmp, 0); irs.patchJmp(f, irs.getIP()); irs.scopeContext = enclosingScope; finalbdy.toIR(irs); irs.gen0(loc, IRfinallyret); irs.patchJmp(e, irs.getIP()); } } else // catchbdy only { c = irs.getIP(); irs.gen2(loc, IRtrycatch, 0, cast(uint)Identifier.build(catchident.toString())); bdy.toIR(irs); irs.gen0(loc, IRpop); e = irs.getIP(); irs.gen1(loc, IRjmp, 0); irs.patchJmp(c, irs.getIP()); catchbdy.toIR(irs); irs.gen0(loc, IRpop); irs.patchJmp(e, irs.getIP()); } irs.scopeContext = enclosingScope; irs.release(marksave); // Help GC bdy = null; catchident = null; catchbdy = null; finalbdy = null; } }