/**
 * 语义分析功能
 * @version 0.5
 * @author 宫文学
 * @license 木兰开源协议
 * @since 2021-06-04
 * 
 * 当前特性:
 * 1.树状的符号表
 * 2.简单的引用消解:没有考虑声明的先后顺序,也没有考虑闭包
 * 3.简单的作用域
 * 
 */

import {AstVisitor, AstNode, Block, Prog, Decl, VariableDecl, FunctionDecl, ParameterList, FunctionCall, Statement, Expression, ExpressionStatement, Binary, IntegerLiteral, DecimalLiteral, StringLiteral, Variable, ReturnStatement, IfStatement, ForStatement, Unary, CallSignature, BooleanLiteral, NullLiteral, VariableStatement, PredefinedTypeExp, ArrayPrimTypeExp, ParenthesizedPrimTypeExp, UnionOrIntersectionTypeExp, TypeReferenceExp, LiteralTypeExp} from './ast';
import {time, assert } from 'console';
import {Symbol, SymKind, FunctionSymbol, VarSymbol, built_ins} from './symbol';
import {Scope} from './scope';
import {SysTypes, Type, FunctionType, ValueType, UnionType} from './types';
import {Op, Operators, Keyword} from './scanner';
import {CompilerError} from './error'

export class SemanticAnalyer{
    passes: SemanticAstVisitor[] = [
        new TypeResolver(),
        new Enter(),
        new RefResolver(),
        new TypeChecker(),
        new AssignAnalyzer(),
        new LiveAnalyzer(),
        // new TypeConverter(),
        new LeftValueAttributor(),
    ];

    errors:CompilerError[] = [];   //语义错误
    warnings:CompilerError[] = []; //语义报警信息

    execute(prog:Prog):void{
        this.errors= [];   
        this.warnings = []; 
        for (let pass of this.passes){
            pass.visitProg(prog);
            this.errors = this.errors.concat(pass.errors);
            this.warnings = this.warnings.concat(pass.warnings);
        }
    }

}

export class SemanticError extends CompilerError{
    node:AstNode;
    constructor(msg:string, node:AstNode, isWarning = false){
        super(msg, node.beginPos, /* node.endPos, */ isWarning);
        this.node = node;
    }
}

abstract class SemanticAstVisitor extends AstVisitor{
    errors:CompilerError[] = [];   //语义错误
    warnings:CompilerError[] = []; //语义报警信息

    addError(msg:string, node:AstNode){
        this.errors.push(new SemanticError(msg,node));
        console.log("Error: @" + node.beginPos.toString() +" : " + msg);
    }

    addWarning(msg:string, node:AstNode){
        this.warnings.push(new SemanticError(msg,node,true));
        console.log("Warning: @" + node.beginPos.toString() +" : " + msg);
    }
}

/////////////////////////////////////////////////////////////////////////
// 消解类型
//

/**
 * 基于TypeExp的AST节点,来确定真正的Type。
 * 注意:这个步骤一定要在建立符号表的前面去做,因为创建符号的时候,需要把类型信息拷贝过去。
 * todo: 需要处理类型先使用后声明的情况。
 */
class TypeResolver extends SemanticAstVisitor{

    visitVariableDecl(variableDecl:VariableDecl):any{
        if(variableDecl.typeExp != null){
            variableDecl.theType = this.visit(variableDecl.typeExp) as Type;
        }
    }

    visitCallSignature(callSignature:CallSignature):any{
        if (callSignature.returnTypeExp != null)
            callSignature.returnType = this.visit(callSignature.returnTypeExp) as Type;
        
        super.visitCallSignature(callSignature);
    }

    visitPredefinedTypeExp(te:PredefinedTypeExp):any{
        let t:SysTypes = SysTypes.Any;
        switch(te.keyword){
            case Keyword.Boolean:
                t = SysTypes.Boolean;
                break;
            case Keyword.Number:
                t = SysTypes.Number;
                break;
            case Keyword.String:
                t = SysTypes.String;
                break;
            case Keyword.Void:
                t = SysTypes.Void;
                break;
        }
        return t;
    }

