001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.js.sourceMap;
018    
019    import com.google.dart.compiler.backend.js.JsToStringGenerationVisitor;
020    import com.google.dart.compiler.backend.js.ast.*;
021    import com.google.dart.compiler.util.TextOutput;
022    import com.intellij.util.SmartList;
023    import org.jetbrains.annotations.Nullable;
024    
025    import java.util.List;
026    
027    public class JsSourceGenerationVisitor extends JsToStringGenerationVisitor implements TextOutput.OutListener {
028        @Nullable
029        private final SourceMapBuilder sourceMapBuilder;
030    
031        private final List<Object> pendingSources = new SmartList<Object>();
032    
033        public JsSourceGenerationVisitor(TextOutput out, @Nullable SourceMapBuilder sourceMapBuilder) {
034            super(out);
035            this.sourceMapBuilder = sourceMapBuilder;
036            out.setOutListener(this);
037        }
038    
039        @Override
040        public void visitProgramFragment(JsProgramFragment x) {
041            x.acceptChildren(this);
042        }
043    
044        @Override
045        public void newLined() {
046            if (sourceMapBuilder != null) {
047                sourceMapBuilder.newLine();
048            }
049        }
050    
051        @Override
052        public void indentedAfterNewLine() {
053            if (pendingSources.isEmpty()) return;
054    
055            assert sourceMapBuilder != null;
056            for (Object source : pendingSources) {
057                sourceMapBuilder.processSourceInfo(source);
058            }
059            pendingSources.clear();
060        }
061    
062        @Override
063        public void accept(JsNode node) {
064            if (!(node instanceof JsNameRef) && !(node instanceof JsLiteral.JsThisRef)) {
065                mapSource(node);
066            }
067            super.accept(node);
068        }
069    
070        private void mapSource(JsNode node) {
071            if (sourceMapBuilder != null) {
072                Object sourceInfo = node.getSource();
073                if (sourceInfo != null) {
074                    if (p.isJustNewlined()) {
075                        pendingSources.add(sourceInfo);
076                    }
077                    else {
078                        sourceMapBuilder.processSourceInfo(sourceInfo);
079                    }
080                }
081            }
082        }
083    
084        @Override
085        protected void beforeNodePrinted(JsNode node) {
086            mapSource(node);
087        }
088    
089        @Override
090        public void visitProgram(JsProgram program) {
091            program.acceptChildren(this);
092            if (sourceMapBuilder != null) {
093                sourceMapBuilder.addLink();
094            }
095        }
096    }