AEON v1 Structure Syntax Reference
Scope: key syntax, structural identities, attributes, datatype clarifiers, list/tuple separators, and newline behavior.
1. Binding Shape
Canonical binding surface:
key\identity\@{attributes}:type = value
Transport form may omit attributes and datatype:
key = value
Strict form requires datatype presence, but not generic arguments:
name:string = "AEON"
items:list = ["a", "b"]
point:tuple = (1, 2)
Core grammar summary:
Grammar productions: Binding ::= Key StructuralIdentity? Attribute? TypeAnnotation? "=" Value.
Grammar productions: StructuralIdentity ::= "\\" StructuralIdentityName "\\".
Grammar productions: Attribute ::= "@{" AttributeEntryList? "}"; AttributeEntryList ::= AttributeEntry (AttributeSep AttributeEntry)* AttributeSep?; AttributeEntry ::= Key StructuralIdentity? Attribute? TypeAnnotation? "=" Value; AttributeSep ::= "," | Newline.
Grammar productions: TypedValue ::= StructuralIdentity? Attribute? TypeAnnotation? "=" Value; TypeAnnotation ::= ":" TypeName GenericArgs? Clarifier?.
Grammar productions: Clarifier ::= "[" ClarifierValue ("," ClarifierValue)* "]"; ClarifierValue ::= StringLiteral | NumberLiteral.
Nuances:
canonical order is
key\id\@{...}:type = value;reversed order such as
key:type@{...} = valueis not Core v1 canonical syntax;structural identity, when present, appears before attributes and datatype;
attributes may appear without datatype;
datatype may appear without attributes.
TypedValueis valid only in anonymous value-element contexts: list elements, tuple elements, and node children.TypedValueis not a binding head and MUST NOT appear whereBindingorAttributeEntryis expected.the datatype on
TypedValueannotates only the immediate followingValue; nested:type = :type = valueforms are invalid.*...*is reserved for out-of-band preprocessing and templating conventions, but it is not part of Core v1 syntax.Core parsers must continue to fail closed if a
*...*placeholder reaches AEON parsing unchanged.A preprocessor may replace
*...*spans before AEON parsing, but that substitution occurs outside the Core language contract.
Informative parser-context illustrations are available in appendices/appendix-grammar-flow.
2. Keys
2.1 Supported Key Forms
Valid key forms in all key positions:
user = 1
'user name' = 2
"a.b" = 3
Unsupported as core keys:
`user` = 1
Key grammar:
Grammar productions: Key ::= Identifier | SingleQuotedKey | DoubleQuotedKey; Identifier ::= IdentifierStart IdentifierContinue*; IdentifierStart ::= "A".."Z" | "a".."z" | "_"; IdentifierContinue ::= IdentifierStart | "0".."9".
Nuances:
bare keys are best used when the key is identifier-safe;
boolean and toggle literal words (
true,false,yes,no,on,off) are valid bare keys in key, attribute-key, tag, and path-segment contexts; they are literals only in value contexts;quoted keys are required for spaces, dots-as-data, and other non-bare characters;
single and double quotes are both valid key delimiters;
quoted keys must not be empty;
backtick-quoted keys are not part of AEON Core v1 key syntax.
asterisk-delimited placeholder forms such as
*secret-key*are reserved for preprocessors and remain invalid as Core keys or Core values until replaced before parsing.
Canonical notes:
canonical paths render non-bare keys using bracketed double-quoted form, for example
$.["a.b"];'a.b'and"a.b"are the same key identity when parsed as keys.
AES notes:
key form is structural and does not create a distinct value kind;
canonical path identity uses member and index segments only.
3. Structural Identities
Structural identity is an optional occurrence identity attached to a binding head or anonymous value head. It lets tools preserve an author-visible identity for a specific structural occurrence even when position, surrounding comments, or formatting change.
person\person-1\:object = {
name\name-1\:string = "Ada"
}
items:list = [
\item-1\:string = "red",
\item-2\@{source:string = "user"}:string = "green"
]
Grammar:
Grammar productions: StructuralIdentity ::= "\\" StructuralIdentityName "\\"; StructuralIdentityName ::= StructuralIdentityChar+; StructuralIdentityChar ::= "A".."Z" | "a".."z" | "0".."9" | "_" | "-".
Nuances:
structural identities are source metadata, not values;
structural identities are optional in both transport and strict form;
structural identities are valid on ordinary bindings, attribute entries, node heads, and anonymous child heads;
structural identities are invalid as standalone scalar values;
document-level structural identity values must be unique;
structural identity appears before attributes and datatype:
key\id\@{...}:type = value;structural identity after attributes, for example
key@{...}\id\:type = value, is invalid;structural identity syntax inside quoted strings is ordinary string content.
Canonical notes:
canonical rendering preserves structural identities in head position;
structural identity does not change canonical path identity;
structural identity is preserved in AST/AES metadata for tools that need stable occurrence identity across rewrites.
4. Attributes
Attributes attach opaque metadata to a binding or node head:
user@{role="admin", level=5} = {
id = 1
}
content = <span@{id="text", class="dark"}("hello")>
Grammar:
Grammar productions: Attribute ::= "@{" AttributeEntryList? "}"; AttributeEntryList ::= AttributeEntry (AttributeSep AttributeEntry)* AttributeSep?; AttributeEntry ::= Key Attribute? TypeAnnotation? "=" Value; AttributeSep ::= "," | Newline.
Nuances:
attribute entries are key/value pairs;
attribute entry heads may themselves carry attributes;
attribute entry datatypes are allowed;
attribute containers may be empty:
@{};attribute entry separators may be commas or newlines;
trailing attribute separator is accepted by current parser behavior.
binding-attached attributes are valid on any binding head, including bindings whose values are objects, lists, tuples, or other literals;
postfix literal attributes are not part of Core v1 syntax:
a = [0]@{b=2}is invalid and fails closed;nested bindings inside container values may carry their own attributes, for example
a = [{x@{b=0}=1}].nested attribute heads are part of Core v1 and count against
max_attribute_depth.duplicate keys inside one attribute block are invalid and fail closed;
repeated nested attribute heads on the same attribute entry are invalid; use one nested attribute block with multiple entries instead.
Reference/addressing forms:
~user.@.role
$.user.@.role
$.user.@.["profile.name"]
$.user.@.["profile.name"].["display.name"]
~user.@.meta.["x.y"]
Canonical notes:
attributes are selectors in addressing expressions, not canonical path identity segments;
data namespace and attribute namespace remain distinct.
quoted bracket member segments may follow ordinary member or attribute traversal using
.[\"...\"].quoted attribute selectors may be followed by ordinary member, quoted member, or index traversal.
empty quoted member segments, empty quoted attribute selectors, and incomplete forms such as
~a.@or~$.a.@.[are invalid.
Examples:
a@{b=1} = [0]
a = [{x@{b=0}=1}]
f@{ns@{origin:string="core"}:string = "aeon"}:string = "fractal"
Rejected examples:
a@{x=1, x=2} = 3
a@{x@{y=1}@{z=2} = 3} = 4
x = { @{meta=1} k = 2 }
Namespace note:
AEON Core v1 has no dedicated namespace syntax for ordinary keys;
#has no intrinsic namespace meaning in core key syntax;when a consumer or ecosystem convention needs namespace labeling, the recommended metadata convention is
@{ns="..."}as defined byaeon.gp.convention.v1:
key@{ns="aeon"} = "value"
Policy notes:
implementations expose
max_attribute_depth;default lock is
1;capability floor is at least
8.
5. Datatype Clarifiers
Datatype clarifiers decorate type annotations:
size:sep["x"] = ^300x250
triple:sep["x", "y", "z"] = ^100x200y300z
semver:kadot = ^3.14.15
Grammar:
Grammar productions: TypeAnnotation ::= ":" TypeName GenericArgs? Clarifier?; Clarifier ::= "[" ClarifierValue ("," ClarifierValue)* "]"; ClarifierValue ::= StringLiteral | NumberLiteral.
Generic-depth notes:
Core v1 reserves generic arguments for
list<T>,tuple<T...>,object<T>,node<T>,null<T>,nan<T>, andinfinity<T>;binding-side
node<T>acceptsT = nodeor custom profile/domain/materialization arguments, but rejects reserved non-nodevalue datatype arguments such asstring;other reserved Core datatypes do not accept generic arguments;
generic depth counts nested type annotations that appear inside generic arguments;
tuple<n, n>has generic depth0;tuple<tuple<n, n>, tuple<n, n>>has generic depth1;tuple<tuple<tuple<n, n>, n>, n>has generic depth2;implementations expose
max_generic_depth;default runtime lock is
1;capability floor is at least
8.
Current official v1 rules:
a datatype may carry at most one clarifier list;
a clarifier list must contain one or more string or numeric values;
string clarifier values use ordinary AEON quoted string syntax;
numeric clarifier values use ordinary AEON number literal syntax;
clarifier value depth is the number of values in the list;
repeated bracket lists such as
sep["x"]["y"]are invalid.only ASCII space, tab, carriage return, and newline act as layout whitespace in Core v1 grammar positions unless another rule says otherwise;
non-structural Unicode separators and joiners such as U+2060 WORD JOINER, U+2028 LINE SEPARATOR, and U+2029 PARAGRAPH SEPARATOR are not document, object, list, tuple, or attribute separators.
Nuances:
size:sep["x"]has separator depth1;triple:sep["x", "y", "z"]has separator depth3;semver:kadothas separator depth0;sep["x"],sep[ "x" ], andsep[\n"x"\n]are legal;sep[x]is invalid because string clarifier values must be quoted;multiple clarifier values are preserved in order, including duplicates;
unparameterized
sepdatatypes may still bind separator literals;unparameterized
kadotdatatypes may bind separator literals; Core does not enforce the dot-separated numeric shape;separator payloads are compact tokens introduced by
^;outside quoted string segments, raw separator payload characters are limited to
A-Za-z0-9!#$%&*+-.:;=?@^_|~<>;quoted segments use ordinary single-quoted or double-quoted AEON string lexical rules;
backtick segments and raw separator escapes are not part of separator-literal syntax;
outside quoted segments, whitespace,
\\,/,,, newline, or a closing container boundary end or invalidate the token depending on surrounding grammar;U+2060, U+2028, and U+2029 do not act as interchangeable layout whitespace or newline tokens in those positions and therefore fail closed when inserted there;
default runtime lock is
1;capability floor is at least
8.
Canonical notes:
datatype clarifiers remain attached to the datatype surface;
AEON Core parses datatype clarifiers but does not assign type-specific meaning to their values. Profiles and AEOS decide whether a clarifier is supported, compatible, or semantically useful.
aeon.gp.profile.v1treats its datatype-semantic clarifier rules as closed: undeclared datatype clarifiers fail,noneentries reject explicit clarifiers,radix_baserequires exactly one integral numeric value from2through64,separator_charsrequires string values, andencoding_namerequires exactly one string value.
6. Assignment and Element Separators
6.1 Top-Level and Object Bindings
At document and object level, bindings may be separated by newline or comma:
a = 1
b = 2
a = 1, b = 2
obj = { a = 1, b = 2 }
Core v1 rules:
newline and comma are structural binding separators at document and object level;
plain spaces alone are never structural separators;
;is not a structural separator.
6.2 Lists
List examples:
items = ["a", "b", "c"]
items = [
"a"
"b"
"c"
]
Grammar summary:
Grammar productions: List ::= "[" (ListElement ListSep?)* "]"; ListElement ::= Value | TypedValue; ListSep ::= "," | Newline.
Nuances:
list elements may be separated by commas or newlines;
mixed comma/newline list formatting is accepted by parser behavior;
indexed elements are addressable as
[0],[1], and so on.anonymous typed/headed elements use
\id\@{...}:type = valueand do not introduce keys or reorder elements.
6.3 Tuples
Tuple examples:
point = (1, 2)
point = (
1
2
)
Grammar summary:
Grammar productions: Tuple ::= "(" (TupleElement TupleSep?)* ")"; TupleElement ::= Value | TypedValue; TupleSep ::= "," | Newline.
Nuances:
tuple elements follow the same separator surface as lists;
tuple semantics differ from list semantics, but the element separator grammar is the same.
anonymous typed/headed tuple elements use
\id\@{...}:type = value; the head metadata is local to that element.
6.4 Node Children
Node child separators follow the same broad rule:
content = <div("hello", <br>, "world")>
content = <div(
"hello"
<br>
"world"
)>
icon = <glyph>
Grammar summary:
Grammar productions: Node ::= "<" Identifier StructuralIdentity? Attribute? TypeAnnotation? ( ">" | "(" (NodeChild NodeSep?)* ")" ">" ); NodeChild ::= Value | TypedValue; NodeSep ::= "," | Newline.
Nuances:
node children accept comma and newline separators;
anonymous typed/headed node children use
\id\@{...}:type = value; the head metadata is local to the immediate child value;empty-node shorthand uses
>immediately after the tag metadata and is equivalent to an empty child list;child-bearing nodes require a closing
>after the closing);canonical printed form uses the closing
>and prefers<tag>over<tag()>for empty nodes;node heads MAY carry an inline datatype syntactically, but strict mode limits this form to
:node;node heads MAY carry
:node<T>; this is a preserved child-content claim and Core does not validate children againstT;transport/custom forms MAY use other inline node-head datatypes, for example
<tag:pair("x", "y")>;generic inline node-head datatypes other than
:node<T>remain invalid Core v1 syntax;trailing child separator acceptance is implementation-supported and documented in node appendices.
6. Newline Rules
Newlines are structural in AEON, but only in specific places.
Between structural tokens, a newline is otherwise treated the same as ordinary inter-token whitespace. A newline becomes special only when the surrounding grammar consumes it as a separator, or when inserting it would split a compact token that must remain contiguous.
6.1 Newline as Separator
Newline can separate:
bindings in documents and objects;
list elements;
tuple elements;
attribute entries;
node children.
6.2 Newline Forbidden in Compact Tokens
Newline is not allowed inside:
bare identifiers;
single-quoted or double-quoted keys;
single-quoted or double-quoted strings;
datatype clarifiers (
["x"],[16], or["x", "y"]);numbers;
hex, radix, encoding, date, datetime, and separator literal tokens.
Notes:
backtick strings may span newlines as string values, but backtick keys are not valid core keys;
trimticks are multiline string values introduced by a contiguous
>through>>>>marker immediately before a backtick string opener;trimticks trim the first empty line, trailing empty lines, and common left indentation according to the marker's tab policy;
separator literals are compact tokens; outside quoted string segments they terminate at the first character that is not valid raw separator payload or at an enclosing grammar boundary.
for worked boundary examples, see
appendices/appendix-whitespace-boundaries.
6.3 Comments and Newlines
Comments do not become separators by themselves.
Implications:
a structured or plain comment may appear between bindings or elements;
comment binding rules determine attachment, but comments do not redefine the surrounding grammar;
line comments end at newline;
block comments may span newlines.
7. Addressing Interaction
Key and attribute syntax affects addressing and references:
"a.b" = 2
ref0 = ~"a.b"
ref1 = ~["a.b"]
ref2 = ~$.["a.b"]
user@{"profile.name"="dark"} = 1
ref3 = ~user.@.["profile.name"]
Nuances:
~a.bmeans traversal through two member segments;~"a.b"and~["a.b"]are equivalent initial quoted-member forms;~["a.b"]means one quoted member segment;.@.keyand.@.["key"]both address attribute namespace segments.
8. Minimum Conformance Reminders
Implementations targeting Core v1 must at minimum:
accept bare, single-quoted, and double-quoted keys;
reject backtick keys;
expose
max_attribute_depthandmax_separator_depth;support capability floor
>=8for both depth knobs;enforce the official separator-char exclusions;
handle newline/comma binding separation deterministically;
reject space-only and semicolon binding separation deterministically.