Skip to content

Group

A Group is a parenthesised sub-formula with an outer multiplicity. Bracket variants are preserved: (, [, {.

FieldTypeSourceExample
nodesArray of Nodeinside the bracketsOH
multiplicityStringsuffix _N2
bracketSymbolthe bracket chars:paren, :square, :brace
KindOpen / CloseUse
:paren( )Generic grouping (Ca(OH)_2)
:square[ ]Coordination complexes ([Fe(CN)_6]^4-)
:brace{ }Rare / optional
┌───────────────────────┐
open_bracket ───►│ Group │
│ │
│ nodes[0] ──┐ │
│ nodes[1] ──┤ │
│ ... │ │
│ │ │
close_bracket ──►│ multiplicity ─── `_N`│
│ bracket ─────── which kind
└───────────────────────┘
group := group_open nodes group_close multiplicity?
nodes := node+
group_open := "(" | "[" | "{"
group_close:= ")" | "]" | "}"
multiplicity := "_" digits

The grammar preserves which bracket was used; the model’s bracket field carries it through.

FormatterBracketsMultiplicity
MathML<mo>(</mo> / <mo>)</mo> around inner<msub> wrapping the inner <mrow>
TextLiteral bracket chars preserved_N suffix
HTMLLiteral bracket chars<sub>N</sub>
LaTeXmhchem bracket chars_N (bare digits)
SVGLiteral bracket chars_N suffix
AsciiChem.parse("Ca(OH)_2").to_text # => "Ca(OH)_2"
AsciiChem.parse("[Fe(CN)_6]^4-").to_text # => "[Fe(CN)_6]^4-" (square preserved)
AsciiChem.parse("{CH_3}").to_text # => "{CH_3}" (brace preserved)

Bracket kind is preserved exactly — (OH)_2 stays as (OH)_2, not canonicalised to [OH]_2.

class Group
def children
nodes
end
end

The linter’s BalanceCheck recurses into groups, applying the multiplicity to the inner atom counts.

  • BracketBalanceCheck — verifies bracket field matches the stored open/close characters. Defensive depth — the grammar already enforces matching pairs, but direct model construction might not.