    visitLiteralTypeExp(te:LiteralTypeExp):any{
        let v = te.literal.value;
        switch (typeof te.literal){
            case 'number':
                if (Number.isInteger(v)){
                    return new ValueType(v, SysTypes.Integer);
                }
                else{
                    return new ValueType(v, SysTypes.Decimal);
                }
            case 'string':
                return new ValueType(v, SysTypes.String);
            case 'boolean':
                return new ValueType(v, SysTypes.Boolean);
            case 'object' :
                return new ValueType(v, SysTypes.Object); //主要对应null。
            case 'undefined' :
                return new ValueType(v, SysTypes.UndefinedType);
            default:
                this.addError("Unsupported type of literal in visitLiteralTypeExp: " + v, te);           
        }
    }

    visitArrayPrimTypeExp(te:ArrayPrimTypeExp):any{
        // let t = this.visit(te.primType) as Type;
        // return new 
    }

    visitParenthesizedPrimTypeExp(te:ParenthesizedPrimTypeExp):any{
        return this.visit(te.typeExp) as Type;
    }

    visitUnionOrIntersectionTypeExp(te:UnionOrIntersectionTypeExp):any{
        if (te.op == Op.BitOr){ //'|'
            let types:Type[] = [];
            for(let t of te.types){
                types.push(this.visit(t) as Type);
            }
            return new UnionType(types);
        }
    }

    visitTypeReferenceExp(te:TypeReferenceExp):any{

    }

}


/////////////////////////////////////////////////////////////////////////
// 建立符号表
// 

/**
 * 把符号加入符号表。
 */
class Enter extends SemanticAstVisitor{
    scope : Scope|null = null;  //当前所属的scope
    functionSym: FunctionSymbol|null = null;

    /**
     * 返回最顶级的Scope对象
     * @param prog 
     */
    visitProg(prog:Prog){
        let sym = new FunctionSymbol('main', new FunctionType(SysTypes.Integer, []));
        prog.sym = sym;
        this.functionSym = sym;

        return super.visitProg(prog);
    }

    /**
     * 把函数声明加入符号表
     * @param functionDecl 
     */
    visitFunctionDecl(functionDecl: FunctionDecl):any{
        let currentScope = this.scope as Scope;
        
        //创建函数的symbol
        let paramTypes:Type[] = []; 
        if (functionDecl.callSignature.paramList != null){
            for (let p of functionDecl.callSignature.paramList.params){
                paramTypes.push(p.theType);
            }
        }
        let sym = new FunctionSymbol(functionDecl.name, new FunctionType(functionDecl.callSignature.returnType,paramTypes));
        sym.decl = functionDecl;
        functionDecl.sym = sym;

        //把函数加入当前scope
        if (currentScope.hasSymbol(functionDecl.name)){
            this.addError("Dumplicate symbol: "+ functionDecl.name, functionDecl);
        }
        else{
            currentScope.enter(functionDecl.name, sym);
        }

        //修改当前的函数符号
        let lastFunctionSym = this.functionSym;
        this.functionSym = sym;

        //创建新的Scope,用来存放参数
        let oldScope = currentScope;
        this.scope = new Scope(oldScope);
        functionDecl.scope = this.scope;

        //遍历子节点
        super.visitFunctionDecl(functionDecl);

        //恢复当前函数
        this.functionSym = lastFunctionSym;

        //恢复原来的Scope
        this.scope = oldScope;
    }

    /**
     * 遇到块的时候,就建立一级新的作用域。
     * 支持块作用域
     * @param block 
     */
    visitBlock(block:Block):any{
        //创建下一级scope
        let oldScope = this.scope;
        this.scope = new Scope(this.scope);
        block.scope = this.scope;

        //调用父类的方法,遍历所有的语句
        super.visitBlock(block);

        //重新设置当前的Scope
        this.scope = oldScope;
   }

    /**
     * 把变量声明加入符号表
     * @param variableDecl 
     */
    visitVariableDecl(variableDecl : VariableDecl):any{
        let currentScope = this.scope as Scope;
        if (currentScope.hasSymbol(variableDecl.name)){
            this.addError("Dumplicate symbol: "+ variableDecl.name, variableDecl);
        }
        //把变量加入当前的符号表
        let sym = new VarSymbol(variableDecl.name, variableDecl.theType);
        variableDecl.sym = sym;
        currentScope.enter(variableDecl.name, sym);

        //把本地变量也加入函数符号中,可用于后面生成代码
        this.functionSym?.vars.push(sym);
    }

