Table of Contents
Tiny v2
Tiny v2 consists of a list of hierarchical sections. Every line starts a new section, whether it continues an existing section is determined by the indentation level. A section's parent is always the closest preceding section indented once less than itself. Accordingly, a section ends just before the next line with the same or a lesser indentation level.
The child-to-parent relationships form the paths to uniquely identify any element globally. For example, all field and method sections that are children of a class section represent members of the represented class.
Sections need to be unique within their level. For example a specific class may only be recorded once, a comment can't be redefined or the same parameter listed twice.
Example:
tiny 2 0 official intermediary named someProperty someValue anotherProperty c a class_123 pkg/SomeClass f [I a field_789 someField m (III)V a method_456 someMethod p 1 param_0 x p 2 param_1 y p 3 param_2 z c Just a method for demonstrating the format. c b class_234 pkg/xy/AnotherClass m (Ljava/lang/String;)I a method_567 anotherMethod
Grammar
<file> ::= <header> | <header> <content> <header> ::= 'tiny' <tab> <major-version> <tab> <minor-version> <tab> <namespace-a> <tab> <namespace-b> <extra-namespaces> <eol> <properties> <major-version> ::= <non-negative-int> <minor-version> ::= <non-negative-int> <namespace-a> ::= <namespace> <namespace-b> ::= <namespace> <extra-namespaces> ::= '' | <tab> <namespace> <extra-namespaces> <namespace> ::= <safe-string> <properties> ::= '' | <tab> <property> <eol> <properties> <property> ::= <property-key> | <property-key> <tab> <property-value> <property-key> ::= <safe-string> <property-value> ::= <escaped-string> <content> ::= '' | <class-section> <content> <class-section> ::= 'c' <tab> <class-name-a> <tab> <class-name-b> <extra-ns-class-names> <eol> <class-sub-sections> <class-name-a> ::= <class-name> <class-name-b> ::= <optional-class-name> <optional-class-name> ::= '' | <class-name> <extra-ns-cls-names> ::= '' | <tab> <optional-class-name> <extra-ns-class-names> <class-name> ::= <conf-safe-string> <class-sub-sections> ::= '' | <class-comment-section> <class-sub-sections> | <field-section> <class-sub-sections> | <method-section> <class-sub-sections> <field-section> ::= <tab> 'f' <tab> <field-desc-a> <tab> <field-name-a> <tab> <field-name-b> <extra-ns-field-names> <eol> <field-sub-sections> <field-name-a> ::= <field-name> <field-name-b> ::= <optional-field-name> <optional-field-name> ::= '' | <field-name> <extra-ns-field-names> ::= '' | <tab> <optional-field-name> <extra-ns-field-names> <field-name> ::= <conf-safe-string> <field-desc-a> ::= <field-desc> <field-desc> ::= <conf-safe-string> <field-sub-sections> ::= '' | <member-comment-section> <field-sub-sections> <method-section> ::= <tab> 'm' <tab> <method-desc-a> <tab> <method-name-a> <tab> <method-name-b> <extra-ns-method-names> <eol> <method-sub-sections> <method-name-a> ::= <method-name> <method-name-b> ::= <optional-method-name> <optional-method-name> ::= '' | <method-name> <extra-ns-method-names> ::= '' | <tab> <optional-method-name> <extra-ns-method-names> <method-name> ::= <conf-safe-string> <method-desc-a> ::= <method-desc> <method-desc> ::= <conf-safe-string> <method-sub-sections> ::= '' | <member-comment-section> <method-sub-sections> | <method-parameter-section> <method-sub-sections> | <method-variable-section> <method-sub-sections> <method-parameter-section> ::= <tab> <tab> 'p' <tab> <lv-index> <tab> <var-name-a> <tab> <var-name-b> <extra-ns-var-names> <eol> <method-parameter-sub-sections> <var-name-a> ::= <optional-var-name> <var-name-b> ::= <optional-var-name> <optional-var-name> ::= '' | <var-name> <extra-ns-var-names> ::= '' | <tab> <optional-var-name> <extra-ns-var-names> <var-name> ::= <conf-safe-string> <lv-index> ::= <non-negative-int> <method-parameter-sub-sections> ::= '' | <var-comment-section> <method-parameter-sub-sections> <method-variable-section> ::= <tab> <tab> 'v' <tab> <lv-index> <tab> <lv-start-offset> <tab> <optional-lvt-index> <tab> <var-name-a> <tab> <var-name-b> <extra-ns-var-names> <eol> <method-variable-sub-sections> <lv-start-offset> ::= <non-negative-int> <optional-lvt-index> ::= '-1' | <lvt-index> <lvt-index> ::= <non-negative-int> <method-variable-sub-sections> ::= '' | <var-comment-section> <method-variable-sub-sections> <comment> ::= <escaped-string> <class-comment-section> ::= <tab> 'c' <tab> <comment> <eol> <member-comment-section> ::= <tab> <tab> 'c' <tab> <comment> <eol> <var-comment-section> ::= <tab> <tab> <tab> 'c' <tab> <comment> <eol>
Notes
<tab>
is\t
.<eol>
is\n
or\r\n
.<safe-string>
is a non-empty string that must not contain:\
,\n
,\r
,\t
or\0
.
<conf-safe-string>
is the same as<safe-string>
if<properties>
doesn't contain a<property>
escaped-names
, otherwise it's a non-empty string further described by<escaped-string>
.<escaped-string>
is a string that must not contain an<eol>
, escapes\
to\\
and the other forbidden values to their string literal equivalents, as seen in the list above.<non-negative-int>
is any integer from 0 to 2147483647 (2^31-1) inclusive, represented as perjava.lang.Integer.toString()
.<class-name>
, once optionally unescaped, is the binary name of a class as specified in JVMS SE 8 §4.2.1. Nested class identifiers are typically separated with$
(e.g.some/package/class$nested$subnested
). Outer names must not be omitted for any namespace.<field-name>
/<method-name>
/<var-name>
, once optionally unescaped, is the unqualified name of a field/method/variable as specified in JVMS SE 8 §4.2.2.<field-desc>
, once optionally unescaped, is a field descriptor as specified in JVMS SE 8 §4.3.2.<method-desc>
, once optionally unescaped, is a method descriptor as specified in JVMS SE 8 §4.3.3.<lv-index>
refers to the local variable array index of the frames having the variable, see “index” in JVMS SE 8 §4.7.13.<lv-start-offset>
is at most the start of the range in which the variable has a value, but doesn't overlap with another variable with the same<lv-index>
, see “start_pc” in JVMS SE 8 §4.7.13. The start offset/range for Tiny v2 is measured in instructions with a valid opcode, not bytes.<lvt-index>
is the index into the LocalVariableTable attribute'slocal_variable_table array
, see “local_variable_table” in JVMS SE 8 §4.7.13, not to be confused with “index” referred by<lv-index>
.
Miscellaneous Notes
- The encoding for the entire file is UTF-8. Escape sequences are limited to the types, locations and conditions mentioned above.
- Indenting uses tab characters exclusively, one tab character equals one level. The amount of leading tab characters is at most 1 more than in the preceding line.
- Sections or properties with unknown types/keys should be skipped without generating an error.
- The amount of extra namespaces defined in the header and the amount of names in every
extra-ns-*-names
definition have to match. They are associated by their relative position, like the mandatory name spacesa
andb
that are associated by the suffix, e.g.namespace-a
coversclass-name-a
,field-name-a
,field-desc-a
,method-name-a
,method-desc-a
andvar-desc-a
,. - Sections representing the same element must not be repeated, e.g. there can be only one top-level section for a specific class or one class-level section for a specific member.
- If any variable mapping doesn't specify a LVT index, e.g. due to a missing
LocalVariableTable
attribute in one of the methods, the propertymissing-lvt-indices
has to be added to. - Mappings without any (useful) names should be omitted.
- Sections without any (useful) mappings or sub-sections should be omitted.
- Comments should be without their enclosing syntax elements, indentation or decoration. For example, the comment
/** * A comment * on two lines. */
(note the indentation) should be recorded as
A comment<eol>on two lines.
Standard Properties
escaped-names
: deserialize values with unescapingmissing-lvt-indices
: expect local variable mappings without a lvt-index value