Esempio n. 1
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);
        }
Esempio n. 2
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);
        }
Esempio n. 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);
            }
        }
Esempio n. 4
0
        public static IDefaultValue ForParameter(IBlockContext context, FunctionParameter parameter)
        {
            if (parameter.defaultValue == null)
            {
                return(null);
            }
            switch (parameter.defaultValue)
            {
            case LiteralBool b when parameter.type == BuiltinType.Bool: return(new BoolDefaultValue(b.value));

            case LiteralInt i when parameter.type == BuiltinType.Int: return(new IntDefaultValue(i.value));

            case LiteralInt i when parameter.type == BuiltinType.Float: return(new FloatDefaultValue(i.value));

            case LiteralFloat f when parameter.type == BuiltinType.Float: return(new FloatDefaultValue(f.value));

            case LiteralString s when parameter.type == BuiltinType.String: return(new StringDefaultValue(s.value));

            default:
                IBlockContext defaultContext = new SyncBlockContext(context.ModuleContext, FunctionModifier.Public,
                                                                    false, $"default_{context.MethodBuilder.Name}_{parameter.name}", parameter.type,
                                                                    new List <FunctionParameter>());
                TO2Type resultType = parameter.defaultValue.ResultType(defaultContext);

                if (!parameter.type.IsAssignableFrom(context.ModuleContext, resultType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.IncompatibleTypes,
                                         $"Default value of parameter {parameter.name} has to be of type {parameter.type}, found {resultType}",
                                         parameter.Start,
                                         parameter.End
                                         ));
                    return(null);
                }

                parameter.defaultValue.EmitCode(defaultContext, false);
                parameter.type.AssignFrom(context.ModuleContext, resultType).EmitConvert(context);
                defaultContext.IL.EmitReturn(parameter.type.GeneratedType(context.ModuleContext));

                foreach (StructuralError error in defaultContext.AllErrors)
                {
                    context.AddError(error);
                }

                return(new DefaultValueFactoryFunction(defaultContext.MethodBuilder));
            }
        }
Esempio n. 5
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);
        }
Esempio n. 6
0
        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);
            }
        }
Esempio n. 7
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);
            }
        }
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            RealizedType sourceType = sourceExpression.ResultType(context).UnderlyingType(context.ModuleContext);
            IForInSource source     = sourceType.ForInSource(context.ModuleContext, null);

            if (source == null)
            {
                context.AddError(
                    new StructuralError(
                        StructuralError.ErrorType.InvalidType,
                        $"{sourceType} cannot be use as for ... in source",
                        Start,
                        End
                        )
                    );
            }
            foreach (DeclarationParameter declaration in declarations)
            {
                if (context.FindVariable(declaration.target) != null)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.DuplicateVariableName,
                                         $"Variable '{declaration.target}' already declared in this scope",
                                         Start,
                                         End
                                         ));
                }
            }

            if (context.HasErrors)
            {
                return;
            }

            switch (source !.ElementType)
            {
Esempio n. 9
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            if (!context.InnerLoop.HasValue)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.InvalidScope,
                                     "continue can only be used inside a loop",
                                     Start,
                                     End
                                     ));
                return;
            }

            context.IL.Emit(context.InnerLoop.Value.start.isShort ? OpCodes.Br_S : OpCodes.Br,
                            context.InnerLoop.Value.start);
        }
        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));
        }
Esempio n. 11
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);
        }
        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();
        }
Esempio n. 13
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            if (context.ExpectedReturn != BuiltinType.Unit)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.IncompatibleTypes,
                                     $"Expected a return value of type {context.ExpectedReturn}",
                                     Start,
                                     End
                                     ));
                return;
            }

            context.IL.Emit(OpCodes.Ldnull);
            if (context.IsAsync)
            {
                context.IL.EmitNew(OpCodes.Newobj,
                                   context.MethodBuilder.ReturnType.GetConstructor(new[] { typeof(object) }));
            }

            context.IL.EmitReturn(context.MethodBuilder.ReturnType);
        }
        public void EmitStore(IBlockContext context, Action <IBlockContext> emitValue)
        {
            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);

            emitValue(context);

            if (targetType == BuiltinType.Bool)
            {
                context.IL.Emit(OpCodes.Stelem_I4);
            }
            else if (targetType == BuiltinType.Int)
            {
                context.IL.Emit(OpCodes.Stelem_I8);
            }
            else if (targetType == BuiltinType.Float)
            {
                context.IL.Emit(OpCodes.Stelem_R8);
            }
            else
            {
                context.IL.Emit(OpCodes.Stelem, targetType.GeneratedType(context.ModuleContext));
            }
        }