    /**
     * 对于for循环来说,由于可以在for的init部分声明变量,所以要新建一个Scope。
     * @param forStmt 
     */
    visitForStatement(forStmt:ForStatement):any{
        //创建下一级scope
        let oldScope = this.scope;
        this.scope = new Scope(this.scope);
        forStmt.scope = this.scope;

        //调用父类的方法,遍历所有的语句
        super.visitForStatement(forStmt);

        //重新设置当前的Scope
        this.scope = oldScope;
    }

}

/////////////////////////////////////////////////////////////////////////
// 引用消解
// 1.函数引用消解
// 2.变量应用消解

/**
 * 引用消解
 * 遍历AST。如果发现函数调用和变量引用,就去找它的定义。
 */
class RefResolver extends SemanticAstVisitor{ 
    scope:Scope|null=null; //当前的Scope

    //每个Scope已经声明了的变量的列表
    declaredVarsMap:Map<Scope, Map<string,VarSymbol>> = new Map();


    visitFunctionDecl(functionDecl:FunctionDecl):any{
        //1.修改scope
        let oldScope = this.scope;
        this.scope = functionDecl.scope as Scope;
        assert(this.scope != null, "Scope不可为null");

        //为已声明的变量设置一个存储区域
        this.declaredVarsMap.set(this.scope, new Map());        

        //2.遍历下级节点
        super.visitFunctionDecl(functionDecl);

        //3.重新设置scope
        this.scope = oldScope;           
    }

    /**
     * 修改当前的Scope
     * @param block 
     */
    visitBlock(block:Block):any{
        //1.修改scope
        let oldScope = this.scope;
        this.scope = block.scope as Scope;
        assert(this.scope != null, "Scope不可为null");

        //为已声明的变量设置一个存储区域
        this.declaredVarsMap.set(this.scope, new Map());        

        //2.遍历下级节点
        super.visitBlock(block);

        //3.重新设置scope
        this.scope = oldScope;    
    }

    visitForStatement(forStmt:ForStatement):any{
        //1.修改scope
        let oldScope = this.scope;
        this.scope = forStmt.scope as Scope;
        assert(this.scope != null, "Scope不可为null");

        //为已声明的变量设置一个存储区域
        this.declaredVarsMap.set(this.scope, new Map());        

        //2.遍历下级节点
        super.visitForStatement(forStmt);

        //3.重新设置scope
        this.scope = oldScope;     
    }

    /**
     * 做函数的消解。
     * 函数不需要声明在前,使用在后。
     * @param functionCall 
     */
    visitFunctionCall(functionCall:FunctionCall):any{
        let currentScope = this.scope as Scope;
        // console.log("in semantic.visitFunctionCall: " + functionCall.name);
        if (built_ins.has(functionCall.name)){  //系统内置函数
            functionCall.sym = built_ins.get(functionCall.name) as FunctionSymbol;
        }
        else{
            functionCall.sym = currentScope.getSymbolCascade(functionCall.name) as FunctionSymbol|null;
        }

        // console.log(functionCall.sym);

        //调用下级,主要是参数。
        super.visitFunctionCall(functionCall);
    }

    /**
     * 标记变量是否已被声明
     * @param variableDecl 
     */
    visitVariableDecl(variableDecl : VariableDecl):any{
        let currentScope = this.scope as Scope;
        let declaredSyms = this.declaredVarsMap.get(currentScope) as Map<string, VarSymbol>;
        let sym = currentScope.getSymbol(variableDecl.name);
        if (sym != null){  //TODO 需要检查sym是否是变量
            declaredSyms.set(variableDecl.name, sym as VarSymbol);
        }

        //处理初始化的部分
        super.visitVariableDecl(variableDecl);
    }

    /**
     * 变量引用消解
     * 变量必须声明在前,使用在后。
     * @param variable 
     */
    visitVariable(variable: Variable):any{
        let currentScope = this.scope as Scope;
        variable.sym = this.findVariableCascade(currentScope, variable);
    }

