/* * Copyright 2010 Jon S Akhtar (Sylvanaar) * * 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.sylvanaar.idea.Lua.lang.psi.impl; import com.intellij.openapi.fileTypes.FileType; import com.intellij.psi.FileViewProvider; import com.intellij.psi.PsiElement; import com.intellij.psi.ResolveState; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.impl.source.PsiFileWithStubSupport; import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.ProjectAndLibrariesScope; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.util.IncorrectOperationException; import com.sylvanaar.idea.Lua.LuaFileType; import com.sylvanaar.idea.Lua.lang.psi.*; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.Instruction; import com.sylvanaar.idea.Lua.lang.psi.controlFlow.impl.ControlFlowBuilder; import com.sylvanaar.idea.Lua.lang.psi.expressions.LuaAnonymousFunctionExpression; import com.sylvanaar.idea.Lua.lang.psi.expressions.LuaDeclarationExpression; import com.sylvanaar.idea.Lua.lang.psi.expressions.LuaExpression; import com.sylvanaar.idea.Lua.lang.psi.statements.*; import com.sylvanaar.idea.Lua.lang.psi.symbols.LuaCompoundIdentifier; import com.sylvanaar.idea.Lua.lang.psi.symbols.LuaIdentifier; import com.sylvanaar.idea.Lua.lang.psi.symbols.LuaLocalIdentifier; import com.sylvanaar.idea.Lua.lang.psi.visitor.LuaElementVisitor; import com.sylvanaar.idea.Lua.lang.psi.visitor.LuaRecursiveElementVisitor; import com.sylvanaar.idea.Lua.util.LuaModuleUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * Created by IntelliJ IDEA. * User: Jon S Akhtar * Date: Apr 10, 2010 * Time: 12:19:03 PM */ public class LuaPsiFileImpl extends LuaPsiFileBaseImpl implements LuaPsiFile, PsiFileWithStubSupport, PsiFileEx, LuaPsiFileBase, LuaExpressionCodeFragment { private boolean sdkFile; public LuaPsiFileImpl(FileViewProvider viewProvider) { super(viewProvider, LuaFileType.LUA_LANGUAGE); } @NotNull @Override public FileType getFileType() { return LuaFileType.LUA_FILE_TYPE; } @Override public String toString() { return "Lua script: " + getName(); } @Override public GlobalSearchScope getFileResolveScope() { return new ProjectAndLibrariesScope(getProject()); } @Override public LuaStatementElement addStatementBefore(@NotNull LuaStatementElement statement, LuaStatementElement anchor) throws IncorrectOperationException { return (LuaStatementElement) addBefore(statement, anchor); } LuaModuleStatement[] moduleStatements; @Override @Nullable public String getModuleNameAtOffset(final int offset) { if (moduleStatements == null) { moduleStatements = findChildrenByClass(LuaModuleStatement.class); } if (moduleStatements.length == 0) return null; for (LuaModuleStatement m : moduleStatements) { if (m.getIncludedTextRange().contains(offset)) return m.getName(); } return null; } @Override public void clearCaches() { super.clearCaches(); moduleStatements = null; } @Override public LuaExpression getReturnedValue() { // This only works for the last statement in the file LuaStatementElement[] stmts = getStatements(); if (stmts.length==0) return null; LuaStatementElement s = stmts[stmts.length-1]; if (! (s instanceof LuaReturnStatement)) return null; return ((LuaReturnStatement) s).getReturnValue(); } @Override public boolean isSdkFile() { LuaModuleUtil.checkForSdkFile(this, getProject()); return sdkFile; } @Override public void setSdkFile(boolean b) { sdkFile = b; } @Override public void removeVariable(LuaIdentifier variable) { } @Override public LuaDeclarationStatement addVariableDeclarationBefore(LuaDeclarationStatement declaration, LuaStatementElement anchor) throws IncorrectOperationException { return null; } @Override public boolean processDeclarations(@NotNull PsiScopeProcessor processor, @NotNull ResolveState resolveState, PsiElement lastParent, @NotNull PsiElement place) { final PsiElement[] children = getChildren(); for (PsiElement child : children) { if (child == lastParent) break; if (!child.processDeclarations(processor, resolveState, lastParent, place)) return false; } return true; } public void accept(LuaElementVisitor visitor) { visitor.visitFile(this); } public void acceptChildren(LuaElementVisitor visitor) { PsiElement child = getFirstChild(); while (child != null) { if (child instanceof LuaPsiElement) { ((LuaPsiElement) child).accept(visitor); } child = child.getNextSibling(); } } @Override public LuaDeclarationExpression[] getSymbolDefs() { final Set<LuaDeclarationExpression> decls = new HashSet<LuaDeclarationExpression>(); LuaElementVisitor v = new LuaRecursiveElementVisitor() { public void visitDeclarationExpression(LuaDeclarationExpression e) { super.visitDeclarationExpression(e); if (!(e instanceof LuaLocalIdentifier)) decls.add(e); } @Override public void visitCompoundIdentifier(LuaCompoundIdentifier e) { super.visitCompoundIdentifier(e); if (e.isAssignedTo()) decls.add(e); } }; v.visitElement(this); return decls.toArray(new LuaDeclarationExpression[decls.size()]); } @Override public LuaStatementElement[] getAllStatements() { final List<LuaStatementElement> stats = new ArrayList<LuaStatementElement>(); LuaElementVisitor v = new LuaRecursiveElementVisitor() { public void visitElement(LuaPsiElement e) { super.visitElement(e); if (e instanceof LuaStatementElement) stats.add((LuaStatementElement) e); } }; v.visitElement(this); return stats.toArray(new LuaStatementElement[stats.size()]); } @Override public LuaStatementElement[] getStatements() { return findChildrenByClass(LuaStatementElement.class); } @Override public LuaFunctionDefinition[] getFunctionDefs() { final List<LuaFunctionDefinition> funcs = new ArrayList<LuaFunctionDefinition>(); LuaElementVisitor v = new LuaRecursiveElementVisitor() { public void visitFunctionDef(LuaFunctionDefinitionStatement e) { super.visitFunctionDef(e); funcs.add(e); } @Override public void visitAnonymousFunction(LuaAnonymousFunctionExpression e) { super.visitAnonymousFunction(e); if (e.getName() != null) funcs.add(e); } }; v.visitElement(this); return funcs.toArray(new LuaFunctionDefinition[funcs.size()]); } @Override public Instruction[] getControlFlow() { assert isValid(); CachedValue<Instruction[]> controlFlow = getUserData(CONTROL_FLOW); if (controlFlow == null) { controlFlow = CachedValuesManager.getManager(getProject()).createCachedValue( new CachedValueProvider<Instruction[]>() { @Override public Result<Instruction[]> compute() { return Result .create(new ControlFlowBuilder(getProject()).buildControlFlow(LuaPsiFileImpl.this), getContainingFile()); } }, false); putUserData(CONTROL_FLOW, controlFlow); } return controlFlow.getValue(); } // Only looks at the current block private class LuaModuleVisitor extends LuaElementVisitor { private final int offset; private String moduleName = null; public LuaModuleVisitor(int offset) {this.offset = offset;} public void visitModuleStatement(LuaModuleStatement e) { super.visitModuleStatement(e); if (e.getIncludedTextRange().contains(offset)) moduleName = e.getName(); } @Nullable public String getModuleName() { return moduleName; } } }