Skip to content

Releases: albertlast/abapParser

v0.5.1

Choose a tag to compare

@github-actions github-actions released this 26 Oct 06:35
d243e64

Logic is 30% faster with the same results, and the repository has its intended name. Nothing in the output or the API changes.

  • Repository renamed to albertlast/abapParser, from abapPaser; GitHub forwards the old address. The package links point to the new name.
  • Faster logic: the inputs of an effect were traced from each statement writing it anew; the statements now share what was already traced. Logic over the corpus takes 30% less time than in 0.5.0, the logic of whole objects 21% less; the results are the same.
  • Benchmark: cargo run --release -p abap-analysis --example bench times each stage over the corpus, node tools/bench.mjs v0.5.0 . compares versions; the README has the times since 0.3.0.

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 15:00
c4576ea

Data has types: from the source, from classes and interfaces, from the dictionary and from function modules. Screens and their dialog modules are in the call graph. Following calls can be limited and cancelled, and what was not found says why. Four corpora that their CI checks against an older release are checked here too, and all of abaplint's invalid test statements are rejected.

  • Types: declarations in symbols and the reads and writes in logic have their type in data_type, as far as the sources tell it: built-in types with length and decimals, local TYPES resolved, LIKE resolved through the data object it names, tables, ranges and references with what they hold, components and table expressions. Inline declarations get the type of what the statement puts there: literals, string templates, constructor expressions (REF #( ) and FILTER #( ) included), table expressions, built-in functions, methods of classes in the source, table lines of LOOP AT and READ TABLE, the rows of SELECT ... INTO @DATA(x), exceptions of CATCH, classes of CASE TYPE OF; and the FOR, LET and INDEX INTO names of constructor expressions. The forms are those of the common old-and-new-syntax overviews; LOOP AT ... GROUP BY groups are not typed yet. Dictionary types stay names, like matnr or mara-matnr. DataType has the new kinds named, structure, table, range and ref, a name and a line.

  • Types from classes and more statements: methods, attributes and types of classes and interfaces type what they give: RETURNING types, lo->mv_x, zcl=>gc_max, TYPE zcl=>ty_s and its components, inherited members and aliases included; through chains link by link (CAST zcl( lo )->get( )-id); in a workspace for every class it can load, SAP's classes through ADT too (checked on the SAP trial system with cl_abap_typedescr and xco_cp). Types of other classes are named with their class, zcl=>ty_s. Inline declarations in method arguments get the type of their parameter. New forms: ASSIGN ... TO FIELD-SYMBOL(<x>), SPLIT ... INTO, FIND ... RESULTS/SUBMATCHES/COUNT, APPEND/INSERT/COLLECT ... ASSIGNING/REFERENCE INTO, SELECT ... FROM @itab, INTO NEW @DATA(r) and INTO (@DATA(a), @DATA(b)), COND #/SWITCH #, lr->comp of data references, constructor expressions inside conditions, abap_true/abap_false/space, numeric functions (abs, ipow, nmax, sqrt, round, ...), the calculation type of arithmetic expressions, LOOP AT and READ TABLE over a table given as an expression, components with VALUE in BEGIN OF. Built-in function types follow SAP's documentation: xsdbool( ) is c(1) typed xsdboolean, boolc( ) string, line_exists( ) none. On the cheat sheets 62.7% of inline declarations are typed file by file (from 52.2%), 66.5% in a workspace, 95.0% with an SAP system connected.

  • Corpora at older releases: abap-wasm, abapPGP (both checked by their CI with abaplint against ABAP 7.50), open-abap-gui (against 7.40 SP08) and abapNTLM (against 7.40 SP02), all MIT, join the corpus. A new test requires that none of their 95,521 statements needs a newer release than the one checked, has a syntax error or is unknown. open-abap-gui brings 187 classic reports with screens, selection screens and dialog modules; its three folders are one corpus, so corpora.txt takes several folders on a line.

  • Dictionary types: in a workspace, data elements have their built-in type and name in data_element (TYPE xubname is c(12), XUBNAME), from ADT, which gives the domain's type with the data element, or from abapGit, which keeps it in the domain: new object kind DOMA, .doma.xml. Data elements typed as references are references. Dictionary structures and tables are structure with their name, and their components have their types, those of included structures and built-in columns (abap.dec(15,2), DATATYPE CURR) included. LIKE bapiret2-message takes the column's type. Failed data element and domain lookups are notes, like those of table types.

  • Function modules: CALL FUNCTION 'Z_FM' IMPORTING ev = DATA(x) types x by the parameter, in the function module's scope, dictionary types included. Function modules whose source has no signature, like those generated for table maintenance, get it from the abapGit XML of their function group (.fugr.xml), so their parameters are known to the call graph and to typing.

  • Screens: CALL SCREEN 100, SET SCREEN 200 and LEAVE TO SCREEN 300 are calls of the new kind screen; in the call graph the flow logic of a program's screens calls its dialog modules, calls of the new kind module from the block screen 0100, with the event and additions like AT EXIT-COMMAND as options. Screens are read from abapGit folders, DYNPROS of .prog.xml and .fugr.xml with their flow logic there or in .prog.screen_NNNN.abap files; selection screens count as screens. Over the corpus, 96.3% of 300 such calls resolve; the rest are in includes analyzed without their main program, or name screens missing in the repositories.

  • Found with open-abap-gui: CONV zif_x=>ty_name( ... ), VALUE, COND and the other constructor expressions with a type of a class or interface read their operands, which were missed. AT SELECTION-SCREEN ON p_carr, ON END OF, ON VALUE-REQUEST FOR and ON HELP-REQUEST FOR read the parameter. SELECT * FROM t100 without INTO writes the work area of TABLES t100.

  • Dynamic attributes in ASSIGN: ASSIGN oref->(name) TO <fs> with a backquote literal no longer needs 7.57; SAP's release news of 7.57 only bring struc-(comp), and an attribute name may be any character-like literal. Found on the 7.02 branch of abap2UI5, which abaplint checks against 7.02.

  • Calls on constructor expressions: NEW zcl( )->m( ) and CAST zcl( x )->m( ) are method calls of the class's method, followed through the chain; the first was taken for a second constructor call, the second was not found. DATA(x) = NEW zcl( )->m( ) types x by what m returns, not as zcl. The corpus call graph finds 173 more method calls, all resolved.

  • Parameters of interface and redefined methods: in METHOD zif_x~meth the parameters are those of the interface, in a method declared REDEFINITION those of the superclass; both were untyped, since the class does not repeat the signature. GET BIT ... INTO DATA(x) and GET RUN TIME FIELD DATA(x) give i, GET TIME FIELD DATA(x) t, GET TIME STAMP FIELD DATA(x) timestamp (p of length 8), as SAP documents them. On abap-wasm, 300 files checked by abaplint against 7.50, 99.6% of inline declarations are typed (from 81.9%).

  • Dictionary lookup for types: in a workspace, the lines of dictionary table types (new object kind TTYP, ADT ddic/tabletypes, abapGit .ttyp.xml) and the types of type groups (new kind TYPE, ADT ddic/typegroups, abapGit .type.abap) type data: LOOP AT over a string_table gives string, abap_compdescr_tab of type group ABAP its structure with components. Since these lookups only add types, a failed one is a note, not an error: table types: 2 lookups failed, their types stay names (first: TTYP:X: HTTP 406 ...), once per kind. Lengths given by constants take the constant's value. With the SAP trial system connected, 95.0% of the cheat sheets' inline declarations are typed.

  • Fewer lookups: names like zif_x are looked up as interfaces first, REF TO data and REF TO object not at all; SELECT ... INTO (@a, @b) without a blank after the parenthesis writes its targets.

  • Syntax checks: all 77 of abaplint's statements invalid at every release are rejected, from 69: unknown additions of CALL TRANSFORMATION and method calls in its SOURCE, a call after CREATE DATA ... TYPE HANDLE, an internal table without alias in MERGE ... USING and WHEN MATCHED after WHEN NOT MATCHED, CLASS-METHODS ... FOR ENTITY EVENT, READ TABLE ... USING KEY with WITH KEY, and WITH ending a table type. None of the 321,490 corpus statements abaplint accepts is reported.

  • Follow filters and limits: follow in the options (--follow, --skip, --limit in the CLI and the MCP server) loads only objects whose names match patterns like Z* or a custom namespace /ABC/*, leaves out others, and stops after a number of objects; the objects given are always loaded. Objects not loaded are in the new skipped of call graph and logic, not in missing, and the notes say when the limit was reached. A progress function is called after each object (progress in Node.js and Python, --progress in the CLI), and an analysis can be cancelled (signal in Node.js, a CancelToken in Python, Workspace::with_cancel in Rust); it then finishes with what it has.

  • Why calls are unresolved: the new unresolved of calls in the call graph says why a target was not found: dynamic, unknown_type, missing, lookup_failed, hierarchy_incomplete, not_followed, limit, cancelled or not_loaded. The compact text writes it, like (unresolved: not followed).

  • Structured errors: errors of call graph and logic are objects instead of text: code (auth, http, network, io, other), object, cause, retryable and the HTTP status. Failures of the connection to an SAP system are network and retryable, as are HTTP 408, 429 and 5xx. Objects whose loading failed are no longer in missing.

Changes to existing output: schema_version is 2, since errors holds objects. Objects not loaded on purpose or whose loading failed are no longer in missing. Calls have the new kinds screen and module, and blocks the kind screen. In Rust, the functions of abap_analysis::json that load sources take Hooks (provider, progress, cancel) ...

Read more

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 10:13
1f9a206

The release each statement needs, syntax checks, and lineage for SAP_BASIS 7.50 systems and HR code: sources from the host, sy-subrc and system fields per statement, infotypes, locks and data clusters.

Changes to existing output: system fields are named by field (sy-dbcnt, before sy), steps carry implicit writes of system fields, and GET statements are steps. In Rust, the functions of abap_analysis::json that load sources take a source provider of the caller as a new last argument.

  • Sources from the host: fetch in the source options of Node.js and Python is a function of the host program, called with each object the analysis needs (CLAS:ZCL_X/implementations, FUNC:Z_FM, ...) and returning its source or nothing, e.g. from the host's own ADT client or cache. It is asked after the folders and before the SAP system; what it throws is listed in errors. In Node.js only the …Async functions take it, a promise as its result included; the blocking ones throw a TypeError. In Rust it is abap_source::FnProvider, with ProviderOptions::build_with. The JSON entry points in abap_analysis::json that load sources take it as a new last argument.
  • sy-subrc per statement: guards on sy-subrc name in the new subrc the statements that may have set the value they check. IF sy-subrc = 0 after a READ TABLE and IF sy-subrc NE 0 after a call inside it were one contradicting condition before. Statements that set sy-subrc, as SAP documents for each, write it (new implicit on data accesses), so the data flow gives its sources: a write under IF sy-subrc = 0 after a READ TABLE now depends on the table read. Method calls set it, PERFORM may. The compact text writes sy-subrc = 0 [sy-subrc of 70]. System fields are each their own data object, sy-subrc, sy-dbcnt, no longer sy.
  • System fields: the 171 fields of SYST are known with their types, as the structure SYST of an SAP system has them (abaplint agrees on 167; it has sy-fdayw untyped and sy-spono as text). Their accesses have the new scope system and the new data_type (kind, length, decimals, data element). Statements set them as SAP documents: sy-tabix (READ TABLE, LOOP AT, APPEND, COLLECT), sy-index (DO, WHILE), sy-dbcnt (database statements, FETCH, EXEC SQL), sy-fdpos (SEARCH, CO, CN, CA, NA, CS, NS, CP, NP), sy-tfill and sy-tleng (DESCRIBE TABLE), the message fields (MESSAGE). Reads of them come from those statements, so a value written from sy-dbcnt depends on what the SELECT before read; fields of the runtime, like sy-datum, are no inputs of effects, since callers do not pass them.
  • Clusters in database access: EXPORT ... TO DATABASE dbtab(ar) ID id, IMPORT ... FROM DATABASE, IMPORT DIRECTORY and DELETE FROM DATABASE are database accesses of the table (modify, select, delete), with the new cluster: area, ID and the names in the cluster; exported data in source, imported data in target. They were only in the logic effects. The compact text writes modify pcl2(ru) cluster.
  • Locks: lock modules are no longer followed into their generated code; ENQUEUE_<lock object> writes the new store lock:<lock object> (Store::Lock), DEQUEUE_ deletes it, DEQUEUE_ALL deletes lock:*. Lock objects start with E, so ENQUEUE_READ is no lock module.
  • HR infotypes: INFOTYPES nnnn is a declaration (kind infotype) of the table pnnnn, so the table is global data. The infotype number decides the table: HRPnnnn for personnel planning (1000 to 1999, 5000 to 5999), PBnnnn for recruitment (4000 to 4999) and applicants, else PAnnnn; customer infotypes (9000 to 9999) after the reader, HRP for PCH and RH_READ_INFTY. At GET PERNR and GET PERAS the logical database fills the infotype tables in PA, at GET OBJEC those in HRP, each from its own, apart from MODE N. HR_READ_INFOTYPE, RH_READ_INFTY, RH_READ_INFTY_1001 and RP-READ-INFOTYPE read the table of the infotype they name. The macros RP-PROVIDE-FROM-LAST/-FRST, RP-READ-INFOTYPE and RP-SET-DATA-INTERVAL read and write their arguments, after SAP's description of their use; their definitions are not read. GET statements are steps now.
  • Releases: each statement gets the oldest on-premise ABAP release that has everything it uses, from 7.02 to 8.16, with the construct that needs it, like 7.40 SP02: inline declaration. New release and error on statements. New command abap release <file> [--release 750] gives the release a file needs and the statements newer than a given release. 98.2% of the corpus statements get the release abaplint gives; all but 3 of the rest are cases where abaplint reads newer syntax as older or dates predicate functions later. The oracle has a new mode, --releases, that parses the corpus once per release.
  • Releases from SAP's release news: where abaplint dates an ABAP SQL construct differently from SAP's ABAP release news, the release news win. INTO @DATA(x) needs 7.40 SP08 (abaplint: SP05), searched CASE WHEN SP08, path expressions 7.50 and with parameters or filters 7.52, CROSS JOIN 7.51, hierarchies 7.53, window expressions (OVER) and INTO … INDICATORS 7.54 (abaplint: 7.57 and 8.16), LIKE_REGEXPR, OCCURRENCES_REGEXPR and REPLACE_REGEXPR 7.55, SUBSTRING_REGEXPR 7.56. New: FIRST_VALUE, LAST_VALUE, NTILE and window frames (ROWS BETWEEN) 7.55, INDICATORS … NULL BITFIELD 7.56, inline declaration in OPEN CURSOR 7.51. The comparison with abaplint counts these apart: 146 corpus statements and 90 abaplint cases. abaplint cases met: 99.0%, from 98.0%.
  • Syntax errors: checks for errors of known kinds, like a keyword as a column, parameter sections out of order or PACKAGE SIZE without a table. They report 69 of abaplint's 77 cases that are invalid at every release, and none of the corpus statements abaplint accepts.
  • SAP macros: calls of the macros of the logical database PNP (RP-PROVIDE-FROM-LAST, RP-PROVIDE-FROM-FRST, RP-READ-INFOTYPE, RP-SET-DATA-INTERVAL), which HR reports use without defining them, are MacroCall statements instead of Unknown. Macros with dashes in their names, DEFINE my-mac., are expanded; only the part before the first dash was the name.
  • Field groups: INSERT f1 f2 INTO header is InsertFieldGroup, not an internal table insert.
  • Text literals: a literal in quotes ends at its closing quote also when no blank follows, as in SQLScript 'x';, like abaplint 2.120.86.
  • abaplint 2.120.86: the reference is updated from 2.120.60, with its statement test cases extracted again.
  • Older SAP systems: tested against an ERP on SAP_BASIS 750 SP35.
    • What a system offers is read from its ADT discovery, not assumed from its release.
    • Data preview queries the system rejects fall back to the table preview, with single-table queries.
    • The enhancement lookup no longer filters on ENHINCINX-FULL_NAME, a long string that SAP_BASIS 750 rejects in a condition. This was the HTTP 400 for every function module.
    • Data elements are requested in the version the system lists.
  • Notes: a lookup the system cannot do is no longer an error. It is a note in the new notes of call graph and logic results, like enhancements: not available (the ADT discovery has no enhancements/enhoxhh to read their code, SAP_BASIS 750 SP 0035). Answers that could not be given are not cached.
  • Mock of SAP_BASIS 750: abap mock-adt --release 750 (MockRelease::Basis750 in Rust) acts like the ERP measured. It has that system's discovery and component list, and serves data elements only in XML version 1 (406 otherwise), structures but no tables, and no enhancement code. Its data preview answers the queries of the ADT provider from the class relations, BAdIs and enhancements of the served folders. It rejects what 7.50 rejects: long strings in WHERE and lines over 255 characters. A test checks that the call graph over it matches the one read from the folder, with one note.
  • Request log: ABAP_ADT_LOG=1 writes every ADT request to stderr: method, path, status, duration, and the SQL of data preview queries. It never writes headers, cookies, tokens or credentials.
  • Fix: two parallel loads of the same object could make a cache write fail.
  • Fix: parallel loads asking for the same BAdI each sent the lookup to the system; now one asks and the others wait. The 7.50 mock showed it: one query went out six times in one call graph.
  • Formatting: Markdown, JavaScript and JSON are formatted with prettier 3.9.10 (.prettierrc.json, npm run --prefix tools format), checked in CI, so editors formatting on save no longer change them.
  • Corpus: three HR projects with logical database PNP, INFOTYPES and payroll clusters. The oracle reads plain NAME.abap files as programs.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 14 Oct 04:42
ba0f07f

BAdIs, enhancements and customer exits are followed to the code that runs; loading from an SAP system is faster.

  • BAdIs: CALL BADI resolves to the interface of the BAdI, and calls through the interface of a classic BAdI (IF_EX_...) reach only its active implementations, not the adapter class. The call graph loads the classes that run, logic follows them. They come from the BAdI tables of an SAP system or from abapGit .enhs.xml, .enho.xml, .sxsd.xml and .sxci.xml files. New badi on calls, MCP tool find_badi_implementations.
  • Enhancements: code of enhancement implementations is put where it runs when an object is loaded: at enhancement points, in place of enhancement sections, and at the begin or end of forms, function modules, methods and includes. It is on the line of its position, so rows stay. From an SAP system through the index of enhancement includes, without implementations switched off, or from abapGit .enho.<hash>.abap files. The call graph lists them as units ENHO:<name>.
  • Parallel loading: objects, class parts and includes are loaded up to 8 at once; the call graph works level by level, logic loads the objects its calls reach before. From an SAP system with an empty cache, the call graph of BAPI_USER_GET_DETAIL two hops deep takes 3 s instead of 14 s, its logic 6.3 s instead of 8.2 s; results are the same.
  • Cache: the cache also keeps the answers of lookups, under lookups/: enhancements, implementations, subclasses and BAdIs. A second call graph of BAPI_USER_GET_DETAIL two hops deep takes 0.6 s.
  • Customer exits: CALL CUSTOMER-FUNCTION '001' calls EXIT_<program>_001, named by the program; it was a dynamic call of -FUNCTION before.

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 17:35
d7c2b94

Tested against a real SAP system (ABAP Cloud Developer Trial 2025), and the pieces for language models and for following data through code.

  • MCP server: abap mcp gives language models the analyses as tools over stdio: source, symbols, call graph, logic, database access, implementations, subclasses, and the analyses of pasted code. Sources come from folders, an SAP system and a cache.
  • Compact text: symbols written like ABAP definitions, one line per call or database access, and per procedure its effects with the statements writing them and their conditions. 6.7 times shorter than the JSON for symbols, 9 times for logic. CLI --text, the default of the MCP server, text and objectText in Node.js, text and object_text in Python.
  • CDS views: data definitions are parsed: sources with joins, associations, parameters, WHERE, and the fields each element is made of. Objects DDLS:NAME, CLI cds, cds() in both packages.
  • Dictionary types: structures, tables (TABL:NAME) and data elements (DTEL:NAME) from ADT and abapGit resolve receivers like ls_node-ref->get( ) and parameters typed with a data element referring to a class.
  • Logic:
    • SUBMIT is followed: the tables of the submitted program count for the caller, connected through the values passed with WITH.
    • Data kept outside the program is handled like tables: ABAP memory, SAP memory (SET/GET PARAMETER), files, shared buffers; data clusters as accesses of their table. New effect scope external and store on table accesses.
    • Calls of instance methods also reach their redefinitions in subclasses.
  • Calls: x = NEW #( ) takes its class from x. Generated lock modules (ENQUEUE_x) are found through their lock object.
  • SAP systems: implementations of interfaces and subclasses come from the class relations through the data preview, the where-used list is the fallback. The root class OBJECT is no longer requested.
  • Tools: tools/version.mjs and tools/gen-types.mjs --check work on a checkout with CRLF line ends.

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 13 Oct 13:30
0f1ef2e

First release: the Rust core with a command line tool, Node.js and Python packages.

  • Symbols: classes, interfaces, methods with signatures, attributes, forms, function modules, dialog modules, event blocks, macros, includes and declarations.
  • Database access: Open SQL in classic and strict syntax, with tables, fields, joins, conditions, targets and the ABAP data read. Native SQL in EXEC SQL and AMDP methods, parsed as HANA SQL and SQLScript.
  • Calls and call graph: methods, function modules, forms, programs, transactions, with receiver types, across objects.
  • Logic: steps nested along the control structures, with conditions, guards, a control flow graph and data flow. Effects list the parameters, attributes, globals and database tables a procedure writes, and what the values depend on. Calls are followed into the procedures they reach: through interfaces, dynamic names with known values, field symbols and references, with arguments matched to parameters.
  • Sources: abapGit or plain folders, a disk cache, and SAP systems through ADT. Includes and function modules are loaded with their object. A local ADT mock server is included for tests.
  • Bindings: every function also as a promise (Node.js) or coroutine (Python) that does not block the event loop. Types are generated for TypeScript and Python.

The JSON results have schema_version 1. It changes when a result changes in a way that breaks readers; new optional fields do not change it.