// This file is part of Visual D
//
// Visual D integrates the D programming language into Visual Studio
// Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
//
// interpret: return null to indicate that execution should continue
//            return special values for program flow control
//            return normal values for returning values
//
module vdc.ast.stmt;

import vdc.util;
import vdc.lexer;
import vdc.ast.node;
import vdc.ast.expr;
import vdc.ast.decl;
import vdc.ast.type;
import vdc.ast.writer;
import vdc.semantic;
import vdc.interpret;

import vdc.parser.engine;

import stdext.util;

import std.conv;

//Statement:
//    [Statement...]
class Statement : Node
{
    mixin ForwardCtor!();

    override Value interpret(Context sc)
    {
        foreach(m; members)
        {
            if (Value v = m.interpret(sc))
                return v;
        }
        return null;
    }
}

class EmptyStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer(";");
        writer.nl;
    }
}

version(obsolete)
{
//ScopeStatement:
//    ;
//    NonEmptyStatement
//    ScopeBlockStatement
//
//ScopeBlockStatement:
//    BlockStatement
class ScopeStatement : Statement
{
    mixin ForwardCtor!();
}

//ScopeNonEmptyStatement:
//    NonEmptyStatement
//    BlockStatement
class ScopeNonEmptyStatement : Statement
{
    mixin ForwardCtor!();
}

//NoScopeNonEmptyStatement:
//    NonEmptyStatement
//    BlockStatement
class NoScopeNonEmptyStatement : ScopeNonEmptyStatement
{
    mixin ForwardCtor!();
}

//NoScopeStatement:
//    ;
//    NonEmptyStatement
//    BlockStatement
class NoScopeStatement : ScopeStatement
{
    mixin ForwardCtor!();
}

//NonEmptyStatement:
//    LabeledStatement
//    ExpressionStatement
//    DeclarationStatement
//    IfStatement
//    WhileStatement
//    DoStatement
//    ForStatement
//    ForeachStatement
//    SwitchStatement
//    FinalSwitchStatement
//    CaseStatement
//    CaseRangeStatement
//    DefaultStatement
//    ContinueStatement
//    BreakStatement
//    ReturnStatement
//    GotoStatement
//    WithStatement
//    SynchronizedStatement
//    VolatileStatement
//    TryStatement
//    ScopeGuardStatement
//    ThrowStatement
//    AsmStatement
//    PragmaStatement
//    MixinStatement
//    ForeachRangeStatement
//    ConditionalStatement
//    StaticAssert
//    TemplateMixin
class NonEmptyStatement : Statement
{
    mixin ForwardCtor!();
}
} // version(obsolete)

//LabeledStatement:
//    Identifier : NoScopeStatement
class LabeledStatement : Statement
{
    string ident;

    Statement getStatement() { return getMember!Statement(0); }

    this() {} // default constructor needed for clone()

    this(Token tok)
    {
        super(tok);
        ident = tok.txt;
    }

    override LabeledStatement clone()
    {
        LabeledStatement n = static_cast!LabeledStatement(super.clone());
        n.ident = ident;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.ident == ident;
    }

    override void toD(CodeWriter writer)
    {
        {
            CodeIndenter indent = CodeIndenter(writer, -1);
            writer.writeIdentifier(ident);
            writer(":");
            writer.nl;
        }
        writer(getStatement());
    }
}

//BlockStatement:
//    { }
//    { StatementList }
//
//StatementList:
//    Statement
//    Statement StatementList
class BlockStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("{");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            foreach(m; members)
                writer(m);
        }
        writer("}");
        writer.nl;
    }

    override bool createsScope() const { return true; }

    override void _semantic(Scope sc)
    {
        // TODO: TemplateParameterList, Constraint
        if(members.length > 0)
        {
            sc = enterScope(sc);
            super._semantic(sc);
            sc = sc.pop();
        }
    }

}

//ExpressionStatement:
//    [Expression]
class ExpressionStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer(getMember(0), ";");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        getMember(0).interpret(sc);
        return null;
    }
}

