Files
whetstone_DSL/editor/tests/step1951_test.cpp
Bill 0f6d10e39a Sprint 284: poly-compiler (steps 1948–1952)
5-phase compiler pipeline: C++(lex)→Haskell(parse)→Rust(typecheck)→Lisp(optimize)→Go(emit)

Components:
- CompilerPhaseSpec + CompilerPhaseRegistry: phase descriptors sorted by order field
- CompilerIRNode + IRNodePipeline: IR node kinds (Source→Token→AST→TypedAST→OptimizedAST→Bytecode) + queue
- CompilerPhaseRouter: IRNodeKind→phaseId routing with optional fallback
- CompilerPipelineRunner: chains PhaseTransform functions in order, supports runUpTo

26/26 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:32:40 -07:00

119 lines
4.2 KiB
C++

// Step 1951: CompilerPipelineRunner
//
// t1: addPhase and phaseCount
// t2: runAll chains transforms in order
// t3: runUpTo stops at named phase
// t4: runUpTo throws on unknown phase
// t5: phaseOrder reflects insertion order by spec.order; empty runner throws
#include "CompilerPipelineRunner.h"
#include <iostream>
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;}
// Transform helpers
static ws::CompilerIRNode toToken(const ws::CompilerIRNode& n) {
return {ws::IRNodeKind::Token, "tok:" + n.payload, n.sourceId};
}
static ws::CompilerIRNode toAST(const ws::CompilerIRNode& n) {
return {ws::IRNodeKind::AST, "ast:" + n.payload, n.sourceId};
}
static ws::CompilerIRNode toTyped(const ws::CompilerIRNode& n) {
return {ws::IRNodeKind::TypedAST, "typed:" + n.payload, n.sourceId};
}
static ws::CompilerIRNode toOpt(const ws::CompilerIRNode& n) {
return {ws::IRNodeKind::OptimizedAST, "opt:" + n.payload, n.sourceId};
}
static ws::CompilerIRNode toBytecode(const ws::CompilerIRNode& n) {
return {ws::IRNodeKind::Bytecode, "bc:" + n.payload, n.sourceId};
}
static ws::CompilerPipelineRunner makeRunner() {
ws::CompilerPipelineRunner r;
r.addPhase({"lex", "C++", "Lexing", 1, "Source", "Token"}, toToken);
r.addPhase({"parse", "Haskell", "Parsing", 2, "Token", "AST"}, toAST);
r.addPhase({"typecheck","Rust", "Typechecking",3, "AST", "TypedAST"}, toTyped);
r.addPhase({"optimize", "Lisp", "Optimization",4, "TypedAST", "OptimizedAST"},toOpt);
r.addPhase({"emit", "Go", "Emit", 5, "OptimizedAST", "Bytecode"}, toBytecode);
return r;
}
void t1(){
T(addPhase_and_phaseCount);
ws::CompilerPipelineRunner r;
C(r.phaseCount() == 0, "empty initially");
C(r.empty(), "empty() true");
r.addPhase({"lex","C++","",1,"",""}, toToken);
C(r.phaseCount() == 1, "one phase");
C(!r.empty(), "not empty");
P();
}
void t2(){
T(runAll_chains_transforms);
auto r = makeRunner();
ws::CompilerIRNode input{ws::IRNodeKind::Source, "hello", "main"};
auto result = r.runAll(input);
C(result.kind == ws::IRNodeKind::Bytecode, "final kind Bytecode");
// Payload was chained: bc:opt:typed:ast:tok:hello
C(result.payload == "bc:opt:typed:ast:tok:hello", "chained payload");
C(result.sourceId == "main", "sourceId preserved");
P();
}
void t3(){
T(runUpTo_stops_at_named_phase);
auto r = makeRunner();
ws::CompilerIRNode input{ws::IRNodeKind::Source, "x", ""};
auto result = r.runUpTo(input, "parse");
C(result.kind == ws::IRNodeKind::AST, "kind AST after parse");
C(result.payload == "ast:tok:x", "payload after lex+parse");
auto tc = r.runUpTo(input, "typecheck");
C(tc.kind == ws::IRNodeKind::TypedAST, "TypedAST after typecheck");
P();
}
void t4(){
T(runUpTo_throws_on_unknown_phase);
auto r = makeRunner();
ws::CompilerIRNode input{ws::IRNodeKind::Source, "y", ""};
bool threw = false;
try { r.runUpTo(input, "nonexistent"); }
catch (const std::out_of_range&) { threw = true; }
C(threw, "throws on unknown phase");
P();
}
void t5(){
T(phaseOrder_and_empty_runner_throws);
ws::CompilerPipelineRunner r;
// Add out of order — should sort by spec.order
r.addPhase({"emit", "Go", "",5,"",""}, toBytecode);
r.addPhase({"lex", "C++", "",1,"",""}, toToken);
r.addPhase({"parse", "Haskell","",2,"",""}, toAST);
auto order = r.phaseOrder();
C(order.size() == 3, "three phases");
C(order[0] == "lex", "lex first");
C(order[1] == "parse", "parse second");
C(order[2] == "emit", "emit third");
ws::CompilerPipelineRunner empty;
bool threw = false;
try { empty.runAll({ws::IRNodeKind::Source,"",""});}
catch (const std::runtime_error&) { threw = true; }
C(threw, "empty runner throws");
P();
}
int main(){
std::cout << "Step 1951: CompilerPipelineRunner\n";
t1(); t2(); t3(); t4(); t5();
std::cout << "\n" << p << "/" << (p+f) << " passed\n";
return f > 0 ? 1 : 0;
}