001    /*
002     * Copyright 2010-2012 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.js.compiler;
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 visitBlock(JsBlock x) {
046            printJsBlock(x, false, true);
047        }
048    
049        @Override
050        public void newLined() {
051            if (sourceMapBuilder != null) {
052                sourceMapBuilder.newLine();
053            }
054        }
055    
056        @Override
057        public void indentedAfterNewLine() {
058            if (pendingSources.isEmpty()) return;
059    
060            assert sourceMapBuilder != null;
061            for (Object source : pendingSources) {
062                sourceMapBuilder.processSourceInfo(source);
063            }
064            pendingSources.clear();
065        }
066    
067        @Override
068        public void accept(JsNode node) {
069            if (!(node instanceof JsNameRef) && !(node instanceof JsLiteral.JsThisRef)) {
070                mapSource(node);
071            }
072            super.accept(node);
073        }
074    
075        private void mapSource(JsNode node) {
076            if (sourceMapBuilder != null) {
077                Object sourceInfo = node.getSource();
078                if (sourceInfo != null) {
079                    if (p.isJustNewlined()) {
080                        pendingSources.add(sourceInfo);
081                    }
082                    else {
083                        sourceMapBuilder.processSourceInfo(sourceInfo);
084                    }
085                }
086            }
087        }
088    
089        @Override
090        protected void beforeNodePrinted(JsNode node) {
091            mapSource(node);
092        }
093    
094        @Override
095        public void visitProgram(JsProgram program) {
096            program.acceptChildren(this);
097            if (sourceMapBuilder != null) {
098                sourceMapBuilder.addLink();
099            }
100        }
101    }