// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.code.autocomplete.codegraph.py;
import static com.google.collide.codemirror2.TokenType.KEYWORD;
import static com.google.collide.codemirror2.TokenType.VARIABLE;
import static com.google.collide.codemirror2.TokenType.WHITESPACE;
import com.google.collide.client.code.autocomplete.codegraph.Position;
import com.google.collide.codemirror2.Token;
import com.google.collide.codemirror2.TokenType;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.shared.util.JsonCollections;
/**
* Python specific parsing task.
*
* <p>This class recognizes variables and function names in stream of tokens.
*
*/
@Deprecated
class PyParsingTask /*extends ParsingTask*/ {
/**
* Delimiter that starts new code block.
*/
private static final String LITERAL_COLON = ":";
/**
* Delimiter that starts parameters definition when encountered in
* function definition.
*/
private static final String LITERAL_LEFT_PARANTHESIS = "(";
/**
* Delimiter that can separate multiple variables in lvalue.
*/
private static final String LITERAL_COMMA = ",";
/**
* Assignment operator token.
*/
private static final String LITERAL_EQUALS = "=";
/**
* Runs one-line parsing iteration. During parsing it fills the result scope
* with identifiers.
*/
// @Override
protected void processLine(int lineNumber, JsonArray<Token> tokens) {
PyParseContext context = new PyParseContext();
// TODO: should either remove column information from system
// or add column information to tokens
int fakeTokenColumn = 0;
// Last token in always newline, see DocumentParserWorker.
final int l = tokens.size() - 1;
for (int i = 0; i < l; i++) {
Token token = tokens.get(i);
assert token != null;
// Ignore whitespaces
if (WHITESPACE == token.getType()) {
continue;
}
// Common precondition: context is not too short
if (context.predPred == null) {
context.push(token);
continue;
}
PyToken predPred = context.predPred;
PyToken pred = context.pred;
// In case we get ":" or "(" it may be a function definition
if (LITERAL_COLON.equals(token.getValue())
|| LITERAL_LEFT_PARANTHESIS.equals(token.getValue())) {
if ((KEYWORD == predPred.getType()) && "def".equals(predPred.getContent())) {
// getResultScope().addToken(lineNumber, fakeTokenColumn,
// new CodeToken(pred.getContent(), pred.getType(), true));
}
fakeTokenColumn++;
context.push(token);
continue;
}
// When we get ", id," construction,
// then do not reset accumulator (ids before first comma)
if (LITERAL_COMMA.equals(token.getValue())) {
if (LITERAL_COMMA.equals(predPred.getContent())) {
if (VARIABLE == pred.getType()) {
context.pushSavingAccumulator(token);
continue;
}
}
context.push(token);
continue;
}
// When we got "id =" then register all remembered ids as variables
if (LITERAL_EQUALS.equals(token.getValue())) {
if (VARIABLE == context.pred.getType()) {
context.accumulator.add(context.pred);
while (!context.accumulator.isEmpty()) {
PyToken nextVar = context.accumulator.pop();
// getResultScope().addToken(lineNumber, fakeTokenColumn,
// new CodeToken(nextVar.getContent(), nextVar.getType()));
fakeTokenColumn++;
}
}
context.push(token);
continue;
}
// When we get "id1, id2" construction
// then remember id1, because it is going to be pushed out of context.
if (VARIABLE == token.getType()) {
if (VARIABLE == context.predPred.getType()) {
if (LITERAL_COMMA.equals(context.pred.getContent())) {
context.pushAndAddToAccumulator(token);
continue;
}
}
context.push(token);
continue;
}
context.push(token);
}
context.push(tokens.get(l));
}
/**
* Context that holds a number of previous tokens.
*
* <p>Some tokens are saved to accumulator. Usually accumulator holds
* identifier-tokens within the same context.
*/
private class PyParseContext {
PyToken pred = null;
PyToken predPred = null;
final JsonArray<PyToken> accumulator = JsonCollections.createArray();
void push(Token token) {
accumulator.clear();
pushSavingAccumulator(token);
}
void pushAndAddToAccumulator(Token token) {
accumulator.add(predPred);
pushSavingAccumulator(token);
}
void pushSavingAccumulator(Token token) {
predPred = pred;
pred = new PyToken(token, 0, 0);
}
}
/**
* Immutable combination of token and position.
*
* <p>Dispatches common messages to token.
*/
private static class PyToken {
final Token token;
final Position position;
PyToken(Token token, int lineNumber, int column) {
this.token = token;
this.position = Position.from(lineNumber, column);
}
String getContent() {
return token.getValue();
}
public TokenType getType() {
return token.getType();
}
}
}