C⏚ v2.0.0Updated 2026-05-12·Platform

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.jar

It 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 sync
  • completionProvider: triggered on .
  • hoverProvider (in progress)
  • definitionProvider (in progress)
  • referencesProvider
  • documentSymbolProvider

Diagnostics (errors and warnings) are published proactively via textDocument/publishDiagnostics as the user edits or saves.

Client support note:

  • hoverProvider and definitionProvider are 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:

  1. A test entity named after the source file (e.g. FooTest for Foo.cg).
  2. Any entity in the file whose name contains Test.
  3. Any other test entity in the project.
  4. 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.jar

Logs are written to ~/neosyn-ir-debug.log. The file is appended to, not rotated.

Where to dig deeper

  • The LSP interface itself: CgLanguageServer.java in plugins/com.neosyn.cg.ui/src/com/neosyn/cg/ide/server/.
  • The CLI entry point: CgLanguageServerMain.java in releng/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.