Skip to content

Commit 6c878a1

Browse files
hyperpolymathclaude
andcommitted
fix(rest): unblock /api/v1/consult — 37 pre-existing rest-crate errors
- Add 13 missing variants to models::ProverKind (FStar, Dafny, Why3, TLAPS, Twelf, Nuprl, Minlog, Imandra, GLPK, SCIP, MiniZinc, Chuffed, ORTools) so the FFI ordinal table 17..29 round-trips through the REST schema. - Wire core_kind_to_rest / rest_kind_to_core for the new variants (drops the "_ => Vampire" fallback for everything ≤ ord 29). - Implement the 3 trait methods ProverBackend now requires on FfiProverBackend (search_theorems → empty-vec stub, config / set_config → store ProverConfig in the wrapper). - Use CoreTacticResult (aliased import) consistently in apply_tactic; Success now takes ProofState by value, not Box<ProofState>. - ProofState::new takes Term, not String — wrap parse_string content in Term::Var to match the new core API. - Cast c_char ↔ u8 raw pointers across the Zig FFI boundary (CStr expects c_char; Zig declared the args as *const u8). Reduces rest-crate errors 37 → 0. echidna lib tests still 637 passing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 7197d3e commit 6c878a1

3 files changed

Lines changed: 76 additions & 16 deletions

File tree

src/interfaces/rest/ffi_wrapper.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// REST FFI Wrapper - Connects REST interface to ECHIDNA Rust core via Zig FFI
33

44
use std::ffi::{CString, CStr};
5-
use std::os::raw::{c_int, c_void};
5+
use std::os::raw::{c_char, c_int, c_void};
66
use anyhow::{Result, anyhow};
77

