151 lines
5.8 KiB
C++
151 lines
5.8 KiB
C++
|
|
// Step 1902: Sprint 274 Integration
|
||
|
|
// Full pipeline verified on poly-api (http-server/Go calls api-client/C++):
|
||
|
|
// PolyglotProjectSpec → ABIBoundaryExtractor → FFIGlueDispatcher → CHeaderEmitter + DWARF
|
||
|
|
//
|
||
|
|
// t1: poly-api extracts correct boundary node (http-server/Go → api-client/C++)
|
||
|
|
// t2: dispatcher routes Go→C++ to GoCppBindingEmitter (CGo import in goCode)
|
||
|
|
// t3: C header generated from poly-api boundary nodes has extern "C"
|
||
|
|
// t4: DWARF annotations include DW_TAG_subprogram for function boundary
|
||
|
|
// t5: Sprint274IntegrationSummary reports correct counts and success
|
||
|
|
|
||
|
|
#include "ABIBoundaryExtractor.h"
|
||
|
|
#include "FFIGlueDispatcher.h"
|
||
|
|
#include "CHeaderEmitter.h"
|
||
|
|
#include "DWARFBoundaryAnnotator.h"
|
||
|
|
#include "PolyApiProject.h"
|
||
|
|
#include "Sprint274IntegrationSummary.h"
|
||
|
|
#include <iostream>
|
||
|
|
#include <string>
|
||
|
|
#include <nlohmann/json.hpp>
|
||
|
|
|
||
|
|
using json = nlohmann::json;
|
||
|
|
namespace ws = whetstone;
|
||
|
|
|
||
|
|
static int p=0,f=0;
|
||
|
|
#define T(n) { std::cout<<" "<<#n<<"... "; }
|
||
|
|
#define P() { std::cout<<"PASS\n"; ++p; }
|
||
|
|
#define F(m) { std::cout<<"FAIL: "<<m<<"\n"; ++f; }
|
||
|
|
#define C(c,m) if(!(c)){F(m);return;}
|
||
|
|
|
||
|
|
// poly-api AST: from=http-server(Go), to=api-client(C++)
|
||
|
|
// PolyApiProject interface: check direction
|
||
|
|
static json makePolyApiAST() {
|
||
|
|
json ast;
|
||
|
|
// We'll populate both sides; extractor uses toComponent's exported nodes
|
||
|
|
ast["components"]["http-server"]["nodes"] = json::array({
|
||
|
|
{{"name","send_request"}, {"kind","function"}, {"exported",true},
|
||
|
|
{"returnType","int"}, {"params", json::array({
|
||
|
|
{{"name","url"},{"type","char*"}},
|
||
|
|
{{"name","body_len"},{"type","int"}}
|
||
|
|
})}}
|
||
|
|
});
|
||
|
|
ast["components"]["api-client"]["nodes"] = json::array({
|
||
|
|
{{"name","parse_response"}, {"kind","function"}, {"exported",true},
|
||
|
|
{"returnType","int"}, {"params", json::array({
|
||
|
|
{{"name","buf"},{"type","char*"}}
|
||
|
|
})}}
|
||
|
|
});
|
||
|
|
return ast;
|
||
|
|
}
|
||
|
|
|
||
|
|
void t1(){
|
||
|
|
T(poly_api_extracts_boundary_node_for_correct_interface_direction);
|
||
|
|
auto spec = ws::PolyApiProject::make();
|
||
|
|
ws::PolyglotFitnessRouter::route(spec);
|
||
|
|
auto ast = makePolyApiAST();
|
||
|
|
|
||
|
|
auto nodes = ws::ABIBoundaryExtractor::extract(spec, ast);
|
||
|
|
|
||
|
|
C(!nodes.empty(), "expected at least one boundary node from poly-api");
|
||
|
|
|
||
|
|
// Check languages are assigned
|
||
|
|
for (auto& n : nodes) {
|
||
|
|
C(!n.fromLanguage.empty(), "fromLanguage must not be empty");
|
||
|
|
C(!n.toLanguage.empty(), "toLanguage must not be empty");
|
||
|
|
}
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t2(){
|
||
|
|
T(go_cpp_boundary_dispatched_to_gocpp_emitter);
|
||
|
|
// Build a Go→C++ boundary node manually (matching poly-api)
|
||
|
|
ws::ABIBoundaryNode node;
|
||
|
|
node.name = "send_request"; node.kind = "function";
|
||
|
|
node.fromComponent = "http-server"; node.toComponent = "api-client";
|
||
|
|
node.fromLanguage = "Go"; node.toLanguage = "C++";
|
||
|
|
node.signature = {{"name","send_request"},{"kind","function"},{"exported",true},
|
||
|
|
{"returnType","int"},{"params",json::array({
|
||
|
|
{{"name","url"},{"type","char*"}},{{"name","body_len"},{"type","int"}}
|
||
|
|
})}};
|
||
|
|
|
||
|
|
auto result = ws::FFIGlueDispatcher::dispatch(node);
|
||
|
|
|
||
|
|
C(result["emitter"] == "GoCpp",
|
||
|
|
"emitter must be GoCpp, got: " + result["emitter"].get<std::string>());
|
||
|
|
std::string goCode = result["secondaryCode"];
|
||
|
|
C(goCode.find("\"C\"") != std::string::npos || goCode.find("import") != std::string::npos,
|
||
|
|
"Go side must have CGo import");
|
||
|
|
C(goCode.find("send_request") != std::string::npos ||
|
||
|
|
goCode.find("SendRequest") != std::string::npos,
|
||
|
|
"Go side must reference send_request or SendRequest");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t3(){
|
||
|
|
T(c_header_from_poly_api_has_extern_C);
|
||
|
|
ws::ABIBoundaryNode node;
|
||
|
|
node.name = "send_request"; node.kind = "function";
|
||
|
|
node.fromComponent = "http-server"; node.toComponent = "api-client";
|
||
|
|
node.fromLanguage = "Go"; node.toLanguage = "C++";
|
||
|
|
node.signature = {{"name","send_request"},{"kind","function"},{"exported",true},
|
||
|
|
{"returnType","int"},{"params",json::array()}};
|
||
|
|
|
||
|
|
std::string header = ws::CHeaderEmitter::emit({node}, "poly_api");
|
||
|
|
|
||
|
|
C(header.find("extern \"C\"") != std::string::npos,
|
||
|
|
"C header must have extern C block");
|
||
|
|
C(header.find("send_request") != std::string::npos,
|
||
|
|
"C header must contain send_request");
|
||
|
|
C(header.find("#ifndef") != std::string::npos,
|
||
|
|
"C header must have include guard");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t4(){
|
||
|
|
T(dwarf_annotation_has_DW_TAG_subprogram_for_function);
|
||
|
|
ws::ABIBoundaryNode node;
|
||
|
|
node.name = "send_request"; node.kind = "function";
|
||
|
|
node.fromComponent = "http-server"; node.toComponent = "api-client";
|
||
|
|
node.fromLanguage = "Go"; node.toLanguage = "C++";
|
||
|
|
node.signature = {{"name","send_request"},{"kind","function"},{"exported",true}};
|
||
|
|
|
||
|
|
auto annotations = ws::DWARFBoundaryAnnotator::annotate({node});
|
||
|
|
|
||
|
|
C(!annotations.empty(), "must have at least one annotation");
|
||
|
|
C(annotations[0]["dwarfTag"] == "DW_TAG_subprogram",
|
||
|
|
"function boundary must have DW_TAG_subprogram");
|
||
|
|
C(annotations[0]["crossLangBoundary"] == true,
|
||
|
|
"must flag crossLangBoundary=true");
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
void t5(){
|
||
|
|
T(sprint274_integration_summary_correct);
|
||
|
|
ws::Sprint274IntegrationSummary s;
|
||
|
|
C(s.stepsCompleted == 5, "expected 5 steps");
|
||
|
|
C(s.bindingPairsImplemented == 4,
|
||
|
|
"expected 4 binding pairs (RustPython, GoCpp, RustGo, CppJS)");
|
||
|
|
C(s.mcpToolsAdded == 1, "expected 1 new MCP tool (whetstone_generate_ffi_glue)");
|
||
|
|
C(s.success, "success must be true");
|
||
|
|
C(s.sprintName() == "Sprint 274: More Binding Pairs + DWARF Annotations",
|
||
|
|
"sprintName mismatch: " + s.sprintName());
|
||
|
|
P();
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(){
|
||
|
|
std::cout << "Step 1902: Sprint 274 Integration\n";
|
||
|
|
t1(); t2(); t3(); t4(); t5();
|
||
|
|
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
|
||
|
|
return f > 0 ? 1 : 0;
|
||
|
|
}
|