Esempio n. 15
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. 16
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            if (preparedResult != null)
            {
                if (!dropResult)
                {
                    preparedResult.EmitLoad(context);
                }
                preparedResult = null;
                return;
            }

            TO2Type targetType          = target.ResultType(context);
            IMethodInvokeFactory method = targetType.FindMethod(context.ModuleContext, methodName);

            if (method != null)
            {
                EmitCodeMethodCall(context, targetType, method, dropResult);
                return;
            }

            IFieldAccessFactory field = targetType.FindField(context.ModuleContext, methodName);

            if (field != null)
            {
                EmitCodeDelegateCall(context, targetType, field, dropResult);
                return;
            }

            context.AddError(new StructuralError(
                                 StructuralError.ErrorType.NoSuchMethod,
                                 $"Type '{targetType.Name}' does not have a method or field '{methodName}'",
                                 Start,
                                 End
                                 ));
        }
Esempio n. 17
0
        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);
            }
        }
Esempio n. 18
0
        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);
        }
Esempio n. 19
0
        private void EmitCodeDelegateCall(IBlockContext context, TO2Type targetType, IFieldAccessFactory field,
                                          bool dropResult)
        {
            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;
            }

            if (functionType.isAsync && !context.IsAsync)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchFunction,
                                     $"Cannot call async function of variable {methodName}' of type '{targetType.Name} from a sync context",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (functionType.parameterTypes.Count != arguments.Count)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.ArgumentMismatch,
                                     $"Call to '{methodName}' of type '{targetType.Name}' requires {functionType.parameterTypes.Count} arguments",
                                     Start,
                                     End
                                     ));
                return;
            }

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

            for (int i = 0; i < arguments.Count; i++)
            {
                arguments[i].EmitCode(context, false);
                if (!context.HasErrors)
                {
                    functionType.parameterTypes[i].AssignFrom(context.ModuleContext, arguments[i].ResultType(context))
                    .EmitConvert(context);
                }
            }

            if (context.HasErrors)
            {
                return;
            }

            for (int i = 0; i < arguments.Count; i++)
            {
                TO2Type argumentType = arguments[i].ResultType(context);
                if (!functionType.parameterTypes[i].IsAssignableFrom(context.ModuleContext, argumentType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.ArgumentMismatch,
                                         $"Argument {i + 1} of '{methodName}' of type '{targetType.Name}' has to be a {functionType.parameterTypes[i]}, but {argumentType} was given",
                                         Start,
                                         End
                                         ));
                    return;
                }
            }

            MethodInfo invokeMethod = functionType.GeneratedType(context.ModuleContext).GetMethod("Invoke") ??
                                      throw new ArgumentException($"No Invoke method in generated ${functionType}");

            context.IL.EmitCall(OpCodes.Callvirt, invokeMethod, arguments.Count + 1);
            if (functionType.isAsync)
            {
                context.RegisterAsyncResume(functionType.returnType);
            }
            if (dropResult && invokeMethod.ReturnType != typeof(void))
            {
                context.IL.Emit(OpCodes.Pop);
            }
            if (!dropResult && invokeMethod.ReturnType == typeof(void))
            {
                context.IL.Emit(OpCodes.Ldnull);
            }
        }
