[all pages:] introduction message / location / muli format dtd xantlr tdom ops paisley metajava umod option auxiliaries d2d downloads & licenses people bibliography APPENDICES:: white papers white papers 2 white papers 3 project struct proposal cygwin tips SOURCE:option.dtd SOURCE:dtd.umod DOC:deliverables.ddf DOC-DE:deliverables.ddf DOC:mtdocpage.ddf DOC-DE:mtdocpage.ddf SOURCE:basic.dd2 SOURCE:xslt.dd2
message / location / muli | bandm meta_tools | dtd |
The Format Library
(related API documentation: package format, package formatfrontends )
1
Principles
2
Kinds of Formats and Their Explicit Construction.
2.1
Atomic Formats
2.2
Indentation
2.3
Compound Formats
2.4
Macros
2.5
Format Variables
2.6
Annotated Format
3
Processing Format Terms With Visitors and Rewriters
4
Output Methods
4.1
Output for Debugging
5
Pre-Defined Library of Formats for Java
Source Texts
6
Front-Ends for Format Expressions
6.1
Dynamic Format Generation for Printing Java Data Objects
7
FormatRepository --- A
Persistent Cache Store for Format Objects
The Format library is used to create well-formatted text output.
Some basic outlines of the underlying concept have been published by John Hughes
in 1995 [Hug95]. Our implementation offers additionally parametrization
and diverse front-end notations.
(Please refer also to the API documentation.)
Pretty-printing is necessary for ergonomic reasons in
the many stages of the development of meta-programming software, and is
used in
meta_tools
throughout for producing java sources.
Furthermore, it can be employed for creating
any well-formatted text output on user and application level.
The basic way of using the format library is ...
This output and formatting process is defined as follows:
After resolving all open variables (see Section 2.5 below),
we distinguish atomic and compound formats.
Atomic formats are the basic elements producing output text, while
compound formats combine other formats in a specific manner.
Whenever the top-level format is printed, the output starts in the
leftmost ("0th") column of the output text.
All formats contained in a compound format are positioned relatively to the
containing format. Their printing starts in the same column as the containing
format, or further to the right.
For certain kinds of compound formats (Block, Line and Beside)
the algorithm decides whether and where to insert line breaks between the sub-formats
contained therein.
As an optional attribute, a format may have an integer value as its indentation.
This value is added to the number of the starting column of the
containing format to determine the starting column for printing this sub-format,
if and only if it is the first first format in a newly opened line or the
containing format is a Tabular.
Otherwise the value of the indentation is ignored .
The main properties of the algorithm are ...
Format objects are created as algebraic terms, i.e. bottom-up. This is done by calling static methods found in <METATOOLS>/.../Format.java.
All instances of Format carry algebraic semantics. The instances cannot be modified. So these factory methods may (and should!) employ sharing and caching of Format objects invisibly to the user, and so can do any user's code. For transformation of the algebraic stucture of a format term there is (1) a rewriting mechanism defined with the Compound format, as described below, and (2) a special rewriter class.
The following list mentions all kinds of atomic formats.
They are represented either by a publicly readable constant, or by
a public factory method.
Additionally, each format can be given an indentation
as described in Section 2.2.
Each format delivers a clone with a certain indentation by its method ...
As mentioned above, the compoind formats differ w.r.t. how thwy arrange the sub-formats. They are realized by the following classes, and oftenly identified by an instance of the enumeration type <METATOOLS>/format/CompoundConstructor. This enumeration offers the method public Format apply(Collection<Format> subs), which delivers a new instance of the correspondig sub-classs of format.Compound .
These sub-classes are ...
When using these construction methods it is important to consider that (except Append and Beneath) the formats do not behave in an associative way! (It can always happen that in the midst of a line or beside format, which is printed vertically, there exists a sub-format of the same class which is printed horizontally.)
Please note that (in contrast to all others) the Prior format is context sensitivew.r.t. its output ! For efficiency, this is treated by the layout algoithm only as an approximation. The effects will stay nearly invisible, as long as the character data difference between both versions is in the range of traditional parentheses usage.
common base class of all these sub-classes of Format provides a rewriting interface,i.e. a set of methods for changing the contents of existing format objects, preserving the correctness of the internal attribute caches. Plese refer to the API documentation of Format.Compound for a description.
This very special but frequently needed arrangement can be symbolically depicted like ...
outer combinator | | | | | close | | | inner comb.-----+--- .... ---+ | | | | | Append Append f[last] | | | | | | f[0] separator f[1] separator | open |
For the efficiency of any text generating process it is of central importance that format objects are parametrizable. So a complicated structure can be constructed and partially evaluated once, and subsequently be used more than once, in different variants.
We support two flavours of variables which are identfied by number or by name, and refer to values either by position or by an explicit map.
static Format variable(int) delivers a Format.BoundVariable, and static Format variable(String) delivers a Format.FreeVariable.
There are different ways for resolving variables:
Format.applyTo(Format...)returns a copy of "this".
If it gets n format objects as arguments, in this copy all occurences of the
first bound variables "0" to "n-1" will be replaced by the argument
at this position.
All bound variables with a number >=n will be re-numbered,
starting with zero(0).
There is a second method, the arguments of which are not required to be formats themselves, but may be of class <METATOOLS>/format.Formattable. So they only need a method "format()" which delivers a Format as soon as such is required.
(This interface is e.g. implemented by all many classes from metajava. Therefore generated classes, fields etc. can easily be inserted into pre-defined formats which represent java code. See the metajava user documentation.)
For both methods there is a static variant which takes the format body as an argument, but does do the same evaluation, nameliy apply(Format,Format...)and apply(Format,Formattable...).
For free (=named) variables you currently only have static methods. First is apply(Format,String,Format), which returns a copy of the first format in which all occurences of the free variable with the given name are replaces with the second format.
The only way to substitute more than one variable in one pass is to construct a Format.Context, and then call eval(Context,boolean). (This is the same as static apply(Format,Context,boolean)). This will replace both kinds of variables,as contained in the context, and throw an Assertion Error, if "partial" is set to false but the result still contains unresolved variables.
The "local" modification interface defined with the Compound class has already been described above.
format package additioally defines a visitor classand a rewriter class. Their usage should be self-explaining, it closely follows the architecture realised in the umod generated visitors.
Once a format expression is created, the following output methods calculate the final formatting and create the textual representation:
The function static Format.showLn(Format, int depth) returns a string containing a symbolic representation of the format arguments's term tree, but showing only the top $depth$ levels.
For larger structures it is more convenient to use static Format.showSwingTree(Format, String, boolean) which opens a swing window and shows a swing "JTree" representation of the format's term structure.
If needed in another context, this tree can be produced by using a Format.Forester explicitly, like in ...
final JTree tree = new JTree(new Format.Forester().growRoot(myFormat)) ; |
The library <METATOOLS>/format/java/Formatter.java contains all necessary data items (ie. public static final Format constants, and public static Format()methods) for generating well-formatted java source text.
In our own sources, the usage of this class has been replaced by the much more convenient (since parser-based) methods offered by metajava/FormatClosure.
Both methods closely follow the style rules from [jCodeConv]
On top of the Format library there is a collection of compilers and interpreters for more compact and convenient definitions of format expresssions. E.g. the metajava package includes a java parser, which generates format terms representing java expressions, statements and declarations.
Furthermore, there is an own expression based front-end language for compact descriptions of formats. Basis is a generic grammar and a generic compiler.
Derived from these, there is
one instantiation
for the
umod tool
and
another instantiation
for the
tdom tool :
These are small compilers to generate format based code for the
user-defined visualization of the user-defined data structures.
Further there is a reflection based version for any Java object, described in Section 6.1.
Syntax and semantics of the "lower" constructs, which deal with concrete data, are of course specific to the concrete instantiation of the generic language. Esp. these are
But the part of the language which controls the combinators and literals is common to all these tools. These productions and their semantics are ...
formatDescription ::= blankCharacter
'
character
'
( formatDescription ) nat > formatDescription switch prior java throw tabular text compoundFormatDescription aggregateFormatDescription DOMAIN_SPECIFIC_DATA_ADDRESSING |
switch ::= $switch
DOMAIN_SPECIFIC_SWITCH_SELECTOR
$mode
{ case , case , append } |
prior ::= $prior nat nat ~ ( pattern ) ( pattern ) |
java ::= $java ' character ' ( append ) |
case ::= DOMAIN_SPECIFIC_CASE_LABEL : append |
throw ::= $throw |
tabular ::= $tabular { append , append } |
text ::= $text dataItem |
The meaning of these constructs is ...
The following list contains the combinators which create compound formatsordered by decreasing binding power:
The meaning of these constructs is ...
aggregateFormatDescription ::= name_of_an_aggregate
[
foldOperator
]
name_of_an_aggregate [ f1 foldOp f2 foldOp f3 ] name_of_an_aggregate [ f1 , f2 , f3 / fempty ] name_of_an_aggregate { formatDescription } [ foldOperator ] name_of_an_aggregate { formatDescription } [ f1 , f2 , f3 ] name_of_an_aggregate { formatDescription } [ f1 , f2 , f3 / fempty ] ... |
For values which are of an aggregate type code is generated to (1) recursively create formats for the components of the aggregate, and then (2) to combine these to one result format. Of course, the structure of these aggregates and the means for addressing them is again dependent on the instantiation. But the front-end syntax to specify the combination process is common:
The translation process for all these constructs is implemented in the code of <METATOOLS>/formatfrontends/GenericCompiler.
The class <METATOOLS>/formatfrontends/DynamicFormatter is used to generated format objects for java data dynamically . It is used by a call like ...
new formatfrontends.DynamicFormatter(aMessageReceiver) .format(model, formatcode) |
The formatcode is parsed at run-time, and a format object for pretty-printing the given model is created accordingly.
The instantiation of the specific part of the format front-end language (as described above) is done by the (informally given) definitions ...
All these objects references can serve as a DOMAIN_SPECIFIC_SWITCH_SELECTOR. Corresponding to its class, the DOMAIN_SPECIFIC_CASE_LABELs must be either String constants (for char and String data) or integer constants (for integer or boolean data; boolean is encoded using "0" for false and "1" for true).
Additionally you have some format generating expressions which do not address objects.
Additionally to the production for "aggregateFormatDescription" above, you have
aggregateFormatDescription ::= ...
name_of_a_map_field
[
f1
,
fmap
,
f2
,
f3
]
name_of_a_map_field [ f1 , fmap , f2 , f3 / fempty ] |
These constructs (with the addtional "fmap") must be used iff the field referred to is a map or a multimap. The format "fmap" is used as the separator between both sides of each map entry.
If you want to supply different formats for the same model, may be even interactively, you can split the described process by explicitly calling the two composed steps ...
final DynamicFormatter myFormatter = new DynamicFormatter(myMessageReceiver); Format result = myFormatter.visit(myFormatter.parseHint(myFormatCode)) |
Please refer to the api doc for further details.
The class <METATOOLS>format.FormatRepository provides means for caching dynamically generated format objects, as well as for writing them to disk and reloading them, for sake of efficiency.
The usage is explained in the API documentation.
[all pages:] introduction message / location / muli format dtd xantlr tdom ops paisley metajava umod option auxiliaries d2d downloads & licenses people bibliography APPENDICES:: white papers white papers 2 white papers 3 project struct proposal cygwin tips SOURCE:option.dtd SOURCE:dtd.umod DOC:deliverables.ddf DOC-DE:deliverables.ddf DOC:mtdocpage.ddf DOC-DE:mtdocpage.ddf SOURCE:basic.dd2 SOURCE:xslt.dd2
message / location / muli | bandm meta_tools | dtd |
made
2018-12-30_10h52 by
lepper on
linux-q699.site
produced with
eu.bandm.metatools.d2d
and
XSLT
FYI view
page d2d source text