Download and Run
- Download codeprober.jar from the latest release.
- Start like this:
java -jar codeprober.jar your-analyzer-or-compiler.jar [args-to-forward-to-compiler-on-each-request]
For example, if you have codeprober.jar in your downloads
directory, and your tool is called compiler.jar
and is
located in your home directory, then run:
java -jar ~/Downloads/codeprober.jar ~/compiler.jar
Once started, you should open http://localhost:8000 in your
browser. When the page is loaded, you’ll find a Help
button on the right side which can help you further. See Features for features you can use once inside
CodeProber.
AddNum Compiler
If you would like to try CodeProber but you don’t have an analyzer or compiler of your own, you can use the latest version of AddNum. This is a very small example “compiler” for a language that only supports additions and numbers. Download it, and then run CodeProber with e.g:
java -jar ~/Downloads/codeprober.jar ~/Downloads/AddNum.jar
Compatibility with Custom Tool
To use CodeProber, you must have a compiler or analyzer (a “tool”) that follows certain conventions. There are two main things the tool must provide:
- A way for CodeProber to turn a given text file into an AST (“parsing”).
- A way for CodeProber to traverse nodes in the AST.
Any tool built using JastAdd supports AST traversal automatically. For non-JastAdd tools, please see the “Mandatory API” section in AST API.
There are two options for parsing.
The first option is preferred, and it is to add a method
CodeProber_parse
method in your main class. It can look
like this:
public static Object CodeProber_parse(String[] args) throws Throwable {
// 'args' has at least one entry.
// First are all optional args (see "args-to-forward-to-compiler-on-each-request" above).
// The last entry in the array is path to a source file containing the CodeProber editor text.
String sourceFile = args[args.length - 1];
// "parse" is expected to take the path to a source file and transform it to the root of an AST
return parse(sourceFile);
}
CodeProber will invoke this and use the return value as the entry point into your AST.
The second option is for CodeProber to use your normal main method as an entry point. Since main cannot return anything, the resulting AST must instead be assigned to a static field within your main class. In total, there are therefore two changes that are required: In your main java file, add the following declaration:
public static Object CodeProber_root_node;
Then, immediately after parsing the input file(s), assign the root of your AST to this variable. E.g:
= parse(...);
Program myAst = myAst; CodeProber_root_node
The CodeProber_root_node
variable will be used by
CodeProber as an entry point. Since many tools perform semantic
analysis and call System.exit in main if an error is encountered,
CodeProber attempts to install a System.exit interceptor when using
the main method. This has issues on Java versions 17 and later (see
“System.exit/SecurityManager problem” in Troubleshooting). If you have problems
with this, consider using CodeProber_parse
instead, which
doesn’t rely on intercepting System.exit.
If you define both CodeProber_parse
and
CodeProber_root_node
, then CodeProber_parse
takes precedence.
If you previously used DrAST, then
you likely have DrAST_root_node
declared and assigned.
CodeProber will use this as a fallback if neither
CodeProber_parse
nor CodeProber_root_node
is
not defined, so you don’t have to do any changes. However, the
help/warning messages inside CodeProber
that reference
the root node will reference CodeProber_root_node
, even
if you don’t have it. So for a more consistent experience, consider
adding a specific declaration for CodeProber (or even better, use
CodeProber_parse
).
Wrapper Implementations
Perhaps you read the Mandatory AST API and thought that it doesn’t fit with your tool at all. Perhaps your AST isn’t implemented in a JastAdd-like object-oriented fashion, or perhaps it even runs outside the JVM. There is a solution for you which works almost as well, and that is to create a “wrapper implementation”.
In short, a wrapper implementation is one that creates a very shallow wrapper AST around another “real” AST. It is up to the wrapper to delegate all requests regarding AST traversal, method invocation, etc to the real AST. This can be done via reflection, sockets, native code, etc. CodeProber doesn’t know and doesn’t care where the “real” implementation resides.
The fastest way to get started with a wrapper is to start from the
minimal-prober-wrapper
example implementation found in the CodeProber repository. Once
you have gotten a minimum working example, you can look at the AST APIs to improve the experience.
Several APIs are designed specifically for wrapper implementations,
such as cpr_lInvoke
and cpr_nodeLabel
.
One thing to note about wrappers: CodeProber needs to know a shared supertype of all AST nodes. Any subtype of this supertype is expected to implement the mandatory AST traversal APIs mentioned above. CodeProber tries to automatically detect the common supertype with the following pseudocode:
def find_super(type)
if (type.supertype.package == type.package)
return find_super(type.supertype)
else
return type
find_super
is called with your AST root (returned from
CodeProber_parse
or CodeProber_root_node
).
In other words, it finds the top supertype that belongs to the same
package as the AST root. If your native AST structure uses a hierarchy
of packages rather than a single flat package, then this will likely
cause problems, so you should probably rely on a wrapper
implementation instead.