//DeclarationStatement:
//    [Decl]
class DeclarationStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer(getMember(0));
    }

    override Node[] expandNonScopeBlock(Scope sc, Node[] athis)
    {
        Node n = getMember(0);
        Node[1] nthis = [ n ];
        Node[] nm = n.expandNonScopeBlock(sc, nthis);
        if(nm.length == 1 && nm[0] == n)
            return athis;

        Node[] decls;
        foreach(m; nm)
        {
            auto decl = new DeclarationStatement(id, span);
            decl.addMember(m);
            decls ~= decl;
        }
        return decls;
    }

    override void addSymbols(Scope sc)
    {
        addMemberSymbols(sc);
    }

    override void _semantic(Scope sc)
    {
        auto decl = getMember(0);
        decl.addSymbols(sc); // symbols might already be referenced in an initializer
        super._semantic(sc);
        if(decl.attr & Attr_Static)
        {
            Context ctx = new Context(nullContext);
            ctx.scop = sc;
            initValues(ctx, false);
        }
    }

    override Value interpret(Context sc)
    {
        auto decl = getMember(0);
        if(!(decl.attr & Attr_Static))
            initValues(sc, true);
        return null;
    }

    void initValues(Context sc, bool reinit)
    {
        auto decl = cast(Decl)getMember(0);
        if(!decl)
            return; // classes, enums, etc
        //if(decl.getFunctionBody())
        //    return; // nothing to do for local functions

        auto decls = decl.getDeclarators();
        for(int n = 0; n < decls.members.length; n++)
        {
            auto d = decls.getDeclarator(n);
            if(reinit)
            {
                d.value = null;
                d.interpretReinit(sc);
            }
            else
                d.interpret(sc);
        }
    }
}

//ImportStatement:
//    [ImportDeclaration]
class ImportStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        getMember(0).toD(writer);
    }

    override Value interpret(Context sc)
    {
        return null;
    }
}

//IfStatement:
//    if ( IfCondition ) ThenStatement
//    if ( IfCondition ) ThenStatement else ElseStatement
//
//IfCondition:
//    Expression
//    auto Identifier = Expression
//    Declarator = Expression
//
//ThenStatement:
//    ScopeNonEmptyStatement
//
//ElseStatement:
//    ScopeNonEmptyStatement
class IfStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("if(", getMember(0), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(1));
        }
        if(members.length > 2)
        {
            writer("else");
            writer.nl;
            {
                CodeIndenter indent = CodeIndenter(writer);
                writer(getMember(2));
            }
        }
    }

    override bool createsScope() const { return true; }

    override Value interpret(Context sc)
    {
        Value cond = getMember(0).interpret(sc);
        if(cond.toBool())
        {
            if(Value v = getMember(1).interpret(sc))
                return v;
        }
        else if(members.length > 2)
        {
            if(Value v = getMember(2).interpret(sc))
                return v;
        }
        return null;
    }
}

//WhileStatement:
//    while ( Expression ) ScopeNonEmptyStatement
class WhileStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("while(", getMember(0), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(1));
        }
    }

    override Value interpret(Context sc)
    {
        while(getMember(0).interpret(sc).toBool())
        {
            if(Value v = getMember(1).interpret(sc))
            {
                if(auto bv = cast(BreakValue)v)
                {
                    if(!bv.label)
                        break;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == bv.label)
                            break;
                }
                else if(auto cv = cast(ContinueValue)v)
                {
                    if(!cv.label)
                        continue;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == cv.label)
                            continue;
                }
                return v;
            }
        }
        return null;
    }
}

//DoStatement:
//    do ScopeNonEmptyStatement while ( Expression )
class DoStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("do");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(0));
        }
        writer("while(", getMember(1), ")");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        do
        {
            if(Value v = getMember(0).interpret(sc))
            {
                if(auto bv = cast(BreakValue)v)
                {
                    if(!bv.label)
                        break;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == bv.label)
                            break;
                }
                else if(auto cv = cast(ContinueValue)v)
                {
                    if(!cv.label)
                        continue;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == cv.label)
                            continue;
                }
                return v;
            }
        }
        while(getMember(1).interpret(sc).toBool());
        return null;
    }
}

