예제 #1
0
        Instruction EmitGetFuncAddr(AST_Call ast)
        {
            var func_symb = module.symbols.Resolve(ast.name) as FuncSymbol;

            if (func_symb == null)
            {
                throw new Exception("Func '" + ast.name + "' code not found");
            }

            if (func_symb is FuncSymbolNative fnative)
            {
                int func_idx = types.globs.members.IndexOf(fnative);
                if (func_idx == -1)
                {
                    throw new Exception("Func '" + ast.name + "' idx not found in symbols");
                }
                return(Emit(Opcodes.GetFuncNative, new int[] { func_idx }, ast.line_num));
            }
            else if (func_symb.scope == module.symbols)
            {
                int func_idx = module.symbols.members.IndexOf(func_symb);
                if (func_idx == -1)
                {
                    throw new Exception("Func '" + ast.name + "' idx not found in symbols");
                }

                return(Emit(Opcodes.GetFunc, new int[] { func_idx }, ast.line_num));
            }
            else
            {
                int func_idx = AddConstant(ast.name);

                return(Emit(Opcodes.GetFuncImported, new int[] { func_idx }, ast.line_num));
            }
        }
예제 #2
0
파일: ast.cs 프로젝트: bitdotgames/bhl
 public override void DoVisit(AST_Call node)
 {
     Console.Write("(CALL ");
     Console.Write(node.type + " " + node.name);
     VisitChildren(node);
     Console.Write(")");
 }
예제 #3
0
        public override void DoVisit(AST_Call ast)
        {
            switch (ast.type)
            {
            case EnumCall.VARW:
            {
                Emit(Opcodes.SetVar, new int[] { ast.symb_idx }, ast.line_num);
            }
            break;

            case EnumCall.VAR:
            {
                Emit(Opcodes.GetVar, new int[] { ast.symb_idx }, ast.line_num);
            }
            break;

            case EnumCall.GVAR:
            {
                if (ast.module_name != module.name)
                {
                    int module_idx = AddConstant(ast.module_name);
                    Emit(Opcodes.GetGVarImported, new int[] { module_idx, ast.symb_idx }, ast.line_num);
                }
                else
                {
                    Emit(Opcodes.GetGVar, new int[] { ast.symb_idx }, ast.line_num);
                }
            }
            break;

            case EnumCall.GVARW:
            {
                if (ast.module_name != module.name)
                {
                    int module_idx = AddConstant(ast.module_name);
                    Emit(Opcodes.SetGVarImported, new int[] { module_idx, ast.symb_idx }, ast.line_num);
                }
                else
                {
                    Emit(Opcodes.SetGVar, new int[] { ast.symb_idx }, ast.line_num);
                }
            }
            break;

            case EnumCall.FUNC:
            {
                VisitChildren(ast);
                var instr = EmitGetFuncAddr(ast);
                //let's optimize some primitive calls
                if (instr.op == Opcodes.GetFunc)
                {
                    Pop();
                    Emit(Opcodes.Call, new int[] { ((FuncSymbolScript)module.symbols.members[instr.operands[0]]).ip_addr, (int)ast.cargs_bits }, ast.line_num);
                }
                else if (instr.op == Opcodes.GetFuncNative)
                {
                    Pop();
                    Emit(Opcodes.CallNative, new int[] { instr.operands[0], (int)ast.cargs_bits }, ast.line_num);
                }
                else if (instr.op == Opcodes.GetFuncImported)
                {
                    Pop();
                    Emit(Opcodes.CallImported, new int[] { instr.operands[0], (int)ast.cargs_bits }, ast.line_num);
                }
                else
                {
                    Emit(Opcodes.CallPtr, new int[] { (int)ast.cargs_bits }, ast.line_num);
                }
            }
            break;

            case EnumCall.MVAR:
            {
                if (ast.symb_idx == -1)
                {
                    throw new Exception("Member '" + ast.name + "' idx is not valid: " + ast.scope_type.GetName());
                }

                VisitChildren(ast);

                Emit(Opcodes.GetAttr, new int[] { ast.symb_idx }, ast.line_num);
            }
            break;

            case EnumCall.MVARW:
            {
                if (ast.symb_idx == -1)
                {
                    throw new Exception("Member '" + ast.name + "' idx is not valid: " + ast.scope_type.GetName());
                }

                VisitChildren(ast);

                Emit(Opcodes.SetAttr, new int[] { ast.symb_idx }, ast.line_num);
            }
            break;

            case EnumCall.MFUNC:
            {
                var instance_type = ast.scope_type as IInstanceType;
                if (instance_type == null)
                {
                    throw new Exception("Instance type not found: " + ast.scope_type.GetName());
                }

                var mfunc = instance_type.GetMembers().TryAt(ast.symb_idx) as FuncSymbol;
                if (mfunc == null)
                {
                    throw new Exception("Class method '" + ast.name + "' not found in type '" + ast.scope_type.GetName() + "' by index " + ast.symb_idx);
                }

                VisitChildren(ast);

                if (instance_type is InterfaceSymbol)
                {
                    Emit(Opcodes.CallMethodVirt, new int[] { ast.symb_idx, AddConstant(ast.scope_type), (int)ast.cargs_bits }, ast.line_num);
                }
                else
                {
                    if (mfunc is FuncSymbolScript)
                    {
                        Emit(Opcodes.CallMethod, new int[] { ast.symb_idx, (int)ast.cargs_bits }, ast.line_num);
                    }
                    else
                    {
                        Emit(Opcodes.CallMethodNative, new int[] { ast.symb_idx, (int)ast.cargs_bits }, ast.line_num);
                    }
                }
            }
            break;

            case EnumCall.MVARREF:
            {
                if (ast.symb_idx == -1)
                {
                    throw new Exception("Member '" + ast.name + "' idx is not valid: " + ast.scope_type.GetName());
                }

                VisitChildren(ast);

                Emit(Opcodes.RefAttr, new int[] { ast.symb_idx }, ast.line_num);
            }
            break;

            case EnumCall.ARR_IDX:
            {
                Emit(Opcodes.ArrIdx, null, ast.line_num);
            }
            break;

            case EnumCall.ARR_IDXW:
            {
                Emit(Opcodes.ArrIdxW, null, ast.line_num);
            }
            break;

            case EnumCall.LMBD:
            {
                VisitChildren(ast);
                Emit(Opcodes.LastArgToTop, new int[] { (int)ast.cargs_bits }, ast.line_num);
                Emit(Opcodes.CallPtr, new int[] { (int)ast.cargs_bits }, ast.line_num);
            }
            break;

            case EnumCall.FUNC_VAR:
            {
                VisitChildren(ast);
                Emit(Opcodes.GetFuncFromVar, new int[] { ast.symb_idx }, ast.line_num);
                Emit(Opcodes.CallPtr, new int[] { (int)ast.cargs_bits }, ast.line_num);
            }
            break;

            case EnumCall.FUNC_MVAR:
            {
                VisitChildren(ast);
                Emit(Opcodes.LastArgToTop, new int[] { (int)ast.cargs_bits }, ast.line_num);
                Emit(Opcodes.CallPtr, new int[] { (int)ast.cargs_bits }, ast.line_num);
            }
            break;

            case EnumCall.GET_ADDR:
            {
                EmitGetFuncAddr(ast);
            }
            break;

            default:
                throw new Exception("Not supported call: " + ast.type);
            }
        }
예제 #4
0
파일: ast.cs 프로젝트: bitdotgames/bhl
 public abstract void DoVisit(AST_Call ast);