# EFTL language reference

This is a compact index derived from the documents currently under `docs/`. Re-check the PDFs when exact wording, diagrams, or edge behavior matters.

## Documentation map

- `elixForms_Doc_EFTL.pdf`: EFTL specification through the documented 3.1.0 changes, language behavior, attributes, control flow, and examples.
- `elixForms_EFTLParser_syntax_rels.pdf`: generated lexer/parser relationship diagrams.
- `elixForms_TAG_Sintassi.pdf`: positional syntax for the ElixForms `SCHEMAID` and `GETVALUEBYTAG` plugins.

## Common lexical and structural rules

- EFTL uses square-bracket tags and requires properly nested, non-overlapping elements.
- A bodyless element ends with `/]`; a block has matching opening and closing tags.
- Attribute values are quoted. Attribute order is not semantically significant.
- The main specification says uppercase and lowercase tag spellings are interpreted equally and recommends lowercase style. The current implementation is largely uppercase-only.
- Text outside `[EFTL]...[/EFTL]` is not processed. Text inside an EFTL root but outside an executable tag is emitted as user text where the grammar permits it.
- Comments use `[!-- ... --]` and may span lines.
- The generated relationships include user text, ignored whitespace, CDATA, headers, comments, statements, code blocks, and output blocks. Consult the diagram PDF before enforcing a new parent/child restriction.

## Root, directives, and context

| Construct | Form | Key rules |
| --- | --- | --- |
| EFTL | `[EFTL] ... [/EFTL]` | Root block; no documented attributes; a document needs at least one root to be processed. |
| HEADER | `[HEADER name="..." value="..." type="..." /]` | Declares a directive. The documented directive is `trimDocument`, with boolean `true` or `false`. |
| LOG | `[LOG] ... [/LOG]` | Writes evaluated content to the server log; no documented attributes. |

Predefined execution-context names include `currentDateTime`, `defaultLocale`, `currentLocale`, and `requestId`. Other values may be supplied by the calling service.

## Variables and value functions

| Construct | Form | Key rules |
| --- | --- | --- |
| VAR | `[VAR name="..." type="..." unique="..." ] ... [/VAR]` | `name` identifies a context variable. Documented types: `string`, `boolean`, `number`, `date`, `object`, `iterable`. `unique` defaults to `false` and is meaningful only for `iterable`. |
| VALUE_OF | `[VALUE_OF varname="..." index="..." /]` | Emits a variable value. `index` identifies the position for an iterable and may name another variable. |
| SIZE_OF | `[SIZE_OF varname="..." /]` | Returns iterable size, otherwise `0`. |
| IS_EMPTY | `[IS_EMPTY varname="..." /]` | Tests missing, null, blank string, empty iterable, or empty map according to the documented rules. |
| IS_NOT_EMPTY | `[IS_NOT_EMPTY varname="..." /]` | Logical negative of `IS_EMPTY`. |
| CONTAINS | `[CONTAINS varname="..." value="..." /]` or `[CONTAINS varname="..."] ... [/CONTAINS]` | Supports string or iterable input. Attribute `value` and body are alternatives; `value` has priority when both exist. |

Do not require `type` merely because current examples commonly include it: some examples omit it. Resolve requiredness from the parser relations or runtime contract before emitting an error.

## Transformations

| Construct | Form | Key rules |
| --- | --- | --- |
| FORMAT | `[FORMAT varname="..." type="..." /]` or `[FORMAT type="..." pattern="..."] ... [/FORMAT]` | `varname` takes precedence over the body. Documented formatting covers number and date families; number modes include currency, integer, double, percent, and generic. |
| SPLIT | `[SPLIT regex="..." emptyIfBlank="true|false"] ... [/SPLIT]` | Applies a valid regular expression to a string result. `emptyIfBlank` defaults to `false`. An invalid regex is a runtime parsing error and can be checked statically only for a literal. |
| TRIM | `[TRIM varname="..." /]` or `[TRIM] ... [/TRIM]` | Trims a named variable or evaluated body. A found variable takes precedence; otherwise the body is evaluated. |

## Control structures

- IF shape: `[IF] [CONDITION] ... [/CONDITION] [THEN] ... [/THEN] { [ELSE IF] ... [/ELSE IF] } [ELSE] ... [/ELSE] [/IF]`.
- `CONDITION` must evaluate to boolean. There may be multiple `ELSE IF` blocks and at most one final `ELSE`; both are optional.
- WHILE shape: `[WHILE ...] [CONDITION] ... [/CONDITION] [DO] ... [/DO] [/WHILE]`.
- The WHILE section documents an optional `threshold` with default and maximum `32766`, but also contains a sentence saying the tag has no attributes. Treat this as an explicit documentation inconsistency.
- FOR shape: `[FOR varName="item" iterable="items"] ... [/FOR]`. The loop variable exists during the loop and is removed afterward.
- The FOR prose depends on both `varName` and `iterable`, but the generated relationship only shows a generic attribute node. Treat formal requiredness, attribute-name casing, duplicate/unknown attributes, null or non-iterable input, and shadowing as unresolved until confirmed against the runtime grammar.

## Code blocks

| Kind | Form | Meaning |
| --- | --- | --- |
| Assignment | `[% target = expression; ... %]` | Mutates variables; documented statements end with `;`. |
| Evaluation | `[% expression %]` | Evaluates and returns a result, often boolean in `CONDITION`. |
| Output | `[%= variable %]` | Writes a context variable; a missing variable is a runtime error. |

The expression language examples use assignment, equality/comparison, arithmetic, boolean operators, strings, numbers, booleans, and `null`. The PDFs do not provide a complete operator-precedence grammar; avoid inventing one without a runtime grammar source.

## ElixForms TAG payloads

`SCHEMAID` is positional:

- position 0: plugin name `SCHEMAID`;
- position 1: schema ID;
- position 2: column reference;
- position 3: `IUQOID`;
- position 4: line terminator, with a space selecting the default;
- position 5: column separator;
- position 6: default value;
- position 7: date/time formatter;
- position 8: language (documented as currently unused).

Positions 0 through 4 must be present. Preserve commas for omitted intermediate optional positions.

`GETVALUEBYTAG` is positional:

- position 0: plugin name `GETVALUEBYTAG`;
- position 1: tag name;
- position 2: lookup type: `REQUEST`, `MODULE`, or `USER_PROFILE`;
- position 3: `IUQOID`;
- position 4: weight/order option;
- position 5: column separator;
- position 6: format string.

The weight list in the prose and the final syntax example differ in spelling and membership (`UPDATED_FIST`/`UPDATED_FIRST`, `UPDATE_LAST`/`UPDATED_LAST`, and `CONCAT`). Treat exact validation as ambiguous until confirmed against the TAG runtime.

## Known implementation delta at skill creation

The current TypeScript tokenizer/parser does not yet model all documented constructs. Notably absent or incomplete are `LOG`, `FOR`, `IS_EMPTY`, `IS_NOT_EMPTY`, case-insensitive spellings, structural ordering inside IF/WHILE, attribute validation beyond VAR type, and full expression parsing. Re-check source before relying on this list because it is expected to shrink as the linter evolves.
