9.4. Preprocessing
Libadalang’s integrated preprocessor works thanks to the file reader mechanism: you create a file reader that knows which files to preprocess and with which parameters, and you pass that file reader when creating the analysis context.
9.4.1. Input source
prep-data.txt
"os.ads" -Dos=windows
os.ads
1package OS is 2 # if OS = "linux" then 3 Name : constant String := "gnu-linux"; 4 # elsif OS = "windows" then 5 Name : constant String := "microsoft-windows"; 6 # else 7 Name : constant String := "unknown"; 8 # end if; 9end OS;
print_os.adb
with Ada.Text_IO; use Ada.Text_IO; with OS; procedure Print_OS is begin Put_Line (OS.Name); end Print_OS;
9.4.2. Sample code
9.4.2.1. Python
import libadalang as lal
# Let the file reader find preprocessor data files in the
# current directory.
path = ["."]
# Create the preprocessor file reader from the
# "prep-data.txt" preprocessor file. Force the "blank lines"
# mode to preserve line numbers in the preprocessed code.
fr = lal.FileReader.create_preprocessor_from_file(
filename="prep-data.txt",
path=path,
line_mode=lal.FileReader.LineMode.blank_lines,
)
# Create a context using this preprocessor configuration and
# start using Libadalang's analysis the usual way...
ctx = lal.AnalysisContext(file_reader=fr)
u = ctx.get_from_file("print_os.adb")
for node in u.root.findall(lambda n: n.text == "Name"):
# Fetch the declaration that this "Name" identifier
# references.
decl = node.p_referenced_decl()
print(node)
print(f" references {decl}")
print()
# Show the text of the unit that contain that
# declaration, with line numbers.
print("Unit text:")
for i, line in enumerate(
decl.unit.text.split("\n"), 1
):
print(f"{str(i).rjust(2)} | {line}")
9.4.2.2. Ada
with Ada.Text_IO; use Ada.Text_IO;
with GNATCOLL.File_Paths; use GNATCOLL.File_Paths;
with GNATCOLL.Strings; use GNATCOLL.Strings;
with Langkit_Support.File_Readers; use Langkit_Support.File_Readers;
with Langkit_Support.Text; use Langkit_Support.Text;
with Libadalang.Analysis; use Libadalang.Analysis;
with Libadalang.Common; use Libadalang.Common;
with Libadalang.Preprocessing; use Libadalang.Preprocessing;
procedure Main is
Path : constant Any_Path := Create_Path
(Directories => (1 .. 0 => <>), CWD => If_Empty);
-- Let the file reader find preprocessor data files in
-- the current directory.
FR : constant File_Reader_Reference :=
Create_Preprocessor_From_File
("prep-data.txt", Path, Blank_Lines);
-- Create the preprocessor file reader from the
-- "prep-data.txt" preprocessor file. Force the "blank
-- lines" mode to preserve line numbers in the
-- preprocessed code.
Ctx : constant Analysis_Context :=
Create_Context (File_Reader => FR);
U : constant Analysis_Unit :=
Ctx.Get_From_File ("print_os.adb");
-- Create a context using this preprocessor
-- configuration and start using Libadalang's analysis
-- the usual way...
-----------
-- Visit --
-----------
function Visit (Node : Ada_Node'Class) return Visit_Status is
begin
if Node.Text = "Name" then
-- Fetch the declaration that this "Name"
-- identifier references.
declare
Ref : constant Basic_Decl :=
Node.As_Identifier.P_Referenced_Decl;
begin
Put_Line (Node.Image);
Put_Line (" references " & Ref.Image);
New_Line;
-- Show the text of the unit that contain that
-- declaration, with line numbers.
Put_Line ("Unit text:");
declare
Text : constant XString :=
To_XString (To_UTF8 (Ref.Unit.Text));
Lineno : Positive := 1;
begin
for Line of Text.Split (ASCII.LF) loop
declare
Lineno_Img : constant String :=
" " & Lineno'Image;
Prefix : String renames Lineno_Img
(Lineno_Img'Last - 2
.. Lineno_Img'Last);
begin
Put (Prefix & " | ");
Put_Line (To_String (Line));
Lineno := Lineno + 1;
end;
end loop;
end;
end;
end if;
return Into;
end Visit;
begin
U.Root.Traverse (Visit'Access);
end Main;
9.4.2.3. Output
<Id "Name" print_os.adb:7:17-7:21>
references <ObjectDecl ["Name"] os.ads:6:7-6:53>
Unit text:
1 | package OS is
2 | Bits : constant := 32;
3 |
4 |
5 |
6 | Name : constant String := "microsoft-windows";
7 |
8 |
9 |
10 | end OS;
11 |