Running Bear
Manual
Don BatoryDepartment of Computer ScienceThe University of Texas at AustinAustin, TX, USA
Running Bear (RB) is a MDELite's Model-to-Text (M2T) tool. It is a tiny Java file that offers 14 static methods, of which the most important the two in green rows.
Return Type | Method | Usage |
void | RBSetup(Marquee2Arguments mark, String... args) | Open the command-line specified database and output file |
String | getDatabaseInputFile() | return the name of the database file |
String | getOutputFileName() | return the name of the RB output file |
DB | getDB() | return the DB object produced by reading the database |
|
void | openOut(String filename) | direct RB output to the given file |
void | openOut(PrintStream o) | direct RB output to the given PrintStream |
void | closeOut() | close the opened RB PrintStream or file |
PrintStream | getOut() | return the PrintStream object of RB |
|
String | getDatabase() | return the filename of the current database |
String | getOutputFileName() | return the file name of the current output file |
void | p(String format, Object... args) | print(format,arguments) no line eject |
void | l(String format, Object... args) | println(format, arguments) with line eject |
void | l() | print blank line |
void | l(int n) | print n blank lines |
Outline of an RB Program
An RB program implements a M2T tool. It maps an MDELite database to a text file (which could be a java file, html file, or whatever). The command-line of an RB program is standardized:
> java myRBProgram X.Y.pl [outputfile]
That is, an RB program takes a database file as input (X is the name of the file, Y is the name of its schema, pl designates a MDELite database), and optionally the name of the output file. As we'll see shortly, the output file name is computed from the input file name, and the computation is specified in the RBSetup method. For debugging purposes, I specify an explicit output file (say "out.txt") to avoid output file proliferation. The basic template of a RB program is:
import MDLUtilities.Marquee1In_1Out;
import MDLUtilities.RunningBear;
import PrologDB.Table;
import PrologDB.Tuple;
public class demo extends RunningBear {
static Table cls, fld;
public static void main(String... args) {
// Step 1: standard marquee processing
Marquee1In_1Out mark = new Marquee1In_1Out(demo.class, ".classes.pl", ".txt", args);
RBSetup(mark, args); // opens "X.classes.pl" database, as specified on the command line
// variable db is the opened database
// file "X.java" is opened (or whatever command-line output is specified
// Step 2: open tables of database
cls = db.getTableEH("class");
fld = db.getTableEH("field");
// Step 3: "generate" code ... this is where the heavy lift occurs
}
Simple Example
Here is a simple database:
dbase(classes,[class,field]).
table(class,[cid,name,superName]).
class(c0,entity,null).
class(c1,student,entity).
class(c2,course,entity).
table(field,[fid,name,type,cid]).
field(f0,name,String,c0).
field(f1,UTEID,String,c1).
field(f2,profName,String,c2).
Here is the desired output:
class entity {
String name;
}
class student extends entity {
String UTEID;
}
class course extends entity {
String profName;
}
The extra code that is added to the template above to generate this is:
cls.forEach(c->genClass(c,false));
// Step 4: done
}
static void genClass(Tuple c, boolean separateFile) {
// Step 1: print the class header
String sup = c.get("superName");
String xtends = (!sup.equals("null"))?"extends "+sup:"";
if (separateFile) {
openOut(c.get("name")+".java");
}
l("class %s %s {", c.get("name"), xtends);
// Step 2: compute table of c's fields
Table cfields = c.rightSemiJoin("cid",fld,"cid");
// Step 3: declare all fields and their types
cfields.forEach(f-> l(" %s %s;", f.get("type"), f.get("name")));
// Step 4: print the class footer
l("}");
l(1);
if (separateFile) {
closeOut();
}
}
By invoking method genclass with argument true, separate .java files are produced per class. That's about it.