Esempio n. 1
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);
            }
        }
Esempio n. 2
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);
        }
Esempio n. 3
0
        public override TO2Type ResultType(IBlockContext context)
        {
            TO2Type leftType  = left.ResultType(context);
            TO2Type rightType = right.ResultType(context);

            IOperatorEmitter operatorEmitter =
                leftType.AllowedSuffixOperators(context.ModuleContext)
                .GetMatching(context.ModuleContext, op, rightType) ??
                rightType.AllowedPrefixOperators(context.ModuleContext)
                .GetMatching(context.ModuleContext, op, leftType);

            if (operatorEmitter == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.IncompatibleTypes,
                                     $"Cannot {op} a {leftType} with a {rightType}",
                                     Start,
                                     End
                                     ));
                return(BuiltinType.Unit);
            }

            return(operatorEmitter.ResultType);
        }
Esempio n. 4
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            TO2Type             valueType   = expression.ResultType(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 (target is IAssignContext assignContext)
            {
                if (assignContext.IsConst(context))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.NoSuchField,
                                         $"Type '{targetType.Name}' elements can not be set on a read-only variable",
                                         Start,
                                         End
                                         ));
                    return;
                }
            }
            else
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.CoreGeneration,
                                     $"Index assign '{targetType.Name}'.'{indexSpec}' on invalid target expression",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (op == Operator.Assign)
            {
                if (indexAccess.RequiresPtr)
                {
                    target.EmitPtr(context);
                }
                else
                {
                    target.EmitCode(context, false);
                }

                if (context.HasErrors)
                {
                    return;
                }

                if (!dropResult)
                {
                    using ITempBlockVariable tmpResult =
                              context.MakeTempVariable(indexAccess.TargetType.UnderlyingType(context.ModuleContext));
                    indexAccess.EmitStore(context, subContext => {
                        expression.EmitCode(subContext, false);
                        indexAccess.TargetType.AssignFrom(subContext.ModuleContext, valueType)
                        .EmitConvert(subContext);

                        context.IL.Emit(OpCodes.Dup);
                        // ReSharper disable once AccessToDisposedClosure
                        tmpResult.EmitStore(subContext);
                    });

                    tmpResult.EmitLoad(context);
                }
                else
                {
                    indexAccess.EmitStore(context, subContext => {
                        expression.EmitCode(subContext, false);
                        indexAccess.TargetType.AssignFrom(subContext.ModuleContext, valueType).EmitConvert(subContext);
                    });
                }
            }
            else
            {
                IOperatorEmitter operatorEmitter = indexAccess.TargetType.AllowedSuffixOperators(context.ModuleContext)
                                                   .GetMatching(context.ModuleContext, op, valueType);

                if (operatorEmitter == null)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.IncompatibleTypes,
                                         $"Index assign '{targetType.Name}'.'{indexSpec}': Cannot {op} a {indexAccess.TargetType} with a {valueType}",
                                         Start,
                                         End
                                         ));
                    return;
                }

                expression.Prepare(context);

                if (indexAccess.RequiresPtr)
                {
                    target.EmitPtr(context);
                }
                else
                {
                    target.EmitCode(context, false);
                }

                if (context.HasErrors)
                {
                    return;
                }

                if (!dropResult)
                {
                    using ITempBlockVariable tmpResult =
                              context.MakeTempVariable(indexAccess.TargetType.UnderlyingType(context.ModuleContext));
                    indexAccess.EmitStore(context, subContext => {
                        if (indexAccess.RequiresPtr)
                        {
                            target.EmitPtr(context);
                        }
                        else
                        {
                            target.EmitCode(context, false);
                        }

                        indexAccess.EmitLoad(context);
                        expression.EmitCode(subContext, false);

                        operatorEmitter.OtherType.AssignFrom(context.ModuleContext, valueType).EmitConvert(context);
                        operatorEmitter.EmitCode(context, this);

                        context.IL.Emit(OpCodes.Dup);
                        // ReSharper disable once AccessToDisposedClosure
                        tmpResult.EmitStore(subContext);
                    });

                    tmpResult.EmitLoad(context);
                }
                else
                {
                    indexAccess.EmitStore(context, subContext => {
                        if (indexAccess.RequiresPtr)
                        {
                            target.EmitPtr(context);
                        }
                        else
                        {
                            target.EmitCode(context, false);
                        }

                        indexAccess.EmitLoad(context);
                        expression.EmitCode(subContext, false);

                        operatorEmitter.OtherType.AssignFrom(context.ModuleContext, valueType).EmitConvert(context);
                        operatorEmitter.EmitCode(context, this);
                    });
                }
            }
        }
Esempio n. 5
0
        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);
            }
        }
Esempio n. 6
0
        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);
                }
            }
        }