コード例 #1
0
        protected override void EmitAssignToPtr(IBlockContext context, IBlockVariable tempSource)
        {
            foreach (var kv in targetType.fields)
            {
                IFieldAccessFactory sourceFieldFactory = sourceType.FindField(context.ModuleContext, kv.Key);
                if (sourceFieldFactory == null)
                {
                    continue;
                }

                IFieldAccessEmitter sourceField = sourceFieldFactory.Create(context.ModuleContext);
                context.IL.Emit(OpCodes.Dup);
                if (sourceField.RequiresPtr)
                {
                    tempSource.EmitLoadPtr(context);
                }
                else
                {
                    tempSource.EmitLoad(context);
                }
                sourceField.EmitLoad(context);
                targetType.ItemTypes[kv.Key].AssignFrom(context.ModuleContext, sourceType.ItemTypes[kv.Key])
                .EmitConvert(context);
                context.IL.Emit(OpCodes.Stfld, kv.Value);
            }

            context.IL.Emit(OpCodes.Pop);
        }
コード例 #2
0
        public override TO2Type ResultType(IBlockContext context)
        {
            TO2Type             targetType  = target.ResultType(context);
            IFieldAccessEmitter fieldAccess =
                targetType.FindField(context.ModuleContext, fieldName)?.Create(context.ModuleContext);

            if (fieldAccess == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchField,
                                     $"Type '{targetType.Name}' does not have a field '{fieldName}'",
                                     Start,
                                     End
                                     ));
                return(BuiltinType.Unit);
            }

            if (!fieldAccess.CanStore)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchField,
                                     $"Type '{targetType.Name}' field '{fieldName}' is read-only",
                                     Start,
                                     End
                                     ));
                return(BuiltinType.Unit);
            }

            return(fieldAccess.FieldType);
        }
コード例 #3
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);
        }
コード例 #4
0
        private void EmitCodeDelegateCall(IBlockContext context, TO2Type targetType, IFieldAccessFactory field,
                                          bool dropResult)
        {
            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;
            }

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

            if (functionType.parameterTypes.Count != arguments.Count)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.ArgumentMismatch,
                                     $"Call to '{methodName}' of type '{targetType.Name}' requires {functionType.parameterTypes.Count} arguments",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (fieldAccess.RequiresPtr)
            {
                target.EmitPtr(context);
            }
            else
            {
                target.EmitCode(context, false);
            }
            fieldAccess.EmitLoad(context);

            for (int i = 0; i < arguments.Count; i++)
            {
                arguments[i].EmitCode(context, false);
                if (!context.HasErrors)
                {
                    functionType.parameterTypes[i].AssignFrom(context.ModuleContext, arguments[i].ResultType(context))
                    .EmitConvert(context);
                }
            }

            if (context.HasErrors)
            {
                return;
            }

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

            MethodInfo invokeMethod = functionType.GeneratedType(context.ModuleContext).GetMethod("Invoke") ??
                                      throw new ArgumentException($"No Invoke method in generated ${functionType}");

            context.IL.EmitCall(OpCodes.Callvirt, invokeMethod, arguments.Count + 1);
            if (functionType.isAsync)
            {
                context.RegisterAsyncResume(functionType.returnType);
            }
            if (dropResult && invokeMethod.ReturnType != typeof(void))
            {
                context.IL.Emit(OpCodes.Pop);
            }
            if (!dropResult && invokeMethod.ReturnType == typeof(void))
            {
                context.IL.Emit(OpCodes.Ldnull);
            }
        }
コード例 #5
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            TO2Type             targetType  = target.ResultType(context);
            IFieldAccessEmitter fieldAccess =
                targetType.FindField(context.ModuleContext, fieldName)?.Create(context.ModuleContext);
            TO2Type valueType = expression.ResultType(context);

            if (fieldAccess == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchField,
                                     $"Type '{targetType.Name}' does not have a field '{fieldName}'",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (!fieldAccess.CanStore)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchField,
                                     $"Type '{targetType.Name}' field '{fieldName}' is read-only",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (target is IAssignContext assignContext)
            {
                if (fieldAccess.RequiresPtr && assignContext.IsConst(context))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.NoSuchField,
                                         $"Type '{targetType.Name}' field '{fieldName}' can not be set on a read-only variable",
                                         Start,
                                         End
                                         ));
                    return;
                }
            }
            else
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.CoreGeneration,
                                     $"Field assign '{targetType.Name}'.'{fieldName}' on invalid target expression",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (!fieldAccess.FieldType.IsAssignableFrom(context.ModuleContext, valueType))
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.IncompatibleTypes,
                                     $"Type '{targetType.Name}' field '{fieldName}' is of type {fieldAccess.FieldType} but is assigned to {valueType}",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (op == Operator.Assign)
            {
                if (fieldAccess.RequiresPtr)
                {
                    target.EmitPtr(context);
                }
                else
                {
                    target.EmitCode(context, false);
                }

                if (context.HasErrors)
                {
                    return;
                }

                expression.EmitCode(context, false);
                fieldAccess.FieldType.AssignFrom(context.ModuleContext, valueType).EmitConvert(context);

                if (!dropResult)
                {
                    using ITempBlockVariable tmpResult = context.MakeTempVariable(fieldAccess.FieldType);

                    context.IL.Emit(OpCodes.Dup);
                    tmpResult.EmitStore(context);

                    fieldAccess.EmitStore(context);

                    tmpResult.EmitLoad(context);
                }
                else
                {
                    fieldAccess.EmitStore(context);
                }
            }
            else
            {
                IOperatorEmitter operatorEmitter = fieldAccess.FieldType.AllowedSuffixOperators(context.ModuleContext)
                                                   .GetMatching(context.ModuleContext, op, valueType);

                if (operatorEmitter == null)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.IncompatibleTypes,
                                         $"Type '{targetType.Name}' field '{fieldName}': Cannot {op} a {fieldAccess.FieldType} with a {valueType}",
                                         Start,
                                         End
                                         ));
                    return;
                }

                expression.Prepare(context);

                if (fieldAccess.RequiresPtr)
                {
                    target.EmitPtr(context);
                }
                else
                {
                    target.EmitCode(context, false);
                }

                if (fieldAccess.RequiresPtr)
                {
                    target.EmitPtr(context);
                }
                else
                {
                    target.EmitCode(context, false);
                }

                if (context.HasErrors)
                {
                    return;
                }

                fieldAccess.EmitLoad(context);
                expression.EmitCode(context, false);
                operatorEmitter.OtherType.AssignFrom(context.ModuleContext, valueType).EmitConvert(context);
                operatorEmitter.EmitCode(context, this);

                if (!dropResult)
                {
                    using ITempBlockVariable tmpResult = context.MakeTempVariable(fieldAccess.FieldType);

                    context.IL.Emit(OpCodes.Dup);
                    tmpResult.EmitStore(context);

                    fieldAccess.EmitStore(context);

                    tmpResult.EmitLoad(context);
                }
                else
                {
                    fieldAccess.EmitStore(context);
                }
            }
        }