Design Philosophy

Understanding what CongoCC is trying to be explains many of its specific choices — why the syntax looks as it does, why some legacy options are gone, and why the defaults are what they are.

Convention over configuration

CongoCC aims to make the common case work with no configuration. Names are inferred — the parser and lexer classes, the node package, and the node names all derive from the grammar by default — so a minimal grammar needs almost no settings. Tree building is on by default, because most users want a tree. Settings exist for when you need to override a convention, not as a checklist you must fill in to get started. The guiding idea is that things should just work out of the box.

A clean break with legacy syntax

CongoCC removed the legacy JavaCC syntax rather than carry it forward (Appendix: Legacy Mapping). That is a real cost for people with old grammars, taken deliberately: the old surface had accumulated boilerplate (PARSER_BEGIN/PARSER_END, void Foo() : {} { }) and genuinely broken corners (the original lookahead behavior) that could not be fixed while remaining compatible. Removing them allowed a smaller, more regular language — Foo : ; instead of the ceremony, SCAN and =>|| instead of a LOOKAHEAD that “was always fundamentally broken,” and a single consistent rule that braces mean embedded code.

Modern by default

The same spirit shows in the defaults that were modernized: type-safe TokenType enums instead of integer constants, location information kept always rather than as an option, tree building and informative error reporting built in. The aim throughout is that the obvious way to write a grammar is also the recommended one.