    /**
     * 逐级查找某个符号是不是在声明前就使用了。
     * @param scope 
     * @param name 
     * @param kind 
     */
    private findVariableCascade(scope:Scope, variable:Variable):VarSymbol|null{
        let declaredSyms = this.declaredVarsMap.get(scope) as Map<string,VarSymbol>;
        let symInScope = scope.getSymbol(variable.name);
        if (symInScope != null){
            if (declaredSyms.has(variable.name)){
                return declaredSyms.get(variable.name) as VarSymbol; //找到了,成功返回。
            }
            else{
                if (symInScope.kind == SymKind.Variable){
                    this.addError("Variable: '" + variable.name + "' is used before declaration.", variable);
                }
                else{
                    this.addError("We expect a variable of name: '" + variable.name + "', but find a " + SymKind[symInScope.kind] + ".", variable);
                }
            }
        }
        else{
            if (scope.enclosingScope != null){
                return this.findVariableCascade(scope.enclosingScope, variable);
            }
            else{
                this.addError("Cannot find a variable of name: '" + variable.name +"'", variable);
            }
        }
        return null;
    }
}

/////////////////////////////////////////////////////////////////////////
// 属性分析
// 1.类型计算和检查
// 

class LeftValueAttributor extends SemanticAstVisitor{
    parentOperator: Op|null = null;

    /**
     * 检查赋值符号和.符号左边是否是左值
     * @param binary 
     */
    visitBinary(binary:Binary):any{
        if (Operators.isAssignOp(binary.op) || binary.op == Op.Dot){
            let lastParentOperator = this.parentOperator;
            this.parentOperator = binary.op;

            //检查左子节点
            this.visit(binary.exp1);
            if (!binary.exp1.isLeftValue){
                this.addError("Left child of operator "+ Op[binary.op] + " need a left value",binary.exp1);
            }
            
            //恢复原来的状态信息
            this.parentOperator = lastParentOperator;
            
            //继续遍历右子节点
            this.visit(binary.exp2);
        }
        else{
            super.visitBinary(binary);
        }
    }

    visitUnary(u:Unary):any{
        //要求必须是个左值
        if (u.op == Op.Inc || u.op == Op.Dec){
            let lastParentOperator = this.parentOperator;
            this.parentOperator = u.op;

            this.visit(u.exp);
            if(!u.exp.isLeftValue){
                this.addError("Unary operator " + Op[u.op] + "can only be applied to a left value" ,u);
            }

            //恢复原来的状态信息
            this.parentOperator = lastParentOperator;
        }
        else{
            super.visitUnary(u);
        }
    }

    /**
     * 变量都可以作为左值,除非其类型是void
     * @param v 
     */
    visitVariable(v:Variable):any{
        if (this.parentOperator != null){
            let t = v.theType as Type;
            if (!t.hasVoid()){
                v.isLeftValue = true;
            }
        }
    }

    /**
     * 但函数调用是在.符号左边,并且返回值不为void的时候,可以作为左值
     * @param functionCall 
     */
    visitFunctionCall(functionCall:FunctionCall):any{
        if (this.parentOperator == Op.Dot){
            let functionType = functionCall.theType as FunctionType;
            if (!functionType.returnType.hasVoid()){
                functionCall.isLeftValue = true;
            }
        }
    }

}

/**
 * 类型检查
 */
class TypeChecker extends SemanticAstVisitor{