//ForStatement:
//    for ( Initialize Test ; Increment ) ScopeNonEmptyStatement
//Initialize:
//    ;
//    NoScopeNonEmptyStatement
//
//Test:
//    Expression_opt
//
//Increment:
//    Expression_opt
//
class ForStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("for(", getMember(0), getMember(1), "; ", getMember(2), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(3));
        }
    }

    override Value interpret(Context sc)
    {
        for(getMember(0).interpret(sc); getMember(1).interpret(sc).toBool();
            getMember(2).interpret(sc))
        {
            if(Value v = getMember(3).interpret(sc))
            {
                if(auto bv = cast(BreakValue)v)
                {
                    if(!bv.label)
                        break;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == bv.label)
                            break;
                }
                else if(auto cv = cast(ContinueValue)v)
                {
                    if(!cv.label)
                        continue;
                    if(auto ls = cast(LabeledStatement)parent)
                        if(ls.ident == cv.label)
                            continue;
                }
                return v;
            }
        }
        return null;
    }
}

//ForeachStatement:
//    Foreach ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement
//
//Foreach:
//    foreach
//    foreach_reverse
//
//ForeachTypeList:
//    ForeachType
//    ForeachType , ForeachTypeList
//
//ForeachType:
//    ref Type Identifier
//    Type Identifier
//    ref Identifier
//    Identifier
//
//Aggregate:
//    Expression
//
//ForeachRangeStatement:
//    Foreach ( ForeachType ; LwrExpression .. UprExpression ) ScopeNonEmptyStatement
//
//LwrExpression:
//    Expression
//
//UprExpression:
//    Expression
class ForeachStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    Expression getAggregate() { return getMember!Expression(1); }
    Expression getLwrExpression() { return getMember!Expression(1); }
    Expression getUprExpression() { return getMember!Expression(2); }

    final bool isRangeForeach() const { return members.length > 3; }

    override void toD(CodeWriter writer)
    {
        writer(id, "(", getMember(0), "; ");
        if(members.length == 3)
            writer(getMember(1));
        else
            writer(getMember(1), " .. ", getMember(2));

        writer(")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(members.length - 1));
        }
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

class ForeachTypeList : Node
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer.writeArray(members);
    }

    override void addSymbols(Scope sc)
    {
        addMemberSymbols(sc);
    }
}

class ForeachType : Node
{
    mixin ForwardCtor!();

    bool isRef;
    Type type;

    Type getType() { return members.length == 2 ? getMember!Type(0) : null; }
    Identifier getIdentifier() { return getMember!Identifier(members.length - 1); }

    override ForeachType clone()
    {
        ForeachType n = static_cast!ForeachType(super.clone());
        n.isRef = isRef;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.isRef == isRef;
    }

    override void toD(CodeWriter writer)
    {
        if(isRef)
            writer("ref ");
        writer.writeArray(members, " ");
    }

    override void addSymbols(Scope sc)
    {
        string ident = getIdentifier().ident;
        sc.addSymbol(ident, this);
    }

    override Type calcType()
    {
        if(type)
            return type;

        if(auto t = getType())
            type = t.calcType();

        else if(ForeachStatement stmt = parent ? cast(ForeachStatement) parent.parent : null)
        {
            if(stmt.isRangeForeach())
                type = stmt.getLwrExpression().calcType();
            else
            {
                Expression expr = stmt.getAggregate();
                Type et = expr.calcType();
                if(auto ti = cast(TypeIndirection) et)
                {
                    type = ti.getNextType();
                }
            }
        }
        if(!type)
            type = semanticErrorType("cannot infer type of foreach variable ", getIdentifier().ident);
        return type;
    }
}

