Phase 4: Formularmodell und Objektsprache
This commit is contained in:
@@ -43,9 +43,14 @@ pub fn compile(hir: &HirModule) -> CompiledModule {
|
||||
data: hir
|
||||
.data
|
||||
.iter()
|
||||
.map(|d| DataItem { text: d.text.clone(), line: d.line })
|
||||
.map(|d| DataItem {
|
||||
text: d.text.clone(),
|
||||
line: d.line,
|
||||
})
|
||||
.collect(),
|
||||
jump_tables: cg.jump_tables,
|
||||
objects: hir.objects.clone(),
|
||||
event_procs: hir.event_procs.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +73,7 @@ fn type_init(t: &HTy) -> TypeInit {
|
||||
HTy::Str => TypeInit::Str,
|
||||
HTy::FixedStr(n) => TypeInit::FixedStr(*n),
|
||||
HTy::Udt(id) => TypeInit::Udt(*id),
|
||||
HTy::Form | HTy::Control => TypeInit::Empty,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +175,8 @@ impl Codegen {
|
||||
for (idx, label) in std::mem::take(&mut ctx.fixups) {
|
||||
// Modulweites `ON ERROR GOTO` in einer Prozedur: das Label lebt
|
||||
// im Modulrumpf, nicht im eigenen.
|
||||
let modulweit = proc.kind != hir::HProcKind::Main
|
||||
&& matches!(ctx.code[idx], Instr::OnErrorGoto(_));
|
||||
let modulweit =
|
||||
proc.kind != hir::HProcKind::Main && matches!(ctx.code[idx], Instr::OnErrorGoto(_));
|
||||
let pc = if modulweit {
|
||||
self.modul_label_pc
|
||||
.get(label as usize)
|
||||
@@ -241,6 +247,52 @@ impl Codegen {
|
||||
HStmtKind::Assign { place, value } => {
|
||||
self.store_place(ctx, place, |cg, ctx| cg.expr(ctx, value));
|
||||
}
|
||||
HStmtKind::SetObjectProperty {
|
||||
object,
|
||||
index,
|
||||
property,
|
||||
value,
|
||||
} => {
|
||||
if let Some(index) = index {
|
||||
self.expr(ctx, index);
|
||||
}
|
||||
self.expr(ctx, value);
|
||||
ctx.emit(Instr::StoreObjectProperty(
|
||||
*object,
|
||||
*property,
|
||||
index.is_some(),
|
||||
));
|
||||
}
|
||||
HStmtKind::SetDynamicObjectProperty {
|
||||
object,
|
||||
property,
|
||||
value,
|
||||
} => {
|
||||
self.expr(ctx, object);
|
||||
self.expr(ctx, value);
|
||||
let property = self.pool(property);
|
||||
ctx.emit(Instr::StoreDynamicObjectProperty(property));
|
||||
}
|
||||
HStmtKind::ObjectMethod {
|
||||
object,
|
||||
method,
|
||||
args,
|
||||
} => {
|
||||
for arg in args {
|
||||
self.expr(ctx, arg);
|
||||
}
|
||||
ctx.emit(Instr::ObjectMethod(*object, *method, args.len() as u8));
|
||||
}
|
||||
HStmtKind::ObjectLoad {
|
||||
object,
|
||||
index,
|
||||
unload,
|
||||
} => {
|
||||
if let Some(index) = index {
|
||||
self.expr(ctx, index);
|
||||
}
|
||||
ctx.emit(Instr::ObjectLoad(*object, *unload, index.is_some()));
|
||||
}
|
||||
HStmtKind::Print { items, trailing } => {
|
||||
for item in items {
|
||||
match item {
|
||||
@@ -277,12 +329,21 @@ impl Codegen {
|
||||
}
|
||||
ctx.emit(Instr::Field(fields.len() as u8));
|
||||
}
|
||||
HStmtKind::LsetRset { rset, target, value } => {
|
||||
HStmtKind::LsetRset {
|
||||
rset,
|
||||
target,
|
||||
value,
|
||||
} => {
|
||||
self.make_ref(ctx, target);
|
||||
self.expr(ctx, value);
|
||||
ctx.emit(Instr::LsetRset(*rset));
|
||||
}
|
||||
HStmtKind::GetPut { put, file, recnum, var } => {
|
||||
HStmtKind::GetPut {
|
||||
put,
|
||||
file,
|
||||
recnum,
|
||||
var,
|
||||
} => {
|
||||
self.expr(ctx, file);
|
||||
if let Some(r) = recnum {
|
||||
self.expr(ctx, r);
|
||||
@@ -301,12 +362,19 @@ impl Codegen {
|
||||
HTy::Udt(i) => (7, *i),
|
||||
// Variable Strings: Länge erst zur Laufzeit.
|
||||
HTy::Str => (8, 0),
|
||||
HTy::Form | HTy::Control => (8, 0),
|
||||
}
|
||||
}
|
||||
};
|
||||
ctx.emit(Instr::GetPut(*put, recnum.is_some(), art, zusatz));
|
||||
}
|
||||
HStmtKind::Input { file, line_mode, prompt, question, targets } => {
|
||||
HStmtKind::Input {
|
||||
file,
|
||||
line_mode,
|
||||
prompt,
|
||||
question,
|
||||
targets,
|
||||
} => {
|
||||
if let Some(f) = file {
|
||||
// Dateinummer zuerst, dann die Referenzen darüber.
|
||||
self.expr(ctx, f);
|
||||
@@ -506,7 +574,12 @@ impl Codegen {
|
||||
}
|
||||
}
|
||||
HStmtKind::Restore(idx) => ctx.emit(Instr::Restore(*idx)),
|
||||
HStmtKind::Dim { slot, elem, dims, redim } => {
|
||||
HStmtKind::Dim {
|
||||
slot,
|
||||
elem,
|
||||
dims,
|
||||
redim,
|
||||
} => {
|
||||
for (lo, hi) in dims {
|
||||
self.expr(ctx, lo);
|
||||
self.expr(ctx, hi);
|
||||
@@ -637,6 +710,36 @@ impl Codegen {
|
||||
ctx.emit(Instr::PushStr(idx));
|
||||
}
|
||||
HExpr::Load(p) => self.load_place(ctx, p),
|
||||
HExpr::ObjectProperty {
|
||||
object,
|
||||
index,
|
||||
property,
|
||||
..
|
||||
} => {
|
||||
if let Some(index) = index {
|
||||
self.expr(ctx, index);
|
||||
}
|
||||
ctx.emit(Instr::LoadObjectProperty(
|
||||
*object,
|
||||
*property,
|
||||
index.is_some(),
|
||||
));
|
||||
}
|
||||
HExpr::DynamicObjectProperty { object, property } => {
|
||||
self.expr(ctx, object);
|
||||
let property = self.pool(property);
|
||||
ctx.emit(Instr::LoadDynamicObjectProperty(property));
|
||||
}
|
||||
HExpr::ObjectRef { object, index, .. } => {
|
||||
if let Some(index) = index {
|
||||
self.expr(ctx, index);
|
||||
}
|
||||
ctx.emit(Instr::PushObject(*object, index.is_some()));
|
||||
}
|
||||
HExpr::TypeOf { value, class } => {
|
||||
self.expr(ctx, value);
|
||||
ctx.emit(Instr::TypeOf(class.id()));
|
||||
}
|
||||
HExpr::Conv { from, to, arg } => {
|
||||
self.expr(ctx, arg);
|
||||
emit_conv(ctx, *from, *to);
|
||||
@@ -1276,7 +1379,12 @@ mod tests {
|
||||
let m = compile_src("SUB Inc (x%)\nx% = x% + 1\nEND SUB\nn% = 1\nInc n%\nInc (n%)");
|
||||
let code = main_code(&m);
|
||||
assert!(code.contains(&Instr::MakeRefGlobal(0)));
|
||||
assert!(code.iter().filter(|i| matches!(i, Instr::Call(1, 1))).count() == 2);
|
||||
assert!(
|
||||
code.iter()
|
||||
.filter(|i| matches!(i, Instr::Call(1, 1)))
|
||||
.count()
|
||||
== 2
|
||||
);
|
||||
// Prozedurrumpf liest/schreibt über Referenz
|
||||
let sub = &m.procs[1].code;
|
||||
assert!(sub.contains(&Instr::LoadRef(0)));
|
||||
@@ -1309,7 +1417,12 @@ mod tests {
|
||||
let m = compile_src("DATA 1, 2\nREAD a%, b%\nRESTORE\nREAD c%");
|
||||
let code = main_code(&m);
|
||||
assert_eq!(m.data.len(), 2);
|
||||
assert!(code.iter().filter(|i| matches!(i, Instr::ReadData(1))).count() == 3);
|
||||
assert!(
|
||||
code.iter()
|
||||
.filter(|i| matches!(i, Instr::ReadData(1)))
|
||||
.count()
|
||||
== 3
|
||||
);
|
||||
assert!(code.contains(&Instr::Restore(0)));
|
||||
assert!(code.contains(&Instr::ConvR8I2));
|
||||
}
|
||||
@@ -1318,7 +1431,9 @@ mod tests {
|
||||
fn fehlerbehandlung_emit() {
|
||||
let m = compile_src("ON ERROR GOTO H\nERROR 5\nEND\nH:\nRESUME NEXT");
|
||||
let code = main_code(&m);
|
||||
assert!(code.iter().any(|i| matches!(i, Instr::OnErrorGoto(t) if *t > 0)));
|
||||
assert!(code
|
||||
.iter()
|
||||
.any(|i| matches!(i, Instr::OnErrorGoto(t) if *t > 0)));
|
||||
assert!(code.contains(&Instr::RaiseError));
|
||||
assert!(code.contains(&Instr::ResumeNext));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user