File Coverage

XSParseInfix.h
Criterion Covered Total %
statement 16 20 80.0
branch 9 18 50.0
condition n/a
subroutine n/a
pod n/a
total 25 38 65.7


line stmt bran cond sub pod time code
1             #ifndef __XS_PARSE_INFIX_H__
2             #define __XS_PARSE_INFIX_H__
3              
4             #define XSPARSEINFIX_ABI_VERSION 2
5              
6             /* Infix operator classifications */
7             /* No built-in operators use the _MISC categories, but they are provided for
8             * custom infix operators to use so they are still found by selections */
9             enum XSParseInfixClassification {
10             XPI_CLS_NONE = 0,
11             XPI_CLS_PREDICATE, /* any boolean-returning operator */
12             XPI_CLS_RELATION, /* ... any predicate that is typewise symmetric */
13             XPI_CLS_EQUALITY, /* ... any relation that is true for (x == x) and false otherwise */
14             XPI_CLS_SMARTMATCH, /* ... the predicate smartmatch (~~) */
15             XPI_CLS_MATCHRE, /* ... the predicate regexp match (=~) */
16             XPI_CLS_ISA, /* ... the predicate instance of (isa) */
17             XPI_CLS_MATCH_MISC, /* ... any other match-like predicate */
18             XPI_CLS_ORDERING, /* cmp or <=> */
19              
20             XPI_CLS_ADD_MISC, /* an operator at addition-like precedence */
21             XPI_CLS_MUL_MISC, /* an operator at multiplication-like precedence */
22             XPI_CLS_POW_MISC, /* an operator at power exponentiation-like precedence */
23             };
24              
25             enum XSParseInfixSelection {
26             XPI_SELECT_ANY,
27             XPI_SELECT_PREDICATE, /* any predicate */
28             XPI_SELECT_RELATION, /* any relation */
29             XPI_SELECT_EQUALITY, /* any equality */
30             XPI_SELECT_ORDERING, /* any ordering */
31              
32             XPI_SELECT_MATCH_NOSMART, /* any equality or other match operator, including smartmatch */
33             XPI_SELECT_MATCH_SMART, /* any equality or other match operator, not including smartmatch */
34             };
35              
36             /* lhs_flags, rhs_flags */
37             enum {
38             XPI_OPERAND_TERM_LIST = 6, /* term in list context */
39             XPI_OPERAND_LIST = 7, /* list in list context */
40              
41             /* Other bitflags */
42             XPI_OPERAND_ONLY_LOOK = (1<<3),
43             };
44             // No longer used
45             #define XPI_OPERAND_ARITH 0
46             #define XPI_OPERAND_TERM 0
47             #define XPI_OPERAND_CUSTOM (1<<7)
48              
49             struct XSParseInfixHooks {
50             U16 flags;
51             U8 lhs_flags, rhs_flags;
52             enum XSParseInfixClassification cls;
53              
54             const char *wrapper_func_name;
55              
56             /* These two hooks are ANDed together; both must pass, if present */
57             const char *permit_hintkey;
58             bool (*permit) (pTHX_ void *hookdata);
59              
60             /* These hooks are alternatives; the first one defined is used */
61             OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, SV **parsedata, void *hookdata);
62             OP *(*ppaddr)(pTHX); /* A pp func used directly in newBINOP_custom() */
63              
64             /* optional */
65             void (*parse)(pTHX_ U32 flags, SV **parsedata, void *hookdata);
66             };
67              
68             struct XSParseInfixInfo {
69             const char *opname;
70             OPCODE opcode;
71              
72             const struct XSParseInfixHooks *hooks;
73             void *hookdata;
74             };
75              
76             static bool (*parse_infix_func)(pTHX_ enum XSParseInfixSelection select, struct XSParseInfixInfo **infop);
77             #define parse_infix(select, infop) S_parse_infix(aTHX_ select, infop)
78             static bool S_parse_infix(pTHX_ enum XSParseInfixSelection select, struct XSParseInfixInfo **infop)
79             {
80             if(!parse_infix_func)
81             croak("Must call boot_xs_parse_infix() first");
82              
83             struct XSParseInfixInfo *infocopy;
84              
85             return (*parse_infix_func)(aTHX_ select, infop);
86             }
87              
88             static OP *(*xs_parse_infix_new_op_func)(pTHX_ const struct XSParseInfixInfo *info, U32 flags, OP *lhs, OP *rhs);
89             #define xs_parse_infix_new_op(info, flags, lhs, rhs) S_xs_parse_infix_new_op(aTHX_ info, flags, lhs, rhs)
90             static OP *S_xs_parse_infix_new_op(pTHX_ const struct XSParseInfixInfo *info, U32 flags, OP *lhs, OP *rhs)
91             {
92             if(!xs_parse_infix_new_op_func)
93             croak("Must call boot_xs_parse_infix() first");
94              
95             return (*xs_parse_infix_new_op_func)(aTHX_ info, flags, lhs, rhs);
96             }
97              
98             static void (*register_xs_parse_infix_func)(pTHX_ const char *kw, const struct XSParseInfixHooks *hooks, void *hookdata);
99             #define register_xs_parse_infix(opname, hooks, hookdata) S_register_xs_parse_infix(aTHX_ opname, hooks, hookdata)
100             static void S_register_xs_parse_infix(pTHX_ const char *opname, const struct XSParseInfixHooks *hooks, void *hookdata)
101             {
102 10           if(!register_xs_parse_infix_func)
103 0           croak("Must call boot_xs_parse_infix() first");
104              
105 10           return (*register_xs_parse_infix_func)(aTHX_ opname, hooks, hookdata);
106             }
107              
108             #define boot_xs_parse_infix(ver) S_boot_xs_parse_infix(aTHX_ ver)
109 2           static void S_boot_xs_parse_infix(pTHX_ double ver) {
110             SV **svp;
111 2 50         SV *versv = ver ? newSVnv(ver) : NULL;
112              
113             /* XS::Parse::Infix is implemented in XS::Parse::Keyword's .so file */
114 2           load_module(PERL_LOADMOD_NOIMPORT, newSVpvs("XS::Parse::Keyword"), versv, NULL);
115              
116 2           svp = hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MIN", 0);
117 2 50         if(!svp)
118 0           croak("XS::Parse::Infix ABI minimum version missing");
119 2 50         int abi_ver = SvIV(*svp);
120 2 50         if(abi_ver > XSPARSEINFIX_ABI_VERSION)
121 0           croak("XS::Parse::Infix ABI version mismatch - library supports >= %d, compiled for %d",
122             abi_ver, XSPARSEINFIX_ABI_VERSION);
123              
124 2           svp = hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MAX", 0);
125 2 50         abi_ver = SvIV(*svp);
126 2 50         if(abi_ver < XSPARSEINFIX_ABI_VERSION)
127 0           croak("XS::Parse::Infix ABI version mismatch - library supports <= %d, compiled for %d",
128             abi_ver, XSPARSEINFIX_ABI_VERSION);
129              
130 2 50         parse_infix_func = INT2PTR(bool (*)(pTHX_ enum XSParseInfixSelection, struct XSParseInfixInfo **),
131             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/parse()@2", 0)));
132 2 50         xs_parse_infix_new_op_func = INT2PTR(OP *(*)(pTHX_ const struct XSParseInfixInfo *, U32, OP *, OP *),
133             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/new_op()@0", 0)));
134 2 50         register_xs_parse_infix_func = INT2PTR(void (*)(pTHX_ const char *, const struct XSParseInfixHooks *, void *),
135             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@2", 0)));
136 2           }
137              
138             #endif