    visitVariableDecl(variableDecl:VariableDecl):any{
        super.visitVariableDecl(variableDecl);

        if (variableDecl.init != null){
            let t1 = variableDecl.theType as Type;
            let t2 = variableDecl.init.theType as Type;
            if (!Type.LE(t2,t1)){
                this.addError("Operator '=' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,variableDecl);
            }

            //类型推断:对于any类型,变成=号右边的具体类型
            if (t1===SysTypes.Any){
                variableDecl.theType = t2;   //TODO:此处要调整
                // variableDecl.inferredType = t2;
                //重点是把类型记入符号中,这样相应的变量声明就会获得准确的类型
                //由于肯定是声明在前,使用在后,所以变量引用的类型是准确的。
                (variableDecl.sym as VarSymbol).theType = t2;  
            }
        }
    }
    
    visitBinary(bi:Binary):any{
        super.visitBinary(bi);

        let t1 = bi.exp1.theType as Type;
        let t2 = bi.exp2.theType as Type;

        if (Operators.isAssignOp(bi.op)){
            bi.theType = t1;          
            if(!Type.LE(t2,t1)){  //检查类型匹配
                this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
            }         
        }
        else if (bi.op == Op.Plus){ //有一边是string,或者两边都是number才行。
            if (t1 == SysTypes.String || t2 == SysTypes.String){
                bi.theType = SysTypes.String;
            } 
            else if (Type.LE(t1,SysTypes.Number) && Type.LE(t2,SysTypes.Number)){
                bi.theType = Type.getUpperBound(t1, t2);
            }
            else if (t1 == SysTypes.Any || t2 == SysTypes.Any){
                bi.theType = SysTypes.Any;
            }
            else{
                this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
            }
        }
        else if (Operators.isArithmeticOp(bi.op)){
            if (Type.LE(t1,SysTypes.Number) && Type.LE(t2,SysTypes.Number)){
                bi.theType = Type.getUpperBound(t1, t2);
            }
            else{
                this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
            }
        }
        else if (Operators.isRelationOp(bi.op)){
            if (Type.LE(t1, SysTypes.Number) && Type.LE(t2, SysTypes.Number)){
                bi.theType = SysTypes.Boolean;
            }
            else{
                this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
            }
        }
        else if (Operators.isLogicalOp(bi.op)){
            if (Type.LE(t1,SysTypes.Boolean) && Type.LE(t2,SysTypes.Boolean)){
                bi.theType = SysTypes.Boolean;
            }
            else{
                this.addError("Operator '" + Op[bi.op] + "' can not be applied to '"+t1.toString()+"' and '"+t2.toString()+"'." ,bi);
            }
        }
        else{
            this.addError("Unsupported binary operator: " + Op[bi.op],bi);
        }
    }

    visitUnary(u:Unary):any{
        super.visitUnary(u);

        let t = u.exp.theType as Type;
        //要求必须是个左值
        if (u.op == Op.Inc || u.op == Op.Dec){
            if (Type.LE(t,SysTypes.Number)){
                u.theType = t;
            }
            else{
                this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
            }
        }
        else if (u.op == Op.Minus || u.op == Op.Plus){
            if (Type.LE(t,SysTypes.Number)){
                u.theType = t;
            }
            else{
                this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
            }
        }
        else if (u.op == Op.Not){
            if (Type.LE(t,SysTypes.Boolean)){
                u.theType = t;
            }
            else{
                this.addError("Unary operator " + Op[u.op] + "can not be applied to '"+t.toString()+"'." ,u);
            }
        }
        else{
            this.addError("Unsupported unary operator: " + Op[u.op] + " applied to '"+t.toString()+"'." ,u);
        }     
    }

    /**
     * 用符号的类型(也就是变量声明的类型),来标注本节点
     * @param v 
     */
    visitVariable(v:Variable):any{
        if (v.sym != null){
            v.theType = v.sym.theType;
        }
    }

    visitFunctionCall(functionCall:FunctionCall):any{
        if (functionCall.sym != null){
            let functionType = functionCall.sym.theType as FunctionType;

            //注意:不使用函数类型,而是使用返回值的类型
            functionCall.theType = functionType.returnType;  

            //检查参数数量
            if(functionCall.arguments.length != functionType.paramTypes.length){
                this.addError("FunctionCall of " + functionCall.name +" has " + functionCall.arguments.length + " arguments, while expecting " + functionType.paramTypes.length +".",functionCall);
            }
        
            //检查注意检查参数的类型
            for (let i = 0; i< functionCall.arguments.length; i++){
                this.visit(functionCall.arguments[i]);
                if (i < functionType.paramTypes.length){
                    let t1 = functionCall.arguments[i].theType as Type;
                    let t2 = functionType.paramTypes[i] as Type;
                    if (!Type.LE(t1,t2) && t2 !== SysTypes.String){
                        this.addError("Argument " + i + " of FunctionCall " + functionCall.name + "is of Type " + t1.toString() + ", while expecting "+t2.toString(), functionCall);
                    }
                }
            }
            
        }
    }

}

/**
 * 类型转换
 * 添加必要的AST节点,来完成转换
 * 目前特性:其他类型转换成字符串
 */
class TypeConverter extends SemanticAstVisitor{
    visitBinary(bi:Binary):any{
        super.visitBinary(bi);

        let t1 = bi.exp1.theType as Type;
        let t2 = bi.exp2.theType as Type;

        if (Operators.isAssignOp(bi.op)){
            if (t1 === SysTypes.String && t2 !== SysTypes.String){
                if (t2 === SysTypes.Integer){
                    let exp = new FunctionCall(bi.exp2.beginPos, bi.exp2.endPos,"integer_to_string",[bi.exp2]);
                    exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
                    bi.exp2 = exp;
                }
            }
        }
        else if (bi.op == Op.Plus){ //有一边是string,或者两边都是number才行。
            if (t1 === SysTypes.String || t2 === SysTypes.String){
                if (t1 === SysTypes.Integer || t1 === SysTypes.Number){
                    let exp = new FunctionCall(bi.exp1.beginPos, bi.exp1.endPos,"integer_to_string",[bi.exp1]);
                    exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
                    bi.exp1 = exp;
                }
                if (t2 === SysTypes.Integer || t2 === SysTypes.Number){
                    let exp = new FunctionCall(bi.exp2.beginPos, bi.exp2.endPos,"integer_to_string",[bi.exp2]);
                    exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
                    bi.exp2 = exp;
                }
            }
        }
    }