//SwitchStatement:
//    switch ( Expression ) ScopeNonEmptyStatement
class SwitchStatement : Statement
{
    mixin ForwardCtor!();

    bool isFinal;

    override bool createsScope() const { return true; }

    override SwitchStatement clone()
    {
        SwitchStatement n = static_cast!SwitchStatement(super.clone());
        n.isFinal = isFinal;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.isFinal == isFinal;
    }

    override void toD(CodeWriter writer)
    {
        if(isFinal)
            writer("final ");
        writer("switch(", getMember(0), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(1));
        }
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//FinalSwitchStatement:
//    final switch ( Expression ) ScopeNonEmptyStatement
//
class FinalSwitchStatement : Statement
{
    mixin ForwardCtor!();

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//CaseStatement:
//    case ArgumentList : Statement
//
//CaseRangeStatement:
//    case FirstExp : .. case LastExp : Statement
//
//FirstExp:
//    AssignExpression
//
//LastExp:
//    AssignExpression
class CaseStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        {
            CodeIndenter indent = CodeIndenter(writer, -1);
            writer("case ", getMember(0));
            if(id == TOK_slice)
            {
                writer(": .. case ", getMember(1));
            }
            else
            {
                writer.writeArray(members[1..$], ", ", true);
            }
            writer(":");
        }
        writer.nl();
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//DefaultStatement:
//    default : Statement
class DefaultStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        {
            CodeIndenter indent = CodeIndenter(writer, -1);
            writer("default:");
        }
        writer.nl();
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//ContinueStatement:
//    continue ;
//    continue Identifier ;
class ContinueStatement : Statement
{
    mixin ForwardCtor!();

    string ident;

    override ContinueStatement clone()
    {
        ContinueStatement n = static_cast!ContinueStatement(super.clone());
        n.ident = ident;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.ident == ident;
    }

    override void toD(CodeWriter writer)
    {
        writer("continue");
        if(ident.length)
        {
            writer(" ");
            writer.writeIdentifier(ident);
        }
        writer(";");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return new ContinueValue(ident);
    }
}

//BreakStatement:
//    break ;
//    break Identifier ;
class BreakStatement : Statement
{
    mixin ForwardCtor!();

    string ident;

    override BreakStatement clone()
    {
        BreakStatement n = static_cast!BreakStatement(super.clone());
        n.ident = ident;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.ident == ident;
    }

    override void toD(CodeWriter writer)
    {
        writer("break");
        if(ident.length)
        {
            writer(" ");
            writer.writeIdentifier(ident);
        }
        writer(";");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return new BreakValue(ident);
    }
}


//ReturnStatement:
//    return ;
//    return Expression ;
class ReturnStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("return ", getMember(0), ";");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return getMember(0).interpret(sc);
    }
}


//GotoStatement:
//    goto Identifier ;
//    goto default ;
//    goto case ;
//    goto case Expression ;
class GotoStatement : Statement
{
    mixin ForwardCtor!();

    string ident;

    override GotoStatement clone()
    {
        GotoStatement n = static_cast!GotoStatement(super.clone());
        n.ident = ident;
        return n;
    }
    override bool compare(const(Node) n) const
    {
        if(!super.compare(n))
            return false;

        auto tn = static_cast!(typeof(this))(n);
        return tn.ident == ident;
    }

    override void toD(CodeWriter writer)
    {
        if(id == TOK_Identifier)
        {
            writer("goto ");
            writer.writeIdentifier(ident);
            writer(";");
        }
        else if(id == TOK_default)
            writer("goto default;");
        else
        {
            if(members.length > 0)
                writer("goto case ", getMember(0), ";");
            else
                writer("goto case;");
        }
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//WithStatement:
//    with ( Expression ) ScopeNonEmptyStatement
//    with ( Symbol ) ScopeNonEmptyStatement
//    with ( TemplateInstance ) ScopeNonEmptyStatement
class WithStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("with(", getMember(0), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(1));
        }
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//SynchronizedStatement:
//    [Expression_opt ScopeNonEmptyStatement]
class SynchronizedStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        if(members.length > 1)
            writer("synchronized(", getMember(0), ") ");
        else
            writer("synchronized ");

        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(members.length - 1));
        }
    }

    override Value interpret(Context sc)
    {
        // no need to synhronize, interpreter is single-threaded
        return getMember(members.length - 1).interpret(sc);
    }
}

