P4 LanguageDISCLAIMER: Large parts of this codebase and README are LLM-generated. They may be wrong or contain bugs. Every release is tested extensively by a real human. A Visual Studio Code language server for P4₁₆, built around a hand-written parser that keeps working on code that does not compile — which is when an editor earns its keep. Tuned for v1model / BMv2 programs, but nothing is hard-coded to it: other
architectures work from whatever they Nothing needs to be installed. The p4lang standard library headers ship with the
extension, so What it doesHighlighting, in two layersA TextMate grammar covers the file before the server starts — every reserved
keyword split by role, the contextual table properties ( On top of it, semantic tokens colour what a grammar cannot know: a header
type apart from a struct apart from a control, parser states as their own kind,
parameter directions, Completion that knows where the cursor isCompletion is driven by syntactic position, not prefix matching.
HoverThree sources merged:
NavigationGo-to-definition (including into DiagnosticsEverything below is a mistake Parser state flow
Header validity and the deparser
The validity analysis is deliberately quiet: it understands that
Names and types — unresolved names, a name used before it is declared
( Optional
|
| Setting | Default | |
|---|---|---|
p4.includePaths |
[] |
extra #include directories; the file's own directory and the bundled p4include/ are always searched |
p4.diagnostics.parserStates |
true |
the parser state flow checks |
p4.diagnostics.headerValidity |
true |
the deparser and validity checks |
p4.maxNumberOfProblems |
200 |
|
p4.compiler.enable |
false |
also run p4c on save and merge its errors |
p4.compiler.path |
p4c-bm2-ss |
the compiler executable, found on PATH or given as an absolute path |
p4.compiler.args |
["--p4v", "16"] |
extra arguments passed to it |
p4.compiler.runOn |
save |
save or never |
p4.trace.server |
off |
LSP tracing |
In an untrusted workspace the three p4.compiler.* settings are ignored, since
they name a program to run; everything else works unchanged.
Development
Node 20+.
npm install
npm run build # bundle client + server with esbuild
npm run watch # ... and keep bundling
npm run check-types # tsc --noEmit on both workspaces
npm test # unit + corpus + feature tests
npm run gen:docs # regenerate spec-docs.json from the spec HTML
npm run package # build a .vsix
Press F5 for an Extension Development Host with example1.p4 open. The
Extension + Server compound also attaches a debugger to the language server.
How it fits together
document text
→ preprocess #include as a scope import (never a textual splice),
macro expansion with provenance, #if evaluation
→ lex tokens with exact spans and attached trivia; lossless
→ parse recursive descent, error recovery, no symbol table
→ bind scope tree, symbol table, cross-file through the include graph
→ analyse parser state graph, header validity lattice
→ features hover / completion / definition / tokens / diagnostics
Three decisions shape the rest:
The parser never consults a symbol table. p4c resolves the grammar's
type-name ambiguity by feeding the parser's symbol table back into the lexer.
That is untenable in an editor, where the symbol table is always a keystroke out
of date. The ambiguous positions are parsed speculatively instead, and any
residual ambiguity is recorded on the node for name resolution to settle.
The parser never throws. An unparseable construct becomes an ErrorNode and
parsing resumes at the next declaration boundary. Completion is requested
precisely when the file does not parse — transition with nothing after it —
so a parser that gives up has nothing to offer.
#include is a scope import, not a textual splice. The included file is
parsed as its own document and its top-level scope becomes an import edge. The
edited file's positions stay exact, and go-to-definition into core.p4 falls
out for free.
Tests
npm test runs 186 tests, including a corpus gate that parses and binds every
file in p4include/ (core.p4, v1model.p4, psa.p4, pna.p4 and the rest) plus the
lab programs vendored under test/fixtures/labs/, asserting zero syntax errors
and zero unresolved names. The control-plane name computation is checked against
a real p4c-generated .p4info.txt kept next to the program it was built from.
The suite is self-contained: nothing outside the repository is read.
Licence
Apache-2.0 — see LICENSE.
Two things are bundled from elsewhere, both Apache-2.0 and both credited in
NOTICE: the standard library headers in p4include/, vendored
unmodified from p4lang/p4c, and the
specification excerpts shown on hover, extracted from the P4₁₆ language
specification published by the P4 Language Consortium.