** (Advanced)
** Models a PEG Rule.
**
** Rules are commonly created by using methods from the `Rules` mixin, but may be parsed from string patterns.
**
** `Rule` *may* sub-classed to create your own custom rules.
@Js
abstract class Rule {
** Creates a rule by parsing the given pattern:
**
** syntax: fantom
** Rule.fromPattern("[abc] / [xyz]")
**
** See `Peg.parseRule`
static new parseRule(Str pattern) {
PegGrammar().parseRule(pattern)
}
** The name of this rule, as defined by grammar.
**
** name <- foobar foobar
**
** Only rules with names (or labels) appear in debug output and the output tree, unless explicitly disabled.
**
** Should be a legal Fantom identifier (think variable names!).
virtual Str? name {
// internal set because only "Grammar definitions" should have names
// rules have labels, definitions have names.
// ideally we'd have a separate class for this
internal set {
// allow names to be programmatically re-set
if (it != null)
if (!it.chars.first.isAlpha || it.chars.any { !it.isAlphaNum && it != '_' && it != '-' })
throw ArgErr("Name must be a valid Fantom identifier: $it")
&name = it
}
}
** A label for this rule.
**
** someRule <- label:foobar foobar
**
** Note the same rule definition may have multiple / different labels when used in different parts of PEG grammar.
**
** Only rules with labels (or names) appear in debug output and the output tree, unless explicitly disabled.
**
** Should be a legal Fantom identifier (think variable names!).
virtual Str? label {
set {
// allow labels to be programmatically re-set
if (it != null)
if (!it.chars.first.isAlpha || it.chars.any { !it.isAlphaNum && it != '_' && it != '-' })
throw ArgErr("Label must be a valid Fantom identifier: $it")
&label = it
}
}
** Disable debugging of this rule if it gets too noisy.
virtual Bool debug := true
** Not all rules are useful in the parsed AST.
virtual Bool useInResult := true
** Override to implement Rule logic.
@NoDoc
abstract Bool doProcess(RuleCtx ctx)
** Returns the PEG expression for this rule (with any label definition). Example:
**
** label:[a-zA-Z0-9]
Str expression() {
_labelDis + _expression
}
** Returns the PEG definition for this rule. Example:
**
** alphaNum <- [a-zA-Z0-9]
Str definition() {
if (name == null) return expression
ex := name
if (!useInResult) ex = "-" + ex
if (!debug) ex = ex + "-"
return "${ex} <- ${expression}"
}
** A helpful builder method for setting the label.
**
** someRule <- label:foobar foobar
**
** Note the same rule definition may have multiple / different labels when used in different parts of PEG grammar.
**
** Only rules with labels (or names) appear in debug output and the output tree.
**
** Should be a legal Fantom identifier (think variable names!).
This withLabel(Str? label) {
this.label = label
return this
}
** A helpful builder method for turning debug off.
**
** In PEG grammar, rules are excluded from debug by add a hyphen suffix to the declaration.
**
** noDebugRule- = foobar foobar
This debugOff() {
this.debug = false
return this
}
** A helpful builder method for removing this rule from tree results.
**
** In PEG grammar, rules are excluded from results by add a hyphen prefix to the declaration.
**
** -excludedRule = foobar foobar
This excludeFromResults() {
this.useInResult = false
return this
}
** Matches this rule against the given string.
**
** See `Peg.match`
Match? match(Str str) {
Peg(str, this).match
}
@NoDoc
virtual Str typeName() {
// if converting doProcess() to processFn then THIS method will need to be converted to another field
name := typeof.name.decapitalize
return name.endsWith("Rule") ? name[0..<-4] : name
}
@Operator @NoDoc
virtual This add(Rule rule) {
throw Err("${typeof.qname} does not support add()")
}
** Returns the PEG expression for this rule. Example:
**
** [a-zA-Z0-9]
@NoDoc
abstract Str _expression()
@NoDoc
internal Str _dis() {
dis := name == null && (this is SequenceRule || this is FirstOfRule)
? "(" + _expression + ")"
: (name ?: _expression)
return _labelDis + dis
}
@NoDoc
internal Str _labelDis() {
label == null ? "" : label + ":"
}
@NoDoc
override Str toStr() { definition }
}