Phase 1 vollstaendig abgeschlossen; neue Vorgaben verankert

Frontend-Vervollstaendigung (keine offenen Punkte mehr in Phase 1):
- MID$-Anweisung, DEF-FN-Blockform, COMMON/SHARED/STATIC,
  LPRINT, VIEW PRINT, NAME AS, LOCK/UNLOCK, Ereignissteuerung
  (TIMER/KEY(n)/UEVENT ON|OFF|STOP), Metabefehle $INCLUDE/$STATIC/$DYNAMIC
- Komplette Datei-E/A-Grammatik: OPEN (beide Syntaxen, inkl. ISAM- und
  ACCESS/LOCK-Klauseln), CLOSE, FIELD, GET/PUT, LSET/RSET, WRITE, SEEK
- Semantik: UDT-Feldtypen, SHARED-Import von Modulvariablen,
  Konstantenfaltung (Invalid constant), OPTION BASE erfasst
- Non-Features konsistent zur Compile-Zeit abgewiesen: Hardware-Naehe,
  CHAIN, Grafik-Anweisungen, SOUND/PLAY ("Feature unavailable")
- 33 Frontend-Tests, Korpus-Meilenstein weiter gruen

Neue Vorgaben:
- Stufe-2-Ideen: SQLite/Embedded-SQL mit Record-Buffern; Runtime-
  Bibliotheken (z.B. crossterm) als BASIC-Bibliotheken
- Erster Kompatibilitaetstest: github.com/cout/vbdos (extern, wird nicht
  einvendort); binaer-.FRM-Konverter als Phase-4-Aufgabe (tbc convert-frm)
- Doku als Definition of Done: docs/ = Ist-Dokumentation, IDE-Hilfe
  rendert Markdown dynamisch zur Fenstergroesse (Phase-5-Aufgabe)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-02 09:30:44 +02:00
parent 333e794540
commit d77574d9de
6 changed files with 1059 additions and 165 deletions

View File

@@ -96,7 +96,7 @@ pub struct CaseArm {
pub struct VarDecl {
pub name: String,
pub suffix: Option<Suffix>,
/// `None` = Skalar; sonst Dimensionen `(untergrenze TO obergrenze)`.
/// `None` = Skalar; leerer Vec = Array ohne Dimensionsangabe (`a()`).
pub dims: Option<Vec<(Option<Expr>, Expr)>>,
pub as_type: Option<TypeName>,
pub pos: SourcePos,
@@ -161,12 +161,47 @@ pub struct Proc {
pub pos: SourcePos,
}
/// `OPEN … FOR modus`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OpenMode {
Input,
Output,
Append,
Random,
Binary,
Isam,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccessMode {
Read,
Write,
ReadWrite,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LockClause {
Shared,
LockRead,
LockWrite,
LockReadWrite,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EventAction {
On,
Off,
Stop,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt {
Label(String),
LineNumber(u32),
Assign { target: Expr, value: Expr, pos: SourcePos },
Print {
/// LPRINT (Druckerausgabe) statt PRINT.
printer: bool,
file: Option<Expr>,
using: Option<Expr>,
items: Vec<PrintItem>,
@@ -212,6 +247,17 @@ pub enum Stmt {
System,
Exit { kind: ExitKind, pos: SourcePos },
Dim { shared: bool, redim: bool, decls: Vec<VarDecl>, pos: SourcePos },
/// `SHARED`-Anweisung in einer Prozedur (Zugriff auf Modulvariablen).
SharedDecl { decls: Vec<VarDecl>, pos: SourcePos },
/// `STATIC`-Anweisung in einer Prozedur.
StaticDecl { decls: Vec<VarDecl>, pos: SourcePos },
/// `COMMON [SHARED] [/block/] liste`.
CommonDecl {
shared: bool,
block: Option<String>,
decls: Vec<VarDecl>,
pos: SourcePos,
},
Erase { names: Vec<Expr>, pos: SourcePos },
ConstDecl { items: Vec<(String, Option<Suffix>, Expr)>, pos: SourcePos },
DefType { ty: TypeName, ranges: Vec<(char, char)>, pos: SourcePos },
@@ -234,9 +280,69 @@ pub enum Stmt {
body: Expr,
pos: SourcePos,
},
/// Geparst, aber erst in Phase 3 implementiert (Datei-E/A u. ä.);
/// die Tokens der Anweisung wurden übersprungen.
NotYetImplemented { keyword: String, pos: SourcePos },
/// Blockform `DEF FNname(...) … END DEF`.
DefFnBlock {
name: String,
suffix: Option<Suffix>,
params: Vec<Param>,
body: Vec<Stmt>,
pos: SourcePos,
},
// ---- Datei-E/A (Laufzeit in Phase 3, Grammatik vollständig) ----
Open {
file: Expr,
mode: Option<OpenMode>,
/// Bei `FOR ISAM typname tabellenname`.
isam: Option<(String, String)>,
access: Option<AccessMode>,
lock: Option<LockClause>,
number: Expr,
len: Option<Expr>,
pos: SourcePos,
},
/// Alte Syntax `OPEN modus$, [#]n, datei$ [, reclen]`.
OpenLegacy {
mode: Expr,
number: Expr,
file: Expr,
len: Option<Expr>,
pos: SourcePos,
},
CloseStmt { files: Vec<Expr>, pos: SourcePos },
FieldStmt { file: Expr, fields: Vec<(Expr, Expr)>, pos: SourcePos },
GetPut {
put: bool,
file: Expr,
recnum: Option<Expr>,
var: Option<Expr>,
pos: SourcePos,
},
LsetRset { rset: bool, target: Expr, value: Expr, pos: SourcePos },
WriteStmt { file: Option<Expr>, items: Vec<Expr>, pos: SourcePos },
SeekStmt { file: Expr, position: Expr, pos: SourcePos },
LockStmt {
unlock: bool,
file: Expr,
from: Option<Expr>,
to: Option<Expr>,
pos: SourcePos,
},
NameStmt { old: Expr, new: Expr, pos: SourcePos },
// ---- Bildschirm/Ereignisse ----
/// `VIEW PRINT [oben TO unten]`.
ViewPrint { top: Option<Expr>, bottom: Option<Expr>, pos: SourcePos },
/// `TIMER ON`, `KEY(5) OFF`, `UEVENT STOP` …
EventControl {
device: String,
index: Option<Expr>,
action: EventAction,
pos: SourcePos,
},
// ---- Metabefehle ----
/// `'$INCLUDE: 'datei''` — Auflösung übernimmt der Compile-Treiber.
Include { path: String, pos: SourcePos },
/// `'$STATIC` / `'$DYNAMIC`.
MetaArrays { static_arrays: bool, pos: SourcePos },
}
#[derive(Debug, Clone, PartialEq)]