Phase 4: Formularmodell und Objektsprache
This commit is contained in:
@@ -8,10 +8,12 @@
|
||||
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use tb_frontend::forms::{FormObject, ObjectClass};
|
||||
use tb_frontend::hir::HEventProc;
|
||||
use tb_runtime::value::{TypeInit, UdtLayout};
|
||||
|
||||
pub const TBC_MAGIC: &[u8; 4] = b"TBC\0";
|
||||
pub const TBC_VERSION: u16 = 1;
|
||||
pub const TBC_VERSION: u16 = 3;
|
||||
|
||||
/// Vergleichsoperator (Operand der `Cmp*`-Instruktionen).
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@@ -52,7 +54,10 @@ impl fmt::Display for LoadError {
|
||||
match self {
|
||||
LoadError::BadMagic => write!(f, "Keine .tbc-Datei (Magic fehlt)"),
|
||||
LoadError::Version(v) => {
|
||||
write!(f, "Unbekannte .tbc-Formatversion {v} (unterstützt: {TBC_VERSION})")
|
||||
write!(
|
||||
f,
|
||||
"Unbekannte .tbc-Formatversion {v} (unterstützt: {TBC_VERSION})"
|
||||
)
|
||||
}
|
||||
LoadError::Corrupt(what) => write!(f, "Beschädigte .tbc-Datei ({what})"),
|
||||
}
|
||||
@@ -303,6 +308,14 @@ instrs! {
|
||||
0xB1 RetProc;
|
||||
0xB2 RetFn;
|
||||
0xB3 CallBuiltin(a: u16, b: u8);
|
||||
0xB4 LoadObjectProperty(a: u16, b: u16, c: bool);
|
||||
0xB5 StoreObjectProperty(a: u16, b: u16, c: bool);
|
||||
0xB6 PushObject(a: u16, b: bool);
|
||||
0xB7 TypeOf(a: u8);
|
||||
0xB8 ObjectMethod(a: u16, b: u16, c: u8);
|
||||
0xB9 ObjectLoad(a: u16, b: bool, c: bool); // unload?, Index liegt auf Stack?
|
||||
0xBA LoadDynamicObjectProperty(a: u16);
|
||||
0xBB StoreDynamicObjectProperty(a: u16);
|
||||
|
||||
// 0xE0 — Ereignis-Traps (Sprachreferenz §8); Kennung vom Stack
|
||||
0xE0 TrapDefine(a: u8, b: u32); // Quellenart, Sprungziel
|
||||
@@ -375,6 +388,8 @@ pub struct CompiledModule {
|
||||
pub data: Vec<DataItem>,
|
||||
/// Sprungtabellen für `ON n GOTO/GOSUB`.
|
||||
pub jump_tables: Vec<Vec<u32>>,
|
||||
pub objects: Vec<FormObject>,
|
||||
pub event_procs: Vec<HEventProc>,
|
||||
}
|
||||
|
||||
fn w_string(out: &mut Vec<u8>, s: &str) {
|
||||
@@ -458,6 +473,22 @@ impl CompiledModule {
|
||||
}
|
||||
sections.push((*b"JMPT", jmpt));
|
||||
|
||||
let mut objs = Vec::new();
|
||||
objs.extend_from_slice(&(self.objects.len() as u32).to_le_bytes());
|
||||
for o in &self.objects {
|
||||
w_string(&mut objs, &o.name);
|
||||
objs.push(o.class.id());
|
||||
w_string(&mut objs, o.parent_form.as_deref().unwrap_or(""));
|
||||
objs.push(o.array as u8);
|
||||
}
|
||||
objs.extend_from_slice(&(self.event_procs.len() as u32).to_le_bytes());
|
||||
for e in &self.event_procs {
|
||||
objs.extend_from_slice(&e.object.to_le_bytes());
|
||||
w_string(&mut objs, &e.event);
|
||||
objs.extend_from_slice(&e.proc.to_le_bytes());
|
||||
}
|
||||
sections.push((*b"OBJS", objs));
|
||||
|
||||
// Header + Abschnittstabelle
|
||||
let mut out = Vec::new();
|
||||
out.extend_from_slice(TBC_MAGIC);
|
||||
@@ -567,7 +598,13 @@ impl CompiledModule {
|
||||
for _ in 0..n_instr {
|
||||
code.push(Instr::decode(&mut cr)?);
|
||||
}
|
||||
procs.push(ProcCode { name, n_params, locals_init, local_names, code });
|
||||
procs.push(ProcCode {
|
||||
name,
|
||||
n_params,
|
||||
locals_init,
|
||||
local_names,
|
||||
code,
|
||||
});
|
||||
}
|
||||
|
||||
let mut r = section(b"DATA")?;
|
||||
@@ -591,6 +628,31 @@ impl CompiledModule {
|
||||
jump_tables.push(t);
|
||||
}
|
||||
|
||||
let mut r = section(b"OBJS")?;
|
||||
let n = r.u32()? as usize;
|
||||
let mut objects = Vec::with_capacity(n);
|
||||
for _ in 0..n {
|
||||
let name = r.string()?;
|
||||
let class = ObjectClass::from_id(r.u8()?).ok_or(LoadError::Corrupt("Objektklasse"))?;
|
||||
let parent = r.string()?;
|
||||
let array = r.u8()? != 0;
|
||||
objects.push(FormObject {
|
||||
name,
|
||||
class,
|
||||
parent_form: (!parent.is_empty()).then_some(parent),
|
||||
array,
|
||||
});
|
||||
}
|
||||
let n = r.u32()? as usize;
|
||||
let mut event_procs = Vec::with_capacity(n);
|
||||
for _ in 0..n {
|
||||
event_procs.push(HEventProc {
|
||||
object: r.u16()?,
|
||||
event: r.string()?,
|
||||
proc: r.u16()?,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(CompiledModule {
|
||||
name,
|
||||
option_base,
|
||||
@@ -601,6 +663,8 @@ impl CompiledModule {
|
||||
procs,
|
||||
data,
|
||||
jump_tables,
|
||||
objects,
|
||||
event_procs,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -660,8 +724,13 @@ mod tests {
|
||||
local_names: vec![],
|
||||
code: vec![Instr::Stmt(1), Instr::PushStr(0), Instr::End],
|
||||
}],
|
||||
data: vec![DataItem { text: "1.5".into(), line: 3 }],
|
||||
data: vec![DataItem {
|
||||
text: "1.5".into(),
|
||||
line: 3,
|
||||
}],
|
||||
jump_tables: vec![vec![4, 9]],
|
||||
objects: vec![],
|
||||
event_procs: vec![],
|
||||
};
|
||||
let bytes = m.to_tbc();
|
||||
let back = CompiledModule::from_tbc(&bytes).unwrap();
|
||||
@@ -687,6 +756,8 @@ mod tests {
|
||||
procs: vec![],
|
||||
data: vec![],
|
||||
jump_tables: vec![],
|
||||
objects: vec![],
|
||||
event_procs: vec![],
|
||||
};
|
||||
let mut bytes = m.to_tbc();
|
||||
bytes[4] = 0xFF; // Version hochsetzen
|
||||
|
||||
Reference in New Issue
Block a user