public override bool IsAssignableFrom(ModuleContext context, TO2Type otherType) { if (otherType.UnderlyingType(context) is OptionType otherOption) { return(elementType.IsAssignableFrom(context, otherOption.elementType)); } return(elementType.IsAssignableFrom(context, otherType)); }
public override bool IsAssignableFrom(ModuleContext context, TO2Type otherType) { if (otherType.UnderlyingType(context) is ResultType otherResultType) { return(successType.IsAssignableFrom(context, otherResultType.successType) && errorType.IsAssignableFrom(context, otherResultType.errorType)); } return(successType.IsAssignableFrom(context, otherType)); }
public void EmitCode(IBlockContext context) { TO2Type valueType = expression.ResultType(context); if (declaredReturn != BuiltinType.Unit && !declaredReturn.IsAssignableFrom(context.ModuleContext, valueType)) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"Function '{name}' returns {valueType} but should return {declaredReturn}", Start, End )); return; } if (isAsync) { EmitCodeAsync(context); } else { EmitCodeSync(context); } }
public IOperatorEmitter GetMatching(ModuleContext context, Operator op, TO2Type otherType) { IOperatorEmitter existing = allowedOperators.GetMatching(context, op, otherType); if (existing != null) { return(existing); } if (op != Operator.BitAnd && op != Operator.BitAndAssign) { return(null); } RecordType otherRecordType = otherType.UnderlyingType(context) as RecordType; if (otherRecordType == null) { return(null); } bool hasMatch = false; foreach (var otherKV in otherRecordType.ItemTypes) { TO2Type item = recordType.ItemTypes.Get(otherKV.Key); if (item == null) { continue; } if (!item.IsAssignableFrom(context, otherKV.Value)) { return(null); } hasMatch = true; } return(hasMatch ? recordType.CombineFrom(otherRecordType) : null); }
public override void EmitCode(IBlockContext context, bool dropResult) { if (condition.ResultType(context) != BuiltinType.Bool) { context.AddError( new StructuralError( StructuralError.ErrorType.InvalidType, "Condition of if is not a boolean", Start, End ) ); return; } IBlockContext thenContext = context.CreateChildContext(); IBlockContext elseContext = context.CreateChildContext(); Dictionary <string, TO2Type> scopeVariables = condition.GetScopeVariables(thenContext); if (scopeVariables != null) { foreach (var(name, type) in scopeVariables) { if (thenContext.FindVariable(name) != null) { thenContext.AddError(new StructuralError( StructuralError.ErrorType.DuplicateVariableName, $"Variable '{name}' already declared in this scope", Start, End )); return; } thenContext.DeclaredVariable(name, true, type.UnderlyingType(context.ModuleContext)); } } ILCount thenCount = thenExpression.GetILCount(thenContext, dropResult); ILCount elseCount = elseExpression.GetILCount(elseContext, dropResult); if (!context.HasErrors && thenCount.stack > 1) { context.AddError( new StructuralError( StructuralError.ErrorType.CoreGeneration, "Then expression leaves too many values on stack. This must not happen", Start, End ) ); return; } if (!context.HasErrors && elseCount.stack > 1) { context.AddError( new StructuralError( StructuralError.ErrorType.CoreGeneration, "Else expression leaves too many values on stack. This must not happen", Start, End ) ); return; } condition.EmitCode(thenContext, false); if (context.HasErrors) { return; } TO2Type thenType = thenExpression.ResultType(thenContext); TO2Type elseType = elseExpression.ResultType(elseContext); if (!dropResult) { if (!thenType.IsAssignableFrom(context.ModuleContext, elseType)) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"If condition has incompatible result {thenType} != {elseType}", Start, End )); } } if (context.HasErrors) { return; } LabelRef thenEnd = context.IL.DefineLabel(thenCount.opCodes < 124); LabelRef elseEnd = context.IL.DefineLabel(elseCount.opCodes < 124); context.IL.Emit(thenEnd.isShort ? OpCodes.Brfalse_S : OpCodes.Brfalse, thenEnd); thenExpression.EmitCode(thenContext, dropResult); context.IL.Emit(elseEnd.isShort ? OpCodes.Br_S : OpCodes.Br, elseEnd); context.IL.MarkLabel(thenEnd); if (!dropResult) { context.IL.AdjustStack(-1); // Then leave its result on the stack, so is else supposed to } elseExpression.EmitCode(elseContext, dropResult); if (!dropResult) { thenType.AssignFrom(context.ModuleContext, elseType).EmitConvert(context); } context.IL.MarkLabel(elseEnd); }
public override void EmitCode(IBlockContext context, bool dropResult) { RealizedType sourceType = sourceExpression.ResultType(context).UnderlyingType(context.ModuleContext); IForInSource source = sourceType.ForInSource(context.ModuleContext, variableType); if (source == null) { context.AddError( new StructuralError( StructuralError.ErrorType.InvalidType, $"{sourceType} cannot be use as for ... in source", Start, End ) ); } if (context.FindVariable(variableName) != null) { context.AddError(new StructuralError( StructuralError.ErrorType.DuplicateVariableName, $"Variable '{variableName}' already declared in this scope", Start, End )); } if (source != null && variableType != null && !variableType.IsAssignableFrom(context.ModuleContext, source.ElementType)) { context.AddError( new StructuralError( StructuralError.ErrorType.InvalidType, $"{sourceType} has elements of type {source.ElementType}, expected {variableType}", Start, End ) ); } if (context.HasErrors) { return; } using ITempLocalRef loopCounter = context.IL.TempLocal(typeof(int)); ILCount loopSize = EstimateLoop(context, source); LabelRef start = context.IL.DefineLabel(loopSize.opCodes < 110); LabelRef end = context.IL.DefineLabel(loopSize.opCodes < 110); LabelRef loop = context.IL.DefineLabel(loopSize.opCodes < 100); IBlockContext loopContext = context.CreateLoopContext(start, end); IBlockVariable loopVariable = loopContext.DeclaredVariable(variableName, true, source !.ElementType); sourceExpression.EmitCode(context, false); if (context.HasErrors) { return; } source.EmitInitialize(loopContext); loopContext.IL.Emit(start.isShort ? OpCodes.Br_S : OpCodes.Br, start); loopContext.IL.MarkLabel(loop); // Timeout check LabelRef skipCheck = context.IL.DefineLabel(true); loopCounter.EmitLoad(loopContext); loopContext.IL.Emit(OpCodes.Ldc_I4_1); loopContext.IL.Emit(OpCodes.Add); loopContext.IL.Emit(OpCodes.Dup); loopCounter.EmitStore(loopContext); loopContext.IL.Emit(OpCodes.Ldc_I4, 10000); loopContext.IL.Emit(OpCodes.Cgt); loopContext.IL.Emit(OpCodes.Brfalse, skipCheck); loopContext.IL.Emit(OpCodes.Ldc_I4_0); loopCounter.EmitStore(loopContext); context.IL.EmitCall(OpCodes.Call, typeof(Runtime.ContextHolder).GetMethod("CheckTimeout"), 0); loopContext.IL.MarkLabel(skipCheck); source.EmitNext(loopContext); loopVariable.EmitStore(loopContext); loopExpression.EmitCode(loopContext, true); loopContext.IL.MarkLabel(start); source.EmitCheckDone(loopContext, loop); loopContext.IL.MarkLabel(end); if (!dropResult) { context.IL.Emit(OpCodes.Ldnull); } }