I'd like to introduce Embedded CAL, the work I did this summer.
Embedded CAL allows you to add CAL expressions and modules directly
into the Java editor. The main goal of Embedded CAL is to make it as
easy as possible to switch back and forth between Java and CAL, thus
lowering the barrier of entry to CAL, and providing more opportunities
to use CAL in small places as part of a larger Java application.
Click here if you are interested reading more about Embedded CAL:
http://groups.google.com/group/cal_language/web/embedded-cal
I will be updating this page periodically and notifying this group as
I make big changes.
I spent three and a half months as a summer student working with the
Quark team. I had a great time and I learned quite a bit. And so, I
appreciate all the help that the Quark team has given me with this
project.
thank you,
Andrew Eisenberg
I've been playing with Java/CAL integration using Javassist to replace
annotated methods with calls to CAL functions, so you can say:
// Start.java
...
@Cal(workspace = "myworkspace.cws", module = "TDavies.Start")
public class Start {
@Cal(outputPolicy=CalOutputPolicy.ITERATOR)
private Iterator<Integer> randomList() {
return null;
}
... other java methods...
}
and have the randomList() method replace at class load time with a
call to:
// Start.cal
...
randomList :: [Int];
public randomList = map (\n -> n + 1) $ randomBoundedInts initialSeed
10;
On Sep 13, 3:31 pm, "Andrew Eisenberg" <a...@cs.ubc.ca> wrote:
[snip]
Thanks for the details Andrew.
> That's interesting what you are doing with Javassist. What do the
> pre-processors look like? How do you pass in arguments? Are the entry
> points generated and then cached, or are they re-created for each entry?
On Sep 13, 3:31 pm, "Andrew Eisenberg" <a...@cs.ubc.ca> wrote:
> That's interesting what you are doing with Javassist. What do the
> pre-processors look like? How do you pass in arguments? Are the entry
> points generated and then cached, or are they re-created for each entry?
The class which does the code changes looks like this:
package tdavies.cal;
/**
* This class visits the annotations on a class and provides new
method bodies, as Javassist strings,
* for those methods which should be delegated to CAL functions.
*
* @author tomd
*
*/
public class CalAnnotationInterpreter {
private String classWorkspace;
private String classModule;
private boolean all;
/**
* The client must call this method before calling visitMethod.
*
* @param className a String naming this class.
* @param classAnnotation the Cal annotation on this class, may be
null.
*/
public void visitClass(String className, Cal classAnnotation) {
classWorkspace = null;
classModule = null;
all = false;
if (classAnnotation != null) {
if (!classAnnotation.workspace().equals("")) {
classWorkspace = classAnnotation.workspace();
}
if (!classAnnotation.module().equals("")) {
classModule = classAnnotation.module();
}
if (!classAnnotation.function().equals("")) {
throw new RuntimeException(
"Error: cannot specify a function name ("
+ classAnnotation.function()
+ ") at class level in class "
+ className);
}
all = classAnnotation.allMethods();
}
}
/**
* The client must call this method for each method on the class
whose annotations are being
* processed, even methods with no Cal annotation.
*
* @param methodName a String naming the method.
* @param methodAnnotation the Cal annotation for this method, may be
null.
* @return a String containing the replacement body for the method,
or null if the body should not be replaced.
*/
public String visitMethod(String methodName, Cal methodAnnotation) {
if (methodAnnotation != null || all) {
String workspace = classWorkspace;
String module = classModule;
String function = methodName;
if (methodAnnotation != null) {
if (!methodAnnotation.workspace().equals("")) {
workspace = methodAnnotation.workspace();
}
if (!methodAnnotation.module().equals("")) {
module = methodAnnotation.module();
}
if (!methodAnnotation.function().equals("")) {
function = methodAnnotation.function();
}
}
return "{ return ($r)tdavies.CalFunctionInvoker.runFunction(\""
+ workspace
+ "\", \""
+ module
+ "\", \""
+ function
+ "\", "
+ "tdavies.CalOutputPolicy." + (methodAnnotation == null ?
CalOutputPolicy.DEFAULT : methodAnnotation.outputPolicy()).toString()
+ ", $args); }";
}
else
{
return null;
}
}
}
Javassist can pass on the arguments to the function as an Object[].
I cache the EntryPointSpecs -- but perhaps I could cache more? And I
don't use ExecutionContexts.
The CalFunctionInvoker class referred to in the generated body above
looks like:
package tdavies.cal;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.openquark.cal.compiler.CompilerMessageLogger;
import org.openquark.cal.compiler.MessageLogger;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.compiler.io.EntryPointSpec;
import org.openquark.cal.compiler.io.OutputPolicy;
import org.openquark.cal.services.BasicCALServices;
/**
* This class is responsible for calling a CAL function, given its
workspace, module
* and name.
*
* @author tomd
*
*/
public class CalFunctionInvoker {
private static Map<String, BasicCALServices> workspaces = new
ConcurrentHashMap<String, BasicCALServices>();
//TODO: the key of the cache should include the workspace name
private static Map<QualifiedName, EntryPointSpec> entryPoints = new
ConcurrentHashMap<QualifiedName, EntryPointSpec>();
private static BasicCALServices getWorkspace(String name) {
BasicCALServices bcs = workspaces.get(name);
if (bcs == null) {
CompilerMessageLogger messageLogger = new MessageLogger();
bcs = BasicCALServices.makeCompiled(name, messageLogger);
if (bcs == null)
throw new RuntimeException(messageLogger.toString());
workspaces.put(name, bcs);
}
return bcs;
}
private static EntryPointSpec getEntryPointSpec(String module,
String function, OutputPolicy outputPolicy) {
QualifiedName qn = QualifiedName.make(module, function);
EntryPointSpec eps = entryPoints.get(qn);
if (eps == null) {
eps = EntryPointSpec.make(qn, null, outputPolicy);
entryPoints.put(qn, eps);
}
return eps;
}
public static Object runFunction(String workspace, String module,
String function, CalOutputPolicy outputPolicy, Object[] args) {
try {
return getWorkspace(workspace).runFunction(
getEntryPointSpec(module, function,outputPolicy.outputPolicy),
args);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Tom