예제 #1
0
        public override TO2Type ResultType(IBlockContext context)
        {
            TO2Type targetType          = target.ResultType(context);
            IMethodInvokeFactory method = targetType.FindMethod(context.ModuleContext, methodName);

            if (method != null)
            {
                IMethodInvokeEmitter methodInvoker = method.Create(context,
                                                                   arguments.Select(arg => arg.ResultType(context)).ToList(), this);

                if (methodInvoker != null)
                {
                    return(methodInvoker.ResultType);
                }
            }

            IFieldAccessFactory field = targetType.FindField(context.ModuleContext, methodName);

            if (field != null)
            {
                IFieldAccessEmitter fieldAccess  = field.Create(context.ModuleContext);
                FunctionType        functionType = fieldAccess.FieldType as FunctionType;

                if (functionType == null)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.NoSuchMethod,
                                         $"Field '{methodName}' of type '{targetType.Name}' is neither a method or a function",
                                         Start,
                                         End
                                         ));
                    return(BuiltinType.Unit);
                }
                else
                {
                    return(functionType.returnType);
                }
            }

            context.AddError(new StructuralError(
                                 StructuralError.ErrorType.NoSuchMethod,
                                 $"Type '{targetType.Name}' does not have a method or field '{methodName}'",
                                 Start,
                                 End
                                 ));
            return(BuiltinType.Unit);
        }
예제 #2
0
        public override void Prepare(IBlockContext context)
        {
            if (preparedResult != null)
            {
                return;
            }

            TO2Type targetType = target.ResultType(context);
            IMethodInvokeEmitter methodInvoker = targetType.FindMethod(context.ModuleContext, methodName)
                                                 ?.Create(context, arguments.Select(arg => arg.ResultType(context)).ToList(), this);

            if (methodInvoker == null || !methodInvoker.IsAsync || !context.IsAsync)
            {
                return;
            }

            EmitCode(context, false);
            preparedResult = context.DeclareHiddenLocal(methodInvoker.ResultType.GeneratedType(context.ModuleContext));
            preparedResult.EmitStore(context);
        }
예제 #3
0
        private void EmitCodeMethodCall(IBlockContext context, TO2Type targetType, IMethodInvokeFactory method,
                                        bool dropResult)
        {
            if (target is IAssignContext assignContext)
            {
                if (assignContext.IsConst(context) && !method.IsConst)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.NoSuchMethod,
                                         $"Method '{methodName}' will mutate const variable.",
                                         Start,
                                         End
                                         ));
                }
            }

            List <TO2Type>       argumentTypes = arguments.Select(arg => arg.ResultType(context)).ToList();
            IMethodInvokeEmitter methodInvoker = method.Create(context, argumentTypes, this);

            if (methodInvoker == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchMethod,
                                     $"Type '{targetType.Name}' does not have a method '{methodName}' matching arguments ({string.Join(", ", argumentTypes)})",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (methodInvoker.IsAsync && !context.IsAsync)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchFunction,
                                     $"Cannot call async method of variable '{targetType.Name}.{methodName}' from a sync context",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (methodInvoker.RequiredParameterCount() > arguments.Count)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.ArgumentMismatch,
                                     $"Method '{targetType.Name}.{methodName}' requires {methodInvoker.RequiredParameterCount()} arguments",
                                     Start,
                                     End
                                     ));
                return;
            }

            int i;

            for (i = 0; i < arguments.Count; i++)
            {
                TO2Type argumentType = arguments[i].ResultType(context);
                if (!methodInvoker.Parameters[i].type.IsAssignableFrom(context.ModuleContext, argumentType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.ArgumentMismatch,
                                         $"Argument {methodInvoker.Parameters[i].name} of '{targetType.Name}.{methodName}' has to be a {methodInvoker.Parameters[i].type}, but got {argumentType}",
                                         Start,
                                         End
                                         ));
                    return;
                }
            }

            foreach (Expression argument in arguments)
            {
                argument.Prepare(context);
            }

            if (methodInvoker.RequiresPtr)
            {
                target.EmitPtr(context);
            }
            else
            {
                target.EmitCode(context, false);
            }
            for (i = 0; i < arguments.Count; i++)
            {
                arguments[i].EmitCode(context, false);
                if (!context.HasErrors)
                {
                    methodInvoker.Parameters[i].type.AssignFrom(context.ModuleContext, arguments[i].ResultType(context))
                    .EmitConvert(context);
                }
            }

            if (!context.HasErrors)
            {
                for (; i < methodInvoker.Parameters.Count; i++)
                {
                    methodInvoker.Parameters[i].defaultValue.EmitCode(context);
                }
            }

            if (context.HasErrors)
            {
                return;
            }

            methodInvoker.EmitCode(context);
            if (methodInvoker.IsAsync)
            {
                context.RegisterAsyncResume(methodInvoker.ResultType);
            }
            if (dropResult)
            {
                context.IL.Emit(OpCodes.Pop);
            }
        }
 public static int RequiredParameterCount(this IMethodInvokeEmitter method) =>
 method.Parameters.Count(p => !p.HasDefault);