public IEnumerable <StructuralError> TryImportTypes(ModuleContext context) { IKontrolModule module = context.FindModule(fromModule); if (module == null) { return(new StructuralError( StructuralError.ErrorType.NoSuchModule, $"Module '{fromModule}' not found", Start, End ).Yield()); } if (alias != null) { context.moduleAliases.Add(alias, fromModule); } else { foreach (string name in (names ?? module.AllTypeNames)) { TO2Type type = module.FindType(name); if (type != null) { context.mappedTypes.Add(name, type); } } } return(Enumerable.Empty <StructuralError>()); }
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 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 FunctionParameter(string name, TO2Type type, Expression defaultValue = null, Position start = new Position(), Position end = new Position()) : base(start, end) { this.name = name; this.type = type; this.defaultValue = defaultValue; }
public override void EmitPtr(IBlockContext context) { TO2Type targetType = target.ResultType(context); IIndexAccessEmitter indexAccess = targetType.AllowedIndexAccess(context.ModuleContext, indexSpec); if (indexAccess == null) { context.AddError(new StructuralError( StructuralError.ErrorType.NoIndexAccess, $"Type '{targetType.Name}' does not support access by index", Start, End )); return; } if (indexAccess.RequiresPtr) { target.EmitPtr(context); } else { target.EmitCode(context, false); } if (context.HasErrors) { return; } indexAccess.EmitPtr(context); }
public override bool IsAssignableFrom(ModuleContext context, TO2Type otherType) { if (!(otherType.UnderlyingType(context) is TupleType)) { return(false); } return(GeneratedType(context).IsAssignableFrom(otherType.GeneratedType(context))); }
internal TypeAliasDelegate(ModuleContext declaredModule, TO2Type aliasedType, string description, Node target) { this.declaredModule = declaredModule; this.aliasedType = aliasedType; lookingUp = false; Description = description; this.target = target; }
public override IAssignEmitter AssignFrom(ModuleContext context, TO2Type otherType) { RealizedType underlyingOther = otherType.UnderlyingType(context); return(!(underlyingOther is OptionType) && elementType.IsAssignableFrom(context, underlyingOther) ? new AssignSome(this, otherType) : DefaultAssignEmitter.Instance); }
public TypeAlias(bool exported, string name, string description, TO2Type type, Position start = new Position(), Position end = new Position()) : base(start, end) { this.exported = exported; this.name = name; this.description = description; this.type = type; }
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)); }
null; // TODO: Actually this should be allowed public override IAssignEmitter AssignFrom(ModuleContext context, TO2Type otherType) { Type generatedType = GeneratedType(context); Type generatedOther = otherType.GeneratedType(context); return(otherType is RecordType otherRecordType && generatedType != generatedOther ? new AssignRecordStruct(this, otherRecordType) : DefaultAssignEmitter.Instance); }
public ConstDeclaration(bool isPublic, string name, string description, TO2Type type, Expression expression, Position start = new Position(), Position end = new Position()) : base(start, end) { this.isPublic = isPublic; this.name = name; this.description = description; this.type = type; this.expression = expression; this.expression.TypeHint = context => this.type.UnderlyingType(context.ModuleContext); }
public StructField(string name, TO2Type type, string description, Expression initializer, Position start = new Position(), Position end = new Position()) { this.name = name; this.type = type; this.description = description; this.initializer = initializer; this.start = start; this.end = end; }
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 override void EmitCode(IBlockContext context, bool dropResult) { TO2Type leftType = left.ResultType(context); TO2Type rightType = right.ResultType(context); if (context.HasErrors) { return; } IOperatorEmitter leftEmitter = leftType.AllowedSuffixOperators(context.ModuleContext) .GetMatching(context.ModuleContext, op, rightType); IOperatorEmitter rightEmitter = rightType.AllowedPrefixOperators(context.ModuleContext) .GetMatching(context.ModuleContext, op, leftType); if (leftEmitter == null && rightEmitter == null) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"Cannot {op} a {leftType} with a {rightType}", Start, End )); return; } right.Prepare(context); left.EmitCode(context, false); rightEmitter?.OtherType.AssignFrom(context.ModuleContext, leftType).EmitConvert(context); right.EmitCode(context, false); leftEmitter?.OtherType.AssignFrom(context.ModuleContext, rightType).EmitConvert(context); if (context.HasErrors) { return; } if (leftEmitter != null) { leftEmitter.EmitCode(context, this); } else { rightEmitter.EmitCode(context, this); } if (dropResult) { context.IL.Emit(OpCodes.Pop); } }
public ForIn(string variableName, TO2Type variableType, Expression sourceExpression, Expression loopExpression, Position start = new Position(), Position end = new Position()) : base(start, end) { this.variableName = variableName; this.variableType = variableType; this.sourceExpression = sourceExpression; if (this.variableType != null) { this.sourceExpression.TypeHint = context => new ArrayType(this.variableType.UnderlyingType(context.ModuleContext)); } this.loopExpression = loopExpression; }
public ResultType(TO2Type successType, TO2Type errorType) { this.successType = successType; this.errorType = errorType; allowedSuffixOperators = new OperatorCollection { { Operator.Unwrap, new ResultUnwrapOperator(this) } }; DeclaredFields = new Dictionary <string, IFieldAccessFactory> { { "success", new ResultFieldAccess(this, ResultField.Success) }, { "value", new ResultFieldAccess(this, ResultField.Value) }, { "error", new ResultFieldAccess(this, ResultField.Error) } }; }
public FunctionDeclaration(FunctionModifier modifier, bool isAsync, string name, string description, List <FunctionParameter> parameters, TO2Type declaredReturn, Expression expression, Position start = new Position(), Position end = new Position()) : base(start, end) { this.modifier = modifier; this.name = name; this.description = description; this.isAsync = isAsync; this.parameters = parameters; this.declaredReturn = declaredReturn; this.expression = expression; this.expression.VariableContainer = this; this.expression.TypeHint = context => this.declaredReturn.UnderlyingType(context.ModuleContext); }
public ArrayType(TO2Type elementType) { ElementType = elementType; DeclaredMethods = new Dictionary <string, IMethodInvokeFactory> { { "map", new BoundMethodInvokeFactory("Map the content of the array", true, () => new ArrayType(new GenericParameter("U")), () => new List <RealizedParameter> { new RealizedParameter("mapper", new FunctionType(false, new List <TO2Type> { ElementType }, new GenericParameter("U"))) }, false, typeof(ArrayMethods), typeof(ArrayMethods).GetMethod("Map"), context => ("T", this.ElementType.UnderlyingType(context)).Yield()) }, {
public static TO2Type FindVariable(this IVariableContainer current, IBlockContext context, string name) { while (current != null) { TO2Type variableType = current.FindVariableLocal(context, name); if (variableType != null) { return(variableType); } current = current.ParentContainer; } return(null); }
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); }
public MethodCall(Expression target, string methodName, List <Expression> arguments, Position start = new Position(), Position end = new Position()) : base(start, end) { this.target = target; this.methodName = methodName; this.arguments = arguments; for (int j = 0; j < this.arguments.Count; j++) { int i = j; // Copy for lambda this.arguments[i].TypeHint = context => { TO2Type targetType = this.target.ResultType(context); IMethodInvokeFactory methodInvoker = targetType.FindMethod(context.ModuleContext, this.methodName); return(methodInvoker?.ArgumentHint(i)?.Invoke(context)); }; } }
public OptionType(TO2Type elementType) { this.elementType = elementType; allowedSuffixOperators = new OperatorCollection { { Operator.BitOr, new OptionBitOrOperator(this) }, { Operator.Unwrap, new OptionUnwrapOperator(this) } }; DeclaredMethods = new Dictionary <string, IMethodInvokeFactory> { { "map", new OptionMapFactory(this) }, { "then", new OptionThenFactory(this) }, { "ok_or", new OptionOkOrFactory(this) } }; DeclaredFields = new Dictionary <string, IFieldAccessFactory> { { "defined", new OptionFieldAccess(this, OptionField.Defined) }, { "value", new OptionFieldAccess(this, OptionField.Value) } }; }
public override TO2Type ResultType(IBlockContext context) { if (ElementType != null) { return(new ArrayType(ElementType)); } foreach (Expression element in Elements) { TO2Type valueType = element.ResultType(context); if (valueType != BuiltinType.Unit) { return(new ArrayType(valueType)); } } ArrayType arrayHint = typeHint?.Invoke(context) as ArrayType; return(arrayHint ?? BuiltinType.Unit); }
public override bool IsAssignableFrom(ModuleContext context, TO2Type otherType) { RecordType recordType = otherType.UnderlyingType(context) as RecordType; if (recordType == null) { return(false); } foreach (var kv in ItemTypes) { TO2Type otherItem = recordType.ItemTypes.Get(kv.Key); if (otherItem == null || !kv.Value.IsAssignableFrom(context, otherItem)) { return(false); } } return(true); }
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); }
private void EmitAssign(IBlockContext context, IBlockVariable blockVariable, TO2Type valueType, bool dropResult) { if (!blockVariable.Type.IsAssignableFrom(context.ModuleContext, valueType)) { context.AddError(new StructuralError( StructuralError.ErrorType.IncompatibleTypes, $"Variable '{name}' is of type {blockVariable.Type} but is assigned to {valueType}", Start, End )); } if (context.HasErrors) { return; } blockVariable.Type.AssignFrom(context.ModuleContext, valueType) .EmitAssign(context, blockVariable, expression, dropResult); }
public void EmitPtr(IBlockContext context) { TO2Type resultType = indexExpression.ResultType(context); if (!BuiltinType.Int.IsAssignableFrom(context.ModuleContext, resultType)) { context.AddError(new StructuralError( StructuralError.ErrorType.InvalidType, $"Index has to be of type {BuiltinType.Int}", indexExpression.Start, indexExpression.End )); return; } indexExpression.EmitCode(context, false); BuiltinType.Int.AssignFrom(context.ModuleContext, resultType).EmitConvert(context); context.IL.Emit(OpCodes.Conv_I4); context.IL.Emit(OpCodes.Ldelema, targetType.GeneratedType(context.ModuleContext)); }
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 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); }