Repository navigation
Releases: albertlast/abapParser
Release list
v0.5.1
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 benchtimes 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
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, localTYPESresolved,LIKEresolved 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 #( )andFILTER #( )included), table expressions, built-in functions, methods of classes in the source, table lines ofLOOP ATandREAD TABLE, the rows ofSELECT ... INTO @DATA(x), exceptions ofCATCH, classes ofCASE TYPE OF; and theFOR,LETandINDEX INTOnames of constructor expressions. The forms are those of the common old-and-new-syntax overviews;LOOP AT ... GROUP BYgroups are not typed yet. Dictionary types stay names, likematnrormara-matnr.DataTypehas the new kindsnamed,structure,table,rangeandref, anameand aline. -
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_sand 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 withcl_abap_typedescrandxco_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)andINTO (@DATA(a), @DATA(b)),COND #/SWITCH #,lr->compof 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 ATandREAD TABLEover a table given as an expression, components withVALUEinBEGIN OF. Built-in function types follow SAP's documentation:xsdbool( )isc(1)typedxsdboolean,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.txttakes several folders on a line. -
Dictionary types: in a workspace, data elements have their built-in type and name in
data_element(TYPE xubnameisc(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 kindDOMA,.doma.xml. Data elements typed as references are references. Dictionary structures and tables arestructurewith their name, and their components have their types, those of included structures and built-in columns (abap.dec(15,2),DATATYPECURR) included.LIKE bapiret2-messagetakes 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)typesxby 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 200andLEAVE TO SCREEN 300are calls of the new kindscreen; in the call graph the flow logic of a program's screens calls its dialog modules, calls of the new kindmodulefrom the blockscreen 0100, with the event and additions likeAT EXIT-COMMANDas options. Screens are read from abapGit folders,DYNPROSof.prog.xmland.fugr.xmlwith their flow logic there or in.prog.screen_NNNN.abapfiles; 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,CONDand 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 FORandON HELP-REQUEST FORread the parameter.SELECT * FROM t100withoutINTOwrites the work area ofTABLES 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 bringstruc-(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( )andCAST 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( )typesxby whatmreturns, not aszcl. The corpus call graph finds 173 more method calls, all resolved. -
Parameters of interface and redefined methods: in
METHOD zif_x~meththe parameters are those of the interface, in a method declaredREDEFINITIONthose of the superclass; both were untyped, since the class does not repeat the signature.GET BIT ... INTO DATA(x)andGET RUN TIME FIELD DATA(x)givei,GET TIME FIELD DATA(x)t,GET TIME STAMP FIELD DATA(x)timestamp(pof 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, ADTddic/tabletypes, abapGit.ttyp.xml) and the types of type groups (new kindTYPE, ADTddic/typegroups, abapGit.type.abap) type data:LOOP ATover astring_tablegivesstring,abap_compdescr_tabof type groupABAPits 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_xare looked up as interfaces first,REF TO dataandREF TO objectnot 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 TRANSFORMATIONand method calls in itsSOURCE, a call afterCREATE DATA ... TYPE HANDLE, an internal table without alias inMERGE ... USINGandWHEN MATCHEDafterWHEN NOT MATCHED,CLASS-METHODS ... FOR ENTITY EVENT,READ TABLE ... USING KEYwithWITH KEY, andWITHending a table type. None of the 321,490 corpus statements abaplint accepts is reported. -
Follow filters and limits:
followin the options (--follow,--skip,--limitin the CLI and the MCP server) loads only objects whose names match patterns likeZ*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 newskippedof call graph and logic, not inmissing, and the notes say when the limit was reached. A progress function is called after each object (progressin Node.js and Python,--progressin the CLI), and an analysis can be cancelled (signalin Node.js, aCancelTokenin Python,Workspace::with_cancelin Rust); it then finishes with what it has. -
Why calls are unresolved: the new
unresolvedof calls in the call graph says why a target was not found:dynamic,unknown_type,missing,lookup_failed,hierarchy_incomplete,not_followed,limit,cancelledornot_loaded. The compact text writes it, like(unresolved: not followed). -
Structured errors:
errorsof call graph and logic are objects instead of text:code(auth,http,network,io,other),object,cause,retryableand the HTTPstatus. Failures of the connection to an SAP system arenetworkand retryable, as are HTTP 408, 429 and 5xx. Objects whose loading failed are no longer inmissing.
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) ...
v0.4.0
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:
fetchin 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 inerrors. In Node.js only the…Asyncfunctions take it, a promise as its result included; the blocking ones throw aTypeError. In Rust it isabap_source::FnProvider, withProviderOptions::build_with. The JSON entry points inabap_analysis::jsonthat load sources take it as a new last argument. sy-subrcper statement: guards onsy-subrcname in the newsubrcthe statements that may have set the value they check.IF sy-subrc = 0after a READ TABLE andIF sy-subrc NE 0after a call inside it were one contradicting condition before. Statements that setsy-subrc, as SAP documents for each, write it (newimpliciton data accesses), so the data flow gives its sources: a write underIF sy-subrc = 0after a READ TABLE now depends on the table read. Method calls set it, PERFORM may. The compact text writessy-subrc = 0 [sy-subrc of 70]. System fields are each their own data object,sy-subrc,sy-dbcnt, no longersy.- 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-fdaywuntyped andsy-sponoas text). Their accesses have the new scopesystemand the newdata_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-tfillandsy-tleng(DESCRIBE TABLE), the message fields (MESSAGE). Reads of them come from those statements, so a value written fromsy-dbcntdepends on what the SELECT before read; fields of the runtime, likesy-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 DIRECTORYandDELETE FROM DATABASEare database accesses of the table (modify,select,delete), with the newcluster: area, ID and the names in the cluster; exported data insource, imported data intarget. They were only in the logic effects. The compact text writesmodify pcl2(ru) cluster. - Locks: lock modules are no longer followed into their generated code;
ENQUEUE_<lock object>writes the new storelock:<lock object>(Store::Lock),DEQUEUE_deletes it,DEQUEUE_ALLdeleteslock:*. Lock objects start withE, soENQUEUE_READis no lock module. - HR infotypes:
INFOTYPES nnnnis a declaration (kindinfotype) of the tablepnnnn, so the table is global data. The infotype number decides the table:HRPnnnnfor personnel planning (1000 to 1999, 5000 to 5999),PBnnnnfor recruitment (4000 to 4999) and applicants, elsePAnnnn; customer infotypes (9000 to 9999) after the reader,HRPfor PCH andRH_READ_INFTY. AtGET PERNRandGET PERASthe logical database fills the infotype tables inPA, atGET OBJECthose inHRP, each from its own, apart fromMODE N.HR_READ_INFOTYPE,RH_READ_INFTY,RH_READ_INFTY_1001andRP-READ-INFOTYPEread the table of the infotype they name. The macrosRP-PROVIDE-FROM-LAST/-FRST,RP-READ-INFOTYPEandRP-SET-DATA-INTERVALread and write their arguments, after SAP's description of their use; their definitions are not read.GETstatements 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. Newreleaseanderroron statements. New commandabap 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), searchedCASE WHENSP08, path expressions 7.50 and with parameters or filters 7.52,CROSS JOIN7.51, hierarchies 7.53, window expressions (OVER) andINTO … INDICATORS7.54 (abaplint: 7.57 and 8.16),LIKE_REGEXPR,OCCURRENCES_REGEXPRandREPLACE_REGEXPR7.55,SUBSTRING_REGEXPR7.56. New:FIRST_VALUE,LAST_VALUE,NTILEand window frames (ROWS BETWEEN) 7.55,INDICATORS … NULL BITFIELD7.56, inline declaration inOPEN CURSOR7.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 SIZEwithout 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, areMacroCallstatements instead ofUnknown. 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 headerisInsertFieldGroup, 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
notesof call graph and logic results, likeenhancements: 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::Basis750in 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 inWHEREand 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=1writes 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,
INFOTYPESand payroll clusters. The oracle reads plainNAME.abapfiles as programs.
v0.3.0
BAdIs, enhancements and customer exits are followed to the code that runs; loading from an SAP system is faster.
- BAdIs:
CALL BADIresolves 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.xmland.sxci.xmlfiles. Newbadion calls, MCP toolfind_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>.abapfiles. The call graph lists them as unitsENHO:<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_DETAILtwo 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 ofBAPI_USER_GET_DETAILtwo hops deep takes 0.6 s. - Customer exits:
CALL CUSTOMER-FUNCTION '001'callsEXIT_<program>_001, named by the program; it was a dynamic call of-FUNCTIONbefore.
v0.2.0
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 mcpgives 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,textandobjectTextin Node.js,textandobject_textin Python. - CDS views: data definitions are parsed: sources with joins, associations, parameters, WHERE, and the fields each element is made of. Objects
DDLS:NAME, CLIcds,cds()in both packages. - Dictionary types: structures, tables (
TABL:NAME) and data elements (DTEL:NAME) from ADT and abapGit resolve receivers likels_node-ref->get( )and parameters typed with a data element referring to a class. - Logic:
SUBMITis followed: the tables of the submitted program count for the caller, connected through the values passed withWITH.- 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 scopeexternalandstoreon table accesses. - Calls of instance methods also reach their redefinitions in subclasses.
- Calls:
x = NEW #( )takes its class fromx. 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
OBJECTis no longer requested. - Tools:
tools/version.mjsandtools/gen-types.mjs --checkwork on a checkout with CRLF line ends.
v0.1.0
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.