//! AST-Definitionen: Module, Prozeduren, Anweisungen, Ausdrücke, //! Deklarationen und benutzerdefinierte Typen. use crate::lexer::Suffix; use crate::SourcePos; /// Typangabe in `AS`-Klauseln. #[derive(Debug, Clone, PartialEq)] pub enum TypeName { Integer, Long, Single, Double, Currency, Str, FixedStr(i64), Udt(String), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnOp { Neg, Not, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinOp { Pow, Mul, Div, IntDiv, Mod, Add, Sub, Eq, Ne, Lt, Le, Gt, Ge, And, Or, Xor, Eqv, Imp, } #[derive(Debug, Clone, PartialEq)] pub enum Expr { IntLit(i16), LongLit(i32), SingleLit(f32), DoubleLit(f64), CurrencyLit(i64), StrLit(String), /// Benannter Zugriff: Variable, Arrayelement, Funktionsaufruf oder /// Konstante — Auflösung erfolgt in der Semantik. Name { name: String, suffix: Option, args: Option>, pos: SourcePos, }, Unary { op: UnOp, operand: Box, pos: SourcePos }, Binary { op: BinOp, lhs: Box, rhs: Box, pos: SourcePos }, /// Geklammerter Ausdruck. Semantisch transparent, aber als Argument /// erzwingt die Klammer Wertübergabe (BYVAL) statt BYREF. Paren(Box), /// Ausgelassenes Argument (`LOCATE , 5`). Missing, } impl Expr { pub fn pos(&self) -> SourcePos { match self { Expr::Name { pos, .. } | Expr::Unary { pos, .. } | Expr::Binary { pos, .. } => *pos, Expr::Paren(e) => e.pos(), _ => SourcePos::default(), } } } /// Sprungziel: alphanumerisches Label oder Zeilennummer. #[derive(Debug, Clone, PartialEq)] pub enum LabelRef { Name(String), Line(u32), } #[derive(Debug, Clone, PartialEq)] pub enum PrintItem { Expr(Expr), Comma, Semicolon, } #[derive(Debug, Clone, PartialEq)] pub enum CaseSpec { Expr(Expr), Range(Expr, Expr), Is(BinOp, Expr), } #[derive(Debug, Clone, PartialEq)] pub struct CaseArm { /// Leer = `CASE ELSE`. pub specs: Vec, pub body: Vec, pub pos: SourcePos, } #[derive(Debug, Clone, PartialEq)] pub struct VarDecl { pub name: String, pub suffix: Option, /// `None` = Skalar; leerer Vec = Array ohne Dimensionsangabe (`a()`). pub dims: Option, Expr)>>, pub as_type: Option, pub pos: SourcePos, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ExitKind { For, Do, Sub, Function, Def, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum OptionKind { Explicit, Base(u8), } #[derive(Debug, Clone, PartialEq)] pub enum OnErrorAction { Goto(LabelRef), ResumeNext, Disable, // GOTO 0 } #[derive(Debug, Clone, PartialEq)] pub enum ResumeKind { Retry, // RESUME [0] Next, Label(LabelRef), } #[derive(Debug, Clone, PartialEq)] pub struct Param { pub name: String, pub suffix: Option, pub array: bool, pub as_type: Option, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum ProcKind { Sub, Function, } #[derive(Debug, Clone, PartialEq)] pub struct ProcSig { pub kind: ProcKind, pub name: String, pub suffix: Option, pub params: Vec, } #[derive(Debug, Clone, PartialEq)] pub struct Proc { pub sig: ProcSig, pub is_static: bool, pub body: Vec, 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, using: Option, items: Vec, pos: SourcePos, }, Input { line: bool, file: Option, keep_cursor: bool, prompt: Option<(String, bool)>, // (Text, mit Fragezeichen) vars: Vec, pos: SourcePos, }, If { cond: Expr, then_body: Vec, elseifs: Vec<(Expr, Vec)>, else_body: Option>, pos: SourcePos, }, Select { expr: Expr, arms: Vec, pos: SourcePos }, For { var: Expr, from: Expr, to: Expr, step: Option, body: Vec, pos: SourcePos, }, DoLoop { pre: Option<(bool, Expr)>, // (ist UNTIL, Bedingung) post: Option<(bool, Expr)>, body: Vec, pos: SourcePos, }, While { cond: Expr, body: Vec, pos: SourcePos }, Goto { target: LabelRef, pos: SourcePos }, Gosub { target: LabelRef, pos: SourcePos }, OnGoto { expr: Expr, targets: Vec, gosub: bool, pos: SourcePos }, Return { target: Option, pos: SourcePos }, End(SourcePos), StopStmt(SourcePos), System(SourcePos), Exit { kind: ExitKind, pos: SourcePos }, Dim { shared: bool, redim: bool, decls: Vec, pos: SourcePos }, /// `SHARED`-Anweisung in einer Prozedur (Zugriff auf Modulvariablen). SharedDecl { decls: Vec, pos: SourcePos }, /// `STATIC`-Anweisung in einer Prozedur. StaticDecl { decls: Vec, pos: SourcePos }, /// `COMMON [SHARED] [/block/] liste`. CommonDecl { shared: bool, block: Option, decls: Vec, pos: SourcePos, }, Erase { names: Vec, pos: SourcePos }, ConstDecl { items: Vec<(String, Option, Expr)>, pos: SourcePos }, DefType { ty: TypeName, ranges: Vec<(char, char)>, pos: SourcePos }, OptionStmt { kind: OptionKind, pos: SourcePos }, TypeDecl { name: String, fields: Vec<(String, TypeName)>, pos: SourcePos }, Declare { sig: ProcSig, pos: SourcePos }, /// Expliziter oder impliziter Prozedur-/Builtin-Aufruf als Anweisung. Call { name: String, suffix: Option, args: Vec, pos: SourcePos }, OnError { local: bool, action: OnErrorAction, pos: SourcePos }, Resume { kind: ResumeKind, pos: SourcePos }, ErrorStmt { code: Expr, pos: SourcePos }, Data { items: Vec, pos: SourcePos }, ReadStmt { vars: Vec, pos: SourcePos }, Restore { target: Option, pos: SourcePos }, /// Einzeilige `DEF FNname(...) = ausdruck`-Definition. DefFn { name: String, suffix: Option, params: Vec, body: Expr, pos: SourcePos, }, /// Blockform `DEF FNname(...) … END DEF`. DefFnBlock { name: String, suffix: Option, params: Vec, body: Vec, pos: SourcePos, }, // ---- Datei-E/A (Laufzeit in Phase 3, Grammatik vollständig) ---- Open { file: Expr, mode: Option, /// Bei `FOR ISAM typname tabellenname`. isam: Option<(String, String)>, access: Option, lock: Option, number: Expr, len: Option, pos: SourcePos, }, /// Alte Syntax `OPEN modus$, [#]n, datei$ [, reclen]`. OpenLegacy { mode: Expr, number: Expr, file: Expr, len: Option, pos: SourcePos, }, CloseStmt { files: Vec, pos: SourcePos }, FieldStmt { file: Expr, fields: Vec<(Expr, Expr)>, pos: SourcePos }, GetPut { put: bool, file: Expr, recnum: Option, var: Option, pos: SourcePos, }, LsetRset { rset: bool, target: Expr, value: Expr, pos: SourcePos }, WriteStmt { file: Option, items: Vec, pos: SourcePos }, SeekStmt { file: Expr, position: Expr, pos: SourcePos }, LockStmt { unlock: bool, file: Expr, from: Option, to: Option, pos: SourcePos, }, NameStmt { old: Expr, new: Expr, pos: SourcePos }, // ---- Bildschirm/Ereignisse ---- /// `VIEW PRINT [oben TO unten]`. ViewPrint { top: Option, bottom: Option, pos: SourcePos }, /// `TIMER ON`, `KEY(5) OFF`, `UEVENT STOP` … EventControl { device: String, index: Option, 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)] pub struct Module { pub name: String, pub body: Vec, pub procs: Vec, }