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); }
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); }
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); }
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); } }
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); } } }