[e-lang] safejTemplate.e
Kevin Reid
kpreid at mac.com
Sat Mar 28 08:59:08 EDT 2009
I just committed to the scripts directory safejTemplate.e, which
generates safej files in which everything is suppressed from Java
classes, so that you don't have to write everything out by hand.
Please let me know if you (especially MarcS...) notice any (other) bugs.
For convenience, a copy of the source (will be broken by some line
wrapping):
-----------------------------------------------------------------------
#!/usr/bin/env rune
# Copyright 2004-2009 Kevin Reid, under the terms of the MIT X license
# found at http://www.opensource.org/licenses/mit-
license.html ................
#
# NAME
# safejTemplate -- generate safej from Java classes
#
# SYNOPSIS
# safejTemplate.e [-classpath <classpath>] <Java class name>
#
# DESCRIPTION
# This is a useful hack for getting started in writing a safej
file. It extracts the protocol of a class using 'javap', then writes a
corresponding safej term with everything suppressed, for you to edit.
#
# OPTIONS
# -classpath
# Controls where the class to be examined will be searched for.
#
# BUGS
# Java reflection should perhaps be used instead of parsing the
textual output of javap. There is no guarantee that the parser
understands everything javap might output. (Note however that using
reflection implies loading the classes into the same jvm as the host E.)
#
# There ought to be an option to write the safej into a file into
a directory according to the FQN.
#
# It doesn't know when to use reject instead of suppress.
#
# The regular expressions may be too lenient in some cases.
pragma.syntax("0.9")
pragma.enable("accumulator")
def javap := makeCommand("javap")
# --- Argument parsing ---
var args := interp.getArgs()
var optClassPath := null
switch (args) {
match [`-classpath`, cp] + rest {
args := rest
optClassPath := cp
}
match _ {}
}
def [className] := args
# --- Fetch javap result ---
def [p, _] := if (optClassPath != null) {
javap("-classpath", optClassPath, "-public", className)
} else {
javap("-public", className)
}
# --- javap parsing ---
var statics := []
var methodz := []
/** Remove package qualification from a type name. */
def shortenType(rx`(?:.*\.)?(@x[][A-Za-z_$$]+)`) { return x }
/** Remove package qualification from a comma-separated list of type
names and insert spaces after the commas, thus converting javap
argument lists to safej argument lists. */
def shortenArgs(argStr) {
if (argStr == "") {
return ""
}
return ", ".rjoin(accum [] for x in argStr.split(", ") {
_.with(shortenType(x))
})
}
# Names which SafeJ automatically suppresses, so we don't need to
mention.
# I'd like to import instead of copying this list, but SafeJ doesn't
make it public.
def ALWAYS_REMOVE := [
"clone()",
"equals(Object)",
"finalize()",
"getClass()",
"hashCode()",
"notify()",
"notifyAll()",
"toString()",
"wait()",
"wait(long)",
"wait(long, int)"
].asSet()
for line in p.split("\n") {
stderr.println(line)
switch (line) {
# Public method
match rx` public(?: abstract)?(@stat static)?(?: final)?(?:
synchronized)? [][A-Za-z0-9_$$.]+ (@verb[A-Za-z_]+)\((@argStr.*)\)(?:\s
+throws [A-Za-z_$$., ]+?)?;` {
def name := `$verb(${shortenArgs(argStr)})`
if (ALWAYS_REMOVE.contains(name)) {
continue
}
def mterm := term`method(suppress, .String.$name)`
if (stat != null) {
statics with= mterm
} else {
methodz with= mterm
}
}
# Public constructor
match rx` public $className\((@argStr.*)\);` {
def mterm := term`method(suppress, .String.${`run($
{shortenArgs(argStr)})`})`
statics with= mterm
}
# Public field
match rx` public(@stat static)?(@fin final)? (@type[][A-Za-
z0-9_$$.]+) (@noun[A-Za-z0-9_]+);` {
def [initial] + rest := noun
def capped := __makeTwine.fromChars([initial],
null).toUpperCase() + rest
def mtermGet := term`method(suppress, .String.${`get$capped()`})`
def mtermSet := term`method(suppress, .String.${`set$capped($
{shortenType(type)})`})`
{
def &list := (stat != null).pick(&statics, &methodz)
list with= mtermGet
if (fin == null) {
list with= mtermSet
}
}
}
# Uninteresting
match `Compiled from @_` {}
match `interface @_{` {}
match rx`public(?: abstract)?(?: final)? class [A-Za-z_$$.]+
( extends [A-Za-z_$$.]+)?( implements [A-Za-z_$$., ]+)?{` {}
match ` throws @_` {}
match `` {}
match `}` {}
}
}
# --- Generate final term ---
println(term`class(.String.$className,
statics($statics*),
methods($methodz*))`.asText())
--
Kevin Reid <http://homepage.mac.com/kpreid/>
More information about the e-lang
mailing list