Esempio n. 20
0
        private void EmitCodeMethodCall(IBlockContext context, TO2Type targetType, IMethodInvokeFactory method,
                                        bool dropResult)
        {
            if (target is IAssignContext assignContext)
            {
                if (assignContext.IsConst(context) && !method.IsConst)
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.NoSuchMethod,
                                         $"Method '{methodName}' will mutate const variable.",
                                         Start,
                                         End
                                         ));
                }
            }

            List <TO2Type>       argumentTypes = arguments.Select(arg => arg.ResultType(context)).ToList();
            IMethodInvokeEmitter methodInvoker = method.Create(context, argumentTypes, this);

            if (methodInvoker == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchMethod,
                                     $"Type '{targetType.Name}' does not have a method '{methodName}' matching arguments ({string.Join(", ", argumentTypes)})",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (methodInvoker.IsAsync && !context.IsAsync)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.NoSuchFunction,
                                     $"Cannot call async method of variable '{targetType.Name}.{methodName}' from a sync context",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (methodInvoker.RequiredParameterCount() > arguments.Count)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.ArgumentMismatch,
                                     $"Method '{targetType.Name}.{methodName}' requires {methodInvoker.RequiredParameterCount()} arguments",
                                     Start,
                                     End
                                     ));
                return;
            }

            int i;

            for (i = 0; i < arguments.Count; i++)
            {
                TO2Type argumentType = arguments[i].ResultType(context);
                if (!methodInvoker.Parameters[i].type.IsAssignableFrom(context.ModuleContext, argumentType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.ArgumentMismatch,
                                         $"Argument {methodInvoker.Parameters[i].name} of '{targetType.Name}.{methodName}' has to be a {methodInvoker.Parameters[i].type}, but got {argumentType}",
                                         Start,
                                         End
                                         ));
                    return;
                }
            }

            foreach (Expression argument in arguments)
            {
                argument.Prepare(context);
            }

            if (methodInvoker.RequiresPtr)
            {
                target.EmitPtr(context);
            }
            else
            {
                target.EmitCode(context, false);
            }
            for (i = 0; i < arguments.Count; i++)
            {
                arguments[i].EmitCode(context, false);
                if (!context.HasErrors)
                {
                    methodInvoker.Parameters[i].type.AssignFrom(context.ModuleContext, arguments[i].ResultType(context))
                    .EmitConvert(context);
                }
            }

            if (!context.HasErrors)
            {
                for (; i < methodInvoker.Parameters.Count; i++)
                {
                    methodInvoker.Parameters[i].defaultValue.EmitCode(context);
                }
            }

            if (context.HasErrors)
            {
                return;
            }

            methodInvoker.EmitCode(context);
            if (methodInvoker.IsAsync)
            {
                context.RegisterAsyncResume(methodInvoker.ResultType);
            }
            if (dropResult)
            {
                context.IL.Emit(OpCodes.Pop);
            }
        }