//VolatileStatement:
//    [ScopeNonEmptyStatement]
class VolatileStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("volatile ");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(members.length - 1));
        }
    }

    override Value interpret(Context sc)
    {
        // no need to synhronize, interpreter is single-threaded
        return super.interpret(sc);
    }
}


//TryStatement:
//    try ScopeNonEmptyStatement Catches
//    try ScopeNonEmptyStatement Catches FinallyStatement
//    try ScopeNonEmptyStatement FinallyStatement
//
//Catches:
//    LastCatch
//    Catch
//    Catch Catches
//
//LastCatch:
//    catch NoScopeNonEmptyStatement
//
//Catch:
//    catch ( CatchParameter ) NoScopeNonEmptyStatement
//
//CatchParameter:
//    BasicType Identifier
//
//FinallyStatement:
//    finally NoScopeNonEmptyStatement
class TryStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("try");
        writer.nl();
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(0));
        }
        foreach(m; members[1..$])
            writer(m);
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

class Catch : Node
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        if(members.length > 2)
            writer("catch(", getMember(0), " ", getMember(1), ")");
        else if(members.length > 1)
            writer("catch(", getMember(0), ")");
        else
            writer("catch");
        writer.nl();
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(members.length - 1));
        }
    }
}

class FinallyStatement : Catch
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("finally");
        writer.nl();
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(0));
        }
    }
}


//ThrowStatement:
//    throw Expression ;
class ThrowStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("throw ", getMember(0), ";");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//ScopeGuardStatement:
//    scope ( "exit" ) ScopeNonEmptyStatement
//    scope ( "success" ) ScopeNonEmptyStatement
//    scope ( "failure" ) ScopeNonEmptyStatement
class ScopeGuardStatement : Statement
{
    mixin ForwardCtor!();

    override bool createsScope() const { return true; }

    override void toD(CodeWriter writer)
    {
        writer("scope(", getMember(0), ")");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(1));
        }
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " not implemented.");
    }
}

//AsmStatement:
//    asm { }
//    asm { AsmInstructionList }
//
//AsmInstructionList:
//    AsmInstruction ;
//    AsmInstruction ; AsmInstructionList
class AsmStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("asm {");
        writer.nl;
        {
            CodeIndenter indent = CodeIndenter(writer);
            writer(getMember(0));
        }
        writer("}");
        writer.nl;
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " cannot be interpreted.");
    }
}

class AsmInstructionList : Node
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        foreach(m; members)
        {
            writer(m, ";");
            writer.nl();
        }
    }
}

//PragmaStatement:
//    Pragma NoScopeStatement
class PragmaStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer(getMember(0), " ", getMember(1));
    }

    override Value interpret(Context sc)
    {
        getMember(0).interpret(sc);
        return getMember(1).interpret(sc);
    }
}

//MixinStatement:
//    [ AssignExpression ]
class MixinStatement : Statement
{
    mixin ForwardCtor!();

    override void toD(CodeWriter writer)
    {
        writer("mixin(", getMember(0), ");");
        writer.nl;
    }

    override void _semantic(Scope sc)
    {
        Context ctx = new Context(nullContext);
        ctx.scop = sc;
        Value v = getMember(0).interpretCatch(ctx);
        string s = v.toMixin();
        Parser parser = new Parser;
        if(auto prj = sc.getProject())
            parser.saveErrors = prj.saveErrors;
        Node[] n = parser.parseStatements(s, span);
        parent.replaceMember(this, n);
    }

    override Value interpret(Context sc)
    {
        return semanticErrorValue(this, " semantic not run");
    }
}
