Phase 4: Steuerelemente implementieren

This commit is contained in:
2026-09-05 12:49:46 +02:00
parent 1cb6ae8fd9
commit 19804e0e2d
36 changed files with 6472 additions and 689 deletions

View File

@@ -28,7 +28,18 @@ pub fn parse(module_name: &str, tokens: &[Token]) -> ParseOutput {
match p.k() {
TokenKind::Eof => break,
TokenKind::Kw(Kw::Sub) | TokenKind::Kw(Kw::Function) => {
if let Some(proc) = p.parse_proc() {
if let Some(proc) = p.parse_proc(false) {
procs.push(proc);
}
}
TokenKind::Kw(Kw::Static)
if matches!(
p.k_at(1),
TokenKind::Kw(Kw::Sub) | TokenKind::Kw(Kw::Function)
) =>
{
p.advance();
if let Some(proc) = p.parse_proc(true) {
procs.push(proc);
}
}
@@ -244,10 +255,7 @@ impl<'a> P<'a> {
self.advance();
self.parse_input(true, pos)
} else {
// Grafikform LINE (x1,y1)-(x2,y2): deklariertes Non-Feature.
self.err("Feature unavailable");
self.sync();
None
self.parse_graphics_line(pos)
}
}
TokenKind::Kw(Kw::If) => self.parse_if(pos),
@@ -350,12 +358,8 @@ impl<'a> P<'a> {
TokenKind::Kw(Kw::Erase) => {
self.advance();
let mut names = Vec::new();
loop {
if let Some(e) = self.parse_name_only() {
names.push(e);
} else {
break;
}
while let Some(e) = self.parse_name_only() {
names.push(e);
if !self.eat(&TokenKind::Comma) {
break;
}
@@ -548,12 +552,8 @@ impl<'a> P<'a> {
TokenKind::Kw(Kw::Read) => {
self.advance();
let mut vars = Vec::new();
loop {
if let Some(e) = self.parse_name_ref() {
vars.push(e);
} else {
break;
}
while let Some(e) = self.parse_name_ref() {
vars.push(e);
if !self.eat(&TokenKind::Comma) {
break;
}
@@ -733,6 +733,14 @@ impl<'a> P<'a> {
}
Some(Stmt::ViewPrint { top, bottom, pos })
}
TokenKind::Ident {
ref name,
suffix: None,
} if name == "VIEW" => self.parse_graphics_view(pos),
TokenKind::Ident {
ref name,
suffix: None,
} if name == "PAINT" => self.parse_graphics_paint(pos),
TokenKind::Ident {
ref name,
suffix: None,
@@ -832,6 +840,121 @@ impl<'a> P<'a> {
})
}
fn parse_graphics_point(&mut self) -> Option<(Expr, Expr)> {
if !self.eat(&TokenKind::LParen) {
self.err("Expected: (");
return None;
}
let x = self.parse_expr()?;
if !self.eat(&TokenKind::Comma) {
self.err("Expected: ,");
return None;
}
let y = self.parse_expr()?;
if !self.eat(&TokenKind::RParen) {
self.err("Expected: )");
return None;
}
Some((x, y))
}
fn parse_graphics_line(&mut self, pos: SourcePos) -> Option<Stmt> {
let from = if self.eat(&TokenKind::Minus) {
None
} else {
let point = self.parse_graphics_point()?;
if !self.eat(&TokenKind::Minus) {
self.err("Expected: -");
return None;
}
Some(point)
};
let relative = self.eat_kw(Kw::Step);
let to = self.parse_graphics_point()?;
let mut color = None;
let mut fill = 0;
if self.eat(&TokenKind::Comma) {
if !matches!(
self.k(),
TokenKind::Comma | TokenKind::Colon | TokenKind::Eol | TokenKind::Eof
) {
color = Some(self.parse_expr()?);
}
if self.eat(&TokenKind::Comma) {
if let TokenKind::Ident { name, .. } = self.k() {
fill = match name.as_str() {
"B" => 1,
"BF" => 2,
_ => {
self.err("Expected: B or BF");
return None;
}
};
self.advance();
}
}
}
Some(Stmt::GraphicsLine {
from,
to,
relative,
color,
fill,
pos,
})
}
fn parse_graphics_paint(&mut self, pos: SourcePos) -> Option<Stmt> {
self.advance();
let point = self.parse_graphics_point()?;
let paint = self
.eat(&TokenKind::Comma)
.then(|| self.parse_expr())
.flatten();
let border = self
.eat(&TokenKind::Comma)
.then(|| self.parse_expr())
.flatten();
Some(Stmt::GraphicsPaint {
point,
paint,
border,
pos,
})
}
fn parse_graphics_view(&mut self, pos: SourcePos) -> Option<Stmt> {
self.advance();
if self.at_stmt_end() {
return Some(Stmt::GraphicsView {
rect: None,
fill: None,
border: None,
pos,
});
}
let (x1, y1) = self.parse_graphics_point()?;
if !self.eat(&TokenKind::Minus) {
self.err("Expected: -");
return None;
}
let (x2, y2) = self.parse_graphics_point()?;
let fill = self
.eat(&TokenKind::Comma)
.then(|| self.parse_expr())
.flatten();
let border = self
.eat(&TokenKind::Comma)
.then(|| self.parse_expr())
.flatten();
Some(Stmt::GraphicsView {
rect: Some((x1, y1, x2, y2)),
fill,
border,
pos,
})
}
fn parse_print(&mut self, pos: SourcePos, printer: bool) -> Option<Stmt> {
self.advance(); // PRINT bzw. LPRINT
let file = if !printer && self.eat(&TokenKind::Hash) {
@@ -1056,12 +1179,8 @@ impl<'a> P<'a> {
}
}
let mut vars = Vec::new();
loop {
if let Some(e) = self.parse_name_ref() {
vars.push(e);
} else {
break;
}
while let Some(e) = self.parse_name_ref() {
vars.push(e);
if !self.eat(&TokenKind::Comma) {
break;
}
@@ -1384,11 +1503,8 @@ impl<'a> P<'a> {
return None;
};
let mut targets = Vec::new();
loop {
match self.parse_label_ref() {
Some(t) => targets.push(t),
None => break,
}
while let Some(t) = self.parse_label_ref() {
targets.push(t);
if !self.eat(&TokenKind::Comma) {
break;
}
@@ -1432,11 +1548,7 @@ impl<'a> P<'a> {
let dims = if self.eat(&TokenKind::LParen) {
let mut ds = Vec::new();
if !self.eat(&TokenKind::RParen) {
loop {
let a = match self.parse_expr() {
Some(e) => e,
None => break,
};
while let Some(a) = self.parse_expr() {
if self.eat_kw(Kw::To) {
match self.parse_expr() {
Some(b) => ds.push((Some(a), b)),
@@ -1602,44 +1714,42 @@ impl<'a> P<'a> {
}
};
let mut params = Vec::new();
if self.eat(&TokenKind::LParen) {
if !self.eat(&TokenKind::RParen) {
loop {
match self.k() {
TokenKind::Ident {
if self.eat(&TokenKind::LParen) && !self.eat(&TokenKind::RParen) {
loop {
match self.k() {
TokenKind::Ident {
name: pname,
suffix: psfx,
} => {
self.advance();
let array = if self.eat(&TokenKind::LParen) {
self.eat(&TokenKind::RParen);
true
} else {
false
};
let as_type = if self.eat_kw(Kw::As) {
self.parse_type_name()
} else {
None
};
params.push(Param {
name: pname,
suffix: psfx,
} => {
self.advance();
let array = if self.eat(&TokenKind::LParen) {
self.eat(&TokenKind::RParen);
true
} else {
false
};
let as_type = if self.eat_kw(Kw::As) {
self.parse_type_name()
} else {
None
};
params.push(Param {
name: pname,
suffix: psfx,
array,
as_type,
});
}
_ => {
self.err("Expected: identifier");
break;
}
array,
as_type,
});
}
if !self.eat(&TokenKind::Comma) {
_ => {
self.err("Expected: identifier");
break;
}
}
self.eat(&TokenKind::RParen);
if !self.eat(&TokenKind::Comma) {
break;
}
}
self.eat(&TokenKind::RParen);
}
Some(ProcSig {
kind,
@@ -1649,10 +1759,10 @@ impl<'a> P<'a> {
})
}
fn parse_proc(&mut self) -> Option<Proc> {
fn parse_proc(&mut self, leading_static: bool) -> Option<Proc> {
let pos = self.pos();
let sig = self.parse_proc_sig()?;
let is_static = self.eat_kw(Kw::Static);
let is_static = leading_static || self.eat_kw(Kw::Static);
let end_kw = match sig.kind {
ProcKind::Sub => Kw::Sub,
ProcKind::Function => Kw::Function,
@@ -1697,33 +1807,31 @@ impl<'a> P<'a> {
}
};
let mut params = Vec::new();
if self.eat(&TokenKind::LParen) {
if !self.eat(&TokenKind::RParen) {
loop {
match self.k() {
TokenKind::Ident {
if self.eat(&TokenKind::LParen) && !self.eat(&TokenKind::RParen) {
loop {
match self.k() {
TokenKind::Ident {
name: pname,
suffix: psfx,
} => {
self.advance();
params.push(Param {
name: pname,
suffix: psfx,
} => {
self.advance();
params.push(Param {
name: pname,
suffix: psfx,
array: false,
as_type: None,
});
}
_ => {
self.err("Expected: identifier");
break;
}
array: false,
as_type: None,
});
}
if !self.eat(&TokenKind::Comma) {
_ => {
self.err("Expected: identifier");
break;
}
}
self.eat(&TokenKind::RParen);
if !self.eat(&TokenKind::Comma) {
break;
}
}
self.eat(&TokenKind::RParen);
}
if self.eat(&TokenKind::Eq) {
let body = self.parse_expr()?;
@@ -1818,8 +1926,8 @@ impl<'a> P<'a> {
other => Expr::Paren(Box::new(other)),
})
.collect();
if !self.at_stmt_end() && call_args.is_empty() {
call_args = self.parse_arg_list_to_stmt_end();
if !self.at_stmt_end() && (call_args.is_empty() || name.contains('.')) {
call_args.extend(self.parse_arg_list_to_stmt_end());
}
Some(Stmt::Call {
name,
@@ -1842,7 +1950,7 @@ impl<'a> P<'a> {
match self.k() {
TokenKind::Ident { mut name, suffix } => {
self.advance();
let args = if self.eat(&TokenKind::LParen) {
let mut args = if self.eat(&TokenKind::LParen) {
let a = self.parse_arg_list(&TokenKind::RParen);
self.eat(&TokenKind::RParen);
Some(a)
@@ -1858,6 +1966,11 @@ impl<'a> P<'a> {
name.push('.');
name.push_str(&member);
self.advance();
if self.eat(&TokenKind::LParen) {
let member_args = self.parse_arg_list(&TokenKind::RParen);
self.eat(&TokenKind::RParen);
args.get_or_insert_with(Vec::new).extend(member_args);
}
}
_ => self.err("Expected: property"),
}
@@ -1935,6 +2048,7 @@ impl<'a> P<'a> {
args.push(Expr::Missing);
continue;
}
self.eat(&TokenKind::Hash);
match self.parse_expr() {
Some(e) => args.push(e),
None => break,
@@ -1985,11 +2099,7 @@ impl<'a> P<'a> {
fn parse_bin(&mut self, min_prec: u8) -> Option<Expr> {
let mut lhs = self.parse_prefix()?;
loop {
let (prec, op) = match self.infix_op() {
Some(x) => x,
None => break,
};
while let Some((prec, op)) = self.infix_op() {
if prec < min_prec {
break;
}