COCOR-LSP.md 4.5 KB

Coco/R diagnostics through LSP

Version 0.1.7 adds the first real Language Server connection. The Theia/VS Code extension starts out/server.js through vscode-languageclient; the server invokes a configured executable containing the generated Coco/R parser/validator.

Coco/R itself is a compiler-compiler: it generates a scanner/parser from an .atg grammar. It is therefore not run for every keystroke. The editor runs the generated validator instead.

Configuration

"modula2.cocoR.validatorCommand": "/path/to/generated-modula2-validator",
"modula2.cocoR.validatorArguments": ["{file}"]

{file} is replaced by a temporary copy of the current .mod or .def document. The validator is run with the original document directory as its working directory.

The server understands the editor-oriented Coco/R output used by the CRQ frame:

source.mod (12,7) message

Line numbers are converted from one-based to LSP zero-based positions.

When validatorCommand is empty, the LSP publishes no Coco/R diagnostics; the existing lightweight diagnostics remain available.

Tested validator (GNU-grammar)

GNU-grammar/bin/GM2 is a validator built from the tested gm2-gcc-0.2 grammar. Besides the .LST listing file, it prints one editor-oriented diagnostic per error to standard output:

/tmp/.../multi.mod (3,0) 'MODULE' expected
/tmp/.../multi.mod (5,15) invalid SetOrDesignatorOrFunction

Line numbers are one-based, columns are zero-based, matching the file (line,column) message pattern above. A clean file prints only Parsing / Parsed correctly (no diagnostic lines).

Example configuration:

"modula2.cocoR.validatorCommand": "/home/eric/Projets/Projets-Modula2/MyWork/Theia/GNU-grammar/bin/GM2",
"modula2.cocoR.validatorArguments": ["{file}"]

The reference grammar lives at grammars/Modula2.atg (copy of the tested gm2-gcc-0.2.atg); parser regression tests live in grammars/tests/ and are checked with <GNU-grammar>/bin/GM2 <test>.mod (expect 0 errors).

Differential results (GM2 vs gm2 -fiso)

Measured with bin/GM2 against gm2 16.0.1: 21 real files (m2compiler-V3, m2-sunrise, hello), 22 accepted-construct probes and 9 broken probes. GM2 is syntax-only by design — it never type-checks, so semantic errors (unknown names, type mismatches, bad arities) are always missed and do not count below. GM2 exits 0 either way; consumers must parse stdout.

  • Valid files: 20/21 clean. The one gap is FORWARD procedure headings (85 diags on the generated M2P.mod): the grammar's ProcedureDeclaration = ProcedureHeading ";" ( ProcedureBlock Ident ) has no FORWARD alternative, while gm2 accepts it. Probable fix: ( "FORWARD" | ProcedureBlock Ident ) (plus regenerating the validator with the Coco/R toolchain).
  • Accepted constructs: 21/22, same FORWARD gap. WITH, CASE/ELSE, REPEAT, LOOP/EXIT, nested comments, set constructors, all literal forms, BY -1 steps and the empty module all parse.
  • Broken files: 6/7 caught with gm2-matching positions (GM2 columns are zero-based, which the server already accounts for — no column adjustment needed). Missed: module END-name mismatch (unchecked). Two probes were correctly not errors: gm2 itself only warns on a missing ; before END and on an unclosed ( (separator/recovery leniency), and GM2 agrees with it.

Pascal dialects (.pas / .pp / .p)

The same server validates Pascal files with the pilot validators from grammars/. Each pilot binary takes the source file as its single argument and writes a .LST listing next to it; the server parses the listing's ***** ^ message lines (positions are caret-relative to the code after the listing prefix, zero-based columns).

"modula2.pascal.dialect": "freepascal",
"modula2.pascal.validators": {
  "p2": "<root>/grammars/P2/build/P2",
  "p4": "<root>/grammars/P4/build/P4",
  "p6": "<root>/grammars/P6/build/P6",
  "pascal": "<root>/grammars/Pascal/build/PStd",
  "turbopascal3": "<root>/grammars/TurboPascal3/build/TP3",
  "freepascal": "<root>/grammars/FreePascal/build/FPC",
  "blaise": "<root>/grammars/Blaise/build/BlaiseV",
  "pascals": "<root>/grammars/PascalS/build/PascalS"
}

Build each binary first with its pilot build.sh (needs CR and gm2 -fiso). The local Modula-2 analysis never runs on Pascal text. With no command configured for the active dialect the server publishes no diagnostics. Never point these at the pcom/psc oracle compilers — they can hang on invalid input.