Phase 4: Steuerelemente implementieren
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user