Commit 10403c4a authored by Vít Kabele's avatar Vít Kabele

Duplicated DislClasses code extracted to common abstract parent.

parent 98e36e86
......@@ -6,21 +6,110 @@
*/
package ch.usi.dag.disl;
import ch.usi.dag.disl.annotation.ArgumentProcessor;
import ch.usi.dag.disl.exception.ParserException;
import ch.usi.dag.disl.exception.ProcessorException;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import ch.usi.dag.disl.snippet.Snippet;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Provide an interface for getting snippets.
* Abstract class providing interface for getting snippets.
*/
public interface DislClasses {
abstract class DislClasses {
final SnippetParser snippetParser;
/**
* Create new instance of {@link DislClasses} class.
*
* @param snippetParser SnippetParser.
*/
DislClasses(SnippetParser snippetParser){
this.snippetParser = snippetParser;
}
/**
* Initialization method common for all inherited classes.
*
* @param sp Snippet parser
* @param options Code options
* @param classNodes Class nodes.
* @throws InitializationException
* @throws ParserException
* @throws ProcessorException
* @throws ReflectionException
*/
static void InitMethod(
final SnippetParser sp,
final Set<DiSL.CodeOption> options,
List<ClassNode> classNodes
) throws
InitializationException,
ParserException,
ProcessorException,
ReflectionException
{
if (classNodes.isEmpty ()) {
throw new InitializationException (
"No DiSL classes found. They must be explicitly specified "+
"using the disl.classes system property or the DiSL-Classes "+
"attribute in the instrumentation JAR manifest."
);
}
//
final ArgProcessorParser app = new ArgProcessorParser ();
for (final ClassNode classNode : classNodes) {
if (__isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
sp.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
sp.getAllLocalVars (), app.getAllLocalVars ()
);
final Map<Type, ArgProcessor> processors = app.initProcessors (localVars);
// TODO LB: Consider whether we need to create the argument processor
// invocation map now -- we basically discard the argument processors
// and keep an invocation map keyed to instruction indices! :-(
// TODO LB: Move the loop to the SnippetParser class
for (final Snippet snippet : sp.getSnippets ()) {
snippet.init (localVars, processors, options);
}
}
/**
* Get all possible snippets.
* @return All snippets
*/
List<Snippet> getSnippets ();
List<Snippet> getSnippets () {
return snippetParser.getSnippets ();
}
/**
* Get matching snippets.
......@@ -30,6 +119,37 @@ public interface DislClasses {
* @return Matching snippets.
*/
List<Snippet> selectMatchingSnippets (
String className, String methodName, String methodDesc
);
String className, String methodName, String methodDesc) {
return snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
.collect (Collectors.toList ());
}
/**
* An argument processor must have an @ArgumentProcessor annotation
* associated with the class. DiSL instrumentation classes may have
* an @Instrumentation annotation. DiSL classes without annotations
* are by default considered to be instrumentation classes.
*
* @param classNode Class node.
* @return True, when class node is argument processor, false otherwise.
*/
private static boolean __isArgumentProcessor (final ClassNode classNode) {
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
for (final AnnotationNode annotation : classNode.invisibleAnnotations) {
final Type annotationType = Type.getType (annotation.desc);
if (apType.equals (annotationType)) {
return true;
}
}
}
// default: not an argument processor
return false;
}
}
......@@ -25,82 +25,54 @@ import java.util.stream.Stream;
* Parser for DiSL classes containing either snippets or method argument
* processors. This class is not meant for public use.
*/
public final class DislClassesImpl implements DislClasses {
public final class DislClassesImpl extends DislClasses {
private final SnippetParser __snippetParser;
//
private DislClassesImpl (final SnippetParser snippetParser) {
/**
* Create new instance of {@link DislClassesImpl} class.
* @param _snippetParser Snippet parser.
*/
private DislClassesImpl (final SnippetParser _snippetParser) {
// not to be instantiated from outside
__snippetParser = snippetParser;
super(_snippetParser);
}
//
public static DislClasses load (
final Set <CodeOption> options, final Stream <String> classNames
) throws ParserException, StaticContextGenException, ReflectionException,
ProcessorException {
final Set <CodeOption> options,
final Stream <String> classNames
) throws
ParserException,
ReflectionException,
ProcessorException
{
//
// Get an ASM tree representation of the DiSL classes first, then
// parse them as snippets or argument processors depending on the
// annotations associated with each class.
//
final List <ClassNode> classNodes = classNames
.map (className -> __createClassNode (className))
.map (DislClassesImpl::__createClassNode)
.collect (Collectors.toList ());
if (classNodes.isEmpty ()) {
throw new InitializationException (
"No DiSL classes found. They must be explicitly specified "+
"using the disl.classes system property or the DiSL-Classes "+
"attribute in the instrumentation JAR manifest."
);
}
//
final SnippetParser sp = new SnippetParser ();
final ArgProcessorParser app = new ArgProcessorParser ();
for (final ClassNode classNode : classNodes) {
if (__isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
sp.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
sp.getAllLocalVars (), app.getAllLocalVars ()
);
final Map <Type, ArgProcessor> processors = app.initProcessors (localVars);
// TODO LB: Consider whether we need to create the argument processor
// invocation map now -- we basically discard the argument processors
// and keep an invocation map keyed to instruction indices! :-(
// TODO LB: Move the loop to the SnippetParser class
for (final Snippet snippet : sp.getSnippets ()) {
snippet.init (localVars, processors, options);
}
InitMethod (sp, options, classNodes);
return new DislClassesImpl (sp);
}
/**
* Parse input stream into a class node. Include debug information so
* that we can report line numbers in case of problems in DiSL classes.
* Re-throw any exceptions as DiSL initialization exceptions.
*
* @param className Class name.
* @return ClassNode
*/
private static ClassNode __createClassNode (final String className) {
//
// Parse input stream into a class node. Include debug information so
// that we can report line numbers in case of problems in DiSL classes.
// Re-throw any exceptions as DiSL initialization exceptions.
//
try {
return ClassNodeHelper.SNIPPET.load (className);
......@@ -112,39 +84,5 @@ public final class DislClassesImpl implements DislClasses {
}
private static boolean __isArgumentProcessor (final ClassNode classNode) {
//
// An argument processor must have an @ArgumentProcessor annotation
// associated with the class. DiSL instrumentation classes may have
// an @Instrumentation annotation. DiSL classes without annotations
// are by default considered to be instrumentation classes.
//
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
for (final AnnotationNode annotation : classNode.invisibleAnnotations) {
final Type annotationType = Type.getType (annotation.desc);
if (apType.equals (annotationType)) {
return true;
}
}
}
// default: not an argument processor
return false;
}
//
@Override public List <Snippet> getSnippets () {
return __snippetParser.getSnippets ();
}
@Override public List <Snippet> selectMatchingSnippets (
final String className, final String methodName, final String methodDesc
) {
return __snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
.collect (Collectors.toList ());
}
}
......@@ -8,29 +8,20 @@
*/
package ch.usi.dag.disl;
import ch.usi.dag.disl.annotation.ArgumentProcessor;
import ch.usi.dag.disl.exception.ParserException;
import ch.usi.dag.disl.exception.ProcessorException;
import ch.usi.dag.disl.exception.ReflectionException;
import ch.usi.dag.disl.localvar.LocalVars;
import ch.usi.dag.disl.processor.ArgProcessor;
import ch.usi.dag.disl.snippet.Snippet;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AnnotationNode;
import org.objectweb.asm.tree.ClassNode;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Provide access to disl classes from a {@link ch.usi.dag.disl.DiSL} instance.
*/
public class IsolatedDislClasses implements DislClasses {
private final SnippetParser snippetParser;
class IsolatedDislClasses extends DislClasses {
/**
* Create new instance of the {@link IsolatedDislClasses} class.
......@@ -47,86 +38,14 @@ public class IsolatedDislClasses implements DislClasses {
final List<ClassNode> classNodes,
final Map<String, byte[]> allClasses
)
throws ParserException, ProcessorException, ReflectionException {
if (classNodes.isEmpty ()) {
throw new InitializationException (
"No DiSL classes found. They must be explicitly specified "+
"using the disl.classes system property or the DiSL-Classes "+
"attribute in the instrumentation JAR manifest."
);
}
//
final SnippetParser sp = new IsolatedSnippetParser ( allClasses );
final ArgProcessorParser app = new ArgProcessorParser ();
for (final ClassNode classNode : classNodes) {
if (isArgumentProcessor (classNode)) {
app.parse (classNode);
} else {
sp.parse (classNode);
}
}
//
// Collect all local variables and initialize the argument processor
// and snippets.
//
final LocalVars localVars = LocalVars.merge (
sp.getAllLocalVars (), app.getAllLocalVars ()
);
final Map<Type, ArgProcessor> processors = app.initProcessors (localVars);
// TODO LB: Consider whether we need to create the argument processor
// invocation map now -- we basically discard the argument processors
// and keep an invocation map keyed to instruction indices! :-(
// TODO LB: Move the loop to the SnippetParser class
for (final Snippet snippet : sp.getSnippets ()) {
snippet.init (localVars, processors, options);
}
snippetParser = sp;
}
@Override
public List<Snippet> getSnippets () {
return snippetParser.getSnippets ();
}
@Override
public List<Snippet> selectMatchingSnippets (
String className, String methodName, String methodDesc) {
return snippetParser.getSnippets ().stream ().unordered ()
.filter (s -> s.getScope ().matches (className, methodName, methodDesc))
.collect (Collectors.toList ());
}
throws ParserException,
ProcessorException,
ReflectionException
{
private boolean isArgumentProcessor (final ClassNode classNode) {
//
// An argument processor must have an @ArgumentProcessor annotation
// associated with the class. DiSL instrumentation classes may have
// an @Instrumentation annotation. DiSL classes without annotations
// are by default considered to be instrumentation classes.
//
if (classNode.invisibleAnnotations != null) {
final Type apType = Type.getType (ArgumentProcessor.class);
super( new IsolatedSnippetParser ( allClasses ) );
for (final AnnotationNode annotation : classNode.invisibleAnnotations) {
final Type annotationType = Type.getType (annotation.desc);
if (apType.equals (annotationType)) {
return true;
}
}
}
InitMethod (snippetParser, options, classNodes);
// default: not an argument processor
return false;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment