blob: f26e631616db68d239104bdfdcdd402dbf9794cd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 Xored Software Inc and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* Xored Software Inc - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.rcptt.core.ecl.parser.model;
import static org.eclipse.rcptt.core.ecl.parser.model.ScriptContainer.globalVars;
import static org.eclipse.rcptt.core.ecl.parser.model.ScriptContainer.procFromPipeline;
import static org.eclipse.rcptt.core.ecl.parser.model.ScriptContainer.varFromArg;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.rcptt.core.ecl.model.BaseContainer;
import org.eclipse.rcptt.core.ecl.model.ProcDecl;
import org.eclipse.rcptt.core.ecl.model.VarDecl;
import org.eclipse.rcptt.core.ecl.parser.ast.Arg;
import org.eclipse.rcptt.core.ecl.parser.ast.Command;
import org.eclipse.rcptt.core.ecl.parser.ast.Pipeline;
import org.eclipse.rcptt.core.ecl.parser.ast.Script;
import org.eclipse.rcptt.core.ecl.parser.ast.ScriptArg;
/**
* All variables and procs from current script visible from given offset
*/
public class LocalContainer extends BaseContainer {
public static LocalContainer fromScript(Script script, int offset, String resource) {
LocalContainer result = new LocalContainer();
result.setResource(resource);
NodePath path = PathBuilder.path(script, offset);
result.addAllVars(findLocalVars(path, offset));
boolean isInProc = isInProc(path);
Pipeline firstInPath = path.firstOf(Pipeline.class);
for (int i = 0; i < script.pipelines.size(); i++) {
Pipeline pipeline = script.pipelines.get(i);
if (pipeline == firstInPath && !isInProc) {
break;
}
ProcDecl proc = procFromPipeline(pipeline);
if (proc != null) {
result.addProc(proc);
proc.setDescription(script.findProcDescription(pipeline.begin));
}
if (pipeline == firstInPath) {
// this is enclosing proc
result.addAllVars(Arrays.<VarDecl> asList(proc.getArgs()));
}
result.addAllVars(globalVars(pipeline));
}
return result;
}
private static List<VarDecl> findLocalVars(NodePath path, int offset) {
List<VarDecl> result = new ArrayList<VarDecl>();
List<Command> commands = path.findCommands("let", "foreach", "each", "repeat", "loop");
// for each 'let' command, we need to make sure that found
// path is inside
// the last arg
List<Command> visibleCommands = new ArrayList<Command>();
for (Command command : commands) {
Arg last = command.lastArg();
if (last == null) {
continue;
}
if (last instanceof ScriptArg && last.contains(offset)) {
visibleCommands.add(command);
}
}
// Reversing so that inner variables with the same name 'override'
// outer variables
Collections.reverse(visibleCommands);
Set<String> names = new HashSet<String>();
for (Command command : visibleCommands) {
for (Arg arg : command.args) {
VarDecl var = varFromArg(arg);
if (var == null) {
continue;
}
if (names.contains(var.name)) {
continue;
}
names.add(var.name);
result.add(var);
}
}
return result;
}
private static boolean isInProc(NodePath path) {
Command procCmd = path.lastCommand("proc");
if (procCmd == null) {
return false;
}
Arg last = procCmd.lastArg();
if (last == null) {
return false;
}
if (!(last instanceof ScriptArg) || !last.contains(path.offset)) {
return false;
}
return true;
}
}