Language Server
The Neosyn C⏚ language server speaks the standard
Language Server Protocol
plus a small set of custom JSON-RPC methods under the neosyn/
namespace. The same server JAR powers the VS Code extension and the
cg-language-server.jar command-line tool.
This page is for editor integrators. It documents the
JSON-RPC API the server exposes, including the custom methods
under the neosyn/ namespace that drive the FSM and graph views.
If you want to run commands from a shell or a CI script, see CLI reference instead. Both surfaces are backed by the same JAR.
Running the server
Start the server in LSP mode with no arguments:
java -jar cg-language-server.jarIt reads JSON-RPC requests on stdin and writes responses on stdout. Editors connect by spawning this process and speaking LSP over the pipe.
The JAR ships with the VS Code extension under server/ and is
built into releng/lsp-server/target/cg-language-server.jar.
Scope and versioning
This page documents the current tool behavior at a high level. The
custom method names are intended to be stable, but exact DTO fields,
defaults, and client behavior can change between releases. When in
doubt, compare against --help, the DTO classes in source, and the
release notes for the version you are integrating.
Standard LSP capabilities
The server advertises these capabilities in its initialize
response:
textDocumentSync: full synccompletionProvider: triggered on.hoverProvider(in progress)definitionProvider(in progress)referencesProviderdocumentSymbolProvider
Diagnostics (errors and warnings) are published proactively via
textDocument/publishDiagnostics as the user edits or saves.
Client support note:
hoverProvideranddefinitionProviderare still marked in-progress here. Treat them as capabilities that may be partial rather than feature-complete across every client.
Custom methods
All custom methods live under the neosyn/ segment. Each takes a
JSON parameter object and returns a JSON result. Field types below
match the Java DTOs in
plugins/com.neosyn.cg.ui/src/com/neosyn/cg/ide/server/.
neosyn/generateIR
Compile one or more .cg source files to IR (XMI). The IR is the
backend-agnostic representation that all generators consume.
interface GenerateIRParams {
uri?: string // single file
uris?: string[] // batch
projectUri?: string // project root - generates every .cg
outputDirectory?: string // default: ".ir"
}
interface GenerateResult {
success: boolean
message: string
generatedFiles: string[]
errors: string[]
warnings: string[]
}Notes:
- Called automatically by clients on file save and on project open.
- Inline tasks declared inside networks are serialized as separate IR files.
neosyn/generate
Generate HDL (Verilog or VHDL) from a source file or project.
interface GenerateParams {
uri: string
target: 'verilog' | 'vhdl'
outputDirectory?: string // default: "verilog-gen" or "vhdl-gen"
}Returns the same GenerateResult shape as neosyn/generateIR.
IR is regenerated automatically if it's missing or out of date.
Output preserves the source package structure (e.g.
com/example/Module.v); networks emit module files for every
inline task they contain.
neosyn/simulate
Run the bytecode simulator on a test network. See Bytecode simulator for the full feature.
interface SimulateParams {
uri: string
entityName?: string // pick a top entity if the file declares many
maxCycles?: number // default 10000
generateVcd?: boolean // default true
}
interface SimulateResult {
success: boolean
message: string
output: string // sim console output (print statements, etc.)
vcdPath: string // path to the generated VCD
cyclesExecuted: number
errors: string[]
warnings: string[]
}When entityName is omitted, the server picks a top entity using
this priority:
- A test entity named after the source file (e.g.
FooTestforFoo.cg). - Any entity in the file whose name contains
Test. - Any other test entity in the project.
- The single top-level entity in the file.
If none of those rules identify the intended top-level entity
reliably, pass entityName explicitly from the client or use the
CLI --entity flag.
neosyn/getFsm
Extract the FSM (state graph) of a task, for the FSM view. The FSM is read from the compiled IR - the same state machine the Verilog backend emits - so the state count matches the generated HDL.
interface GetFsmParams {
uri: string
taskName?: string
}
interface FsmData {
taskName: string
initialState: string
states: StateData[]
transitions: TransitionData[]
error?: string
}
interface StateData {
name: string
isInitial: boolean
line: number; endLine: number // 0-based source span of the state
actions: string[] // statements that run in this state
lines: number[] // source line for each action
x: number; y: number // pre-computed layout (clients may ignore)
}
interface TransitionData {
source: string; target: string
action: string // the guard/trigger expression
label: string
lines: number[]
}State positions (x, y) are pre-computed for layout; clients can
ignore them and lay out from scratch. line/endLine/lines let a
client jump from a state or action to its source.
neosyn/getGraph
Extract a network's dataflow graph, for the graph view. The graph is read from the compiled design (the network the Verilog backend walks), so the ports, widths, interfaces, and connections match the generated HDL.
interface GetGraphParams {
uri: string
networkName?: string
}
interface GraphData {
networkName: string
inputPorts: PortData[] // network-level inputs
outputPorts: PortData[] // network-level outputs
instances: InstanceData[]
connections: ConnectionData[]
error?: string
}
interface PortData {
name: string
type: string // C⏚ type - e.g. "u32", "bool", "addr_t"
direction: 'input' | 'output'
width: number // bus width in bits; -1 if none/unknown
signalType: string // "bool" | "bus" | "custom"
interfaceType: string // "bare" | "push" | "stream" | "confirm"
x: number; y: number
}
interface InstanceData {
name: string
entityName: string // fully-qualified type
inputs: PortData[]
outputs: PortData[]
line: number; endLine: number // 0-based source span of the instantiation
network: boolean // true if the instantiated entity is itself a network
x: number; y: number; width: number; height: number
}
interface ConnectionData {
sourceInstance?: string // null/absent for a network input port
sourcePort: string
targetInstance?: string // null/absent for a network output port
targetPort: string
width: number // bus width in bits; -1 if none/unknown
signalType: string // "bool" | "bus" | "custom"
interfaceType: string // "bare" | "push" | "stream" | "confirm"
}Error handling
All custom methods return errors in the errors array rather than
raising JSON-RPC errors. success is false whenever errors is
non-empty.
{
"success": false,
"message": "Generation failed",
"generatedFiles": [],
"errors": [
"Line 10: undefined reference 'foo'",
"Line 25: type mismatch in assignment"
],
"warnings": []
}For simulation failures, the simulator's Java stack trace (if any)
appears in output.
Debug logging
Set NEOSYN_DEBUG=1 in the environment before launching the JAR to
enable verbose logging:
NEOSYN_DEBUG=1 java -jar cg-language-server.jarLogs are written to ~/neosyn-ir-debug.log. The file is appended
to, not rotated.
Where to dig deeper
- The LSP interface itself:
CgLanguageServer.javainplugins/com.neosyn.cg.ui/src/com/neosyn/cg/ide/server/. - The CLI entry point:
CgLanguageServerMain.javainreleng/lsp-server/src/main/java/com/neosyn/cg/ide/server/. - DTO classes (param + result objects): same package as the interface.
- Found a bug? Open one at Neosyn-Logic/neosyn-studio.