abstract class
Analyzer::Cfml::CfmlEngine
- Analyzer::Cfml::CfmlEngine
- Analyzer
- Reference
- Object
Overview
Shared CFML parsing layer.
See AGENTS.md §"Analyzer Layering": this owns file selection and the syntax handling every CFML adapter needs, so framework analyzers (Taffy, ColdBox, Wheels, FW/1) consume components and functions rather than re-implementing tag/script parsing.
The two syntaxes are the whole problem. CFML is written either as
tags (<cffunction name="x" access="remote">) or as cfscript
(remote string function x()), the two mix inside a single file, and
everything is case-insensitive.
Direct Known Subclasses
- Analyzer::Cfml::Coldbox
- Analyzer::Cfml::Fw1
- Analyzer::Cfml::Pure
- Analyzer::Cfml::Taffy
- Analyzer::Cfml::Wheels
Defined in:
analyzer/engines/cfml_engine.crConstant Summary
-
CFARGUMENT_TAG_RE =
/<cfargument\b([\s\S]*?)>/i -
CFCOMPONENT_TAG_RE =
/<cfcomponent\b([\s\S]*?)>/i -
Tags may span lines and pad their
=for alignment, so attributes are matched with\s*=\s*and tag bodies with[\s\S]*?. -
CFFUNCTION_TAG_RE =
/<cffunction\b([\s\S]*?)>/i -
HTTP_VERBS =
Set {"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"} -
Verbs a CFML framework can register. Route DSLs take verbs as free text, so a value outside this set is not turned into a method.
-
NAMED_ARGUMENT_RE =
/\A([A-Za-z_]\w*)\s*[:=]\s*(.+)\z/m -
SCRIPT_COMPONENT_HEADER_LIMIT =
2000 -
A component header is a handful of attributes; bound the scan so a file with no opening brace cannot walk the whole content.
-
SCRIPT_COMPONENT_RE =
/(?<![\w.])component\b/i -
component ... {header in script syntax, and a function declaration with its trailing attribute list up to the body brace. -
SCRIPT_FUNCTION_RE =
/(?<![\w.])function\s+(\w+)\s*\(/i -
SPLIT_ARGUMENTS_RULES =
Noir::TopLevelSplit::Rules.new(nest: (Noir::TopLevelSplit::Nest::Paren | Noir::TopLevelSplit::Nest::Bracket) | Noir::TopLevelSplit::Nest::Brace, quotes: "\"'", escape: Noir::TopLevelSplit::Escape::None, strip: true, empties: Noir::TopLevelSplit::Empties::DropAll, per_kind: false, clamp: false) -
Rules::JAVAwithEmpties::DropAlland, like erlang/cowboy.cr and php/wordpress.cr, WITHOUT clamping: the body this replaces closed brackets with a baredepth -= 1, so an argument slice that opens on a closer drives depth negative and suppresses every later split. Observable on the unbalanced fragments the CFML regexes hand over, so it is preserved rather than normalised.Escape::Nonebecause CFML has no backslash escape at all."C:\log\"is the seven-character stringC:\log\, and a quote is escaped by DOUBLING it ("say ""hi"""). Reading\as an escape — which the hand-rolled body this replaced did, and which the rest of this engine did too until the same change — swallowed the closing quote of any string ending in a backslash, i.e. any Windows path, leaving the run open so the remainder of the argument list merged into the current part and every argument after it was lost.There is deliberately no doubled-quote mode for the OTHER half of the rule, and that is not an oversight. For a top-level splitter "a repeated delimiter is a literal delimiter" and "quotes toggle" are indistinguishable: a doubled pair is two ADJACENT quote characters, so the toggling model's spurious closed-then-reopened window is zero characters wide. The state after any maximal run of quotes is the same under both models (a run of length L flips the state iff L is odd either way), and the only characters ever processed in a differing state are the quote characters themselves, which neither nest nor split. Checked by brute force rather than by argument: a doubling model run against
TopLevelSplitover all 1,440Rulescombinations x 111,111 inputs (every string up to length 5 over" ' , a \ ( ) <backtick{) agreed on all 159,999,840 comparisons.matching_delimiterbelow implements doubling explicitly; that is equally correct and equally immaterial, and it is kept because a byte scanner reads more obviously with the rule written out.File-local because this is the only splitter pairing
clamp: falsewithDropAll. -
TAG_ATTR_RE =
/([\w:.-]+)\s*=\s*(?:"([^"]*)"|'([^']*)')/ -
Attribute names carry
:and-in the wild (taffy:uri,data-required), and values use either quote style. -
TEST_COMPONENT_RE =
/.+(?:Test|Spec)\.cfc\z/i -
TestBox names suites
<Something>Test.cfc/<Something>Spec.cfc. The leading.+is load-bearing: a component named exactlyTest.cfcis a demo, not a suite (fw1 ships one that declares a realremotemethod), and an anchoredends_with?swallowed it.