Пример #1
0
        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>());
        }
Пример #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 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);
            }
        }
Пример #4
0
 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;
 }
Пример #5
0
        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);
        }
Пример #6
0
 public override bool IsAssignableFrom(ModuleContext context, TO2Type otherType)
 {
     if (!(otherType.UnderlyingType(context) is TupleType))
     {
         return(false);
     }
     return(GeneratedType(context).IsAssignableFrom(otherType.GeneratedType(context)));
 }
Пример #7
0
 internal TypeAliasDelegate(ModuleContext declaredModule, TO2Type aliasedType, string description, Node target)
 {
     this.declaredModule = declaredModule;
     this.aliasedType    = aliasedType;
     lookingUp           = false;
     Description         = description;
     this.target         = target;
 }
Пример #8
0
        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);
        }
Пример #9
0
 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;
 }
Пример #10
0
        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));
        }
Пример #11
0
        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);
        }
Пример #12
0
 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);
 }
Пример #13
0
 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;
 }
Пример #14
0
        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));
        }
Пример #15
0
        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);
            }
        }
Пример #16
0
 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;
 }
Пример #17
0
 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) }
     };
 }
Пример #18
0
 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);
 }
Пример #19
0
 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())
         }, {
Пример #20
0
        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);
        }
Пример #21
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);
        }
Пример #22
0
        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));
                };
            }
        }
Пример #23
0
 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) }
     };
 }
Пример #24
0
        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);
        }
Пример #25
0
        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);
        }
Пример #26
0
        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);
        }
Пример #27
0
        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);
        }
Пример #28
0
        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));
        }
Пример #29
0
        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();
        }
Пример #30
0
        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);
        }