view release on metacpan or search on metacpan
infix/include/infix/infix.h view on Meta::CPAN
* printf("Result: %d\n", result); // Output: Result: 42
*
* infix_forward_destroy(trampoline);
* return 0;
* }
* ```
*/
#pragma once
/**
* @defgroup version_info Version Information
* @brief Macros defining the semantic version of the infix library.
* @details The versioning scheme follows Semantic Versioning 2.0.0 (SemVer).
* @{
*/
#define INFIX_MAJOR 0 /**< The major version number. Changes with incompatible API updates. */
#define INFIX_MINOR 1 /**< The minor version number. Changes with new, backward-compatible features. */
#define INFIX_PATCH 4 /**< The patch version number. Changes with backward-compatible bug fixes. */
#if defined(__has_c_attribute)
#define _INFIX_HAS_C_ATTRIBUTE(x) __has_c_attribute(x)
#else
infix/src/common/double_tap.h view on Meta::CPAN
// C++ Headers must be included BEFORE extern "C"
#if defined(__cplusplus)
#include <atomic>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Portability Macros for Atomics and Thread-Local Storage
#if defined(__cplusplus)
#define TAP_ATOMIC_SIZE_T std::atomic<size_t>
#define TAP_ATOMIC_FETCH_ADD(ptr, val) std::atomic_fetch_add(ptr, (size_t)(val))
#define TAP_ATOMIC_INIT(val) (val)
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
#include <stdatomic.h>
#define TAP_ATOMIC_SIZE_T _Atomic size_t
#define TAP_ATOMIC_FETCH_ADD(ptr, val) atomic_fetch_add(ptr, val)
#define TAP_ATOMIC_INIT(val) = val
#elif defined(__GNUC__) || defined(__clang__)
infix/src/common/double_tap.h view on Meta::CPAN
void tap_skip(size_t count, const char * reason, ...) DBLTAP_PRINTF_FORMAT(2, 3);
void tap_skip_all(const char * reason, ...) DBLTAP_PRINTF_FORMAT(1, 2);
void diag(const char * fmt, ...) DBLTAP_PRINTF_FORMAT(1, 2);
void tap_note(const char * fmt, ...) DBLTAP_PRINTF_FORMAT(1, 2);
void test_body(void);
#ifdef __cplusplus
}
#endif
// Public Test Harness Macros
/** @brief Declares the total number of tests to be run in the current scope. Must be called before any tests. */
#define plan(count) tap_plan(count)
/** @brief Concludes testing, validates the plan, and returns an exit code based on success or failure. */
#define done() tap_done()
/** @brief Immediately terminates the entire test suite with a failure message. Useful for fatal setup errors. */
#define bail_out(...) tap_bail_out(__VA_ARGS__)
/** @brief The core assertion macro. Checks a condition and prints an "ok" or "not ok" TAP line with diagnostics on
* failure. */
#define ok(cond, ...) tap_ok(!!(cond), __FILE__, __LINE__, __func__, #cond, __VA_ARGS__)
/** @brief A convenience macro that always passes. Equivalent to `ok(true, ...)`. */
infix/src/common/infix_config.h view on Meta::CPAN
*
* Its most critical function is to select the correct **Application Binary Interface (ABI)**
* implementation to use for JIT code generation. This is achieved through a cascade
* of preprocessor checks that can be overridden by the user for cross-compilation.
* By the end of this file, exactly one `INFIX_ABI_*` macro must be defined, which
* determines which `abi_*.c` file is included in the unity build.
*
* @internal
*/
#pragma once
// System Feature Test Macros
/**
* @details These macros are defined to ensure that standard POSIX and other
* necessary function declarations (like `dlopen`, `dlsym`, `snprintf`, `shm_open`)
* are made available by system headers in a portable way across different C
* library implementations (glibc, musl, BSD libc, etc.). Failing to define these
* can lead to compilation failures due to implicitly declared functions on
* stricter build environments.
*/
#if !defined(_POSIX_C_SOURCE)
#define _POSIX_C_SOURCE 200809L
infix/src/common/infix_internals.h view on Meta::CPAN
* @details Located in `src/jit/executor.c`, this function is called by the JIT-compiled
* stub. It receives the marshalled arguments and dispatches the call to either
* the type-safe callback (via a cached forward trampoline) or the generic closure handler.
* @param[in] context The `infix_reverse_t` context for this call.
* @param[out] return_value_ptr A pointer to the stack buffer for the return value.
* @param[in] args_array A pointer to the `void**` array of argument pointers.
*/
INFIX_INTERNAL void infix_internal_dispatch_callback_fn_impl(infix_reverse_t * context,
void * return_value_ptr,
void ** args_array);
// Utility Macros & Inlines
/** @brief Appends a sequence of bytes (e.g., an instruction opcode) to a code buffer. */
#define EMIT_BYTES(buf, ...) \
do { \
const uint8_t bytes[] = {__VA_ARGS__}; \
code_buffer_append((buf), bytes, sizeof(bytes)); \
} while (0)
/**
* @brief Aligns a value up to the next multiple of a power-of-two alignment.
* @param value The value to align.
* @param alignment The alignment boundary (must be a power of two).
lib/Affix.h view on Meta::CPAN
/// Type alias for an infix type registry. Represents a collection of named types.
infix_registry_t * registry;
/// // Smart enums
HV * enum_registry;
// Cache for coercion strings to avoid re-fetching from SV objects
HV * coercion_cache;
} my_cxt_t;
START_MY_CXT;
// Helper macro to fetch a value from a hash if it exists, otherwise return a default.
#define hv_existsor(hv, key, _or) hv_exists(hv, key, strlen(key)) ? *hv_fetch(hv, key, strlen(key), 0) : _or
// Macros to handle passing the Perl interpreter context ('THX') explicitly,
// which is necessary for thread-safe code.
#ifdef MULTIPLICITY
#define storeTHX(var) (var) = aTHX
#define dTHXfield(var) tTHX var;
#else
#define storeTHX(var) dNOOP
#define dTHXfield(var)
#endif
// Forward-declare the primary structures.
lib/Affix.h view on Meta::CPAN
#ifdef newXS_flags
#define newXSproto_portable(name, c_impl, file, proto) newXS_flags(name, c_impl, file, proto, 0)
#else
#define newXSproto_portable(name, c_impl, file, proto) \
(PL_Sv = (SV *)newXS(name, c_impl, file), sv_setpv(PL_Sv, proto), (CV *)PL_Sv)
#endif
#define newXS_deffile(a, b) Perl_newXS_deffile(aTHX_ a, b)
#define export_function(package, what, tag) \
_export_function(aTHX_ get_hv(form("%s::EXPORT_TAGS", package), GV_ADD), what, tag)
// Debugging Macros
#if DEBUG > 1
#define PING warn("Ping at %s line %d", __FILE__, __LINE__);
#else
#define PING
#endif
#define DumpHex(addr, len) _DumpHex(aTHX_ addr, len, __FILE__, __LINE__)
void _DumpHex(pTHX_ const void *, size_t, const char *, int);
#define DD(scalar) _DD(aTHX_ scalar, __FILE__, __LINE__)
void _DD(pTHX_ SV *, const char *, int);
lib/Affix/Wrap.pm view on Meta::CPAN
return $type->affix_type if builtin::blessed($type);
return 'Void';
}
method affix {
return $definition->affix if defined $definition;
builtin::blessed($type) ? $type->affix : Void;
}
}
class #
Affix::Wrap::Macro : isa(Affix::Wrap::Entity) {
field $value : reader : param //= ();
method affix_type {
$value // return '';
my $v = $value // '';
$v =~ s/^\s+|\s+$//g;
return '' unless length $v;
if ( $v =~ /^-?(?:0x[\da-fA-F]+|\d+(?:\.\d+)?)$/ || $v =~ /^".*"$/ || $v =~ /^'.*'$/ ) {
return $v;
}
lib/Affix/Wrap.pm view on Meta::CPAN
method _walk( $node, $acc, $current_file ) {
return unless ref $node eq 'HASH';
my $kind = $node->{kind} // 'Unknown';
my $node_file = $self->_get_node_file($node);
if ($node_file) {
$current_file = $self->_normalize($node_file);
$last_seen_file = $current_file;
}
elsif ( defined $last_seen_file ) { $current_file = $last_seen_file; }
if ( $self->_is_valid_file($current_file) && !$node->{isImplicit} ) {
if ( $kind eq 'MacroDefinitionRecord' ) {
if ( $node->{range} ) { $self->_macro( $node, $acc, $current_file ); }
}
elsif ( $kind eq 'TypedefDecl' ) { $self->_typedef( $node, $acc, $current_file ); }
elsif ( $kind eq 'RecordDecl' || $kind eq 'CXXRecordDecl' ) {
$self->_record( $node, $acc, $current_file );
return;
}
elsif ( $kind eq 'EnumDecl' ) {
$self->_enum( $node, $acc, $current_file );
return;
lib/Affix/Wrap.pm view on Meta::CPAN
my $t = $self->_extract_trailing( $f, $e );
return $d unless defined $t && length $t;
return $t unless defined $d && length $d;
return "$d\n$t";
}
method _macro( $n, $acc, $f ) {
my ( $s, $e, $l, $el ) = $self->_meta($n);
my $val = $self->_extract_macro_val( $n, $f );
push @$acc,
Affix::Wrap::Macro->new(
name => $n->{name},
file => $f,
line => $l,
end_line => $el,
value => $val,
doc => $self->_extract_doc( $f, $s ),
start_offset => $s,
end_offset => $e
);
}
lib/Affix/Wrap.pm view on Meta::CPAN
$v =~ s/\/\/.*$//;
$v =~ s/\/\*.*?\*\///g;
$v =~ s/^\s+|\s+$//g;
return $v;
}
}
'';
}
method _scan_macros_fallback($acc) {
my %seen = map { $_->name => 1 } grep { ref($_) eq 'Affix::Wrap::Macro' } @$acc;
for my $f ( keys %$allowed_files ) {
next unless $self->_is_valid_file($f);
my $c = $self->_get_content($f);
while ( $c =~ /^\s*#\s*define\s+(\w+)(?:[ \t]+(.*?))?\s*$/mg ) {
my $name = $1;
next if $seen{$name};
my $val = $2 // '';
my $off = $-[0];
my $end = $+[0];
my $pre = substr( $c, 0, $off );
my $line = ( $pre =~ tr/\n// ) + 1;
$val =~ s/\/\/.*$//;
$val =~ s/\/\*.*?\*\///g;
$val =~ s/^\s+|\s+$//g;
push @$acc,
Affix::Wrap::Macro->new(
name => $name,
file => $f,
line => $line,
end_line => $line,
value => $val,
doc => $self->_extract_doc( $f, $off ),
start_offset => $off,
end_offset => $end
);
}
lib/Affix/Wrap.pm view on Meta::CPAN
method _read($f) {
my $abs = $self->_normalize($f);
return $file_cache->{$abs} if exists $file_cache->{$abs};
return $file_cache->{$abs} = Path::Tiny::path($f)->slurp_utf8;
}
method _scan( $f, $acc ) {
my $c = $self->_read($f);
# Macros
while ( $c =~ /^\s*#\s*define\s+(\w+)(?:[ \t]+(.*?))?$/gm ) {
my $name = $1;
my $val = $2 // '';
my $s = $-[0];
my $e = $+[0];
$val =~ s/\/\/.*$//;
$val =~ s/\/\*.*?\*\///g;
$val =~ s/^\s+|\s+$//g;
push @$acc,
Affix::Wrap::Macro->new(
name => $name,
value => $val,
file => $f,
line => $self->_ln( $c, $s ),
end_line => $self->_ln( $c, $e ),
doc => $self->_doc( $c, $s ),
start_offset => $s,
end_offset => $e
);
}
lib/Affix/Wrap.pm view on Meta::CPAN
# Pre-register User Types
# This ensures they are available in the Affix registry before signatures are parsed,
# and allows using them in recursive definitions or opaque handles.
for my $name ( keys %$types ) {
my $type = $types->{$name};
my $type_str = builtin::blessed($type) ? $type : "$type";
Affix::typedef( $name, $type_str );
}
my @nodes = $self->parse;
# Macro resolution pass
my %macros;
for my $node (@nodes) {
if ( $node isa Affix::Wrap::Macro ) {
my $val = $node->value // '';
# Strip C suffixes (U, L, UL, LL) from hex/decimal numbers
# e.g. 0x01U -> 0x01
$val =~ s/(?<=\d)[Uu][Ll]{0,2}//g;
$macros{ $node->name } = $val;
}
}
my %cache;
my $resolve;
lib/Affix/Wrap.pm view on Meta::CPAN
# Generation pass
my @installed;
for my $node (@nodes) {
# Skip definitions if the user provided a manual type override
if ( ( $node isa Affix::Wrap::Typedef || $node isa Affix::Wrap::Struct || $node isa Affix::Wrap::Enum ) &&
exists $types->{ $node->name } ) {
next;
}
if ( $node isa Affix::Wrap::Macro ) {
# Attempt to resolve value to a pure number
my $val = $resolve->( $node->name );
if ( defined $val ) {
# It's a number. Inject constant sub returning integer
no strict 'refs';
no warnings 'redefine';
*{ "${target}::" . $node->name } = sub () {$val};
push @installed, $node;
lib/Affix/Wrap.pod view on Meta::CPAN
A global C<extern> variable.
=over
=item * C<affix_type>: Returns string C<pin my $var, $lib, name =E<gt> Type>.
=item * C<affix( $lib, $pkg )>: Installs the variable accessor into C<$pkg>.
=back
=head2 Affix::Wrap::Macro
A preprocessor C<#define>. Only simple value macros are captured.
=over
=item * C<affix_type>: Returns string C<use constant Name =E<gt> Value>. Expressions (e.g., C<A + B>) are quoted as strings, while literals are preserved.
=item * C<affix( undef, $pkg )>: Installs the constant into C<$pkg>.
=back
lib/Affix/Wrap.pod view on Meta::CPAN
# Generate Perl code
if ( $node isa Affix::Wrap::Function ) {
# e.g. "affix $lib, 'my_func', [Int], Void;"
$code .= $node->affix_type . "\n";
}
elsif ( $node isa Affix::Wrap::Typedef ) {
# e.g. "typedef MyStruct => Struct[ ... ];"
$code .= $node->affix_type . ";\n";
}
elsif ( $node isa Affix::Wrap::Macro ) {
# e.g. "use constant MAX_VAL => 100;"
$code .= $node->affix_type . ";\n";
}
elsif ( $node isa Affix::Wrap::Variable ) {
# e.g. "pin my $var, $lib, ..."
$code .= $node->affix_type . ";\n";
}
}
$code .= "\n1;\n";