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)); } }
public override void DoVisit(AST_Call node) { Console.Write("(CALL "); Console.Write(node.type + " " + node.name); VisitChildren(node); Console.Write(")"); }
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); } }
public abstract void DoVisit(AST_Call ast);