001    // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file
002    // for details. All rights reserved. Use of this source code is governed by a
003    // BSD-style license that can be found in the LICENSE file.
004    
005    package org.jetbrains.kotlin.js.backend.ast;
006    
007    import org.jetbrains.kotlin.js.common.Symbol;
008    import org.jetbrains.kotlin.js.util.AstUtil;
009    import com.intellij.util.SmartList;
010    import org.jetbrains.annotations.NotNull;
011    import org.jetbrains.annotations.Nullable;
012    
013    import java.util.List;
014    
015    public final class JsFunction extends JsLiteral implements HasName {
016        @NotNull
017        private JsBlock body;
018        private List<JsParameter> params;
019        @NotNull
020        private final JsFunctionScope scope;
021        private JsName name;
022    
023        public JsFunction(@NotNull JsScope parentScope, @NotNull String description) {
024            this(parentScope, description, null);
025        }
026    
027        public JsFunction(@NotNull JsScope parentScope, @NotNull JsBlock body, @NotNull String description) {
028            this(parentScope, description, null);
029            this.body = body;
030        }
031    
032        private JsFunction(@NotNull JsScope parentScope, @NotNull String description, @Nullable JsName name) {
033            this.name = name;
034            scope = new JsFunctionScope(parentScope, name == null ? description : name.getIdent());
035        }
036    
037        @NotNull
038        public JsBlock getBody() {
039            return body;
040        }
041    
042        @Override
043        public JsName getName() {
044            return name;
045        }
046    
047        @Override
048        public Symbol getSymbol() {
049            return name;
050        }
051    
052        @NotNull
053        public List<JsParameter> getParameters() {
054            if (params == null) {
055                params = new SmartList<JsParameter>();
056            }
057            return params;
058        }
059    
060        @NotNull
061        public JsFunctionScope getScope() {
062            return scope;
063        }
064    
065        public void setBody(@NotNull JsBlock body) {
066            this.body = body;
067        }
068    
069        @Override
070        public void setName(@Nullable JsName name) {
071            this.name = name;
072        }
073    
074        @Override
075        public void accept(JsVisitor v) {
076            v.visitFunction(this);
077        }
078    
079        @Override
080        public void acceptChildren(JsVisitor visitor) {
081            visitor.acceptWithInsertRemove(getParameters());
082            visitor.accept(body);
083        }
084    
085        @Override
086        public void traverse(JsVisitorWithContext v, JsContext ctx) {
087            if (v.visit(this, ctx)) {
088                v.acceptList(getParameters());
089                body = v.acceptStatement(body);
090            }
091            v.endVisit(this, ctx);
092        }
093    
094        @NotNull
095        @Override
096        public JsFunction deepCopy() {
097            JsFunction functionCopy = new JsFunction(scope.getParent(), scope.getDescription(), name);
098            functionCopy.getScope().copyOwnNames(scope);
099            functionCopy.setBody(body.deepCopy());
100            functionCopy.params = AstUtil.deepCopy(params);
101    
102            return functionCopy.withMetadataFrom(this);
103        }
104    }