Esempio n. 21
0
        internal static AsyncClass Create(IBlockContext parent, string name, TO2Type declaredReturn,
                                          List <FunctionParameter> parameters, Expression expression)
        {
            Type returnType    = declaredReturn.GeneratedType(parent.ModuleContext);
            Type typeParameter = returnType == typeof(void) ? typeof(object) : returnType;

            ModuleContext asyncModuleContext = parent.ModuleContext.DefineSubContext($"AsyncFunction_{name}",
                                                                                     typeof(Future <>).MakeGenericType(typeParameter));

            List <ClonedFieldVariable> clonedParameters = new List <ClonedFieldVariable>();

            foreach (FunctionParameter parameter in parameters)
            {
                FieldBuilder field = asyncModuleContext.typeBuilder.DefineField(parameter.name,
                                                                                parameter.type.GeneratedType(parent.ModuleContext), FieldAttributes.Private);
                clonedParameters.Add(
                    new ClonedFieldVariable(parameter.type.UnderlyingType(parent.ModuleContext), field));
            }

            // ------------- PollValue -------------
            AsyncBlockContext asyncContext = new AsyncBlockContext(asyncModuleContext, FunctionModifier.Public,
                                                                   "PollValue", declaredReturn, typeof(FutureResult <>).MakeGenericType(typeParameter), clonedParameters);

            LabelRef applyState   = asyncContext.IL.DefineLabel(false);
            LabelRef initialState = asyncContext.IL.DefineLabel(false);

            asyncContext.IL.Emit(OpCodes.Br, applyState);
            asyncContext.IL.MarkLabel(initialState);

            expression.EmitCode(asyncContext, false);
            if (!asyncContext.HasErrors)
            {
                declaredReturn.AssignFrom(asyncContext.ModuleContext, expression.ResultType(asyncContext))
                .EmitConvert(asyncContext);
            }

            asyncContext.IL.EmitNew(OpCodes.Newobj,
                                    asyncContext.MethodBuilder.ReturnType.GetConstructor(new[] { typeParameter }));
            asyncContext.IL.EmitReturn(asyncContext.MethodBuilder.ReturnType);

            // Apply state
            asyncContext.IL.MarkLabel(applyState);
            asyncContext.IL.Emit(OpCodes.Ldarg_0);
            asyncContext.IL.Emit(OpCodes.Ldfld, asyncContext.stateField);
            asyncContext.IL.Emit(OpCodes.Switch,
                                 initialState.Yield().Concat(asyncContext.asyncResumes.Select(ar => ar.pollLabel)));
            asyncContext.IL.Emit(OpCodes.Ldarg_0);
            asyncContext.IL.Emit(OpCodes.Ldfld, asyncContext.stateField);
            asyncContext.IL.EmitNew(OpCodes.Newobj,
                                    typeof(InvalidAsyncStateException).GetConstructor(new[] { typeof(int) }), 1);
            asyncContext.IL.Emit(OpCodes.Throw);

            foreach (AsyncResume asyncResume in asyncContext.asyncResumes)
            {
                asyncResume.EmitPoll(asyncContext);
            }

            // Restore state
            asyncContext.IL.MarkLabel(asyncContext.resume);
            foreach (StateRef stateRef in asyncContext.stateRefs)
            {
                stateRef.EmitRestore(asyncContext);
            }
            asyncContext.IL.Emit(OpCodes.Ldarg_0);
            asyncContext.IL.Emit(OpCodes.Ldfld, asyncContext.stateField);
            asyncContext.IL.Emit(OpCodes.Switch,
                                 initialState.Yield().Concat(asyncContext.asyncResumes.Select(ar => ar.resumeLabel)));
            asyncContext.IL.Emit(OpCodes.Ldarg_0);
            asyncContext.IL.Emit(OpCodes.Ldfld, asyncContext.stateField);
            asyncContext.IL.EmitNew(OpCodes.Newobj,
                                    typeof(InvalidAsyncStateException).GetConstructor(new[] { typeof(int) }), 1);
            asyncContext.IL.Emit(OpCodes.Throw);

            // Store state
            asyncContext.IL.MarkLabel(asyncContext.storeState);
            foreach (StateRef stateRef in asyncContext.stateRefs)
            {
                stateRef.EmitStore(asyncContext);
            }

            asyncContext.IL.MarkLabel(asyncContext.notReady);
            using (ITempLocalRef notReady = asyncContext.IL.TempLocal(asyncContext.MethodBuilder.ReturnType)) {
                notReady.EmitLoadPtr(asyncContext);
                asyncContext.IL.Emit(OpCodes.Initobj, asyncContext.MethodBuilder.ReturnType, 1, 0);
                notReady.EmitLoad(asyncContext);
                asyncContext.IL.EmitReturn(asyncContext.MethodBuilder.ReturnType);
            }

            foreach (StructuralError error in asyncContext.AllErrors)
            {
                parent.AddError(error);
            }

            // ------------- Constructor -------------
            List <FieldInfo>   parameterFields    = clonedParameters.Select(c => c.valueField).ToList();
            ConstructorBuilder constructorBuilder = asyncModuleContext.typeBuilder.DefineConstructor(
                MethodAttributes.Public, CallingConventions.Standard,
                parameterFields.Select(f => f.FieldType).ToArray());
            IILEmitter constructorEmitter = new GeneratorILEmitter(constructorBuilder.GetILGenerator());

            int argIndex = 1;

            foreach (FieldInfo field in parameterFields)
            {
                constructorEmitter.Emit(OpCodes.Ldarg_0);
                MethodParameter.EmitLoadArg(constructorEmitter, argIndex++);
                constructorEmitter.Emit(OpCodes.Stfld, field);
            }

            constructorEmitter.Emit(OpCodes.Ldarg_0);
            constructorEmitter.Emit(OpCodes.Ldc_I4_0);
            constructorEmitter.Emit(OpCodes.Stfld, asyncContext.stateField);

            constructorEmitter.EmitReturn(typeof(void));

            return(new AsyncClass(asyncModuleContext.typeBuilder, constructorBuilder));
        }
