Phase 4: Ereignisschleife und klassische Traps
This commit is contained in:
@@ -666,12 +666,11 @@ impl<'a> P<'a> {
|
||||
let decls = self.parse_var_decls();
|
||||
Some(Stmt::StaticDecl { decls, pos })
|
||||
}
|
||||
TokenKind::Ident { ref name, .. } if name == "LPRINT" => {
|
||||
self.parse_print(pos, true)
|
||||
}
|
||||
TokenKind::Ident { ref name, suffix: None }
|
||||
if name == "VIEW" && self.k_at(1) == TokenKind::Kw(Kw::Print) =>
|
||||
{
|
||||
TokenKind::Ident { ref name, .. } if name == "LPRINT" => self.parse_print(pos, true),
|
||||
TokenKind::Ident {
|
||||
ref name,
|
||||
suffix: None,
|
||||
} if name == "VIEW" && self.k_at(1) == TokenKind::Kw(Kw::Print) => {
|
||||
self.advance(); // VIEW
|
||||
self.advance(); // PRINT
|
||||
let (mut top, mut bottom) = (None, None);
|
||||
@@ -972,9 +971,7 @@ impl<'a> P<'a> {
|
||||
}
|
||||
if matches!(self.k(), TokenKind::Eol) {
|
||||
// Blockform
|
||||
let stop = |p: &P| {
|
||||
p.is_kw(Kw::ElseIf) || p.is_kw(Kw::Else) || p.at_end_pair(Kw::If)
|
||||
};
|
||||
let stop = |p: &P| p.is_kw(Kw::ElseIf) || p.is_kw(Kw::Else) || p.at_end_pair(Kw::If);
|
||||
let then_body = self.parse_stmt_list(stop);
|
||||
let mut elseifs = Vec::new();
|
||||
while self.eat_kw(Kw::ElseIf) {
|
||||
@@ -1071,10 +1068,12 @@ impl<'a> P<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
let body = self.parse_stmt_list(|p: &P| {
|
||||
p.is_kw(Kw::Case) || p.at_end_pair(Kw::Select)
|
||||
let body = self.parse_stmt_list(|p: &P| p.is_kw(Kw::Case) || p.at_end_pair(Kw::Select));
|
||||
arms.push(CaseArm {
|
||||
specs,
|
||||
body,
|
||||
pos: arm_pos,
|
||||
});
|
||||
arms.push(CaseArm { specs, body, pos: arm_pos });
|
||||
}
|
||||
if self.at_end_pair(Kw::Select) {
|
||||
self.advance();
|
||||
@@ -1149,6 +1148,46 @@ impl<'a> P<'a> {
|
||||
Some(Stmt::While { cond, body, pos })
|
||||
}
|
||||
|
||||
/// `ON <quelle>[(n)] GOSUB ziel`. Liefert `None` und lässt den Cursor
|
||||
/// unberührt, wenn hier kein Trap steht.
|
||||
fn parse_trap_def(&mut self, pos: SourcePos) -> Option<Stmt> {
|
||||
let start = self.i;
|
||||
let TokenKind::Ident { name, suffix: None } = self.k() else {
|
||||
return None;
|
||||
};
|
||||
if !matches!(
|
||||
name.as_str(),
|
||||
"TIMER" | "KEY" | "UEVENT" | "SIGNAL" | "COM" | "PEN" | "PLAY" | "STRIG"
|
||||
) {
|
||||
return None;
|
||||
}
|
||||
let device = name.clone();
|
||||
self.advance();
|
||||
let index = if self.eat(&TokenKind::LParen) {
|
||||
let e = self.parse_expr();
|
||||
if e.is_none() || !self.eat(&TokenKind::RParen) {
|
||||
self.i = start;
|
||||
return None;
|
||||
}
|
||||
e
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if !self.eat_kw(Kw::Gosub) {
|
||||
// Doch kein Trap — z. B. `ON TIMER GOTO …` gibt es nicht, aber
|
||||
// die Diagnose dafür gehört an die allgemeine Stelle.
|
||||
self.i = start;
|
||||
return None;
|
||||
}
|
||||
let target = self.parse_label_ref()?;
|
||||
Some(Stmt::TrapDef {
|
||||
device,
|
||||
index,
|
||||
target,
|
||||
pos,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_on(&mut self, pos: SourcePos) -> Option<Stmt> {
|
||||
self.advance(); // ON
|
||||
let local = self.eat_kw(Kw::Local);
|
||||
@@ -1186,7 +1225,13 @@ impl<'a> P<'a> {
|
||||
self.sync();
|
||||
return None;
|
||||
}
|
||||
// ON ausdruck GOTO/GOSUB liste (Event-Traps: Phase 3/4)
|
||||
// ON <quelle>[(n)] GOSUB ziel — klassische Ereignis-Traps (§8).
|
||||
// Muss vor dem berechneten `ON ausdruck GOSUB` stehen, sonst
|
||||
// verschwindet `ON TIMER(5) GOSUB Marke` still darin.
|
||||
if let Some(st) = self.parse_trap_def(pos) {
|
||||
return Some(st);
|
||||
}
|
||||
// ON ausdruck GOTO/GOSUB liste
|
||||
let expr = self.parse_expr()?;
|
||||
let gosub = if self.eat_kw(Kw::Goto) {
|
||||
false
|
||||
@@ -1528,26 +1573,34 @@ impl<'a> P<'a> {
|
||||
return None;
|
||||
}
|
||||
// Ereignissteuerung: `TIMER ON`, `KEY(5) OFF`, `UEVENT STOP` …
|
||||
if let Expr::Name { ref name, suffix: None, ref args, .. } = target {
|
||||
if let Expr::Name {
|
||||
ref name,
|
||||
suffix: None,
|
||||
ref args,
|
||||
..
|
||||
} = target
|
||||
{
|
||||
if matches!(
|
||||
name.as_str(),
|
||||
"TIMER" | "KEY" | "COM" | "PEN" | "PLAY" | "STRIG" | "UEVENT"
|
||||
| "EVENT"
|
||||
"TIMER" | "KEY" | "COM" | "PEN" | "PLAY" | "STRIG" | "UEVENT" | "EVENT"
|
||||
) {
|
||||
let action = match self.k() {
|
||||
TokenKind::Kw(Kw::On) => Some(EventAction::On),
|
||||
TokenKind::Kw(Kw::Stop) => Some(EventAction::Stop),
|
||||
TokenKind::Ident { ref name, suffix: None }
|
||||
if name == "OFF" =>
|
||||
{
|
||||
Some(EventAction::Off)
|
||||
}
|
||||
TokenKind::Ident {
|
||||
ref name,
|
||||
suffix: None,
|
||||
} if name == "OFF" => Some(EventAction::Off),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(action) = action {
|
||||
self.advance();
|
||||
let index = args.clone().and_then(|mut a| {
|
||||
if a.is_empty() { None } else { Some(a.remove(0)) }
|
||||
if a.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(a.remove(0))
|
||||
}
|
||||
});
|
||||
return Some(Stmt::EventControl {
|
||||
device: name.clone(),
|
||||
|
||||
Reference in New Issue
Block a user