@@ -144,9 +144,10 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
144144 -- Emit a type reference, either as-is or as $ with parameterization
145145 -- skip_identifier: if true, don't emit the identifier part (for struct fields)
146146 -- self_struct: name of the struct being defined (for self-referential structs)
147- local function emit_type_ref (decl , parameterized , skip_name , skip_identifier , self_struct )
147+ -- keep_const: if true, keep const/volatile qualifiers (needed for pointer base types like const char*)
148+ local function emit_type_ref (decl , parameterized , skip_name , skip_identifier , self_struct , keep_const )
148149 if decl .type == " root" then
149- return emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct )
150+ return emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct , keep_const )
150151 end
151152
152153 if decl .type == " type" then
@@ -175,6 +176,9 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
175176 table.insert (parameterized , mod )
176177 elseif is_custom_type (mod ) then
177178 buf :put (" $ " )
179+ elseif not keep_const and (mod == " const" or mod == " volatile" ) then
180+
181+ -- Skip const/volatile for non-pointer struct fields to avoid LuaJIT issues
178182 else
179183 buf :put (mod , " " )
180184 end
@@ -195,7 +199,8 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
195199 elseif decl .type == " pointer" then
196200 local buf = buffer .new ()
197201 -- Pass skip_identifier through for pointer types
198- local base = emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct )
202+ -- Pass keep_const=true to preserve const for pointer base types (e.g., const char*)
203+ local base = emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct , true )
199204 -- Trim trailing whitespace from base
200205 base = base :gsub (" %s+$" , " " )
201206 buf :put (base )
@@ -210,6 +215,9 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
210215 elseif skip_identifier and not valid_qualifiers [mod ] then
211216
212217 -- Skip it (likely an identifier)
218+ elseif not keep_const and (mod == " const" or mod == " volatile" ) then
219+
220+ -- Skip const/volatile on the pointer itself when not keeping const
213221 else
214222 buf :put (" " , mod )
215223 end
@@ -218,7 +226,7 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
218226
219227 return tostring (buf )
220228 elseif decl .type == " array" then
221- local base = emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct )
229+ local base = emit_type_ref (decl .of , parameterized , skip_name , skip_identifier , self_struct , keep_const )
222230 base = base :gsub (" %s+$" , " " )
223231 local size_str = decl .size or " "
224232 return base .. " [" .. size_str .. " ]"
@@ -494,59 +502,67 @@ local function build_lua(c_header, expanded_defines, extra_lua, options)
494502 buf :put (
495503 " ffi.metatype(mod." ,
496504 struct_name ,
497- " , {__tostring = function(s) return ('struct " .. struct_name .. " [%p]'):format(s) end,__new = function(T, t) if not t then return N(T) end \n "
505+ " , {__tostring = function(s) return ('struct " .. struct_name .. " [%p]'):format(s) end,__new = function(T, t) \n "
498506 )
499507
500508 if v .type == " union" then
501509 -- For unions: create object, then assign whichever field is provided
502510 buf :put (" local obj = N(T)\n " )
511+ buf :put (" if not t then return obj end\n " )
503512
504513 for i , field in ipairs (v .fields ) do
505514 if field .identifier then
506515 if lua_keywords [field .identifier ] then
507516 buf :put (
508- " if t['" ,
509- field .identifier ,
510- " '] ~= nil then obj." ,
517+ " obj['" ,
511518 field .identifier ,
512- " = t['" ,
519+ " '] = t['" ,
513520 field .identifier ,
514- " '] end \n "
521+ " ']"
515522 )
516523 else
517524 buf :put (
518- " if t." ,
519- field .identifier ,
520- " ~= nil then obj." ,
525+ " obj." ,
521526 field .identifier ,
522527 " = t." ,
523- field .identifier ,
524- " end\n "
528+ field .identifier
525529 )
526530 end
531+
532+ buf :put (" \n " )
527533 end
528534 end
529535
530536 buf :put (" return obj\n " )
531537 else
532- -- For structs: use the original N(T, ...) pattern
533- buf :put (" return N(\n\t T,\n " )
538+ -- For structs: use field-by-field assignment to avoid LuaJIT NYI
539+ -- issues with union members (same pattern as unions above)
540+ buf :put (" local obj = N(T)\n " )
541+ buf :put (" if not t then return obj end\n " )
534542
535543 for i , field in ipairs (v .fields ) do
536544 if field .identifier then
537545 if lua_keywords [field .identifier ] then
538- buf :put (" \t t['" , field .identifier , " ']" )
546+ buf :put (
547+ " obj['" ,
548+ field .identifier ,
549+ " '] = t['" ,
550+ field .identifier ,
551+ " ']\n "
552+ )
539553 else
540- buf :put (" \t t." , field .identifier )
554+ buf :put (
555+ " obj." ,
556+ field .identifier ,
557+ " = t." ,
558+ field .identifier ,
559+ " \n "
560+ )
541561 end
542-
543- if i ~= # v .fields then buf :put (" ," ) end
544-
545- buf :put (" \n " )
546562 end
547563 end
548564
549- buf :put (" ) \n " )
565+ buf :put (" return obj \n " )
550566 end
551567
552568 buf :put (" end,\n })" )
0 commit comments