Esempio n. 22
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            if (condition.ResultType(context) != BuiltinType.Bool)
            {
                context.AddError(
                    new StructuralError(
                        StructuralError.ErrorType.InvalidType,
                        "Condition of while is not a boolean",
                        Start,
                        End
                        )
                    );
            }

            IBlockContext tmpContext =
                context.CreateLoopContext(context.IL.DefineLabel(false), context.IL.DefineLabel(false));
            Dictionary <string, TO2Type> scopeVariables = condition.GetScopeVariables(tmpContext);

            if (scopeVariables != null)
            {
                foreach (var(name, type) in scopeVariables)
                {
                    tmpContext.DeclaredVariable(name, true, type.UnderlyingType(context.ModuleContext));
                }
            }

            ILCount conditionCount = condition.GetILCount(tmpContext, false);
            ILCount loopCount      = loopExpression.GetILCount(tmpContext, true);

            if (loopCount.stack > 0)
            {
                context.AddError(
                    new StructuralError(
                        StructuralError.ErrorType.CoreGeneration,
                        "Body of the while expression leaves values on stack. This must not happen",
                        Start,
                        End
                        )
                    );
                return;
            }

            if (context.HasErrors)
            {
                return;
            }

            using ITempLocalRef loopCounter = context.IL.TempLocal(typeof(int));
            LabelRef      whileStart  = context.IL.DefineLabel(conditionCount.opCodes + loopCount.opCodes < 110);
            LabelRef      whileEnd    = context.IL.DefineLabel(conditionCount.opCodes + loopCount.opCodes < 110);
            LabelRef      whileLoop   = context.IL.DefineLabel(conditionCount.opCodes + loopCount.opCodes < 100);
            IBlockContext loopContext = context.CreateLoopContext(whileStart, whileEnd);

            if (scopeVariables != null)
            {
                foreach (var(name, type) in scopeVariables)
                {
                    if (loopContext.FindVariable(name) != null)
                    {
                        loopContext.AddError(new StructuralError(
                                                 StructuralError.ErrorType.DuplicateVariableName,
                                                 $"Variable '{name}' already declared in this scope",
                                                 Start,
                                                 End
                                                 ));
                        return;
                    }

                    loopContext.DeclaredVariable(name, true, type.UnderlyingType(context.ModuleContext));
                }
            }

            loopContext.IL.Emit(whileStart.isShort ? OpCodes.Br_S : OpCodes.Br, whileStart);
            context.IL.MarkLabel(whileLoop);

            // 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);

            loopExpression.EmitCode(loopContext, true);
            loopContext.IL.MarkLabel(whileStart);
            condition.EmitCode(loopContext, false);

            loopContext.IL.Emit(whileLoop.isShort ? OpCodes.Brtrue_S : OpCodes.Brtrue, whileLoop);

            loopContext.IL.MarkLabel(whileEnd);
            if (!dropResult)
            {
                context.IL.Emit(OpCodes.Ldnull);
            }
        }
Esempio n. 23
0
        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();
            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, true);

            if (!context.HasErrors && thenCount.stack > 0)
            {
                context.AddError(
                    new StructuralError(
                        StructuralError.ErrorType.CoreGeneration,
                        "Then expression leaves values on stack. This must not happen",
                        Start,
                        End
                        )
                    );
                return;
            }

            condition.EmitCode(thenContext, false);

            if (context.HasErrors)
            {
                return;
            }

            TO2Type thenResultType = thenExpression.ResultType(thenContext);

            if (dropResult)
            {
                LabelRef skipThen = context.IL.DefineLabel(thenCount.opCodes < 124);

                thenContext.IL.Emit(skipThen.isShort ? OpCodes.Brfalse_S : OpCodes.Brfalse, skipThen);
                thenExpression.EmitCode(thenContext, true);
                thenContext.IL.MarkLabel(skipThen);
            }
            else
            {
                OptionType optionType    = new OptionType(thenResultType);
                Type       generatedType = optionType.GeneratedType(thenContext.ModuleContext);
                using ITempLocalRef tempResult = thenContext.IL.TempLocal(generatedType);
                LabelRef skipThen = thenContext.IL.DefineLabel(thenCount.opCodes < 114);

                thenContext.IL.Emit(skipThen.isShort ? OpCodes.Brfalse_S : OpCodes.Brfalse, skipThen);
                thenExpression.Prepare(thenContext);
                tempResult.EmitLoadPtr(context);
                thenContext.IL.Emit(OpCodes.Dup);
                thenContext.IL.Emit(OpCodes.Initobj, generatedType, 1, 0);
                thenContext.IL.Emit(OpCodes.Dup);
                thenContext.IL.Emit(OpCodes.Ldc_I4_1);
                thenContext.IL.Emit(OpCodes.Stfld, generatedType.GetField("defined"));
                thenExpression.EmitCode(thenContext, false);
                thenContext.IL.Emit(OpCodes.Stfld, generatedType.GetField("value"));
                LabelRef ifEnd = context.IL.DefineLabel(true);
                thenContext.IL.Emit(OpCodes.Br_S, ifEnd);

                thenContext.IL.MarkLabel(skipThen);

                tempResult.EmitLoadPtr(context);
                thenContext.IL.Emit(OpCodes.Initobj, generatedType, 1, 0);

                thenContext.IL.MarkLabel(ifEnd);

                tempResult.EmitLoad(thenContext);
            }
        }
