blob: e40bb4c2d089bca7315e12f5195be2b6548c87dc [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.compiler.parser;
import com.google.dart.compiler.DartCompilationError;
import com.google.dart.compiler.DartCompilerListener;
import com.google.dart.compiler.DartSource;
import com.google.dart.compiler.Source;
import com.google.dart.compiler.ast.DartUnit;
import com.google.dart.compiler.common.HasSourceInfo;
import com.google.dart.compiler.common.HasSourceInfoSetter;
import com.google.dart.compiler.common.SourceInfo;
import com.google.dart.compiler.metrics.CompilerMetrics;
import com.google.dart.compiler.parser.DartScanner.Location;
import com.google.dart.compiler.parser.DartScanner.State;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Stack;
/**
* A ParserContext backed by a DartScanner.
*/
class DartScannerParserContext implements ParserContext {
private DartScanner scanner;
private Deque<DartScanner.State> stateStack = new ArrayDeque<DartScanner.State>();
private Deque<Integer> positionStack = new ArrayDeque<Integer>();
private Source source;
private DartCompilerListener listener;
private final CompilerMetrics compilerMetrics;
public DartScannerParserContext(Source source, String sourceCode,
DartCompilerListener listener) {
this(source, sourceCode, listener, null);
}
public DartScannerParserContext(Source source, String sourceCode,
DartCompilerListener listener, CompilerMetrics compilerMetrics) {
this.source = source;
this.scanner = createScanner(sourceCode, source, listener);
this.listener = listener;
this.compilerMetrics = compilerMetrics;
}
@Override
public void begin() {
stateStack.push(scanner.getState());
positionStack.push(getBeginLocation(0));
}
private int getBeginLocation(int n) {
DartScanner.Location tokenLocation = scanner.peekTokenLocation(n);
return tokenLocation != null ? tokenLocation.getBegin() : 0;
}
private int getEndLocation() {
DartScanner.Location tokenLocation = scanner.getTokenLocation();
return tokenLocation != null ? tokenLocation.getEnd() : 0;
}
@Override
public <T> T done(T result) {
DartScanner.State oldState = stateStack.pop();
DartScanner.State newState = stateStack.peek();
// If there is more state left, push the newer token changes to them.
if (newState != null) {
if (oldState.rollbackTokens != null) {
if (newState.rollbackTokens != null) {
oldState.rollbackTokens.addAll(newState.rollbackTokens);
}
newState.rollbackTokens = oldState.rollbackTokens;
}
}
setSourcePosition(result, positionStack.pop());
if (result instanceof DartUnit) {
if (compilerMetrics != null) {
compilerMetrics.unitParsed(scanner.getCharCount(), scanner.getNonCommentCharCount(),
0, 0);
}
}
// want next begin() call to seek to the next token and skip whitespace after previous done()
return result;
}
/**
* Set the source position on a result, if it is a {@link HasSourceInfo}.
*
* @param <T> result type
* @param result
* @param startPos
*/
private <T> void setSourcePosition(T result, int startPos) {
if (result instanceof HasSourceInfoSetter) {
HasSourceInfoSetter hasSourceInfoSetter = (HasSourceInfoSetter) result;
int start = startPos;
int end = getEndLocation();
if (start != -1 && end < start) {
// handle 0-length tokens, including where there is trailing whitespace
end = start;
}
hasSourceInfoSetter.setSourceInfo(new SourceInfo(source, start, end - start));
}
}
@Override
public <T> T doneWithoutConsuming(T result) {
// do not throw away state
setSourcePosition(result, positionStack.peek());
// want next begin() call to seek to the next token and skip whitespace after previous done()
return result;
}
@Override
public void error(DartCompilationError dartError) {
listener.onError(dartError);
}
@Override
public void unitAboutToCompile(DartSource source, boolean diet) {
listener.unitAboutToCompile(source, diet);
}
@Override
public void advance() {
scanner.next();
}
@Override
public Token getCurrentToken() {
return scanner.getToken();
}
@Override
public Token peek(int steps) {
return scanner.peek(steps);
}
@Override
public void rollback() {
// undo changes made to scanner tokens
DartScanner.State oldState = stateStack.pop();
scanner.restoreState(oldState);
// Restore the replaced tokens to their state.
if (oldState.rollbackTokens != null) {
while (!oldState.rollbackTokens.isEmpty()) {
State.RollbackToken token = oldState.rollbackTokens.pop();
scanner.setAbsolutePeek(token.absoluteOffset, token.replacedToken);
}
}
positionStack.pop();
}
@Override
public String getTokenString() {
return scanner.getTokenValue();
}
@Override
public Location peekTokenLocation(int n) {
return scanner.peekTokenLocation(n);
}
@Override
public String peekTokenString(int steps) {
return scanner.peekTokenValue(steps);
}
@Override
public void replaceNextToken(Token token) {
DartScanner.State state = stateStack.peek();
DartScanner.State.RollbackToken oldToken
= new DartScanner.State.RollbackToken(scanner.getOffset() + 1, scanner.peek(0));
if (state.rollbackTokens == null) {
state.rollbackTokens = new Stack<State.RollbackToken>();
}
state.rollbackTokens.push(oldToken);
scanner.setPeek(0, token);
}
@Override
public DartScanner.Location getTokenLocation() {
return scanner.getTokenLocation();
}
protected DartScanner createScanner(String sourceCode, Source source, DartCompilerListener listener) {
return new DartScanner(sourceCode, 0, source, listener);
}
@Override
public Source getSource() {
return source;
}
}