    visitFunctionCall(functionCall:FunctionCall):any{
        if (functionCall.sym != null){
            let functionType = functionCall.sym.theType as FunctionType;

            //看看参数有没有可以转换的。
            for (let i = 0; i< functionCall.arguments.length; i++){
                this.visit(functionCall.arguments[i]);
                if (i < functionType.paramTypes.length){
                    let t1 = functionCall.arguments[i].theType as Type;
                    let t2 = functionType.paramTypes[i] as Type;
                    if ((t1 === SysTypes.Integer  || t1 === SysTypes.Number) && t2 === SysTypes.String){
                        let exp = new FunctionCall(functionCall.arguments[i].beginPos, functionCall.arguments[i].endPos,"integer_to_string",[functionCall.arguments[i]]);
                        exp.sym = built_ins.get("integer_to_string") as FunctionSymbol;
                        functionCall.arguments[i] = exp;
                    }
                }
            }
            
        }
    }

}

/**
 * 常量折叠
 */
class ConstFolder extends SemanticAstVisitor{
    
    visitBinary(bi:Binary):any{
        let v1 = bi.exp1.constValue;
        let v2 = bi.exp2.constValue;
        if (Operators.isAssignOp(bi.op)){
            if (typeof v2 != 'undefined'){
                if (bi.op == Op.Assign){ //暂时只支持=号
                    bi.exp1.constValue = v1;
                    bi.constValue = v1;              
                }
                else{
                    this.addError("Unsupported operator: " + Op[bi.op] +"in ConstFolder",bi);
                }
            }
        }
        else if(typeof v1 != 'undefined' && typeof v2 != 'undefined'){
            let v:any;
            switch(bi.op){
                case Op.Plus: //'+'
                    v = v1 + v2;
                    break;
                case Op.Minus: //'-'
                    v = v1 - v2;
                    break;
                case Op.Multiply: //'*'
                    v = v1 * v2;
                    break;
                case Op.Divide: //'/'
                    v = v1 / v2;
                    break;
                case Op.Modulus: //'%'
                    v = v1 % v2;
                    break;
                case Op.G: //'>'
                    v = v1 > v2;
                    break;
                case Op.GE: //'>='
                    v = v1 >= v2;
                    break;
                case Op.L: //'<'
                    v = v1 < v2;
                    break;
                case Op.LE: //'<='
                    v = v1 <= v2;
                    break;
                case Op.EQ: //'=='
                    v = v1 == v2;
                    break;
                case Op.NE: //'!='
                    v = v1 != v2;
                    break;
                case Op.And: //'&&'
                    v = v1 && v2;
                    break;
                case Op.Or: //'||'
                    v = v1 || v2;
                    break;
                default:
                    this.addError("Unsupported binary operator: " + Op[bi.op] +"in ConstFolder",bi);
            }
            bi.op = v;
        }
    }