Esempio n. 24
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);
                }
            }
        }
Esempio n. 25
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. 26
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. 27
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            TO2Type leftType  = left.ResultType(context);
            TO2Type rightType = right.ResultType(context);

            if (leftType != BuiltinType.Bool)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.IncompatibleTypes,
                                     "Expected boolean",
                                     left.Start,
                                     left.End
                                     ));
            }
            if (rightType != BuiltinType.Bool)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.IncompatibleTypes,
                                     "Expected boolean",
                                     right.Start,
                                     right.End
                                     ));
            }

            if (context.HasErrors)
            {
                return;
            }

            left.EmitCode(context, false);
            if (!dropResult)
            {
                context.IL.Emit(OpCodes.Dup);
            }

            ILCount  rightCount = right.GetILCount(context, dropResult);
            LabelRef skipRight  = context.IL.DefineLabel(rightCount.opCodes < 124);

            if (context.HasErrors)
            {
                return;
            }

            switch (op)
            {
            case Operator.BoolAnd:
                context.IL.Emit(skipRight.isShort ? OpCodes.Brfalse_S : OpCodes.Brfalse, skipRight);
                break;

            case Operator.BoolOr:
                context.IL.Emit(skipRight.isShort ? OpCodes.Brtrue_S : OpCodes.Brtrue, skipRight);
                break;

            default:
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.InvalidOperator,
                                     $"Invalid boolean operator {op}",
                                     Start,
                                     End
                                     ));
                return;
            }

            if (!dropResult)
            {
                context.IL.Emit(OpCodes.Pop);
            }

            right.EmitCode(context, dropResult);
            context.IL.MarkLabel(skipRight);
        }
Esempio n. 28
0
        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);
            }
        }
Esempio n. 29
0
        public override void EmitCode(IBlockContext context, bool dropResult)
        {
            if (dropResult)
            {
                return;
            }

            ArrayType arrayType = ResultType(context) as ArrayType;

            if (arrayType == null)
            {
                context.AddError(new StructuralError(
                                     StructuralError.ErrorType.InvalidType,
                                     "Unable to infer type of array. Please add some type hint",
                                     Start,
                                     End
                                     ));
                return;
            }

            RealizedType elementType = arrayType.ElementType.UnderlyingType(context.ModuleContext);

            context.IL.Emit(OpCodes.Ldc_I4, Elements.Count);
            context.IL.Emit(OpCodes.Newarr, elementType.GeneratedType(context.ModuleContext));

            foreach (var element in Elements)
            {
                TO2Type valueType = element.ResultType(context);
                if (!elementType.IsAssignableFrom(context.ModuleContext, valueType))
                {
                    context.AddError(new StructuralError(
                                         StructuralError.ErrorType.InvalidType,
                                         "Element {i} is of type {valueType}, expected {elementType}",
                                         element.Start,
                                         element.End
                                         ));
                }
            }

            if (context.HasErrors)
            {
                return;
            }

            for (var i = 0; i < Elements.Count; i++)
            {
                context.IL.Emit(OpCodes.Dup);
                context.IL.Emit(OpCodes.Ldc_I4, i);
                Elements[i].EmitCode(context, false);
                if (elementType == BuiltinType.Bool)
                {
                    context.IL.Emit(OpCodes.Stelem_I4);
                }
                else if (elementType == BuiltinType.Int)
                {
                    context.IL.Emit(OpCodes.Stelem_I8);
                }
                else if (elementType == BuiltinType.Float)
                {
                    context.IL.Emit(OpCodes.Stelem_R8);
                }
                else
                {
                    context.IL.Emit(OpCodes.Stelem, elementType.GeneratedType(context.ModuleContext));
                }
            }
        }