Skip to content

Commit 2c0bb2e

Browse files
committed
refactoring
1 parent 503cdef commit 2c0bb2e

File tree

4 files changed

+110
-97
lines changed

4 files changed

+110
-97
lines changed

examples/c_preprocessor.lua

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
local preprocess = require("nattlua.definitions.lua.ffi.preprocessor.preprocessor")
2+
local vulkan_test = [[
3+
#include <vulkan/vulkan.h>
4+
5+
// Use some Vulkan defines/types to verify they're available
6+
VkResult result;
7+
const uint32_t version = VK_API_VERSION_1_0;
8+
9+
// Test that platform defines work - these will expand to 1 if defines are set
10+
int wayland_enabled = VK_USE_PLATFORM_WAYLAND_KHR;
11+
int xcb_enabled = VK_USE_PLATFORM_XCB_KHR;
12+
int xlib_enabled = VK_USE_PLATFORM_XLIB_KHR;
13+
14+
// Test standard predefined macros
15+
#ifdef __STDC__
16+
int stdc_defined = __STDC__;
17+
long stdc_version = __STDC_VERSION__;
18+
#endif
19+
20+
#ifdef __GNUC__
21+
int gcc_major = __GNUC__;
22+
int gcc_minor = __GNUC_MINOR__;
23+
#endif
24+
]]
25+
local res = preprocess(
26+
vulkan_test,
27+
{
28+
working_directory = "/Users/caps/github/ffibuild/vulkan/repo/include",
29+
system_include_paths = {"/Users/caps/github/ffibuild/vulkan/repo/include"},
30+
defines = {
31+
-- Linux platform defines (uncomment to test platform-specific headers)
32+
VK_USE_PLATFORM_WAYLAND_KHR = 1, -- Wayland support
33+
VK_USE_PLATFORM_XCB_KHR = 1, -- X11 XCB support
34+
VK_USE_PLATFORM_XLIB_KHR = 1, -- X11 Xlib support
35+
-- Other common Linux platform defines:
36+
-- VK_USE_PLATFORM_XLIB_XRANDR_EXT = 1, -- X11 XRandR extension
37+
-- VK_USE_PLATFORM_DIRECTFB_EXT = 1, -- DirectFB support
38+
-- Note: The output is intentionally minimal because:
39+
-- 1. vulkan_core.h has extensive include guards (#ifndef/#define)
40+
-- 2. Most Vulkan content is already expanded (types, constants, etc.)
41+
-- 3. Platform-specific extensions are wrapped in #ifdef directives
42+
-- The preprocessor is correctly handling all of this!
43+
},
44+
on_include = function(filename, full_path)
45+
print(string.format("Including: %s", filename))
46+
end,
47+
}
48+
)
49+
print(res)

nattlua/definitions/lua/ffi/preprocessor/parser.lua

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
--[[HOTRELOAD
22
run_lua("test/tests/nattlua/c_declarations/preprocessor.lua")
33
]]
4-
local META = require("nattlua.parser.base")()
4+
local Lexer = require("nattlua.definitions.lua.ffi.preprocessor.lexer").New
5+
local Code = require("nattlua.code").New
56
local buffer = require("string.buffer")
7+
local META = require("nattlua.parser.base")()
68

79
-- Deep copy tokens to prevent shared state corruption
810
-- This is CRITICAL because:
@@ -22,14 +24,51 @@ end
2224

2325
local old = META.New
2426

25-
function META.New(...)
26-
local obj = old(...)
27-
obj.defines = {}
28-
obj.define_stack = {}
29-
obj.expansion_stack = {}
30-
obj.conditional_stack = {} -- Track nested #if/#ifdef/#ifndef states
31-
obj.position_stack = {} -- Track positions for directive token removal
32-
return obj
27+
function META.New(tokens, code, config)
28+
config = config or {}
29+
config.working_directory = config.working_directory or os.getenv("PWD") or "."
30+
config.defines = config.defines or {}
31+
config.include_paths = config.include_paths or {}
32+
config.max_include_depth = config.max_include_depth or 100
33+
config.on_include = config.on_include -- Optional callback for includes
34+
config.system_include_paths = config.system_include_paths or {}
35+
36+
if config.add_standard_defines ~= false then
37+
local standard_defines = {
38+
__STDC__ = 1,
39+
__STDC_VERSION__ = "201710L",
40+
__STDC_HOSTED__ = 1,
41+
__GNUC__ = 4,
42+
__GNUC_MINOR__ = 2,
43+
__GNUC_PATCHLEVEL__ = 1,
44+
}
45+
46+
for name, value in pairs(standard_defines) do
47+
if config.defines[name] == nil then config.defines[name] = value end
48+
end
49+
end
50+
51+
local self = old(tokens, code, config)
52+
self.defines = {}
53+
self.define_stack = {}
54+
self.conditional_stack = {} -- Track nested #if/#ifdef/#ifndef states
55+
self.position_stack = {} -- Track positions for directive token removal
56+
self.include_depth = 0 -- Track current include depth
57+
-- Add predefined macros
58+
for name, value in pairs(config.defines) do
59+
if type(value) == "boolean" then
60+
value = value and "1" or "0"
61+
else
62+
value = tostring(value)
63+
end
64+
65+
local value_tokens = Lexer(Code(value, "define")):GetTokens()
66+
assert(value_tokens[#value_tokens].type == "end_of_file")
67+
table.remove(value_tokens)
68+
self:Define(name, nil, value_tokens)
69+
end
70+
71+
return self
3372
end
3473

3574
-- Helper functions for saving/restoring positions when removing directive tokens
@@ -745,7 +784,7 @@ do -- #include directive
745784
local fs = require("nattlua.other.fs")
746785

747786
local function resolve_include_path(self, filename, is_system_include)
748-
local opts = self.preprocess_options
787+
local opts = self.config
749788

750789
if not opts then return nil, "No preprocessor options available" end
751790

@@ -874,8 +913,8 @@ do -- #include directive
874913
end
875914

876915
-- Callback for tracking includes
877-
if self.preprocess_options.on_include then
878-
self.preprocess_options.on_include(filename, full_path)
916+
if self.config.on_include then
917+
self.config.on_include(filename, full_path)
879918
end
880919

881920
-- Preprocess the included file recursively
@@ -898,14 +937,14 @@ do -- #include directive
898937
-- Create a copy of options with updated working directory
899938
local include_opts = {}
900939

901-
for k, v in pairs(self.preprocess_options) do
940+
for k, v in pairs(self.config) do
902941
include_opts[k] = v
903942
end
904943

905944
-- Set working directory to the directory of the included file
906945
-- so relative includes from that file work correctly
907-
include_opts.working_directory = full_path:match("(.*/)") or self.preprocess_options.working_directory
908-
include_parser.preprocess_options = include_opts
946+
include_opts.working_directory = full_path:match("(.*/)") or self.config.working_directory
947+
include_parser.config = include_opts
909948
include_parser.include_depth = self.include_depth + 1
910949
-- Process the included file
911950
include_parser:Parse()

nattlua/definitions/lua/ffi/preprocessor/preprocessor.lua

Lines changed: 3 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4,89 +4,11 @@
44
local Lexer = require("nattlua.definitions.lua.ffi.preprocessor.lexer").New
55
local Parser = require("nattlua.definitions.lua.ffi.preprocessor.parser").New
66
local Code = require("nattlua.code").New
7-
8-
-- Get GCC/C standard predefined macros
9-
local function get_standard_defines()
10-
return {
11-
-- Standard C macros
12-
__STDC__ = 1,
13-
__STDC_VERSION__ = "201710L", -- C17
14-
__STDC_HOSTED__ = 1,
15-
-- GCC version (simulating GCC 4.2.1 for compatibility)
16-
__GNUC__ = 4,
17-
__GNUC_MINOR__ = 2,
18-
__GNUC_PATCHLEVEL__ = 1,
19-
-- Common architecture/platform detection
20-
-- Note: Users should override these based on their target platform
21-
-- __linux__ = 1,
22-
-- __unix__ = 1,
23-
-- __x86_64__ = 1,
24-
-- __LP64__ = 1,
25-
}
26-
end
27-
287
-- Main preprocessor function with options support
29-
return function(code_or_options, options)
30-
local code, opts
31-
32-
-- Handle both old and new calling conventions
33-
if type(code_or_options) == "string" then
34-
code = code_or_options
35-
opts = options or {}
36-
else
37-
opts = code_or_options or {}
38-
code = opts.code
39-
end
40-
41-
-- Default options
42-
opts.working_directory = opts.working_directory or os.getenv("PWD") or "."
43-
opts.defines = opts.defines or {}
44-
opts.include_paths = opts.include_paths or {}
45-
opts.max_include_depth = opts.max_include_depth or 100
46-
opts.on_include = opts.on_include -- Optional callback for includes
47-
opts.system_include_paths = opts.system_include_paths or {}
48-
49-
-- Merge standard defines with user defines (user defines take precedence)
50-
if opts.add_standard_defines ~= false then
51-
local standard_defines = get_standard_defines()
52-
53-
for name, value in pairs(standard_defines) do
54-
if opts.defines[name] == nil then opts.defines[name] = value end
55-
end
56-
end
57-
58-
-- Create Code and Lexer instances
59-
-- Create code object
60-
local code_obj = Code(code, opts.filename or "input.c")
8+
return function(code, config)
9+
local code_obj = Code(code, "cpreprocessor")
6110
local tokens = Lexer(code_obj):GetTokens()
62-
local parser = Parser(tokens, code_obj)
63-
64-
-- Add predefined macros
65-
for name, value in pairs(opts.defines) do
66-
if type(value) == "string" then
67-
-- Parse the value as tokens
68-
local value_tokens = Lexer(Code(value, "define")):GetTokens()
69-
70-
-- Remove EOF token
71-
if value_tokens[#value_tokens] and value_tokens[#value_tokens].type == "end_of_file" then
72-
table.remove(value_tokens)
73-
end
74-
75-
parser:Define(name, nil, value_tokens)
76-
elseif type(value) == "boolean" then
77-
if value then
78-
parser:Define(name, nil, {parser:NewToken("number", "1")})
79-
end
80-
else
81-
parser:Define(name, nil, {parser:NewToken("number", tostring(value))})
82-
end
83-
end
84-
85-
-- Store options in parser for include handling
86-
parser.preprocess_options = opts
87-
parser.include_depth = 0
88-
-- Parse/preprocess
11+
local parser = Parser(tokens, code_obj, config)
8912
parser:Parse()
90-
-- Return processed code
9113
return parser:ToString()
9214
end

test/tests/nattlua/c_declarations/preprocessor.lua

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,10 @@ do -- conditional compilation
364364
test("#if 0\n>x=1<\n#elif 0\n>x=2<\n#else\n>x=3<\n#endif", "x=3")
365365
-- Multiple #elif
366366
test("#if 0\n>x=1<\n#elif 0\n>x=2<\n#elif 1\n>x=3<\n#endif", "x=3")
367-
test("#define A 2\n#if A == 1\n>x=1<\n#elif A == 2\n>x=2<\n#elif A == 3\n>x=3<\n#endif", "x=2")
367+
test(
368+
"#define A 2\n#if A == 1\n>x=1<\n#elif A == 2\n>x=2<\n#elif A == 3\n>x=3<\n#endif",
369+
"x=2"
370+
)
368371
-- Nested conditionals
369372
test("#ifdef FOO\n#ifdef BAR\n>x=1<\n#endif\n#endif\n>y=2<", "y=2")
370373
test(

0 commit comments

Comments
 (0)