    visitUnary(u:Unary):any{
        let v1 = u.exp.constValue;
        if (typeof v1 != 'undefined'){
            if (u.op == Op.Inc){
                if (u.isPrefix){
                    u.exp.constValue += 1;
                    u.constValue = u.exp.constValue;
                }
                else{
                    u.constValue = v1;
                    u.exp.constValue += 1;
                }
            }
            else if (u.op == Op.Dec){
                if (u.isPrefix){
                    u.exp.constValue -= 1;
                    u.constValue = u.exp.constValue;
                }
                else{
                    u.constValue = v1;
                    u.exp.constValue -= 1;
                }
            }
            else if (u.op == Op.Plus){
                u.constValue = v1;
            }
            else if (u.op == Op.Minus){
                u.constValue = -v1;
            }
            else if (u.op == Op.Not){
                u.constValue = !v1;
            }
            else{
                this.addError("Unsupported unary operator: " + Op[u.op] +"in ConstFolder",u);
            }
        }
    }

}


/**
 * 检查每个变量是否都被赋值了。
 */
class AssignAnalyzer extends SemanticAstVisitor{ 
    //每个变量的赋值情况
    assignMode:Map<VarSymbol, boolean> = new Map();

    private cloneMap(map1:Map<VarSymbol, boolean>):Map<VarSymbol, boolean>{
        let map2:Map<VarSymbol, boolean> = new Map();
        for (let sym of map1.keys()){
            let value = map1.get(sym) as boolean;
            map2.set(sym,value);
        }
        return map2;
    }

    private merge(map1:Map<VarSymbol, boolean>, map2:Map<VarSymbol, boolean>):Map<VarSymbol, boolean>{
        let map:Map<VarSymbol, boolean> = new Map();
        for (let sym of map1.keys()){
            let value1 = map1.get(sym) as boolean;
            let value2 = map2.get(sym) as boolean;
            map.set(sym, value1 && value2);
        }
        return map;
    }

    visitProg(prog:Prog):any{
        this.assignMode = new Map();

        super.visitProg(prog);

        return this.assignMode;
    }

    //参数都是被赋值过的。
    visitParameterList(paramList:ParameterList):any{
        for (let varDecl of paramList.params){
            this.assignMode.set(varDecl.sym as VarSymbol, true);
        }
    }

    //略过死代码
    visitBlock(block:Block):any{
        for (let stmt of block.stmts){
            let alive = this.visit(stmt) as boolean;
            if(typeof alive == 'boolean'){
                //如果遇到return语句,后面的就是死代码了,必须忽略掉。
                return;
            }     
        }
    }
    
    //检测return语句
    visitReturnStatement(rtnStmt: ReturnStatement):any{
        if(rtnStmt.exp != null)  this.visit(rtnStmt.exp);
        return false;  //表示代码活跃性为false
    }

    //变量声明中可能会初始化变量
    visitVariableDecl(variableDecl: VariableDecl):any{
        if (variableDecl.init != null) this.visit(variableDecl.init);
        //如果有初始化部分,那么assigned就设置为true
        this.assignMode.set(variableDecl.sym as VarSymbol, variableDecl.init != null);
    }

    //检查变量使用前是否被赋值了
    visitVariable(variable: Variable):any{
        let varSym = variable.sym as VarSymbol;
        if (this.assignMode.has(varSym)){
            let assigned = this.assignMode.get(varSym) as boolean;
            if (!assigned){
                this.addError("variable '" + variable.name + "' is used before being assigned.", variable);
            }
        }
        else{
            console.log("whoops,不可能到这里@semantic.ts/visitVariable");
        }
    }

    //处理赋值语句
    visitBinary(binary:Binary):any{
        if (Operators.isAssignOp(binary.op)){
            this.visit(binary.exp2); //表达式右侧要照常遍历,但左侧就没有必要了。
            if (typeof (binary.exp1 as Variable).sym == 'object'){
                let varSym = (binary.exp1 as Variable).sym as VarSymbol;
                this.assignMode.set(varSym, true);
            }
        }
        else{
            super.visitBinary(binary);
        }
    }

    visitIfStatement(ifStmt:IfStatement):any{
        //if条件有没有常量的值,是否为常真或常假
        if (typeof ifStmt.condition.constValue != 'undefined'){
            if (ifStmt.condition.constValue){
                
            }
            else{
                if (ifStmt.elseStmt == null){
                    
                }
                else{
                    
                }
            }
        }
        else{
            //算法:把assignMode克隆两份,分别代表遍历左支和右支的结果,然后做交汇运算
            let oldMode = this.cloneMap(this.assignMode);
            //遍历if块
            this.visit(ifStmt.stmt);
            let mode1 = this.assignMode;
            //遍历else块
            this.assignMode = this.cloneMap(oldMode);
            if (ifStmt.elseStmt != null) this.visit(ifStmt.elseStmt);
            let mode2 = this.assignMode;
            //交汇运算
            this.assignMode = this.merge(mode1, mode2);
        }
    }

