Diese Seite ist die formale Wahrheit. Wenn ihr unsicher seid ob ein Konstrukt erlaubt ist, schaut hier. Für den alltäglichen Sprachgebrauch gibt es die kompakte Syntax-Übersicht, die nach Use-Case sortiert ist.
Datei-Struktur
<file> ::= <directive>* <query>
<directive> ::= '@' <name> <directive-value>
<directive-value> ::= <string-literal> | <identifier>
<query> ::= <query-syntax> | <fluent-syntax>
Eine .ccr-Datei enthält null oder mehr Direktiven, gefolgt von
genau einer Query. Mehrere Queries hintereinander sind ein Parse-Fehler.
Direktiven
Direktiven setzen Metadaten. Alle sind optional. Unbekannte Direktiv-Namen werden ignoriert, damit Regeln zukunftskompatibel bleiben.
| Direktive | Pflicht | Wert | Beschreibung |
|---|---|---|---|
@name |
nein | string | Menschenlesbarer Titel der Regel |
@severity |
nein | enum | info, warn (auch warning), error. Default warn |
@category |
nein | string | Frei wählbare Gruppe (z.B. Async, Design) |
@description |
nein | string | Eine Zeile, was die Regel prüft |
@recommendation |
nein | string | Eine Zeile, wie man es fixt |
Strings nutzen C-Escapes für \", \\, \n, \r, \t, \0.
Unbekannte Escapes bleiben unverändert stehen, damit "Handler\d*$"
für Regex-Patterns natürlich bleibt.
Query-Syntax (LINQ-Form)
<query-syntax> ::= 'from' <id> 'in' <id>
( <let-clause> | <where-clause> )*
<orderby-clause>?
'select' <expression>
<let-clause> ::= 'let' <id> '=' <expression>
<where-clause> ::= 'where' <expression>
<orderby-clause> ::= 'orderby' <expression> ('asc' | 'desc')?
Beispiel:
from t in Types
where t.Kind == "Class"
let methodCount = t.Methods.Count
where methodCount > 20
orderby methodCount desc
select t
Fluent-Syntax (Method-Form)
<fluent-syntax> ::= <id> <method-call>+
<method-call> ::= '.' <id> ( '(' <argument>* ')' )?
<argument> ::= <expression> | <lambda>
<lambda> ::= <id> '=>' <expression>
Beispiel:
Methods.Where(m => m.IsAsync && m.Parameters.Count > 5)
Beide Formen ergeben identische Findings. Bei mehreren where-Bedingungen
liest sich die LINQ-Form meist besser. Bei kurzen Filter-Ketten ist
Fluent oft kompakter.
Ausdrucksgrammatik
Operatoren von festester zu loseter Bindung:
- Primär: Literale, Identifier,
( expr ) - Member-Access und Method-Call:
a.b,a.b(args) - Unär:
!expr,-expr - Multiplikativ:
*,/,% - Additiv:
+,- - Vergleich:
==,!=,>,>=,<,<= - Logisches UND:
&& - Logisches ODER:
||
Literale die der Lexer kennt: Integer, Float, String ("..."),
true, false.
Whitespace und Kommentare
- Whitespace zwischen Tokens ist bedeutungslos.
- Zeilenkommentare beginnen mit
//und gehen bis Zeilenende. - Es gibt keine Block-Kommentare in
.ccr-Dateien.
Was nicht geht
Die DSL ist absichtlich klein und seiteneffektfrei:
- Kein File-IO aus einem Query-Body.
- Kein mutabler State, jedes Property ist ein Read.
- Kein async, Auswertung ist synchron über dem gecachten Code-Modell.
Wenn euch ein Prädikat fehlt, schreibt uns lieber eine kurze Issue mit dem Use-Case statt mit Reflection zu basteln. Die DSL wächst absichtlich, nicht zufällig.
Wo geht's weiter
- Prädikat-Katalog: vollständige Liste der Properties auf jeder Entität
- Syntax-Übersicht: kompakte, Use-Case-orientierte Variante dieser Seite
- Regel-Beispiele: praktische Anwendungen der Grammatik