Beispiel #1
0
        public static BoundProgram Perform(BoundProgram program, IList<BoundExpression> resultExpressions)
        {
            // If the last statement of the program is a return, we don't
            // have to rewrite the program.

            var body = program.Body;
            if (
                body.Body.Nodes.Count > 0 &&
                body.Body.Nodes[body.Body.Nodes.Count - 1] is BoundReturn
            )
                return program;

            // If we don't have any result expressions, we only have to
            // insert a return statement.

            if (resultExpressions == null || resultExpressions.Count == 0)
            {
                // Create a new nodes list with the added return statement.

                var nodes = new ReadOnlyArray<BoundStatement>.Builder();

                nodes.AddRange(body.Body.Nodes);
                nodes.Add(new BoundReturn(
                    null,
                    SourceLocation.Missing
                ));

                // Return the updated program.

                return program.Update(
                    body.Update(
                        body.Body.Update(
                            body.Body.Temporaries,
                            nodes.ToReadOnly(),
                            body.Body.Location
                            ),
                        body.Closure,
                        body.ScopedClosure,
                        body.Arguments,
                        body.Locals,
                        body.MappedArguments,
                        body.Flags,
                        body.TypeManager
                    )
                );
            }

            // Otherwise, we need to do a full rewrite.

            return program.Update(
                (BoundBody)new Rewriter(resultExpressions, body.TypeManager).Visit(program.Body)
            );
        }
Beispiel #2
0
            private ReadOnlyArray<SyntaxNode> GetStatements()
            {
                var builder = new ReadOnlyArray<SyntaxNode>.Builder();

                if (_declaredFunctions != null)
                    builder.AddRange(_declaredFunctions);
                if (_statements != null)
                    builder.AddRange(_statements);

                return builder.ToReadOnly();
            }
Beispiel #3
0
            private ReadOnlyArray<IIdentifier> CommitIdentifiers()
            {
                var identifiers = new Dictionary<string, ResolvedIdentifier>();

                // Create the parameters.

                if (_parameters != null)
                {
                    for (int i = _parameters.Count - 1; i >= 0; i--)
                    {
                        if (!identifiers.ContainsKey(_parameters[i]))
                        {
                            identifiers.Add(
                                _parameters[i],
                                new ResolvedIdentifier(
                                    _parameters[i],
                                    i,
                                    IdentifierType.Parameter,
                                    true
                                )
                            );
                        }
                    }
                }

                // Add the declared identifiers.

                foreach (string identifier in _declaredIdentifiers)
                {
                    if (!identifiers.ContainsKey(identifier))
                    {
                        identifiers.Add(
                            identifier,
                            new ResolvedIdentifier(
                                identifier,
                                null,
                                _bodyType == BodyType.Program ? IdentifierType.Global : IdentifierType.Local,
                                true
                            )
                        );
                    }
                }

                // Resolve all identifiers.

                foreach (var identifier in _identifiers)
                {
                    ResolvedIdentifier resolved = null;

                    // First check whether we have a catch variable in scope.

                    if (identifier.CatchScope != null && identifier.CatchScope.Scope == this)
                    {
                        var catchScope = identifier.CatchScope;

                        while (catchScope != null && catchScope.Scope == this)
                        {
                            if (catchScope.Identifier.Name == identifier.Name)
                            {
                                resolved = catchScope.Identifier;
                                break;
                            }

                            catchScope = catchScope.Parent;
                        }

                        if (resolved != null)
                        {
                            identifier.Identifier.ResolvedIdentifier = resolved;

                            if (identifier.Scope != this)
                                _closedOverIdentifiers.Add(resolved);

                            continue;
                        }

                        // We need to change the catch scope of the unresolved
                        // identifier to strip the catch scopes that belong to
                        // us. This way resolving in the parent scope resolves
                        // to a declared variable or to the catch variable of
                        // that scope.

                        identifier.CatchScope = catchScope;
                    }

                    if (identifiers.TryGetValue(identifier.Name, out resolved))
                    {
                        // We have this identifier.

                        identifier.Identifier.ResolvedIdentifier = resolved;

                        // If the identifier does not belong to this scope,
                        // it's being closed over.

                        if (identifier.Scope != this && resolved.Type != IdentifierType.Global)
                            _closedOverIdentifiers.Add(resolved);
                    }
                    else if (Parent == null)
                    {
                        // It's an undeclared global identifier.

                        resolved = new ResolvedIdentifier(
                            identifier.Name,
                            null,
                            IdentifierType.Global,
                            false
                        );

                        identifiers.Add(identifier.Name, resolved);
                        identifier.Identifier.ResolvedIdentifier = resolved;
                    }
                    else
                    {
                        // Else, push it to the parent and let that figure it out.

                        Parent._identifiers.Add(identifier);
                    }
                }

                var builder = new ReadOnlyArray<IIdentifier>.Builder();

                builder.AddRange(identifiers.Select(p => p.Value));
                builder.AddRange(_resolvedIdentifiers);

                return builder.ToReadOnly();
            }
Beispiel #4
0
            public override BoundNode VisitBody(BoundBody node)
            {
                node = (BoundBody)base.VisitBody(node);

                // Add the initialization of the result temporary and the
                // return statement.

                var nodes = new ReadOnlyArray<BoundStatement>.Builder(node.Body.Nodes.Count + 2);

                // We always add the default value. The reason for this is that
                // we're already passed the definite assignment phase, so it won't
                // be inserted for us automatically.

                nodes.Add(new BoundSetVariable(
                    _resultTemporary,
                    new BoundGetVariable(BoundMagicVariable.Undefined),
                    SourceLocation.Missing
                ));

                nodes.AddRange(node.Body.Nodes);

                nodes.Add(new BoundReturn(
                    new BoundGetVariable(_resultTemporary),
                    SourceLocation.Missing
                ));

                return node.Update(
                    node.Body.Update(
                        node.Body.Temporaries,
                        nodes.ToReadOnly(),
                        node.Body.Location
                    ),
                    node.Closure,
                    node.ScopedClosure,
                    node.Arguments,
                    node.Locals,
                    node.MappedArguments,
                    node.Flags,
                    node.TypeManager
                );
            }
            public BoundBlock BuildBlock(SourceLocation location)
            {
                if (_nodes == null)
                {
                    Debug.Assert(_temporaries == null);

                    return new BoundBlock(
                        ReadOnlyArray<BoundTemporary>.Empty,
                        ReadOnlyArray<BoundStatement>.Empty,
                        location
                    );
                }

                var nodes = new ReadOnlyArray<BoundStatement>.Builder();

                foreach (var node in _nodes.ToReadOnly())
                {
                    // Flatten blocks. Nested blocks have no use, so we flatten
                    // them into this block. First we try to see whether the node
                    // is a block. If not, we try to see whether the node is an
                    // expression statement that has an expression block
                    // as its expression. In that case, we're taking the value of
                    // an expression block without doing anything with it.

                    var block = node as BoundBlock;
                    if (block != null)
                    {
                        if (_temporaries == null)
                            _temporaries = new ReadOnlyArray<BoundTemporary>.Builder();

                        _temporaries.AddRange(block.Temporaries);
                        if (block.Location != SourceLocation.Missing)
                            nodes.Add(new BoundEmpty(block.Location));
                        nodes.AddRange(block.Nodes);
                        continue;
                    }

                    // Otherwise, we keep the node unchanged.
                    nodes.Add(node);
                }

                return new BoundBlock(
                    _temporaries == null ? ReadOnlyArray<BoundTemporary>.Empty : _temporaries.ToReadOnly(),
                    nodes.ToReadOnly(),
                    location
                );
            }