88
// Re-export FFI types from core
@@ -32,7 +32,7 @@ pub fn init_ffi() -> Result<()> {
3232
let err_msg = if err_ptr.is_null() {
3333
"Unknown FFI initialization error".to_string()
3434
} else {
35-
CStr::from_ptr(err_ptr).to_string_lossy().into_owned()
35+
CStr::from_ptr(err_ptr as *const c_char).to_string_lossy().into_owned()
3636
};
3737
return Err(anyhow!("FFI initialization failed: {}", err_msg));
3838
}
@@ -47,7 +47,7 @@ pub fn get_version() -> Result<String> {
4747
if ptr.is_null() {
4848
return Err(anyhow!("FFI version pointer is null"));
4949
}
50-
let version = CStr::from_ptr(ptr).to_string_lossy().into_owned();
50+
let version = CStr::from_ptr(ptr as *const c_char).to_string_lossy().into_owned();
5151
Ok(version)
5252
}
5353
}
@@ -59,7 +59,7 @@ pub fn get_last_error() -> Result<String> {
5959
if ptr.is_null() {
6060
return Err(anyhow!("No error message available"));
6161
}
62-
let error = CStr::from_ptr(ptr).to_string_lossy().into_owned();
62+
let error = CStr::from_ptr(ptr as *const c_char).to_string_lossy().into_owned();
6363
Ok(error)
6464
}
6565
}
@@ -88,7 +88,7 @@ pub fn destroy_prover(handle: i32) -> Result<()> {
8888
pub fn parse_string(handle: i32, content: &str) -> Result<()> {
8989
unsafe {
9090
let c_content = CString::new(content)?;
91-
let rc = echidna_parse_string(handle, c_content.as_ptr(), content.len());
91+
let rc = echidna_parse_string(handle, c_content.as_ptr() as *const u8, content.len());
9292
if rc != 0 {
9393
let error = get_last_error()?;
9494
return Err(anyhow!("Parse failed: {}", error));
@@ -109,7 +109,7 @@ pub fn verify_proof(handle: i32) -> Result<bool> {
109109
pub fn apply_tactic(handle: i32, tactic: &str) -> Result<bool> {
110110
unsafe {
111111
let c_tactic = CString::new(tactic)?;
112-
let rc = echidna_apply_tactic(handle, c_tactic.as_ptr(), tactic.len());
112+
let rc = echidna_apply_tactic(handle, c_tactic.as_ptr() as *const u8, tactic.len());
113113
Ok(rc == 0)
114114
}
115115
}

src/interfaces/rest/handlers.rs

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@ use crate::{models::*, AppState, ProofSession};
2222
/// Wrapper for FFI-based prover backend
2323
struct FfiProverBackend {
2424
handle: i32,
25+
config: ProverConfig,
2526
}
2627

2728
impl FfiProverBackend {
2829
pub fn new(handle: i32) -> Self {
29-
FfiProverBackend { handle }
30+
FfiProverBackend {
31+
handle,
32+
config: ProverConfig::default(),
33+
}
3034
}
3135
}
3236

@@ -38,34 +42,34 @@ impl ProverBackend for FfiProverBackend {
3842
) -> anyhow::Result<echidna::core::ProofState> {
3943
let content = std::fs::read_to_string(&path)?;
4044
ffi_wrapper::parse_string(self.handle, &content)?;
41-
Ok(echidna::core::ProofState::new(content))
45+
Ok(echidna::core::ProofState::new(Term::Var(content)))
4246
}
4347

4448
async fn parse_string(&self, content: &str) -> anyhow::Result<echidna::core::ProofState> {
4549
ffi_wrapper::parse_string(self.handle, content)?;
46-
Ok(echidna::core::ProofState::new(content.to_string()))
50+
Ok(echidna::core::ProofState::new(Term::Var(content.to_string())))
4751
}
4852

49-
async fn verify_proof(&self, state: &echidna::core::ProofState) -> anyhow::Result<bool> {
53+
async fn verify_proof(&self, _state: &echidna::core::ProofState) -> anyhow::Result<bool> {
5054
ffi_wrapper::verify_proof(self.handle)
5155
}
5256

5357
async fn apply_tactic(
5458
&self,
5559
state: &echidna::core::ProofState,
5660
tactic: &CoreTactic,
57-
) -> anyhow::Result<TacticResult> {
61+
) -> anyhow::Result<CoreTacticResult> {
5862
let tactic_str = format!("{:?}", tactic);
5963
if ffi_wrapper::apply_tactic(self.handle, &tactic_str)? {
60-
Ok(TacticResult::Success(Box::new(state.clone())))
64+
Ok(CoreTacticResult::Success(state.clone()))
6165
} else {
62-
Ok(TacticResult::Error("Tactic failed".to_string()))
66+
Ok(CoreTacticResult::Error("Tactic failed".to_string()))
6367
}
6468
}
6569

6670
async fn suggest_tactics(
6771
&self,
68-
state: &echidna::core::ProofState,
72+
_state: &echidna::core::ProofState,
6973
limit: usize,
7074
) -> anyhow::Result<Vec<CoreTactic>> {
7175
let tactic_names = ffi_wrapper::suggest_tactics(self.handle, limit)?;
@@ -80,7 +84,7 @@ impl ProverBackend for FfiProverBackend {
8084
Ok(tactics)
8185
}
8286

83-
async fn export(&self, state: &echidna::core::ProofState) -> anyhow::Result<String> {
87+
async fn export(&self, _state: &echidna::core::ProofState) -> anyhow::Result<String> {
8488
ffi_wrapper::export_proof(self.handle)
8589
}
8690

@@ -92,6 +96,20 @@ impl ProverBackend for FfiProverBackend {
9296
// This is a bit simplified - in a real implementation we'd track the kind
9397
CoreProverKind::Lean // Default, would need to be set during creation
9498
}
99+
100+
async fn search_theorems(&self, _pattern: &str) -> anyhow::Result<Vec<String>> {
101+
// FFI shim doesn't expose theorem search yet. Return empty list rather
102+
// than failing so portfolio/search callers degrade gracefully.
103+
Ok(Vec::new())
104+
}
105+
106+
fn config(&self) -> &ProverConfig {
107+
&self.config
108+
}
109+
110+
fn set_config(&mut self, config: ProverConfig) {
111+
self.config = config;
112+
}
95113
}
96114

97115
/// List all available provers (all 30)
@@ -558,7 +576,20 @@ fn core_kind_to_rest(kind: &CoreProverKind) -> ProverKind {
558576
CoreProverKind::EProver => ProverKind::EProver,
559577
CoreProverKind::SPASS => ProverKind::Spass,
560578
CoreProverKind::AltErgo => ProverKind::AltErgo,
561-
_ => ProverKind::Vampire, // fallback for remaining provers
579+
CoreProverKind::FStar => ProverKind::FStar,
580+
CoreProverKind::Dafny => ProverKind::Dafny,
581+
CoreProverKind::Why3 => ProverKind::Why3,
582+
CoreProverKind::TLAPS => ProverKind::TLAPS,
583+
CoreProverKind::Twelf => ProverKind::Twelf,
584+
CoreProverKind::Nuprl => ProverKind::Nuprl,
585+
CoreProverKind::Minlog => ProverKind::Minlog,
586+
CoreProverKind::Imandra => ProverKind::Imandra,
587+
CoreProverKind::GLPK => ProverKind::GLPK,
588+
CoreProverKind::SCIP => ProverKind::SCIP,
589+
CoreProverKind::MiniZinc => ProverKind::MiniZinc,
590+
CoreProverKind::Chuffed => ProverKind::Chuffed,
591+
CoreProverKind::ORTools => ProverKind::ORTools,
592+
_ => ProverKind::Vampire, // fallback for remaining provers (>30 in core)
562593
}
563594
}
564595

@@ -581,6 +612,19 @@ fn rest_kind_to_core(kind: &ProverKind) -> CoreProverKind {
581612
ProverKind::EProver => CoreProverKind::EProver,
582613
ProverKind::Spass => CoreProverKind::SPASS,
583614
ProverKind::AltErgo => CoreProverKind::AltErgo,
615+
ProverKind::FStar => CoreProverKind::FStar,
616+
ProverKind::Dafny => CoreProverKind::Dafny,
617+
ProverKind::Why3 => CoreProverKind::Why3,
618+
ProverKind::TLAPS => CoreProverKind::TLAPS,
619+
ProverKind::Twelf => CoreProverKind::Twelf,
620+
ProverKind::Nuprl => CoreProverKind::Nuprl,
621+
ProverKind::Minlog => CoreProverKind::Minlog,
622+
ProverKind::Imandra => CoreProverKind::Imandra,
623+
ProverKind::GLPK => CoreProverKind::GLPK,
624+
ProverKind::SCIP => CoreProverKind::SCIP,
625+
ProverKind::MiniZinc => CoreProverKind::MiniZinc,
626+
ProverKind::Chuffed => CoreProverKind::Chuffed,
627+
ProverKind::ORTools => CoreProverKind::ORTools,
584628
}
585629
}
586630

src/interfaces/rest/models.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ pub enum ProverKind {
2424
EProver,
2525
Spass,
2626
AltErgo,
27+
FStar,
28+
Dafny,
29+
Why3,
30+
#[serde(rename = "tlaps")]
31+
TLAPS,
32+
Twelf,
33+
Nuprl,
34+
Minlog,
35+
Imandra,
36+
#[serde(rename = "glpk")]
37+
GLPK,
38+
#[serde(rename = "scip")]
39+
SCIP,
40+
MiniZinc,
41+
Chuffed,
42+
ORTools,
2743
}
2844

2945
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema)]

0 commit comments

Comments
 (0)