Skip to content

DSL-Grammatik

Formale Referenz der CodeCharter-DSL. Was der Parser akzeptiert, in EBNF-naher Notation.

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:

  1. Primär: Literale, Identifier, ( expr )
  2. Member-Access und Method-Call: a.b, a.b(args)
  3. Unär: !expr, -expr
  4. Multiplikativ: *, /, %
  5. Additiv: +, -
  6. Vergleich: ==, !=, >, >=, <, <=
  7. Logisches UND: &&
  8. 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