Questa guida mostra come aggiungere un linguaggio a lungo generate con un plugin, nello
stesso modo in cui i programmi protoc-gen-<language> aggiungono linguaggi a protoc.
Scrivi il programma
Un plugin legge una GenerateRequest (JSON) dallo standard input e scrive una
GenerateResponse (JSON) sullo standard output. Il
riferimento del protocollo elenca ogni campo. In Rust, il crate
lungo-build fornisce i tipi:
use lungo_build::codegen::plugin::{GenerateRequest, GenerateResponse};
use std::io::Read;
fn main() {
let mut input = String::new();
std::io::stdin().read_to_string(&mut input).unwrap();
let request: GenerateRequest = serde_json::from_str(&input).unwrap();
let mut response = GenerateResponse::default();
for key in request.options.keys() {
response.errors.push(format!("unknown option `{key}`"));
}
if response.errors.is_empty() {
let mut api = String::new();
for f in &request.boundary.functions {
api.push_str(&format!("// {} : {}\n// entry point: {}\n", f.lean_name, f.lean_type, f.symbol));
}
response.files.insert("api.txt".into(), api);
// The program's C, which the package compiles and links against the runtime.
response.files.extend(request.program_files.clone());
}
println!("{}", serde_json::to_string(&response).unwrap());
}
Un generatore per un linguaggio reale:
- copia
program_files: il pacchetto compila ogni file.cconprogram/nel percorso degli include, e collega il runtime direquest.runtime(tramite URL della release e SHA-256, oppure dalla distribuzione locale); - emette i tipi del linguaggio per
boundary.tableeboundary.types, e una funzione per ogni voce diboundary.functionsche codifica i suoi argomenti nel formato di trasmissione, chiama il punto di ingressosymbole decodifica il risultato secondoreturns; - si installa come host del processo (
lungo_set_host) per ricevere le chiamate delle funzioni dell’host, dà a ogni facility diboundary.facilitiesuna funzione che la installa registrando l’implementazione di ciascuna sua operazione conset_host_extern(tramite l’indexdell’operazione), e rifiuta una chiamata precedente all’installazione di ogni facility, indicando la facility e una sua operazione; - per una funzione il cui
returnsèasync, chiama il punto di ingresso per ottenere il primo passo del programma e lo porta avanti: chiede all’handler del chiamante di eseguire ogni operazione (della facility asincrona diboundary.async_facilitiescon quel tipo di operazioni), riprende il programma con la risposta (lungo_async_resume) e lo abbandona (lungo_async_cancel) quando l’handler fallisce o la chiamata viene annullata (vedi il formato di trasmissione); - se il linguaggio può esporlo, incorpora il documento di garanzia del programma
(
request.assurance) esattamente come lungo lo serializza. lungo scriveassurance.jsonin ogni output da sé; un plugin la cui risposta contiene quel file fallisce.
Le librerie di supporto dei linguaggi integrati (lungo-go,
lungo-py, lungo-ts
e lungo-swift) sono esempi completi del lato
runtime, e
compiler-tests/wire/vectors.json
in lungo-rs verifica un codec.
Installalo ed eseguilo
Metti il programma nel PATH come lungo-gen-<language> (.exe su Windows):
cargo install --path my-plugin # installa lungo-gen-kotlin
lungo generate --kotlin_out=gen/kotlin --kotlin_opt=package=org.example
oppure configuralo in lungo.toml:
[plugins.kotlin]
out = "gen/kotlin"
options = { package = "org.example" }
La directory di output viene sostituita dai file della risposta, con l’aggiunta di
assurance.json. Un plugin che fallisce, scrive una risposta malformata o segnala errori fa
fallire il comando con
LNG0504, mostrando il suo standard error o i suoi errori;
non viene scritto nulla.