@abapify/aclass 0.0.0 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/tokens.ts","../src/errors.ts","../src/lex.ts","../src/parser.ts","../src/assert.ts"],"sourcesContent":["/**\n * Chevrotain Token Definitions for the ABAP OO surface grammar.\n *\n * Scope: everything `@abapify/aclass` needs to tokenise a `.clas.abap` or\n * `.intf.abap` source file up to the point where method bodies become\n * opaque text. Method-body statements are NOT tokenised here — they are\n * captured verbatim by a dedicated body-capture token.\n *\n * ABAP is case-insensitive. All keywords use `/i` patterns so `CLASS`,\n * `Class`, and `class` all tokenise the same way.\n *\n * Keyword order inside `allTokens` matters:\n * 1. Multi-char operators before their single-char prefixes.\n * 2. Longer keywords before their prefixes (e.g. `CLASS-DATA` before\n * `CLASS`, `INTERFACES` before `INTERFACE`, `NON-UNIQUE` before\n * `UNIQUE`).\n * 3. `ABAPDocLine` BEFORE `LineComment` so `\"! foo` is captured as\n * documentation instead of as a regular line comment.\n * 4. `Identifier` must come last among the word-shaped tokens so that\n * keywords win their matches via `longer_alt`.\n */\nimport { createToken, Lexer } from 'chevrotain';\n\n// ============================================\n// Whitespace\n// ============================================\n\nexport const WhiteSpace = createToken({\n name: 'WhiteSpace',\n pattern: /[ \\t]+/,\n group: Lexer.SKIPPED,\n});\n\nexport const Newline = createToken({\n name: 'Newline',\n pattern: /\\r?\\n/,\n group: Lexer.SKIPPED,\n});\n\n// ============================================\n// Comments\n// ============================================\n\n/**\n * ABAPDoc line: `\"! …` up to end of line. MUST come before LineComment\n * because `\"!` is a prefix of `\"`.\n */\nexport const ABAPDocLine = createToken({\n name: 'ABAPDocLine',\n pattern: /\"![^\\r\\n]*/,\n});\n\n/** Regular line comment: `\" …` up to end of line. */\nexport const LineComment = createToken({\n name: 'LineComment',\n pattern: /\"[^\\r\\n]*/,\n group: Lexer.SKIPPED,\n});\n\n/** Full-line comment starting at column 1 with `*`. Only recognised at SOL. */\ntype CustomPattern = {\n exec: (text: string, offset: number) => RegExpExecArray | null;\n line_breaks?: boolean;\n};\nconst starCommentPattern: CustomPattern = {\n line_breaks: false,\n exec: (text, offset) => {\n // Only match when at start of line (offset 0 or previous char is \\n).\n if (offset !== 0 && text.charCodeAt(offset - 1) !== 0x0a /* \\n */) {\n return null;\n }\n if (text.charCodeAt(offset) !== 0x2a /* * */) return null;\n let end = offset;\n while (end < text.length) {\n const c = text.charCodeAt(end);\n if (c === 0x0a || c === 0x0d) break;\n end++;\n }\n const match = text.slice(offset, end);\n return [match] as unknown as RegExpExecArray;\n },\n};\nexport const StarComment = createToken({\n name: 'StarComment',\n pattern: starCommentPattern as unknown as RegExp,\n line_breaks: false,\n group: Lexer.SKIPPED,\n});\n\n// ============================================\n// Literals\n// ============================================\n\n/** Single-quoted ABAP text literal: `'...'` with doubled `''` for escaping. */\nexport const StringLiteral = createToken({\n name: 'StringLiteral',\n pattern: /'(?:[^']|'')*'/,\n});\n\n/** Backtick string literal: \\`...\\`. */\nexport const BacktickLiteral = createToken({\n name: 'BacktickLiteral',\n pattern: /`(?:[^`]|``)*`/,\n});\n\nexport const IntegerLiteral = createToken({\n name: 'IntegerLiteral',\n pattern: /-?\\d+/,\n});\n\n// ============================================\n// Identifier (must come AFTER all keywords in allTokens)\n// ============================================\n\n/**\n * ABAP identifier: starts with letter or underscore; may contain letters,\n * digits, underscores, slash (for namespaces like `/ui2/cl_json`), and\n * tilde (for qualified names like `zif_foo~method`) — but tilde is\n * reserved for qualified references, so at the lexer level we only allow\n * the \"simple\" form here. Qualified `~` and `=>` are handled in the\n * parser via separate tokens.\n *\n * Note: the `=>` operator (static scope) is tokenised as a distinct\n * symbol, not as part of the identifier.\n */\nexport const Identifier = createToken({\n name: 'Identifier',\n pattern: /[A-Za-z_][A-Za-z0-9_/]*/,\n});\n\n// ============================================\n// Keyword factory\n// ============================================\n\n// All characters that have a special meaning inside a RegExp literal.\n// We escape every one of them when embedding `word` into a dynamic\n// pattern so CodeQL's `js/incomplete-sanitization` stops complaining\n// and callers cannot inject pattern metacharacters by accident.\nconst REGEX_META = /[.*+?^${}()|[\\]\\\\/-]/g;\nfunction kw(name: string, word: string) {\n // Case-insensitive, whole-word match. `longer_alt: Identifier` makes\n // the keyword lose to `Identifier` when followed by an identifier\n // character, avoiding false positives like `CLASSIFIER` being split\n // into `CLASS IFIER`.\n const pattern = new RegExp(word.replace(REGEX_META, '\\\\$&'), 'i');\n return createToken({ name, pattern, longer_alt: Identifier });\n}\n\n// ============================================\n// Keywords (compound ones first)\n// ============================================\n\n// `CLASS-METHODS`, `CLASS-DATA`, `CLASS-EVENTS` — must be declared BEFORE\n// `CLASS` itself so the longer keyword wins.\nexport const ClassMethods = kw('ClassMethods', 'class-methods');\nexport const ClassData = kw('ClassData', 'class-data');\nexport const ClassEvents = kw('ClassEvents', 'class-events');\n\n// `NON-UNIQUE` before `UNIQUE`\nexport const NonUnique = kw('NonUnique', 'non-unique');\n\n// Core OO keywords\nexport const Class = kw('Class', 'class');\nexport const Interfaces = kw('Interfaces', 'interfaces'); // MUST come before Interface\nexport const Interface = kw('Interface', 'interface');\nexport const EndClass = kw('EndClass', 'endclass');\nexport const EndInterface = kw('EndInterface', 'endinterface');\nexport const EndMethod = kw('EndMethod', 'endmethod');\nexport const Definition = kw('Definition', 'definition');\nexport const Implementation = kw('Implementation', 'implementation');\nexport const Deferred = kw('Deferred', 'deferred');\nexport const Load = kw('Load', 'load');\n\n// Section visibility\nexport const Public = kw('Public', 'public');\nexport const Protected = kw('Protected', 'protected');\nexport const Private = kw('Private', 'private');\nexport const Section = kw('Section', 'section');\n\n// Member declaration keywords\nexport const Methods = kw('Methods', 'methods');\nexport const Method = kw('Method', 'method');\nexport const Data = kw('Data', 'data');\nexport const Types = kw('Types', 'types');\nexport const Constants = kw('Constants', 'constants');\nexport const Events = kw('Events', 'events');\nexport const Aliases = kw('Aliases', 'aliases');\n\n// Class-header modifiers\nexport const Inheriting = kw('Inheriting', 'inheriting');\nexport const From = kw('From', 'from');\nexport const For = kw('For', 'for');\nexport const Testing = kw('Testing', 'testing');\nexport const Risk = kw('Risk', 'risk');\nexport const Level = kw('Level', 'level');\nexport const Duration = kw('Duration', 'duration');\nexport const Final = kw('Final', 'final');\nexport const Abstract = kw('Abstract', 'abstract');\nexport const Create = kw('Create', 'create');\n\n// Method signature keywords\nexport const Importing = kw('Importing', 'importing');\nexport const Exporting = kw('Exporting', 'exporting');\nexport const Changing = kw('Changing', 'changing');\nexport const Returning = kw('Returning', 'returning');\nexport const Raising = kw('Raising', 'raising');\nexport const Value = kw('Value', 'value');\nexport const Optional = kw('Optional', 'optional');\nexport const Default = kw('Default', 'default');\nexport const Redefinition = kw('Redefinition', 'redefinition');\n\n// Type-ref keywords\nexport const Type = kw('Type', 'type');\nexport const Ref = kw('Ref', 'ref');\nexport const To = kw('To', 'to');\nexport const Like = kw('Like', 'like');\n\n// Table / structure type keywords\nexport const Begin = kw('Begin', 'begin');\nexport const End = kw('End', 'end');\nexport const Of = kw('Of', 'of');\nexport const Standard = kw('Standard', 'standard');\nexport const Sorted = kw('Sorted', 'sorted');\nexport const Hashed = kw('Hashed', 'hashed');\nexport const Table = kw('Table', 'table');\nexport const With = kw('With', 'with');\nexport const Key = kw('Key', 'key');\nexport const Empty = kw('Empty', 'empty');\nexport const Unique = kw('Unique', 'unique');\n\n// Constants / aliases linking\nexport const As = kw('As', 'as');\nexport const ReadOnly = kw('ReadOnly', 'read-only');\n\n// Visibility risk-level / duration literals (these are IDENTIFIERS in\n// the real grammar, but we keep them as plain Identifier and interpret\n// them in the visitor; no dedicated tokens).\n\n// ============================================\n// Symbols — multi-char first\n// ============================================\n\n/** Static scope operator: `=>` */\nexport const FatArrow = createToken({\n name: 'FatArrow',\n pattern: /=>/,\n});\n\n/** Instance member operator: `->` */\nexport const Arrow = createToken({\n name: 'Arrow',\n pattern: /->/,\n});\n\n/** Component selector inside generic reference: `::` (rare, reserved). */\nexport const ColonColon = createToken({\n name: 'ColonColon',\n pattern: /::/,\n});\n\n// Single-char symbols\nexport const Dot = createToken({ name: 'Dot', pattern: /\\./ });\nexport const Comma = createToken({ name: 'Comma', pattern: /,/ });\nexport const Colon = createToken({ name: 'Colon', pattern: /:/ });\nexport const Tilde = createToken({ name: 'Tilde', pattern: /~/ });\nexport const LParen = createToken({ name: 'LParen', pattern: /\\(/ });\nexport const RParen = createToken({ name: 'RParen', pattern: /\\)/ });\nexport const LBracket = createToken({ name: 'LBracket', pattern: /\\[/ });\nexport const RBracket = createToken({ name: 'RBracket', pattern: /\\]/ });\nexport const Eq = createToken({ name: 'Eq', pattern: /=/ });\n\n// `#` — inferred-type placeholder in `VALUE #(…)`, `NEW #(…)`, `COND #(…)`, etc.\nexport const Hash = createToken({ name: 'Hash', pattern: /#/ });\n\n// String templates `|…|` with interpolation braces `{` / `}`.\n// We tokenise them at the single-character level — good enough for\n// opaque-body preservation, since the parser never inspects expression\n// interior for MethodImpl.body.\nexport const Pipe = createToken({ name: 'Pipe', pattern: /\\|/ });\nexport const LBrace = createToken({ name: 'LBrace', pattern: /\\{/ });\nexport const RBrace = createToken({ name: 'RBrace', pattern: /\\}/ });\n\n// Arithmetic / comparison operators that appear inside method bodies.\n// Treated as plain symbols — the body parser doesn't need their semantics.\nexport const Plus = createToken({ name: 'Plus', pattern: /\\+/ });\nexport const Minus = createToken({ name: 'Minus', pattern: /-/ });\nexport const Star = createToken({ name: 'Star', pattern: /\\*/ });\nexport const Slash = createToken({ name: 'Slash', pattern: /\\// });\nexport const Lt = createToken({ name: 'Lt', pattern: /</ });\nexport const Gt = createToken({ name: 'Gt', pattern: />/ });\nexport const Question = createToken({ name: 'Question', pattern: /\\?/ });\nexport const At = createToken({ name: 'At', pattern: /@/ });\nexport const Ampersand = createToken({ name: 'Ampersand', pattern: /&/ });\n\n// ============================================\n// Full token array — lexer dispatch order\n// ============================================\n\nexport const allTokens = [\n // whitespace / comments\n WhiteSpace,\n Newline,\n StarComment,\n ABAPDocLine,\n LineComment,\n\n // multi-char symbols before single-char variants\n FatArrow,\n Arrow,\n ColonColon,\n\n // literals\n StringLiteral,\n BacktickLiteral,\n IntegerLiteral,\n\n // compound keywords MUST come before their prefixes\n ClassMethods,\n ClassData,\n ClassEvents,\n NonUnique,\n ReadOnly,\n\n // core OO\n Class,\n Interfaces,\n Interface,\n EndClass,\n EndInterface,\n EndMethod,\n Definition,\n Implementation,\n Deferred,\n Load,\n\n // visibility\n Public,\n Protected,\n Private,\n Section,\n\n // members\n Methods,\n Method,\n Data,\n Types,\n Constants,\n Events,\n Aliases,\n\n // header modifiers\n Inheriting,\n From,\n For,\n Testing,\n Risk,\n Level,\n Duration,\n Final,\n Abstract,\n Create,\n\n // signature\n Importing,\n Exporting,\n Changing,\n Returning,\n Raising,\n Value,\n Optional,\n Default,\n Redefinition,\n\n // type refs\n Type,\n Ref,\n To,\n Like,\n As,\n\n // table / structure\n Begin,\n End,\n Of,\n Standard,\n Sorted,\n Hashed,\n Table,\n With,\n Key,\n Empty,\n Unique,\n\n // Identifier — must come after all keywords\n Identifier,\n\n // single-char symbols\n Dot,\n Comma,\n Colon,\n Tilde,\n LParen,\n RParen,\n LBracket,\n RBracket,\n Eq,\n Hash,\n Pipe,\n LBrace,\n RBrace,\n Plus,\n Minus,\n Star,\n Slash,\n Lt,\n Gt,\n Question,\n At,\n Ampersand,\n];\n\nexport const AclassLexer = new Lexer(allTokens, {\n // Track newline positions so error locations have line/column.\n positionTracking: 'full',\n});\n","/**\n * Normalised parse errors for `@abapify/aclass`.\n *\n * Both Chevrotain lex errors and parse errors are flattened into a single\n * `ParseError` shape so callers don't need to know which phase produced\n * the diagnostic.\n */\nimport type { ILexingError, IRecognitionException } from 'chevrotain';\n\nexport interface ParseError {\n severity: 'error' | 'warning';\n message: string;\n line: number;\n column: number;\n offset: number;\n length: number;\n}\n\nexport function fromLexError(err: ILexingError): ParseError {\n return {\n severity: 'error',\n message: err.message,\n line: err.line ?? 1,\n column: err.column ?? 1,\n offset: err.offset,\n length: err.length,\n };\n}\n\nexport function fromParseError(err: IRecognitionException): ParseError {\n const token = err.token;\n return {\n severity: 'error',\n message: err.message,\n line: token.startLine ?? 1,\n column: token.startColumn ?? 1,\n offset: token.startOffset,\n length: (token.endOffset ?? token.startOffset) - token.startOffset + 1,\n };\n}\n","/**\n * Wave 0 entry point: tokenise an ABAP OO source string and return the\n * resulting token list along with any lex errors, normalised to\n * `ParseError`.\n *\n * Wave 1 replaces this with a full `parse()` that feeds the token list\n * into a Chevrotain `CstParser` and yields a typed AST. This function\n * stays around as the low-level primitive.\n */\nimport { AclassLexer } from './tokens';\nimport type { IToken } from 'chevrotain';\nimport { fromLexError, type ParseError } from './errors';\n\nexport interface LexResult {\n tokens: IToken[];\n errors: ParseError[];\n}\n\nexport function tokenize(source: string): LexResult {\n const result = AclassLexer.tokenize(source);\n return {\n tokens: result.tokens,\n errors: result.errors.map(fromLexError),\n };\n}\n","/**\n * Statement-based ABAP OO parser.\n *\n * ABAP is a statement-terminated language: every declaration ends with\n * a `.` (`Dot` token). Rather than building a full Chevrotain CstParser\n * (which would require declaring the entire expression grammar just to\n * parse type references), we:\n *\n * 1. Tokenise with `AclassLexer` (Wave 0).\n * 2. Split the token stream into statements on `Dot`.\n * 3. Classify each statement by its leading keyword and build a typed\n * AST node from the token slice — or produce a `RawMember` /\n * `ParseError` when the shape is outside MVP scope.\n *\n * The trade-off versus a CstParser: we lose automatic recovery and\n * lookahead machinery, but gain (a) drastically simpler code, (b) direct\n * access to token offsets for building exact source spans, (c) easy\n * `RawMember` fallback for any shape we haven't taught yet.\n */\nimport type { IToken } from 'chevrotain';\nimport { tokenize } from './lex';\nimport type { ParseError } from './errors';\nimport type {\n AbapDefinition,\n AbapSourceFile,\n AliasDecl,\n AttributeDecl,\n ClassDef,\n ClassImpl,\n ClassMember,\n ConstantDecl,\n EventDecl,\n InterfaceDef,\n InterfaceStmt,\n MethodDecl,\n MethodImpl,\n MethodParam,\n Section,\n SourceSpan,\n StructureField,\n TableKind,\n TableTypeRef,\n TypeDecl,\n TypeRef,\n Visibility,\n} from './ast';\n\nexport interface ParseResult {\n readonly ast: AbapSourceFile;\n readonly errors: readonly ParseError[];\n}\n\n/**\n * Parse an ABAP OO source file into a typed AST plus any diagnostics.\n * Returns a `{ ast, errors }` shape; never throws for malformed input.\n */\nexport function parse(source: string): ParseResult {\n const errors: ParseError[] = [];\n const { tokens, errors: lexErrors } = tokenize(source);\n errors.push(...lexErrors);\n\n const definitions: AbapDefinition[] = [];\n const cursor = new Cursor(tokens, source, errors);\n\n try {\n while (!cursor.eof()) {\n const def = parseTopLevel(cursor);\n if (def) definitions.push(def);\n }\n } catch (err) {\n // The parser is documented to never throw — any unexpected exception\n // (e.g. a missing `eof()` guard in a future helper) is normalised\n // into a `ParseError` and attached to the result so callers still\n // get a best-effort AST.\n errors.push({\n severity: 'error',\n message: `internal parser error: ${\n err instanceof Error ? err.message : String(err)\n }`,\n line: 1,\n column: 1,\n offset: 0,\n length: 0,\n });\n }\n\n const ast: AbapSourceFile = {\n kind: 'AbapSourceFile',\n source,\n definitions,\n };\n return { ast, errors };\n}\n\n// ============================================\n// Cursor — linear token stream with helpers\n// ============================================\n\nclass Cursor {\n private position = 0;\n constructor(\n private readonly tokens: readonly IToken[],\n private readonly source: string,\n private readonly errors: ParseError[],\n ) {}\n\n eof(): boolean {\n return this.position >= this.tokens.length;\n }\n\n peek(offset = 0): IToken | undefined {\n return this.tokens[this.position + offset];\n }\n\n current(): IToken {\n const t = this.tokens[this.position];\n if (!t) throw new Error('Cursor.current() called past end of stream');\n return t;\n }\n\n advance(): IToken {\n const t = this.current();\n this.position += 1;\n return t;\n }\n\n matches(name: string, offset = 0): boolean {\n return this.peek(offset)?.tokenType.name === name;\n }\n\n /** Collect tokens up to (not including) the next `Dot` at top level. */\n collectStatement(): {\n readonly tokens: IToken[];\n readonly terminator?: IToken;\n readonly startOffset: number;\n readonly endOffset: number;\n } {\n const collected: IToken[] = [];\n const start = this.peek()?.startOffset ?? 0;\n while (!this.eof()) {\n const t = this.current();\n if (t.tokenType.name === 'Dot') {\n this.advance();\n return {\n tokens: collected,\n terminator: t,\n startOffset: start,\n endOffset: t.endOffset ?? t.startOffset,\n };\n }\n collected.push(t);\n this.advance();\n }\n // EOF without terminating dot — pragmatic: return what we have.\n return {\n tokens: collected,\n startOffset: start,\n endOffset: collected[collected.length - 1]?.endOffset ?? start,\n };\n }\n\n /** Accumulate consecutive ABAPDoc lines at the current position. */\n consumeAbapDoc(): string[] | undefined {\n const doc: string[] = [];\n while (this.matches('ABAPDocLine')) {\n const t = this.advance();\n // Strip the leading `\"!` and one optional leading space.\n doc.push(t.image.replace(/^\"!\\s?/, ''));\n }\n return doc.length > 0 ? doc : undefined;\n }\n\n report(\n message: string,\n at: IToken,\n severity: ParseError['severity'] = 'error',\n ): void {\n this.errors.push({\n severity,\n message,\n line: at.startLine ?? 1,\n column: at.startColumn ?? 1,\n offset: at.startOffset,\n length: (at.endOffset ?? at.startOffset) - at.startOffset + 1,\n });\n }\n\n sliceSource(startOffset: number, endOffset: number): string {\n return this.source.slice(startOffset, endOffset + 1);\n }\n\n /**\n * Return the first token whose start offset is greater than or equal\n * to the given offset. Useful for recovering line/column metadata for\n * a source-slice boundary that doesn't land on a token (e.g. the\n * start of a method body, which is usually whitespace).\n */\n firstTokenAtOrAfter(offset: number): IToken | undefined {\n for (const t of this.tokens) {\n if (t.startOffset >= offset) return t;\n }\n return undefined;\n }\n}\n\n// ============================================\n// Top-level dispatcher\n// ============================================\n\nfunction parseTopLevel(c: Cursor): AbapDefinition | null {\n const abapDoc = c.consumeAbapDoc();\n if (c.eof()) return null;\n const t = c.current();\n const name = t.tokenType.name;\n\n if (name === 'Class') {\n return parseClassOrImpl(c, abapDoc);\n }\n if (name === 'Interface') {\n return parseInterface(c, abapDoc);\n }\n // Unknown top-level token — skip ahead to next `Dot` to recover.\n c.report(`unexpected top-level token \"${t.image}\"`, t);\n c.collectStatement();\n return null;\n}\n\n// ============================================\n// CLASS … DEFINITION OR CLASS … IMPLEMENTATION\n// ============================================\n\nfunction parseClassOrImpl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): ClassDef | ClassImpl | null {\n // Lookahead: find the DEFINITION / IMPLEMENTATION keyword after the name.\n // Pattern: CLASS <name> {DEFINITION|IMPLEMENTATION} [ … ] .\n const classTok = c.current();\n const startOffset = classTok.startOffset;\n const startLine = classTok.startLine ?? 1;\n const startColumn = classTok.startColumn ?? 1;\n\n const header = c.collectStatement();\n // header.tokens[0] = Class (already advanced past)\n // Rebuild: [Class, name, DEFINITION|IMPLEMENTATION, …rest]\n\n const tokens = header.tokens;\n if (tokens[0]?.tokenType.name !== 'Class') {\n c.report('expected CLASS keyword', classTok);\n return null;\n }\n const nameTok = tokens[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected class name after CLASS', nameTok ?? classTok);\n return null;\n }\n const kindTok = tokens[2];\n if (!kindTok) {\n c.report('expected DEFINITION or IMPLEMENTATION after class name', nameTok);\n return null;\n }\n\n if (kindTok.tokenType.name === 'Implementation') {\n return parseClassImpl(c, nameTok.image, {\n startOffset,\n endOffset: header.endOffset,\n startLine,\n startColumn,\n });\n }\n if (kindTok.tokenType.name !== 'Definition') {\n c.report(\n `expected DEFINITION or IMPLEMENTATION, got \"${kindTok.image}\"`,\n kindTok,\n );\n return null;\n }\n\n return parseClassDef(c, tokens, abapDoc, {\n startOffset,\n endOffset: header.endOffset,\n startLine,\n startColumn,\n });\n}\n\nfunction parseClassDef(\n c: Cursor,\n headerTokens: IToken[],\n abapDoc: string[] | undefined,\n headerSpan: SourceSpan,\n): ClassDef {\n // headerTokens: [Class, Ident, Definition, …modifiers…]\n const name = headerTokens[1].image;\n const mods = headerTokens.slice(3);\n\n // Forward declaration: `CLASS x DEFINITION DEFERRED.` / `… DEFINITION LOAD.`\n // has no body and must NOT expect ENDCLASS.\n const isForwardDecl = mods.some(\n (t) => t.tokenType.name === 'Deferred' || t.tokenType.name === 'Load',\n );\n if (isForwardDecl) {\n return {\n kind: 'ClassDef',\n name,\n abapDoc,\n isFinal: false,\n isAbstract: false,\n isForTesting: false,\n createVisibility: 'public',\n sections: [],\n span: headerSpan,\n };\n }\n\n let isFinal = false;\n let isAbstract = false;\n let isForTesting = false;\n let createVisibility: Visibility = 'public';\n let superClass: string | undefined;\n\n for (let i = 0; i < mods.length; i++) {\n const t = mods[i];\n switch (t.tokenType.name) {\n case 'Public':\n break;\n case 'Final':\n isFinal = true;\n break;\n case 'Abstract':\n isAbstract = true;\n break;\n case 'Inheriting': {\n // INHERITING FROM <super>\n const from = mods[i + 1];\n const sup = mods[i + 2];\n if (from?.tokenType.name === 'From' && sup) {\n superClass = sup.image;\n i += 2;\n }\n break;\n }\n case 'Create': {\n const v = mods[i + 1];\n if (v?.tokenType.name === 'Private') createVisibility = 'private';\n else if (v?.tokenType.name === 'Protected')\n createVisibility = 'protected';\n else createVisibility = 'public';\n i += 1;\n break;\n }\n case 'For': {\n // FOR TESTING [ RISK LEVEL <x> ] [ DURATION <y> ]\n if (mods[i + 1]?.tokenType.name === 'Testing') {\n isForTesting = true;\n }\n break;\n }\n default:\n break;\n }\n }\n\n const sections: Section[] = [];\n while (!c.eof() && !c.matches('EndClass')) {\n const sec = parseSection(c);\n if (sec) sections.push(sec);\n else break;\n }\n // Consume the closing `ENDCLASS.` or report that it never arrived.\n if (c.matches('EndClass')) {\n c.collectStatement();\n } else {\n c.report(\n `unterminated CLASS ${name} DEFINITION — expected ENDCLASS`,\n headerTokens[0],\n );\n }\n\n return {\n kind: 'ClassDef',\n name,\n abapDoc,\n isFinal,\n isAbstract,\n isForTesting,\n createVisibility,\n superClass,\n sections,\n span: headerSpan,\n };\n}\n\nfunction parseClassImpl(\n c: Cursor,\n name: string,\n headerSpan: SourceSpan,\n): ClassImpl {\n const methods: MethodImpl[] = [];\n while (!c.eof() && !c.matches('EndClass')) {\n // Skip ABAPDoc before method impl (rarely seen, but be safe)\n c.consumeAbapDoc();\n if (c.eof() || c.matches('EndClass')) break;\n if (!c.matches('Method')) {\n // Skip stray statements inside IMPLEMENTATION block\n const stray = c.collectStatement();\n if (stray.tokens.length === 0) break;\n continue;\n }\n const mi = parseMethodImpl(c);\n if (mi) methods.push(mi);\n }\n if (c.matches('EndClass')) {\n c.collectStatement();\n } else {\n // No token handy — synthesise a diagnostic anchored at the header span.\n c['errors'].push({\n severity: 'error',\n message: `unterminated CLASS ${name} IMPLEMENTATION — expected ENDCLASS`,\n line: headerSpan.startLine,\n column: headerSpan.startColumn,\n offset: headerSpan.startOffset,\n length: headerSpan.endOffset - headerSpan.startOffset + 1,\n });\n }\n return { kind: 'ClassImpl', name, methods, span: headerSpan };\n}\n\nfunction parseMethodImpl(c: Cursor): MethodImpl | null {\n const methodTok = c.current();\n const header = c.collectStatement();\n // header.tokens: [Method, <qualifiedName>, …]\n const qual = readQualifiedName(header.tokens, 1);\n if (!qual) {\n c.report(\n 'expected method name after METHOD',\n header.tokens[1] ?? methodTok,\n );\n return null;\n }\n // Body: everything up to the next ENDMETHOD. We operate on source\n // offsets because we preserve the body verbatim.\n const bodyStart = header.endOffset + 1;\n // Walk tokens until ENDMETHOD Dot at top level. Methods don't nest, so a\n // flat scan is enough for well-formed input.\n while (!c.eof()) {\n if (c.matches('EndMethod')) {\n const endMethodStart = c.current().startOffset;\n const stmt = c.collectStatement();\n const bodyEnd = endMethodStart - 1;\n const totalEnd = stmt.endOffset;\n const body = c['sliceSource'](bodyStart, bodyEnd);\n // Locate the first non-whitespace line/column inside the body so\n // bodySpan points at the actual content, not at the `METHOD`\n // keyword that terminated with the `.` before bodyStart.\n const firstBodyTok = c.firstTokenAtOrAfter(bodyStart);\n const bodyLine = firstBodyTok?.startLine ?? methodTok.startLine ?? 1;\n const bodyCol = firstBodyTok?.startColumn ?? 1;\n return {\n kind: 'MethodImpl',\n name: qual.name,\n body,\n bodySpan: {\n startOffset: bodyStart,\n endOffset: bodyEnd,\n startLine: bodyLine,\n startColumn: bodyCol,\n },\n span: {\n startOffset: methodTok.startOffset,\n endOffset: totalEnd,\n startLine: methodTok.startLine ?? 1,\n startColumn: methodTok.startColumn ?? 1,\n },\n };\n }\n c.advance();\n }\n c.report('ENDMETHOD not found for METHOD block', methodTok);\n return null;\n}\n\n// ============================================\n// INTERFACE … ENDINTERFACE\n// ============================================\n\nfunction parseInterface(\n c: Cursor,\n abapDoc: string[] | undefined,\n): InterfaceDef | null {\n const ifaceTok = c.current();\n const header = c.collectStatement();\n const tokens = header.tokens;\n // [Interface, Ident, [Public], …]\n if (tokens[0]?.tokenType.name !== 'Interface') {\n c.report('expected INTERFACE keyword', ifaceTok);\n return null;\n }\n const nameTok = tokens[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected interface name after INTERFACE', nameTok ?? ifaceTok);\n return null;\n }\n const isPublic = tokens.slice(2).some((t) => t.tokenType.name === 'Public');\n\n const members: ClassMember[] = [];\n while (!c.eof() && !c.matches('EndInterface')) {\n const m = parseMember(c);\n if (m) members.push(m);\n else break;\n }\n if (c.matches('EndInterface')) c.collectStatement();\n\n return {\n kind: 'InterfaceDef',\n name: nameTok.image,\n abapDoc,\n isPublic,\n members,\n span: {\n startOffset: ifaceTok.startOffset,\n endOffset: header.endOffset,\n startLine: ifaceTok.startLine ?? 1,\n startColumn: ifaceTok.startColumn ?? 1,\n },\n };\n}\n\n// ============================================\n// Sections (PUBLIC / PROTECTED / PRIVATE SECTION.)\n// ============================================\n\nfunction parseSection(c: Cursor): Section | null {\n c.consumeAbapDoc(); // ABAPDoc on a section header is rare; drop\n if (c.eof()) return null;\n const first = c.current();\n let visibility: Visibility;\n if (first.tokenType.name === 'Public') visibility = 'public';\n else if (first.tokenType.name === 'Protected') visibility = 'protected';\n else if (first.tokenType.name === 'Private') visibility = 'private';\n else return null;\n // consume \"<vis> SECTION .\"\n const header = c.collectStatement();\n const sectionStart = header.startOffset;\n const members: ClassMember[] = [];\n while (!c.eof() && !isSectionBoundary(c)) {\n const m = parseMember(c);\n if (m) members.push(m);\n else break;\n }\n const end =\n members.length > 0\n ? members[members.length - 1].span.endOffset\n : header.endOffset;\n return {\n kind: 'Section',\n visibility,\n members,\n span: {\n startOffset: sectionStart,\n endOffset: end,\n startLine: first.startLine ?? 1,\n startColumn: first.startColumn ?? 1,\n },\n };\n}\n\nfunction isSectionBoundary(c: Cursor): boolean {\n if (c.matches('EndClass')) return true;\n if (c.matches('EndInterface')) return true;\n // `<vis> SECTION .` — we only accept these as section-starters, not\n // as member starts.\n const t = c.peek();\n if (!t) return true;\n if (\n t.tokenType.name === 'Public' ||\n t.tokenType.name === 'Protected' ||\n t.tokenType.name === 'Private'\n ) {\n return c.peek(1)?.tokenType.name === 'Section';\n }\n return false;\n}\n\n// ============================================\n// Members\n// ============================================\n\nfunction parseMember(c: Cursor): ClassMember | null {\n const abapDoc = c.consumeAbapDoc();\n if (c.eof()) return null;\n const head = c.current();\n const name = head.tokenType.name;\n\n switch (name) {\n case 'Methods':\n case 'ClassMethods':\n return parseMethodDecl(c, abapDoc);\n case 'Data':\n case 'ClassData':\n return parseAttributeDecl(c, abapDoc);\n case 'Types':\n return parseTypeDecl(c, abapDoc);\n case 'Constants':\n return parseConstantDecl(c, abapDoc);\n case 'Events':\n case 'ClassEvents':\n return parseEventDecl(c, abapDoc);\n case 'Interfaces':\n return parseInterfaceStmt(c, abapDoc);\n case 'Aliases':\n return parseAliasDecl(c, abapDoc);\n default: {\n // Unrecognised member → capture as RawMember for round-trip fidelity.\n const stmt = c.collectStatement();\n const source = c['sliceSource'](stmt.startOffset, stmt.endOffset);\n return {\n kind: 'RawMember',\n source,\n abapDoc,\n span: {\n startOffset: stmt.startOffset,\n endOffset: stmt.endOffset,\n startLine: head.startLine ?? 1,\n startColumn: head.startColumn ?? 1,\n },\n };\n }\n }\n}\n\n// --- METHODS / CLASS-METHODS ---\n\nfunction parseMethodDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): MethodDecl | null {\n const head = c.current();\n const isClassMethod = head.tokenType.name === 'ClassMethods';\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n // toks: [Methods|ClassMethods, <qualifiedName>, …]\n const qual = readQualifiedName(toks, 1);\n if (!qual) {\n c.report('expected method name', toks[1] ?? head);\n return null;\n }\n\n const importing: MethodParam[] = [];\n const exporting: MethodParam[] = [];\n const changing: MethodParam[] = [];\n let returning: MethodParam | undefined;\n const raising: string[] = [];\n\n let isAbstract = false;\n let isFinal = false;\n let isRedefinition = false;\n let isForTesting = false;\n\n let section:\n | 'none'\n | 'importing'\n | 'exporting'\n | 'changing'\n | 'returning'\n | 'raising' = 'none';\n\n let i = qual.lastIdx + 1;\n while (i < toks.length) {\n const t = toks[i];\n const tn = t.tokenType.name;\n if (tn === 'Abstract') {\n isAbstract = true;\n i += 1;\n continue;\n }\n if (tn === 'Final') {\n isFinal = true;\n i += 1;\n continue;\n }\n if (tn === 'Redefinition') {\n isRedefinition = true;\n i += 1;\n continue;\n }\n if (tn === 'For' && toks[i + 1]?.tokenType.name === 'Testing') {\n isForTesting = true;\n i += 2;\n continue;\n }\n if (tn === 'Importing') {\n section = 'importing';\n i += 1;\n continue;\n }\n if (tn === 'Exporting') {\n section = 'exporting';\n i += 1;\n continue;\n }\n if (tn === 'Changing') {\n section = 'changing';\n i += 1;\n continue;\n }\n if (tn === 'Returning') {\n section = 'returning';\n i += 1;\n continue;\n }\n if (tn === 'Raising') {\n section = 'raising';\n i += 1;\n continue;\n }\n\n if (section === 'raising') {\n if (tn === 'Identifier') {\n raising.push(t.image);\n i += 1;\n continue;\n }\n i += 1;\n continue;\n }\n\n if (section === 'none') {\n i += 1;\n continue;\n }\n\n // Consume one parameter starting at i\n const consumed = consumeMethodParam(toks, i, c);\n if (!consumed) break;\n const { param, nextIndex } = consumed;\n if (section === 'importing') importing.push(param);\n else if (section === 'exporting') exporting.push(param);\n else if (section === 'changing') changing.push(param);\n else if (section === 'returning') returning = param;\n i = nextIndex;\n }\n\n return {\n kind: 'MethodDecl',\n name: qual.name,\n abapDoc,\n isClassMethod,\n isAbstract,\n isFinal,\n isRedefinition,\n isForTesting,\n importing,\n exporting,\n changing,\n returning,\n raising,\n span: spanFromStmt(stmt, head),\n };\n}\n\nfunction consumeMethodParam(\n toks: IToken[],\n start: number,\n c: Cursor,\n): { param: MethodParam; nextIndex: number } | null {\n let i = start;\n let isValue = false;\n // Optional VALUE(name)\n if (\n toks[i]?.tokenType.name === 'Value' &&\n toks[i + 1]?.tokenType.name === 'LParen'\n ) {\n isValue = true;\n const nameTok = toks[i + 2];\n if (!isNameLike(nameTok)) return null;\n if (toks[i + 3]?.tokenType.name !== 'RParen') return null;\n i += 4;\n // Followed by TYPE <typeref> etc. Fall through to common path but\n // we already captured the name.\n const paramName = nameTok.image;\n return parseParamTail(toks, i, c, paramName, isValue);\n }\n // Plain name — may be a keyword-as-name (`data`, `type`, `ref`, ...).\n const nameTok = toks[i];\n if (!isNameLike(nameTok)) return null;\n i += 1;\n return parseParamTail(toks, i, c, nameTok.image, isValue);\n}\n\nfunction parseParamTail(\n toks: IToken[],\n start: number,\n c: Cursor,\n name: string,\n isValue: boolean,\n): { param: MethodParam; nextIndex: number } | null {\n let i = start;\n // TYPE <typeref>\n if (toks[i]?.tokenType.name !== 'Type') {\n c.report(\n 'expected TYPE in parameter declaration',\n toks[i] ?? toks[start - 1],\n );\n return null;\n }\n i += 1;\n const typeRes = consumeTypeRef(toks, i, c);\n if (!typeRes) return null;\n const type = typeRes.type;\n i = typeRes.nextIndex;\n\n let isOptional = false;\n let defaultValue: string | undefined;\n\n while (i < toks.length) {\n const t = toks[i];\n const tn = t.tokenType.name;\n if (tn === 'Optional') {\n isOptional = true;\n i += 1;\n continue;\n }\n if (tn === 'Default') {\n // Greedy: take everything until the next keyword that would start a\n // new section or the next parameter.\n i += 1;\n const startTok = toks[i];\n if (!startTok) break;\n const valStart = startTok.startOffset;\n let valEnd = startTok.endOffset ?? startTok.startOffset;\n while (i < toks.length) {\n const nt = toks[i]?.tokenType.name;\n if (\n nt === 'Optional' ||\n nt === 'Importing' ||\n nt === 'Exporting' ||\n nt === 'Changing' ||\n nt === 'Returning' ||\n nt === 'Raising'\n ) {\n break;\n }\n valEnd = toks[i].endOffset ?? valEnd;\n i += 1;\n if (i < toks.length && toks[i]?.tokenType.name === 'Identifier') {\n // Likely start of next parameter — stop.\n // Heuristic: two consecutive idents without a connective is a new param.\n break;\n }\n }\n defaultValue = c['sliceSource'](valStart, valEnd);\n continue;\n }\n // Unknown keyword → param ends here\n break;\n }\n\n const startTok = toks[start - (isValue ? 4 : 1)];\n const endTok = toks[i - 1] ?? startTok;\n const param: MethodParam = {\n kind: 'MethodParam',\n name,\n type,\n isValue,\n isOptional,\n defaultValue,\n span: {\n startOffset: startTok.startOffset,\n endOffset: endTok.endOffset ?? endTok.startOffset,\n startLine: startTok.startLine ?? 1,\n startColumn: startTok.startColumn ?? 1,\n },\n };\n return { param, nextIndex: i };\n}\n\n/**\n * Shared body for member declarations shaped like `<head> <name> TYPE\n * <typeref> [rest…]`. Returns `{ nameTok, typeRes, toks, stmt, tailIdx }`\n * where `tailIdx` is the index of the first token AFTER the type-ref so\n * callers can inspect modifiers such as `READ-ONLY` / `VALUE <lit>`.\n */\nfunction parseNameTypeStatement(\n c: Cursor,\n expectation: { name: string; type: string },\n): {\n nameTok: IToken;\n typeRes: { type: TypeRef; nextIndex: number };\n toks: IToken[];\n stmt: ReturnType<Cursor['collectStatement']>;\n tailIdx: number;\n} | null {\n const head = c.current();\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n // toks[0] = head keyword (already validated by the caller dispatching on it)\n const nameTok = toks[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report(`expected ${expectation.name}`, nameTok ?? head);\n return null;\n }\n if (toks[2]?.tokenType.name !== 'Type') {\n c.report(`expected TYPE in ${expectation.type}`, toks[2] ?? head);\n return null;\n }\n const typeRes = consumeTypeRef(toks, 3, c);\n if (!typeRes) return null;\n return { nameTok, typeRes, toks, stmt, tailIdx: typeRes.nextIndex };\n}\n\n// --- DATA / CLASS-DATA ---\n\nfunction parseAttributeDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): AttributeDecl | null {\n const head = c.current();\n const isClassData = head.tokenType.name === 'ClassData';\n const parsed = parseNameTypeStatement(c, {\n name: 'attribute name',\n type: 'attribute declaration',\n });\n if (!parsed) return null;\n const { nameTok, typeRes, toks, stmt, tailIdx } = parsed;\n const isReadOnly = toks[tailIdx]?.tokenType.name === 'ReadOnly';\n return {\n kind: 'AttributeDecl',\n name: nameTok.image,\n abapDoc,\n isClassData,\n isReadOnly,\n type: typeRes.type,\n span: spanFromStmt(stmt, head),\n };\n}\n\n// --- TYPES ---\n\nfunction parseTypeDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): TypeDecl | null {\n const head = c.current();\n // Two shapes: `TYPES <name> TYPE …` or `TYPES: BEGIN OF <name>. … END OF <name>.`\n // The latter spans multiple statements.\n\n const first = c.peek(1);\n const second = c.peek(2);\n const third = c.peek(3);\n\n // Detect `TYPES: BEGIN OF name,` form\n if (\n first?.tokenType.name === 'Colon' &&\n second?.tokenType.name === 'Begin' &&\n third?.tokenType.name === 'Of'\n ) {\n return parseStructureTypes(c, abapDoc);\n }\n\n // Simple form — single statement ending with Dot.\n const parsed = parseNameTypeStatement(c, {\n name: 'type name after TYPES',\n type: 'TYPES declaration',\n });\n if (!parsed) return null;\n const { nameTok, typeRes, stmt } = parsed;\n return {\n kind: 'TypeDecl',\n name: nameTok.image,\n abapDoc,\n shape: { kind: 'alias', type: typeRes.type },\n span: spanFromStmt(stmt, head),\n };\n}\n\nfunction parseStructureTypes(\n c: Cursor,\n abapDoc: string[] | undefined,\n): TypeDecl | null {\n const head = c.current(); // Types\n // `TYPES: BEGIN OF <name>, <field> TYPE <typeref>, … END OF <name>.`\n // is a SINGLE chained statement terminated by one Dot. Collect the\n // whole thing; commas inside split the chain items.\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n // [Types, Colon, Begin, Of, Ident, Comma, <field>, Comma, <field>, Comma, End, Of, Ident]\n const nameTok = toks[4];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected struct name in BEGIN OF', nameTok ?? head);\n return null;\n }\n const structName = nameTok.image;\n\n // Locate the terminating `END OF <name>` tail and harvest fields between.\n let endIdx = -1;\n for (let k = 5; k < toks.length - 1; k++) {\n if (\n toks[k].tokenType.name === 'End' &&\n toks[k + 1]?.tokenType.name === 'Of'\n ) {\n endIdx = k;\n break;\n }\n }\n const fieldsEnd = endIdx >= 0 ? endIdx : toks.length;\n const fields: StructureField[] = [];\n parseFieldRun(toks.slice(5, fieldsEnd), fields, c);\n\n return {\n kind: 'TypeDecl',\n name: structName,\n abapDoc,\n shape: { kind: 'structure', fields },\n span: {\n startOffset: head.startOffset,\n endOffset: stmt.endOffset,\n startLine: head.startLine ?? 1,\n startColumn: head.startColumn ?? 1,\n },\n };\n}\n\nfunction parseFieldRun(toks: IToken[], out: StructureField[], c: Cursor): void {\n let i = 0;\n while (i < toks.length) {\n // Skip a leading Comma (from end-of-previous-field in the raw source)\n if (toks[i]?.tokenType.name === 'Comma') {\n i += 1;\n continue;\n }\n const nameTok = toks[i];\n if (!isNameLike(nameTok)) {\n // Unexpected — skip to next comma to recover\n while (i < toks.length && toks[i].tokenType.name !== 'Comma') i += 1;\n continue;\n }\n if (toks[i + 1]?.tokenType.name !== 'Type') {\n i += 1;\n continue;\n }\n // Slurp type-ref tokens up to the next Comma (or end)\n let j = i + 2;\n const typeStart = j;\n while (j < toks.length && toks[j].tokenType.name !== 'Comma') {\n j += 1;\n }\n const typeRes = consumeTypeRef(toks, typeStart, c, j);\n if (typeRes) {\n const last = toks[j - 1] ?? nameTok;\n out.push({\n kind: 'StructureField',\n name: nameTok.image,\n type: typeRes.type,\n span: {\n startOffset: nameTok.startOffset,\n endOffset: last.endOffset ?? last.startOffset,\n startLine: nameTok.startLine ?? 1,\n startColumn: nameTok.startColumn ?? 1,\n },\n });\n }\n i = j;\n }\n}\n\n// --- CONSTANTS ---\n\nfunction parseConstantDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): ConstantDecl | null {\n const head = c.current();\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n // [Constants, Ident, Type, <type>, Value, <value tokens>]\n const nameTok = toks[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected constant name', nameTok ?? head);\n return null;\n }\n if (toks[2]?.tokenType.name !== 'Type') {\n c.report('expected TYPE in CONSTANTS', toks[2] ?? head);\n return null;\n }\n // Find VALUE keyword\n let vIdx = -1;\n for (let k = 3; k < toks.length; k++) {\n if (toks[k].tokenType.name === 'Value') {\n vIdx = k;\n break;\n }\n }\n if (vIdx < 0) {\n c.report('expected VALUE in CONSTANTS', head);\n return null;\n }\n const typeRes = consumeTypeRef(toks, 3, c, vIdx);\n if (!typeRes) return null;\n const valueStart = toks[vIdx + 1]?.startOffset ?? 0;\n const valueEnd = toks[toks.length - 1]?.endOffset ?? valueStart;\n const value = c['sliceSource'](valueStart, valueEnd);\n return {\n kind: 'ConstantDecl',\n name: nameTok.image,\n abapDoc,\n type: typeRes.type,\n value,\n span: spanFromStmt(stmt, head),\n };\n}\n\n// --- EVENTS / CLASS-EVENTS ---\n\nfunction parseEventDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): EventDecl | null {\n const head = c.current();\n const isClassEvent = head.tokenType.name === 'ClassEvents';\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n // toks: [Events|ClassEvents, Ident, [Exporting, <paramList…>]]\n const nameTok = toks[1];\n if (!isNameLike(nameTok)) {\n c.report('expected event name', nameTok ?? head);\n return null;\n }\n const exporting: MethodParam[] = [];\n if (toks[2]?.tokenType.name === 'Exporting') {\n let i = 3;\n while (i < toks.length) {\n const consumed = consumeMethodParam(toks, i, c);\n if (!consumed) break;\n exporting.push(consumed.param);\n i = consumed.nextIndex;\n }\n }\n return {\n kind: 'EventDecl',\n name: nameTok.image,\n abapDoc,\n isClassEvent,\n exporting,\n span: spanFromStmt(stmt, head),\n };\n}\n\n// --- INTERFACES <name> . ---\n\nfunction parseInterfaceStmt(\n c: Cursor,\n abapDoc: string[] | undefined,\n): InterfaceStmt | null {\n const head = c.current();\n const stmt = c.collectStatement();\n const nameTok = stmt.tokens[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected interface name after INTERFACES', nameTok ?? head);\n return null;\n }\n return {\n kind: 'InterfaceStmt',\n name: nameTok.image,\n abapDoc,\n span: spanFromStmt(stmt, head),\n };\n}\n\n// --- ALIASES <local> FOR <target> . ---\n\nfunction parseAliasDecl(\n c: Cursor,\n abapDoc: string[] | undefined,\n): AliasDecl | null {\n const head = c.current();\n const stmt = c.collectStatement();\n const toks = stmt.tokens;\n const nameTok = toks[1];\n if (!nameTok || nameTok.tokenType.name !== 'Identifier') {\n c.report('expected alias name', nameTok ?? head);\n return null;\n }\n if (toks[2]?.tokenType.name !== 'For') {\n c.report('expected FOR in ALIASES', toks[2] ?? head);\n return null;\n }\n const targetStart = toks[3]?.startOffset ?? 0;\n const targetEnd = toks[toks.length - 1]?.endOffset ?? targetStart;\n const target = c['sliceSource'](targetStart, targetEnd);\n return {\n kind: 'AliasDecl',\n name: nameTok.image,\n target,\n abapDoc,\n span: spanFromStmt(stmt, head),\n };\n}\n\n// ============================================\n// Type-ref consumption\n// ============================================\n\nfunction consumeTypeRef(\n toks: IToken[],\n start: number,\n c: Cursor,\n endBound?: number,\n): { type: TypeRef; nextIndex: number } | null {\n const limit = endBound ?? toks.length;\n const i = start;\n if (i >= limit) {\n c.report('expected type reference', toks[i - 1] ?? toks[0]);\n return null;\n }\n\n // REF TO <target>\n if (\n toks[i]?.tokenType.name === 'Ref' &&\n toks[i + 1]?.tokenType.name === 'To'\n ) {\n const inner = consumeTypeRef(toks, i + 2, c, limit);\n if (!inner) return null;\n const startTok = toks[i];\n const lastTok = toks[inner.nextIndex - 1] ?? startTok;\n return {\n type: {\n kind: 'RefToTypeRef',\n target: inner.type,\n source: c['sliceSource'](\n startTok.startOffset,\n lastTok.endOffset ?? lastTok.startOffset,\n ),\n },\n nextIndex: inner.nextIndex,\n };\n }\n\n // STANDARD|SORTED|HASHED TABLE OF <row> [WITH …]\n const tableKind = peekTableKind(toks, i);\n if (tableKind) {\n return consumeTableTypeRef(toks, i, c, limit, tableKind);\n }\n\n // Simple name / qualified form: <name> (=>|~) <name> [(=>|~) <name> …]\n // `<name>` accepts any identifier-shaped token, including keywords\n // that the grammar re-purposes as names in declaration positions\n // (`DATA data TYPE i.`, `REF TO data`, `TYPE type`, etc.).\n const startTok: IToken | undefined = toks[i];\n if (!isNameLike(startTok)) {\n // `startTok` is narrowed to `undefined` here (isNameLike rejected a\n // present token would also land here; in that case the image is\n // already captured in `toks[i]` so read from there).\n const at = toks[i] ?? toks[i - 1] ?? toks[0];\n const label = at ? at.image : '<eof>';\n c.report(`expected type name, got \"${label}\"`, at);\n return null;\n }\n let lastIdx = i;\n const nameParts: string[] = [startTok.image];\n let j = i + 1;\n while (j < limit) {\n const t = toks[j]?.tokenType.name;\n if (t === 'FatArrow' || t === 'Tilde') {\n const next = toks[j + 1];\n if (!isNameLike(next)) break;\n nameParts.push(t === 'FatArrow' ? '=>' : '~', next.image);\n lastIdx = j + 1;\n j += 2;\n continue;\n }\n break;\n }\n const lastTok = toks[lastIdx];\n const source = c['sliceSource'](\n startTok.startOffset,\n lastTok.endOffset ?? lastTok.startOffset,\n );\n const fullName = nameParts.join('');\n const type: TypeRef = isBuiltinName(fullName)\n ? { kind: 'BuiltinTypeRef', name: fullName, source }\n : { kind: 'NamedTypeRef', name: fullName, source };\n return { type, nextIndex: lastIdx + 1 };\n}\n\nfunction peekTableKind(toks: IToken[], i: number): TableKind | null {\n const t = toks[i]?.tokenType.name;\n if (t === 'Standard' && toks[i + 1]?.tokenType.name === 'Table')\n return 'standard';\n if (t === 'Sorted' && toks[i + 1]?.tokenType.name === 'Table')\n return 'sorted';\n if (t === 'Hashed' && toks[i + 1]?.tokenType.name === 'Table')\n return 'hashed';\n return null;\n}\n\nfunction consumeTableTypeRef(\n toks: IToken[],\n start: number,\n c: Cursor,\n limit: number,\n tableKind: TableKind,\n): { type: TableTypeRef; nextIndex: number } {\n // STANDARD TABLE OF <row> WITH …\n let i = start + 2; // skip STANDARD TABLE\n if (toks[i]?.tokenType.name !== 'Of') {\n c.report('expected OF in TABLE OF', toks[i] ?? toks[start]);\n return fallbackTable(toks, start, i, tableKind, c);\n }\n i += 1;\n const rowRes = consumeTypeRef(toks, i, c, limit);\n if (!rowRes) {\n return fallbackTable(toks, start, i, tableKind, c);\n }\n i = rowRes.nextIndex;\n // WITH … key clause runs to end of statement / bound\n const keyStart = i;\n while (i < limit) i += 1;\n const keyTokens = toks.slice(keyStart, limit);\n const keyClause =\n keyTokens.length > 0\n ? c['sliceSource'](\n keyTokens[0].startOffset,\n (keyTokens[keyTokens.length - 1].endOffset ??\n keyTokens[keyTokens.length - 1].startOffset) as number,\n )\n : '';\n const startTok = toks[start];\n const lastTok = toks[limit - 1] ?? startTok;\n return {\n type: {\n kind: 'TableTypeRef',\n tableKind,\n row: rowRes.type,\n keyClause,\n source: c['sliceSource'](\n startTok.startOffset,\n lastTok.endOffset ?? lastTok.startOffset,\n ),\n },\n nextIndex: i,\n };\n}\n\nfunction fallbackTable(\n toks: IToken[],\n start: number,\n i: number,\n tableKind: TableKind,\n c: Cursor,\n): { type: TableTypeRef; nextIndex: number } {\n const startTok = toks[start];\n const lastTok = toks[i - 1] ?? startTok;\n return {\n type: {\n kind: 'TableTypeRef',\n tableKind,\n row: { kind: 'NamedTypeRef', name: '?', source: '?' },\n keyClause: '',\n source: c['sliceSource'](\n startTok.startOffset,\n lastTok.endOffset ?? lastTok.startOffset,\n ),\n },\n nextIndex: i,\n };\n}\n\n// ============================================\n// Helpers\n// ============================================\n\nfunction spanFromStmt(\n stmt: { startOffset: number; endOffset: number },\n anchor: IToken,\n): SourceSpan {\n return {\n startOffset: stmt.startOffset,\n endOffset: stmt.endOffset,\n startLine: anchor.startLine ?? 1,\n startColumn: anchor.startColumn ?? 1,\n };\n}\n\n/**\n * True when the token can legally appear in a position that expects an\n * ABAP identifier (type name, field name, parameter name, qualified part).\n *\n * The ABAP grammar allows many reserved words to be reused as names in\n * declaration positions — e.g. `DATA data TYPE i.`, `METHODS foo IMPORTING\n * type TYPE string.`, `TYPES: BEGIN OF x, data TYPE i, END OF x.`.\n * At the lexer level those tokens are classified as keywords; the parser\n * has to reinterpret them contextually.\n *\n * We accept: `Identifier`, plus any token whose `image` is a plain ABAP\n * identifier (starts with letter/underscore, only contains the chars a\n * real identifier would). This keeps the rule cheap (no huge keyword\n * allowlist) and catches every keyword that can legally be a name.\n */\n/**\n * Read a possibly-qualified ABAP name starting at `start`: a chain of\n * identifier-shaped tokens separated by `~` (interface member) or `=>`\n * (static scope). Returns the joined `image` plus the last-consumed\n * index, or `null` if the head token is not name-like.\n *\n * `zif_foo~bar` → `{ name: 'zif_foo~bar', lastIdx: start + 2 }`\n * `zcl_x=>method` → `{ name: 'zcl_x=>method', lastIdx: start + 2 }`\n * `plain_name` → `{ name: 'plain_name', lastIdx: start }`\n */\nfunction readQualifiedName(\n toks: IToken[],\n start: number,\n): { name: string; lastIdx: number } | null {\n const head = toks[start];\n if (!isNameLike(head)) return null;\n const parts: string[] = [head.image];\n let lastIdx = start;\n let j = start + 1;\n while (j < toks.length) {\n const sep = toks[j]?.tokenType.name;\n if (sep !== 'Tilde' && sep !== 'FatArrow') break;\n const next = toks[j + 1];\n if (!isNameLike(next)) break;\n parts.push(sep === 'Tilde' ? '~' : '=>', next.image);\n lastIdx = j + 1;\n j += 2;\n }\n return { name: parts.join(''), lastIdx };\n}\n\nfunction isNameLike(t: IToken | undefined): t is IToken {\n if (!t) return false;\n if (t.tokenType.name === 'Identifier') return true;\n // Symbols (`Dot`, `Comma`, `FatArrow`, ...) have non-alphabetic images.\n return /^[A-Za-z_][A-Za-z0-9_/]*$/.test(t.image);\n}\n\nconst BUILTIN_ABAP_TYPES = new Set([\n 'string',\n 'xstring',\n 'i',\n 'int8',\n 'int4',\n 'int2',\n 'int1',\n 'f',\n 'p',\n 'c',\n 'n',\n 'd',\n 't',\n 'decfloat16',\n 'decfloat34',\n 'timestampl',\n 'timestamp',\n 'abap_bool',\n 'abap_boolean',\n 'abap_true',\n 'abap_false',\n 'sy-subrc',\n 'sy-tabix',\n]);\nfunction isBuiltinName(name: string): boolean {\n return BUILTIN_ABAP_TYPES.has(name.toLowerCase());\n}\n","/**\n * Assertions derived from `parse()`. Useful for downstream consumers\n * (generators, linters, CI gates) that want to guarantee their output\n * stays inside the structural subset of ABAP OO that `aclass`\n * understands, without writing the same filtering logic each time.\n */\nimport { parse } from './parser';\nimport type { ParseError } from './errors';\n\nexport class AclassParseError extends Error {\n public readonly source: string;\n public readonly errors: readonly ParseError[];\n constructor(\n fileLabel: string,\n errors: readonly ParseError[],\n source: string,\n ) {\n super(\n `aclass: ${errors.length} parse error${errors.length === 1 ? '' : 's'} in ${fileLabel}:\\n` +\n errors\n .slice(0, 10)\n .map((e) => ` [${e.line}:${e.column}] ${e.message}`)\n .join('\\n'),\n );\n this.name = 'AclassParseError';\n this.source = source;\n this.errors = errors;\n }\n}\n\n/**\n * Throw `AclassParseError` if the source has any lex / parse errors.\n * `fileLabel` is included in the message so CI output points at the\n * offending file without the caller having to format it.\n *\n * Intended use in test suites:\n *\n * ```ts\n * for (const f of generated) {\n * assertCleanParse(readFileSync(f, 'utf8'), f);\n * }\n * ```\n */\nexport function assertCleanParse(source: string, fileLabel = '<source>'): void {\n const { errors } = parse(source);\n if (errors.length === 0) return;\n throw new AclassParseError(fileLabel, errors, source);\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __defProp = Object.defineProperty;
3
+ var __exportAll = (all, no_symbols) => {
4
+ let target = {};
5
+ for (var name in all) {
6
+ __defProp(target, name, {
7
+ get: all[name],
8
+ enumerable: true
9
+ });
10
+ }
11
+ if (!no_symbols) {
12
+ __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ }
14
+ return target;
15
+ };
16
+
17
+ //#endregion
18
+ export { __exportAll as t };
package/package.json CHANGED
@@ -1 +1,42 @@
1
- {"name":"@abapify/aclass","version":"0.0.0","description":"Placeholder — real package is published via CI/CD (trusted publishing)."}
1
+ {
2
+ "name": "@abapify/aclass",
3
+ "publishConfig": {
4
+ "access": "public"
5
+ },
6
+ "version": "0.4.6",
7
+ "description": "ABAP OO source parser — tokenizer, Chevrotain CstParser, and typed AST for CLASS / INTERFACE declarations",
8
+ "type": "module",
9
+ "types": "./dist/index.d.mts",
10
+ "exports": {
11
+ ".": "./dist/index.mjs",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "dependencies": {
15
+ "chevrotain": "^11.0.0"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "keywords": [
22
+ "abap",
23
+ "clas",
24
+ "intf",
25
+ "oo",
26
+ "parser",
27
+ "chevrotain",
28
+ "sap",
29
+ "adt"
30
+ ],
31
+ "author": "abapify",
32
+ "license": "MIT",
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/abapify/adt-cli.git",
36
+ "directory": "packages/aclass"
37
+ },
38
+ "homepage": "https://github.com/abapify/adt-cli/tree/main/packages/aclass#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/abapify/adt-cli/issues"
41
+ }
42
+ }
package/README.md DELETED
@@ -1 +0,0 @@
1
- # @abapify/aclass