Пример #1
0
        public LambdaAction(ParseInfo parseInfo, Scope scope, DeltinScriptParser.LambdaContext context)
        {
            Scope lambdaScope = scope.Child();

            RecursiveCallHandler = new LambdaRecursionHandler(this);
            CallInfo             = new CallInfo(RecursiveCallHandler, parseInfo.Script);

            // Get the lambda parameters.
            Parameters   = new Var[context.define().Length];
            InvokedState = new SubLambdaInvoke[Parameters.Length];
            for (int i = 0; i < Parameters.Length; i++)
            {
                InvokedState[i] = new SubLambdaInvoke();
                // TODO: Make custom builder.
                Parameters[i] = new ParameterVariable(lambdaScope, new DefineContextHandler(parseInfo, context.define(i)), InvokedState[i]);
            }

            CodeType[] argumentTypes = Parameters.Select(arg => arg.CodeType).ToArray();

            // context.block() will not be null if the lambda is a block.
            // () => {}
            if (context.block() != null)
            {
                // Parse the block.
                Block = new BlockAction(parseInfo.SetCallInfo(CallInfo), lambdaScope, context.block());

                // Validate the block.
                BlockTreeScan validation = new BlockTreeScan(parseInfo, Block, "lambda", DocRange.GetRange(context.INS()));
                validation.ValidateReturns();

                if (validation.ReturnsValue)
                {
                    LambdaType    = new ValueBlockLambda(validation.ReturnType, argumentTypes);
                    MultiplePaths = validation.MultiplePaths;
                }
                else
                {
                    LambdaType = new BlockLambda(argumentTypes);
                }
            }
            // context.expr() will not be null if the lambda is an expression.
            // () => 2 * x
            else if (context.expr() != null)
            {
                // Get the lambda expression.
                Expression = parseInfo.SetCallInfo(CallInfo).GetExpression(lambdaScope, context.expr());
                LambdaType = new MacroLambda(Expression.Type(), argumentTypes);
            }

            // Add so the lambda can be recursive-checked.
            parseInfo.TranslateInfo.RecursionCheck(CallInfo);

            // Add hover info
            parseInfo.Script.AddHover(DocRange.GetRange(context.INS()), new MarkupBuilder().StartCodeLine().Add(LambdaType.GetName()).EndCodeLine().ToString());
        }
Пример #2
0
        public LambdaAction(ParseInfo parseInfo, Scope scope, LambdaExpression context)
        {
            _context     = context;
            _lambdaScope = scope.Child();
            _parseInfo   = parseInfo;
            _contextualParameterTypesKnown = _parseInfo.ExpectingLambda != null && _parseInfo.ExpectingLambda.Type.ParameterTypesKnown;
            RecursiveCallHandler           = new LambdaRecursionHandler(this);
            CallInfo = new CallInfo(RecursiveCallHandler, parseInfo.Script);
            This     = scope.GetThis();

            _isExplicit = context.Parameters.Any(p => p.Type != null);
            var parameterState = context.Parameters.Count == 0 || _isExplicit ? ParameterState.CountAndTypesKnown : ParameterState.CountKnown;

            // Get the lambda parameters.
            Parameters     = new Var[context.Parameters.Count];
            InvokedState   = new SubLambdaInvoke[Parameters.Length];
            _argumentTypes = new CodeType[Parameters.Length];

            for (int i = 0; i < Parameters.Length; i++)
            {
                if (_isExplicit && context.Parameters[i].Type == null)
                {
                    parseInfo.Script.Diagnostics.Error("Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit", context.Parameters[i].Range);
                }

                InvokedState[i]   = new SubLambdaInvoke();
                Parameters[i]     = new LambdaVariable(i, _parseInfo.ExpectingLambda?.Type, _lambdaScope, new LambdaContextHandler(parseInfo, context.Parameters[i]), InvokedState[i]);
                _argumentTypes[i] = Parameters[i].CodeType;
            }

            new CheckLambdaContext(
                parseInfo,
                this,
                "Cannot determine lambda in the current context",
                context.Range,
                parameterState
                ).Check();

            // Add hover info
            // parseInfo.Script.AddHover(context.Arrow.Range, new MarkupBuilder().StartCodeLine().Add(LambdaType.GetName()).EndCodeLine().ToString());
        }
        public void GetLambdaContent(PortableLambdaType expectingType)
        {
            _resolved = true;

            // Get the lambda parameters.
            Parameters     = new Var[_context.Parameters.Count];
            InvokedState   = new SubLambdaInvoke[Parameters.Length];
            _argumentTypes = new CodeType[Parameters.Length];

            for (int i = 0; i < Parameters.Length; i++)
            {
                if (_isExplicit && _context.Parameters[i].Type == null)
                {
                    _parseInfo.Script.Diagnostics.Error("Inconsistent lambda parameter usage; parameter types must be all explicit or all implicit", _context.Parameters[i].Range);
                }

                InvokedState[i]   = new SubLambdaInvoke();
                Parameters[i]     = (Var) new LambdaVariable(i, expectingType, _lambdaScope, new LambdaContextHandler(_parseInfo, _context.Parameters[i]), InvokedState[i]).GetVar();
                _argumentTypes[i] = Parameters[i].GetDefaultInstance(null).CodeType.GetCodeType(_parseInfo.TranslateInfo);
            }

            ParseInfo parser = _parseInfo.SetCallInfo(CallInfo).AddVariableTracker(this).SetExpectType(expectingType?.ReturnType).SetReturnType(expectingType?.ReturnType);

            bool returnsValue = false;

            // Get the statements.
            if (_context.Statement is Block block)
            {
                var returnTracker = new ReturnTracker();

                // Parse the block.
                Statement = new BlockAction(parser.SetReturnTracker(returnTracker), _lambdaScope, block);

                if (returnTracker.ReturnsValue)
                {
                    ReturnType    = returnTracker.InferredType;
                    MultiplePaths = returnTracker.IsMultiplePaths;
                    returnsValue  = true;
                }
            }
            else if (_context.Statement is ExpressionStatement exprStatement)
            {
                // Get the lambda expression.
                Expression   = parser.GetExpression(_lambdaScope, exprStatement.Expression);
                ReturnType   = Expression.Type();
                returnsValue = true;
            }
            else
            {
                // Statement
                Statement = parser.GetStatement(_lambdaScope, _context.Statement);
                if (Statement is IExpression expr)
                {
                    Expression = expr;
                    ReturnType = expr.Type();
                    if (ReturnType != null)
                    {
                        returnsValue = true;
                    }
                }
            }

            LambdaType = new PortableLambdaType(new PortableLambdaTypeBuilder(
                                                    kind: expectingType?.LambdaKind ?? LambdaKind.Anonymous,
                                                    parameters: _argumentTypes,
                                                    returnType: ReturnType,
                                                    returnsValue: returnsValue,
                                                    parameterTypesKnown: _isExplicit));

            // Add so the lambda can be recursive-checked.
            _parseInfo.TranslateInfo.GetComponent <RecursionCheckComponent>().AddCheck(CallInfo);
        }