// 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 com.google.collide.client.code.autocomplete.CodeAnalyzer; import com.google.collide.codemirror2.Token; import com.google.collide.codemirror2.TokenType; import com.google.collide.json.shared.JsonArray; import com.google.collide.shared.TaggableLine; import javax.annotation.Nonnull; /** * Python specific code analyzer. * * <p>This class calculates scope for each line of code. */ public class PyIndexUpdater implements CodeAnalyzer { public static final String TAG_SCOPE = PyIndexUpdater.class.getName() + ".scope"; /** * Python keyword for function definition. */ private static final String LITERAL_DEF = "def"; /** * Python keyword for class definition. */ private static final String LITERAL_CLASS = "class"; @Override public void onBeforeParse() { } @Override public void onParseLine( TaggableLine previousLine, TaggableLine line, @Nonnull JsonArray<Token> tokens) { PyCodeScope prevScope = previousLine.getTag(TAG_SCOPE); PyCodeScope scope = prevScope; int indent = 0; int n = tokens.size(); int i = 0; if (n > 0) { Token token = tokens.get(i); if (TokenType.WHITESPACE == token.getType()) { i++; indent = token.getValue().length(); } if (n >= i + 3 && TokenType.KEYWORD == tokens.get(i).getType() && TokenType.WHITESPACE == tokens.get(i + 1).getType() && TokenType.VARIABLE == tokens.get(i + 2).getType()) { String keyword = tokens.get(i).getValue(); boolean isClass = LITERAL_CLASS.equals(keyword); boolean isDef = LITERAL_DEF.equals(keyword); if (isClass || isDef) { while (prevScope != null) { if (prevScope.getIndent() < indent) { break; } prevScope = prevScope.getParent(); } PyCodeScope.Type type = isDef ? PyCodeScope.Type.DEF : PyCodeScope.Type.CLASS; scope = new PyCodeScope(prevScope, tokens.get(i + 2).getValue(), indent, type); } } } line.putTag(TAG_SCOPE, scope); } @Override public void onAfterParse() { } @Override public void onLinesDeleted(JsonArray<TaggableLine> deletedLines) { } }