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 com.google.dart.compiler.backend.js.ast;
006    
007    import com.google.dart.compiler.common.Symbol;
008    import com.google.dart.compiler.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        public void setName(@Nullable JsName name) {
070            this.name = name;
071        }
072    
073        @Override
074        public void accept(JsVisitor v) {
075            v.visitFunction(this);
076        }
077    
078        @Override
079        public void acceptChildren(JsVisitor visitor) {
080            visitor.acceptWithInsertRemove(getParameters());
081            visitor.accept(body);
082        }
083    
084        @Override
085        public void traverse(JsVisitorWithContext v, JsContext ctx) {
086            if (v.visit(this, ctx)) {
087                v.acceptList(getParameters());
088                body = v.accept(body);
089            }
090            v.endVisit(this, ctx);
091        }
092    
093        @NotNull
094        @Override
095        public JsFunction deepCopy() {
096            JsFunction functionCopy = new JsFunction(scope.getParent(), scope.getDescription(), name);
097            functionCopy.getScope().copyOwnNames(scope);
098            functionCopy.setBody(body.deepCopy());
099            functionCopy.params = AstUtil.deepCopy(params);
100    
101            return functionCopy.withMetadataFrom(this);
102        }
103    }