    /**
     * 因为我们现在不支持break,所以检查起来比较简单。
     * @param forStmt 
     */
    visitForStatement(forStmt:ForStatement):any{
        //for循环语句的初始化部分也可能有
        if (forStmt.init != null)
            super.visit(forStmt.init);
        
        //查看是否满足进入条件
        let skipLoop = forStmt.condition != null && typeof forStmt.condition.constValue != 'undefined' && forStmt.condition.constValue;
        if (!skipLoop){
            this.visit(forStmt.stmt);
            if (forStmt.increment!=null)
                this.visit(forStmt.increment);
        }
    }

}

/**
 * 检查函数的所有分枝是否都正确的返回。
 */
class LiveAnalyzer extends SemanticAstVisitor{ 
    /**
     * 分析主程序是否正确的renturn了。如果没有,那么自动添加return语句。
     * @param prog 
     */
    visitProg(prog:Prog):any{
        let alive = super.visitBlock(prog);

        //如果主程序没有return语句,那么在最后面加一下。
        if (alive){
            prog.stmts.push(new ReturnStatement(prog.endPos, prog.endPos, null));
        }
    }

    /**
     * 检查每个函数是否都正确的return了。也就是alive是false。
     * @param functionDecl 
     */
    visitFunctionDecl(functionDecl:FunctionDecl):any{
        let alive = true;
        let sym = functionDecl.sym as FunctionSymbol;
        let functionType = sym.theType as FunctionType;
        if (functionType.returnType != SysTypes.Any && functionType.returnType != SysTypes.Void && functionType.returnType != SysTypes.Undefined){
            alive = super.visitBlock(functionDecl.body);
        }
        else{
            alive = false;
        }

        if (alive){
            this.addError("Function lacks ending return statement and return type does not include 'undefined'.", functionDecl);
        }
        return alive;
    }

    visitBlock(block:Block):any{
        let alive:boolean = true;
        let deadCodes:Statement[] = []; //死代码
        for (let stmt of block.stmts){
            if (alive){
                alive = this.visit(stmt) as boolean;
            }
            //return语句之后的语句,都是死代码。
            else{ 
                //作为Warning,而不是错误。
                this.addWarning("Unreachable code detected.",stmt);
                deadCodes.push(stmt);
            }        
        }

        //去除死代码
        for (let stmt of deadCodes){
            let index = block.stmts.indexOf(stmt);
            block.stmts.splice(index,1);
        }

        return alive;
    }

    visitReturnStatement(stmt:ReturnStatement):any{
        return false;
    }

    visitVariableStatement(stmt:VariableStatement):any{
        return true;
    }

    visitExpressionStatement(stmt:ExpressionStatement):any{
        return true;
    }

    /**
     * 
     * @param ifStmt 
     */
    visitIfStatement(ifStmt:IfStatement):any{
        let alive:boolean;

        //if条件有没有常量的值,是否为常真或长假
        if (typeof ifStmt.condition.constValue != 'undefined'){
            if (ifStmt.condition.constValue){
                alive = this.visit(ifStmt.stmt) as boolean;
            }
            else{
                if (ifStmt.elseStmt == null){
                    alive = true;
                }
                else{
                    alive = this.visit(ifStmt.stmt) as boolean;
                }
            }
        }
        else{
            let alive1 = this.visit(ifStmt.stmt) as boolean;
            let alive2 = ifStmt.elseStmt == null ? true : (this.visit(ifStmt.elseStmt) as boolean);
            alive = alive1 || alive2;  //只有两个分支都是false,才返回false;
        }
        return alive;
    }

    /**
     * 因为我们现在不支持break,所以检查起来比较简单。只要有return语句,我们就认为alive=false;
     * @param forStmt 
     */
    visitForStatement(forStmt:ForStatement):any{
        //查看是否满足进入条件

        if (forStmt.condition != null && typeof forStmt.condition.constValue != 'undefined'){
            if (forStmt.condition.constValue){
                return this.visit(forStmt.stmt);
            }
            else{ //如果不可能进入循环体,那么就不用继续遍历了
                return true;
            }
        }
        else{
            return this.visit(forStmt.stmt);
        }
    }

}