com.eprosima.idl.context.Context Maven / Gradle / Ivy
The newest version!
// Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// 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.eprosima.idl.context;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Stack;
import java.util.Scanner;
import java.util.NoSuchElementException;
import java.util.Collection;
import com.eprosima.idl.parser.grammar.IDLLexer;
import com.eprosima.idl.util.Pair;
import com.eprosima.idl.parser.tree.Definition;
import com.eprosima.idl.parser.tree.Module;
import com.eprosima.idl.parser.tree.Interface;
import com.eprosima.idl.parser.tree.Operation;
import com.eprosima.idl.parser.tree.Param;
import com.eprosima.idl.parser.tree.AnnotationDeclaration;
import com.eprosima.idl.parser.tree.TypeDeclaration;
import com.eprosima.idl.parser.typecode.TypeCode;
import com.eprosima.idl.parser.typecode.StructTypeCode;
import com.eprosima.idl.util.Util;
import com.eprosima.idl.parser.exception.ParseException;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
public class Context
{
public Context(String filename, String file, ArrayList includePaths)
{
// Detect OS
m_os = System.getProperty("os.name");
m_userdir = System.getProperty("user.dir");
m_filename = filename;
m_directoryFile = Util.getIDLFileDirectoryOnly(file);
m_file = file;
// Remove absolute directory where the application was executed
if(startsWith(m_file, m_userdir))
{
m_file = m_file.substring(m_userdir.length());
// Remove possible separator
if(startsWith(m_file, java.io.File.separator))
m_file = m_file.substring(1);
}
/*
// Remove relative directory if is equal that where the processed IDL is.
if(m_directoryFile != null && startsWith(m_file, m_directoryFile))
m_file = m_file.substring(m_directoryFile.length());
*/
m_definitions = new ArrayList();
m_modules = new HashMap();
m_interfaces = new HashMap();
m_exceptions = new HashMap();
m_types = new HashMap();
m_annotations = new HashMap();
// TODO Quitar porque solo es para tipos RTI (usado para las excepciones). Mirar alternativa.
m_includedependency = new HashSet();
// The scope file has to be initialized because could occur the preprocessor
// is not called (using -ppDisable).
m_scopeFile = m_file;
m_includePaths = new ArrayList();
m_dependencies = new LinkedHashSet();
m_directIncludeDependencies = new HashSet();
m_scopeFilesStack = new Stack>();
for(int i = 0; i < includePaths.size(); ++i)
{
String include = (String)includePaths.get(i);
if(startsWith(include, includeFlag))
include = include.substring(includeFlag.length());
if(startsWith(include, m_userdir))
{
include = include.substring(m_userdir.length());
// Remove possible separator
if(startsWith(include, java.io.File.separator))
include = include.substring(1);
}
if(m_directoryFile != null && startsWith(include, m_directoryFile))
include = include.substring(m_directoryFile.length());
// Add last separator.
if(include.charAt(include.length() - 1) != java.io.File.separatorChar)
include += java.io.File.separator;
m_includePaths.add(include);
}
// Reorder include paths;
int pointer = 0;
while(pointer < m_includePaths.size())
{
int count = pointer + 1;
while(count < m_includePaths.size())
{
if(startsWith(m_includePaths.get(count), m_includePaths.get(pointer)))
{
String first = m_includePaths.get(pointer);
String second = m_includePaths.get(count);
m_includePaths.set(pointer, second);
m_includePaths.set(count, first);
break;
}
++count;
}
if(count == m_includePaths.size())
++pointer;
}
}
public String getFilename()
{
return m_filename;
}
public void setFilename(String filename)
{
m_filename = filename;
}
public String getTrimfilename()
{
return Util.stringTrimAll(m_filename);
}
public String getScope()
{
return m_scope;
}
public void setScope(String scope)
{
m_scope = scope;
}
/*!
* @return True if current call is in scoped file.
*/
public boolean isInScopedFile()
{
return m_scopeFile.equals(m_file);
}
public String getScopeFile()
{
return m_scopeFile;
}
public boolean isScopeLimitToAll()
{
return m_scopeLimitToAll;
}
public void setScopeLimitToAll(boolean scopeLimitToAll)
{
m_scopeLimitToAll = scopeLimitToAll;
}
public int getCurrentIncludeLine()
{
return m_currentincludeline;
}
public Stack> getScopeFilesStack()
{
return m_scopeFilesStack;
}
/*!
* @brief This function stores a global definition of the IDL file.
*/
public void addDefinition(Definition definition)
{
m_definitions.add(definition);
}
public ArrayList getDefinitions()
{
return m_definitions;
}
/*!
* @brief This function adds a module to the context.
* This function is used in the parser.
*/
public void addModule(Module module)
{
if(!m_modules.containsKey(module.getScopedname()))
{
m_modules.put(module.getScopedname(), module);
}
}
public Module existsModule(String scopedName)
{
if(m_modules.containsKey(scopedName))
{
return m_modules.get(scopedName);
}
return null;
}
public Interface createInterface(String name, Token token)
{
Interface interfaceObject = new Interface(m_scopeFile, isInScopedFile(), m_scope, name, token);
addInterface(interfaceObject);
return interfaceObject;
}
/*!
* @brief This function adds a interface to the context.
* This function is used in the parser.
*/
protected void addInterface(Interface interf)
{
Interface prev = m_interfaces.put(interf.getScopedname(), interf);
// TODO: Excepcion
if(prev != null)
System.out.println("Warning: Redefined interface " + prev.getScopedname());
}
public Interface getInterface(String name)
{
int lastIndex = -1;
Interface returnedValue = m_interfaces.get(name);
if(returnedValue == null)
{
String scope = m_scope;
while(returnedValue == null && !scope.isEmpty())
{
returnedValue = m_interfaces.get(scope + "::" + name);
lastIndex = scope.lastIndexOf("::");
if(lastIndex != -1)
{
scope = scope.substring(0, lastIndex);
}
else
{
scope = "";
}
}
}
return returnedValue;
}
/*!
* @brief This function returns all interfaces.
* This function is used in string templates.
*/
public ArrayList getInterfaces()
{
return new ArrayList(m_interfaces.values());
}
public ArrayList getScopedInterfaces()
{
ArrayList ret = new ArrayList();
for(Interface interf : m_interfaces.values())
{
if(interf.isInScope())
ret.add(interf);
}
return ret;
}
public com.eprosima.idl.parser.tree.Exception createException(String name, Token token)
{
com.eprosima.idl.parser.tree.Exception exceptionObject = new com.eprosima.idl.parser.tree.Exception(m_scopeFile, isInScopedFile(), m_scope, name, token);
addException(exceptionObject);
return exceptionObject;
}
/*!
* @brief This function adds a global exception to the context.
*/
protected void addException(com.eprosima.idl.parser.tree.Exception exception)
{
com.eprosima.idl.parser.tree.Exception prev = m_exceptions.put(exception.getScopedname(), exception);
// TODO: Exception.
if(prev != null)
System.out.println("Warning: Redefined exception " + prev.getScopedname());
}
/*!
* @brief This function tries to retrieve a global typecode.
*/
public com.eprosima.idl.parser.tree.Exception getException(String name)
{
int lastIndex = -1;
com.eprosima.idl.parser.tree.Exception returnedValue = m_exceptions.get(name);
// Probar si no tiene scope, con el scope actual.
if(returnedValue == null)
{
String scope = m_scope;
while(returnedValue == null && !scope.isEmpty())
{
returnedValue = m_exceptions.get(scope + "::" + name);
lastIndex = scope.lastIndexOf("::");
if(lastIndex != -1)
{
scope = scope.substring(0, lastIndex);
}
else
{
scope = "";
}
}
}
return returnedValue;
}
public Operation createOperation(String name, Token token)
{
Operation operationObject = new Operation(m_scopeFile, isInScopedFile(), null, name, token);
return operationObject;
}
public Param createParam(String name, TypeCode typecode, Param.Kind kind)
{
Param paramObject = new Param(name, typecode, kind);
return paramObject;
}
public StructTypeCode createStructTypeCode(String name, String comments)
{
StructTypeCode structObject = new StructTypeCode(m_scope, name, comments);
return structObject;
}
public String lookForComments(TokenStream tokenStream, Token token, int lookbackDistance)
{
int tokenIndex = token.getTokenIndex();
while (tokenIndex > 0
&& tokenStream.get(tokenIndex).getChannel() != IDLLexer.COMMENTS
&& (token.getTokenIndex() - tokenIndex) < lookbackDistance)
{
int type = tokenStream.get(tokenIndex).getType();
// Make sure not to get comments from another type if this one doesn't have doc
// Check for ";" and "{" only if it's already gone back at least one token,
// because structs start on their first brace
if (type == IDLLexer.SEMICOLON || ((token.getTokenIndex() - tokenIndex) > 0 && type == IDLLexer.LEFT_BRACE))
{
return null;
}
tokenIndex--;
}
if (tokenIndex > 0 && (token.getTokenIndex() - tokenIndex) < lookbackDistance)
{
String comments = tokenStream.get(tokenIndex).getText().trim();
if (!comments.isEmpty())
{
comments = comments.replaceAll("(\n|\r\n|\r) {1,5}\\*", "\n *");
return comments;
}
}
return null;
}
public Collection getTypes()
{
return m_types.values();
}
/*!
* @brief This function adds a global typecode to the context.
*/
public void addTypeDeclaration(TypeDeclaration typedecl)
{
TypeDeclaration prev = m_types.put(typedecl.getScopedname(), typedecl);
if(prev != null)
throw new ParseException(typedecl.getToken(), "was redefined");
}
/*!
* @brief This function tries to retrieve a global typecode.
*/
public TypeCode getTypeCode(String name)
{
int lastIndex = -1;
TypeCode returnedValue = null;
TypeDeclaration typedecl = m_types.get(name);
// Probar si no tiene scope, con el scope actual.
if(typedecl == null)
{
String scope = m_scope;
while(typedecl == null && !scope.isEmpty())
{
typedecl = m_types.get(scope + "::" + name);
lastIndex = scope.lastIndexOf("::");
if(lastIndex != -1)
{
scope = scope.substring(0, lastIndex);
}
else
{
scope = "";
}
}
}
if(typedecl != null)
returnedValue = typedecl.getTypeCode();
return returnedValue;
}
public AnnotationDeclaration createAnnotationDeclaration(String name, Token token)
{
AnnotationDeclaration annotationObject = new AnnotationDeclaration(m_scopeFile, isInScopedFile(), m_scope, name, token);
addAnnotationDeclaration(annotationObject);
return annotationObject;
}
/*!
* @brief This function adds an annotation to the context.
*/
protected void addAnnotationDeclaration(AnnotationDeclaration annotation)
{
AnnotationDeclaration prev = m_annotations.put(annotation.getScopedname(), annotation);
// TODO: Exception.
if(prev != null)
System.out.println("Warning: Redefined annotation " + prev.getScopedname());
}
public AnnotationDeclaration getAnnotationDeclaration(String name)
{
int lastIndex = -1;
AnnotationDeclaration returnedValue = m_annotations.get(name);
// Probar si no tiene scope, con el scope actual.
if(returnedValue == null)
{
String scope = m_scope;
while(returnedValue == null && !scope.isEmpty())
{
returnedValue = m_annotations.get(scope + "::" + name);
lastIndex = scope.lastIndexOf("::");
if(lastIndex != -1)
{
scope = scope.substring(0, lastIndex);
}
else
{
scope = "";
}
}
}
return returnedValue;
}
/*!
* @brief This function add a new library dependency to the project.
*/
public void addDependency(String dependency)
{
m_dependencies.add(dependency);
}
/*!
* @brief This function get the library dependencies of a project.
*/
public LinkedHashSet getDependencies()
{
// At this level the dependencies are in reverse order. Return them
// in correct order.
LinkedHashSet set = new LinkedHashSet();
LinkedList list = new LinkedList(m_dependencies);
Iterator it = list.descendingIterator();
while(it.hasNext())
{
String dep = it.next();
if(getOS().contains("Windows"))
{
// In windows substitute \\ by /
int count = 0;
while((count = dep.indexOf("/")) != -1)
{
dep = dep.substring(0, count) + "\\" + dep.substring(count + 1);
}
}
set.add(dep);
}
return set;
}
/*!
* @brief This function is used in the stringtemplates. For these reason this function
* returns an ArrayList
*/
public ArrayList getDirectIncludeDependencies()
{
return new ArrayList(m_directIncludeDependencies);
}
// TODO Quitar porque solo es para tipos RTI (usado para las excepciones). Mirar alternativa.
/*!
* @brief This function add a new include dependency to the project.
* This dependency will be needed to include our generated file with the types that
* the RTI DDS middleware doesn't generate (right now only exceptions).
* The include dependencies are added without the .idl extension.
*/
public void addIncludeDependency(String dependency)
{
// Remove .idl extension.
String dep = dependency.substring(0, dependency.length() - 4);
// Remove directory if it is the same than main IDL file.
if(m_directoryFile != null && startsWith(dep, m_directoryFile))
dep = dep.substring(m_directoryFile.length());
m_includedependency.add(dep);
}
// TODO Quitar porque solo es para tipos RTI (usado para las excepciones). Mirar alternativa.
/*!
* @brief This function is used in the stringtemplates. For these reason this function
* returns an ArrayList
*/
public ArrayList getIncludeDependencies()
{
return new ArrayList(m_includedependency);
}
/*!
* @brief This function is call when a preprocessor line was found by the lexer.
* In case the line referring to the content included file, this function sets this file as current scope file.
* Also this function saves the scope file in the library dependecy map.
* In case it is a #include directive, this is saved as direct include dependency.
*/
public void processPreprocessorLine(String line, int nline)
{
// If there is a line referring to the content of an included file.
if(line.startsWith("# "))
{
String line_ = line.substring(2);
/* The received preprocessor line has the following form:
* ' numline filename flags'
* where:
* - numline Number of the line where the include was.
* - filename The filename whose content was included.
* - flags
*/
Scanner scanner = new Scanner(line_);
// Read numline
int numline = scanner.nextInt();
line_ = scanner.nextLine();
scanner = new Scanner(line_).useDelimiter("\"");
// Read filename
scanner.next();
String file = scanner.next();
// Read flags.
boolean systemFile = false, enteringFile = false, exitingFile = false;
if(m_os.contains("Linux"))
{
try
{
line_ = scanner.nextLine();
scanner = new Scanner(line_);
scanner.next();
while(true)
{
Integer flag = scanner.nextInt();
if(flag == 1)
enteringFile = true;
else if(flag == 2)
exitingFile = true;
else if(flag == 3)
systemFile = true;
}
}
catch(NoSuchElementException ex)
{
// The line finishes.
}
}
// Only not system files are processed.
if(!systemFile)
{
if(!m_scopeFile.equals(file))
{
// Remove absolute directory where the application was executed
if(startsWith(file, m_userdir))
{
file = file.substring(m_userdir.length());
// Remove possible separator
if(startsWith(file, java.io.File.separator))
file = file.substring(1);
}
// Remove relative ./ directory.
if(startsWith(file, currentDirS))
{
file = file.substring(currentDirS.length());
// Remove possible separator
if(startsWith(file, java.io.File.separator))
file = file.substring(1);
}
//if it is a idl file.
if(file.substring(file.length() - 4, file.length()).equals(".idl"))
{
if(!m_scopeFile.equals(file))
{
if(!m_scopeFilesStack.empty() && m_scopeFilesStack.peek().first().equals(file))
{
m_scopeFilesStack.pop();
// Add to dependency if there is different IDL file than the processed
addDependency(m_scopeFile);
// See if it is a direct dependency.
if(file.equals(m_file))
{
String includeFile = m_scopeFile;
// Remove relative directory if is equal that where the processed IDL is.
if(m_directoryFile != null && startsWith(includeFile, m_directoryFile))
includeFile = includeFile.substring(m_directoryFile.length());
// Remove relative directory if is equal to a include path.
for(int i = 0; i < m_includePaths.size(); ++i)
{
if(startsWith(includeFile, m_includePaths.get(i)))
{
includeFile = includeFile.substring(m_includePaths.get(i).length());
break;
}
}
m_directIncludeDependencies.add(includeFile.substring(0, includeFile.length() - 4));
}
}
else
{
m_scopeFilesStack.push(new Pair(m_scopeFile, nline - m_currentincludeline - 1));
}
m_scopeFile = file;
}
}
}
//Update the current line.
m_currentincludeline = nline - numline;
}
}
}
protected String getOS()
{
return m_os;
}
protected boolean startsWith(String st, String prefix)
{
if(m_os.contains("Windows"))
{
return st.toLowerCase().startsWith(prefix.toLowerCase());
}
return st.startsWith(prefix);
}
/*** Function to generate random loop variables in string templates ***/
public String getNewLoopVarName()
{
m_loopVarName = 'a';
return Character.toString(m_loopVarName);
}
public String getNextLoopVarName()
{
return Character.toString(++m_loopVarName);
}
/*** End ***/
// OS
String m_os = null;
String m_userdir = null;
private String m_filename = "";
private String m_file = "";
private String m_directoryFile = "";
private String m_scope = "";
private String m_scopeFile = "";
private boolean m_scopeLimitToAll = false;
private int m_currentincludeline = 0;
final String currentDirS = "." + File.separator;
final String includeFlag = "-I";
//! Store all global definitions.
private ArrayList m_definitions;
//! Map that contains all modules that were found processing the IDL file (after preprocessing):
private HashMap m_modules = null;
//! Map that contains all interfaces that were found processing the IDL file (after preprocessing):
private HashMap m_interfaces = null;
//! Map that contains all global exceptions that were found processing the IDL file (after preprocessing).
private HashMap m_exceptions = null;
//! Map that contains all types that were found processing the IDL file (after preprocessing).
protected HashMap m_types = null;
//! Map that contains all annotations that where found processing the IDL file.
private HashMap m_annotations = null;
private ArrayList m_includePaths = null;
//! Set that contains the library dependencies that were found because there was a line of the preprocessor.
private LinkedHashSet m_dependencies = null;
//! Set that contains the direct include dependencies in the IDL file. Used to regenerate the IDL in a supported form.
private HashSet m_directIncludeDependencies = null;
// TODO Quitar porque solo es para tipos RTI (usado para las excepciones). Mirar alternativa.
//! Set that contains the include dependencies that force to include our type generated file (right now only with exceptions in RTI DDS types).
private HashSet m_includedependency = null;
// TODO Lleva la cuenta del nombre de variables para bucles anidados.
private char m_loopVarName = 'a';
private Stack> m_scopeFilesStack;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy