Projektmodule und vollständiges TBC-Kompilat umsetzen und Change archivieren
This commit is contained in:
@@ -16,6 +16,12 @@ use tb_runtime::value::TypeInit;
|
||||
|
||||
pub fn compile(hir: &HirModule) -> CompiledModule {
|
||||
let mut cg = Codegen {
|
||||
common_arrays: hir
|
||||
.commons
|
||||
.iter()
|
||||
.filter(|c| c.dims.is_some())
|
||||
.map(|c| c.slot)
|
||||
.collect(),
|
||||
strings: Vec::new(),
|
||||
string_ids: HashMap::new(),
|
||||
jump_tables: Vec::new(),
|
||||
@@ -30,6 +36,13 @@ pub fn compile(hir: &HirModule) -> CompiledModule {
|
||||
procs.push(cg.compile_proc(proc));
|
||||
}
|
||||
CompiledModule {
|
||||
modules: vec![(hir.name.clone(), hir.option_base)],
|
||||
sources: vec![tb_frontend::source::SourceFile {
|
||||
module: 0,
|
||||
path: hir.name.clone(),
|
||||
}],
|
||||
form_initial: vec![],
|
||||
startup_form: None,
|
||||
name: hir.name.clone(),
|
||||
option_base: hir.option_base,
|
||||
strings: cg.strings,
|
||||
@@ -67,7 +80,7 @@ fn slot_init(v: &hir::HVar) -> TypeInit {
|
||||
}
|
||||
}
|
||||
|
||||
fn type_init(t: &HTy) -> TypeInit {
|
||||
pub(crate) fn type_init(t: &HTy) -> TypeInit {
|
||||
match t {
|
||||
HTy::Num(NumTy::Int) => TypeInit::Int,
|
||||
HTy::Num(NumTy::Lng) => TypeInit::Lng,
|
||||
@@ -82,6 +95,7 @@ fn type_init(t: &HTy) -> TypeInit {
|
||||
}
|
||||
|
||||
struct Codegen {
|
||||
common_arrays: std::collections::HashSet<u16>,
|
||||
strings: Vec<Rc<str>>,
|
||||
string_ids: HashMap<String, u16>,
|
||||
jump_tables: Vec<Vec<u32>>,
|
||||
@@ -95,6 +109,7 @@ struct Codegen {
|
||||
}
|
||||
|
||||
struct ProcCtx {
|
||||
pos: tb_frontend::SourcePos,
|
||||
code: Vec<Instr>,
|
||||
/// LabelId → Instruktionsindex.
|
||||
label_pc: Vec<Option<u32>>,
|
||||
@@ -134,6 +149,10 @@ impl ProcCtx {
|
||||
self.label_pc[label as usize] = Some(pc);
|
||||
}
|
||||
fn emit(&mut self, i: Instr) {
|
||||
if matches!(i, Instr::Stmt(_) | Instr::InitStmt(_)) {
|
||||
self.code
|
||||
.push(Instr::Source(self.pos.source, self.pos.column));
|
||||
}
|
||||
self.code.push(i);
|
||||
}
|
||||
/// Sprunginstruktion mit noch unbekanntem Ziel emittieren.
|
||||
@@ -162,6 +181,7 @@ impl Codegen {
|
||||
|
||||
fn compile_proc(&mut self, proc: &hir::HProc) -> ProcCode {
|
||||
let mut ctx = ProcCtx {
|
||||
pos: tb_frontend::SourcePos::default(),
|
||||
code: Vec::new(),
|
||||
label_pc: vec![None; proc.label_count as usize],
|
||||
fixups: Vec::new(),
|
||||
@@ -238,6 +258,10 @@ impl Codegen {
|
||||
}
|
||||
|
||||
ProcCode {
|
||||
module: 0,
|
||||
kind: proc.kind,
|
||||
params: proc.params.clone(),
|
||||
ret_ty: proc.ret_ty.clone(),
|
||||
name: proc.name.clone(),
|
||||
n_params: proc.params.len() as u16,
|
||||
locals_init: proc.locals.iter().map(slot_init).collect(),
|
||||
@@ -268,13 +292,14 @@ impl Codegen {
|
||||
}
|
||||
|
||||
fn stmt_inner(&mut self, ctx: &mut ProcCtx, proc: &hir::HProc, stmt: &HStmt, boundary: bool) {
|
||||
ctx.pos = stmt.pos;
|
||||
match &stmt.kind {
|
||||
HStmtKind::Label(l) => {
|
||||
ctx.bind(*l);
|
||||
return;
|
||||
}
|
||||
_ if boundary => ctx.emit(Instr::Stmt(stmt.line)),
|
||||
_ => {}
|
||||
_ => ctx.emit(Instr::InitStmt(stmt.line)),
|
||||
}
|
||||
match &stmt.kind {
|
||||
HStmtKind::Label(_) => unreachable!(),
|
||||
@@ -478,6 +503,7 @@ impl Codegen {
|
||||
}
|
||||
}
|
||||
HStmtKind::Loop {
|
||||
end_pos,
|
||||
pre,
|
||||
post,
|
||||
body,
|
||||
@@ -496,6 +522,8 @@ impl Codegen {
|
||||
for s in body {
|
||||
self.stmt(ctx, proc, s);
|
||||
}
|
||||
ctx.pos = *end_pos;
|
||||
ctx.emit(Instr::Stmt(end_pos.line));
|
||||
match post {
|
||||
Some((is_until, cond)) => {
|
||||
self.expr(ctx, cond);
|
||||
@@ -511,6 +539,7 @@ impl Codegen {
|
||||
ctx.bind(*exit_label);
|
||||
}
|
||||
HStmtKind::For {
|
||||
end_pos,
|
||||
var,
|
||||
ty,
|
||||
from,
|
||||
@@ -533,7 +562,7 @@ impl Codegen {
|
||||
*step_slot,
|
||||
body,
|
||||
*exit_label,
|
||||
stmt.line,
|
||||
*end_pos,
|
||||
);
|
||||
}
|
||||
HStmtKind::Goto(l) => ctx.emit_jump(Instr::Jump(0), *l),
|
||||
@@ -663,6 +692,8 @@ impl Codegen {
|
||||
let init = type_init(elem);
|
||||
if *redim {
|
||||
ctx.emit(Instr::RedimArr(global, s, dims.len() as u8, init));
|
||||
} else if global && self.common_arrays.contains(&s) {
|
||||
ctx.emit(Instr::CommonArr(global, s, dims.len() as u8, init));
|
||||
} else {
|
||||
ctx.emit(Instr::DimArr(global, s, dims.len() as u8, init));
|
||||
}
|
||||
@@ -697,7 +728,7 @@ impl Codegen {
|
||||
step_slot: Option<VarSlot>,
|
||||
body: &[HStmt],
|
||||
exit_label: u16,
|
||||
line: u32,
|
||||
end_pos: tb_frontend::SourcePos,
|
||||
) {
|
||||
// Startwert, Grenze, ggf. Schritt einmal auswerten.
|
||||
self.store_place(ctx, var, |cg, ctx| cg.expr(ctx, from));
|
||||
@@ -715,15 +746,6 @@ impl Codegen {
|
||||
let l_test = ctx.new_label();
|
||||
let l_body = ctx.new_label();
|
||||
ctx.bind(l_test);
|
||||
// Anweisungsgrenze für den Rücksprung von `NEXT`. Sie kann nicht
|
||||
// auf die Grenze des `FOR` zeigen — dort stünde die Initialisierung
|
||||
// noch einmal.
|
||||
//
|
||||
// ponytail: gemeldet wird die Zeile des `FOR`, nicht die des
|
||||
// `NEXT` — die trägt das HIR nicht. Ceiling: braucht der Debugger
|
||||
// in Phase 5 die genaue Zeile, bekommt `HStmtKind::For` ein Feld
|
||||
// `next_line`.
|
||||
ctx.emit(Instr::Stmt(line));
|
||||
match const_step {
|
||||
Some(s) => {
|
||||
// Vergleichsrichtung zur Compilezeit.
|
||||
@@ -757,7 +779,9 @@ impl Codegen {
|
||||
for s in body {
|
||||
self.stmt(ctx, proc, s);
|
||||
}
|
||||
// NEXT: inkrementieren, zurück zum Test.
|
||||
// NEXT: eigene Quellgrenze für Fehler, RESUME und Debugger.
|
||||
ctx.pos = end_pos;
|
||||
ctx.emit(Instr::Stmt(end_pos.line));
|
||||
self.store_place(ctx, var, |cg, ctx| {
|
||||
cg.load_place(ctx, var);
|
||||
match (step, step_slot) {
|
||||
@@ -777,6 +801,7 @@ impl Codegen {
|
||||
match e {
|
||||
HExpr::Int(v) => ctx.emit(Instr::PushInt(*v)),
|
||||
HExpr::Lng(v) => ctx.emit(Instr::PushLng(*v)),
|
||||
HExpr::UdtId(id) => ctx.emit(Instr::PushUdtId(*id)),
|
||||
HExpr::Sng(v) => ctx.emit(Instr::PushSng(*v)),
|
||||
HExpr::Dbl(v) => ctx.emit(Instr::PushDbl(*v)),
|
||||
HExpr::Cur(v) => ctx.emit(Instr::PushCur(*v)),
|
||||
|
||||
Reference in New Issue
Block a user