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); }
// ---------------- IAssignEmitter ----------------- public void EmitAssign(IBlockContext context, IBlockVariable variable, Expression expression, bool dropResult) { using ITempBlockVariable valueTemp = context.MakeTempVariable(sourceType); expression.EmitStore(context, valueTemp, true); variable.EmitLoadPtr(context); EmitAssignToPtr(context, valueTemp); if (!dropResult) { variable.EmitLoad(context); } }
public override void EmitStore(IBlockContext context, IBlockVariable variable, bool dropResult) { if (!BuiltinType.Int.IsAssignableFrom(context.ModuleContext, from.ResultType(context))) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, "Range can only be created from int values", from.Start, from.End )); } if (!BuiltinType.Int.IsAssignableFrom(context.ModuleContext, to.ResultType(context))) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, "Range can only be created from int values", to.Start, to.End )); } if (context.HasErrors) { return; } variable.EmitLoadPtr(context); context.IL.Emit(OpCodes.Dup); from.EmitCode(context, false); context.IL.Emit(OpCodes.Stfld, typeof(Range).GetField("from")); to.EmitCode(context, false); if (inclusive) { context.IL.Emit(OpCodes.Ldc_I4_1); context.IL.Emit(OpCodes.Conv_I8); context.IL.Emit(OpCodes.Add); } context.IL.Emit(OpCodes.Stfld, typeof(Range).GetField("to")); if (!dropResult) { variable.EmitLoad(context); } }
public void EmitConstructor(IBlockContext context) { foreach (StructField field in fields.Where(e => e.IsRight).Select(e => e.Right)) { TO2Type initializerType = field.initializer.ResultType(context); if (!field.type.IsAssignableFrom(context.ModuleContext, initializerType)) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"Expected item {field.name} of {name} to be a {field.type}, found {initializerType}", Start, End )); } } if (context.HasErrors) { return; } Type type = typeDelegate.GeneratedType(context.ModuleContext); IBlockVariable variable = context.DeclaredVariable("instance", false, typeDelegate.UnderlyingType(context.ModuleContext)); variable.EmitLoad(context); foreach (StructField field in fields.Where(e => e.IsRight).Select(e => e.Right)) { context.IL.Emit(OpCodes.Dup); field.initializer.EmitCode(context, false); field.type.AssignFrom(context.ModuleContext, field.initializer.ResultType(context)) .EmitConvert(context); context.IL.Emit(OpCodes.Stfld, type.GetField(field.name)); } context.IL.EmitReturn(type); typeDelegate.CreateStructType(); }
public void EmitAssign(IBlockContext context, IBlockVariable variable, Expression expression, bool dropResult) { Type generatedType = optionType.GeneratedType(context.ModuleContext); using ITempBlockVariable valueTemp = context.MakeTempVariable(optionType.elementType.UnderlyingType(context.ModuleContext)); optionType.elementType.AssignFrom(context.ModuleContext, otherType) .EmitAssign(context, valueTemp, expression, true); variable.EmitLoadPtr(context); context.IL.Emit(OpCodes.Dup); context.IL.Emit(OpCodes.Initobj, generatedType, 1, 0); context.IL.Emit(OpCodes.Dup); context.IL.Emit(OpCodes.Ldc_I4_1); context.IL.Emit(OpCodes.Stfld, generatedType.GetField("defined")); valueTemp.EmitLoad(context); context.IL.Emit(OpCodes.Stfld, generatedType.GetField("value")); if (!dropResult) { variable.EmitLoad(context); } }
public override void EmitStore(IBlockContext context, IBlockVariable variable, bool dropResult) { TupleType tupleType = variable.Type as TupleType; if (tupleType == null) { context.AddError(new StructuralError( StructuralError.ErrorType.InvalidType, $"{variable.Type} is not a tuple", Start, End )); return; } else { if (items.Count != tupleType.itemTypes.Count) { context.AddError(new StructuralError( StructuralError.ErrorType.InvalidType, $"Expected tuple of {tupleType.itemTypes.Count} items, found {items.Count} items", Start, End )); } for (int i = 0; i < items.Count; i++) { TO2Type valueType = items[i].ResultType(context); if (!tupleType.itemTypes[i].IsAssignableFrom(context.ModuleContext, valueType)) { context.AddError(new StructuralError( StructuralError.ErrorType.InvalidType, $"Expected item {i} of {tupleType} to be a {tupleType.itemTypes[i]}, found {valueType}", Start, End )); } } } if (context.HasErrors) { return; } foreach (Expression item in items) { item.Prepare(context); } Type type = tupleType.GeneratedType(context.ModuleContext); variable.EmitLoadPtr(context); // Note: Potentially overoptimized: Since all fields will be set, initialization should not be necessary // context.IL.Emit(OpCodes.Dup); // context.IL.Emit(OpCodes.Initobj, type, 1, 0); for (int i = 0; i < items.Count; i++) { if (i > 0 && i % 7 == 0) { context.IL.Emit(OpCodes.Ldflda, type.GetField("Rest")); type = type.GetGenericArguments()[7]; // context.IL.Emit(OpCodes.Dup); // context.IL.Emit(OpCodes.Initobj, type, 1, 0); } if (i < items.Count - 1) { context.IL.Emit(OpCodes.Dup); } items[i].EmitCode(context, false); tupleType.itemTypes[i].AssignFrom(context.ModuleContext, items[i].ResultType(context)) .EmitConvert(context); context.IL.Emit(OpCodes.Stfld, type.GetField($"Item{i % 7 + 1}")); } if (context.HasErrors) { return; } if (!dropResult) { variable.EmitLoad(context); } }
public override void EmitCode(IBlockContext context, bool dropResult) { IBlockVariable blockVariable = context.FindVariable(name); if (blockVariable == null) { context.AddError(new StructuralError( StructuralError.ErrorType.NoSuchVariable, $"No local variable '{name}'", Start, End )); } else if (blockVariable.IsConst) { context.AddError(new StructuralError( StructuralError.ErrorType.NoSuchVariable, $"Local variable '{name}' is read-only (const)", Start, End )); } if (context.HasErrors) { return; } TO2Type valueType = expression.ResultType(context); if (context.HasErrors) { return; } if (op == Operator.Assign) { EmitAssign(context, blockVariable, valueType, dropResult); return; } IOperatorEmitter operatorEmitter = blockVariable !.Type.AllowedSuffixOperators(context.ModuleContext) .GetMatching(context.ModuleContext, op, valueType); if (operatorEmitter == null) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"Cannot {op} a {blockVariable.Type} with a {valueType}", Start, End )); return; } expression.Prepare(context); blockVariable.EmitLoad(context); expression.EmitCode(context, false); if (context.HasErrors) { return; } operatorEmitter.OtherType.AssignFrom(context.ModuleContext, valueType).EmitConvert(context); operatorEmitter.EmitAssign(context, blockVariable, this); if (!dropResult) { blockVariable.EmitLoad(context); } }