File Coverage

XSParseInfix.h
Criterion Covered Total %
statement 18 23 78.2
branch 11 22 50.0
condition n/a
subroutine n/a
pod n/a
total 29 45 64.4


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             /* Since the _MISC categories never turn up in selections, put them at high
21             * index so as to leave space for more */
22             XPI_CLS_LOW_MISC = 0x80, /* an operator at low precedence */
23             XPI_CLS_LOGICAL_OR_LOW_MISC,
24             XPI_CLS_LOGICAL_AND_LOW_MISC,
25             XPI_CLS_ASSIGN_MISC,
26             XPI_CLS_LOGICAL_OR_MISC,
27             XPI_CLS_LOGICAL_AND_MISC,
28             XPI_CLS_ADD_MISC, /* an operator at addition-like precedence */
29             XPI_CLS_MUL_MISC, /* an operator at multiplication-like precedence */
30             XPI_CLS_POW_MISC, /* an operator at power exponentiation-like precedence */
31             XPI_CLS_HIGH_MISC, /* an operator at high precedence */
32             };
33              
34             enum XSParseInfixSelection {
35             XPI_SELECT_ANY,
36             XPI_SELECT_PREDICATE, /* any predicate */
37             XPI_SELECT_RELATION, /* any relation */
38             XPI_SELECT_EQUALITY, /* any equality */
39             XPI_SELECT_ORDERING, /* any ordering */
40              
41             XPI_SELECT_MATCH_NOSMART, /* any equality or other match operator, including smartmatch */
42             XPI_SELECT_MATCH_SMART, /* any equality or other match operator, not including smartmatch */
43             };
44              
45             /* lhs_flags, rhs_flags */
46             enum {
47             XPI_OPERAND_TERM_LIST = 6, /* term in list context */
48             XPI_OPERAND_LIST = 7, /* list in list context */
49              
50             /* Other bitflags */
51             XPI_OPERAND_ONLY_LOOK = (1<<3),
52             };
53             // No longer used
54             #define XPI_OPERAND_ARITH 0
55             #define XPI_OPERAND_TERM 0
56             #define XPI_OPERAND_CUSTOM (1<<7)
57              
58             struct XSParseInfixHooks {
59             U16 flags;
60             U8 lhs_flags, rhs_flags;
61             enum XSParseInfixClassification cls;
62              
63             const char *wrapper_func_name;
64              
65             /* These two hooks are ANDed together; both must pass, if present */
66             const char *permit_hintkey;
67             bool (*permit) (pTHX_ void *hookdata);
68              
69             /* These hooks are alternatives; the first one defined is used */
70             OP *(*new_op)(pTHX_ U32 flags, OP *lhs, OP *rhs, SV **parsedata, void *hookdata);
71             OP *(*ppaddr)(pTHX); /* A pp func used directly in newBINOP_custom() */
72              
73             /* optional */
74             void (*parse)(pTHX_ U32 flags, SV **parsedata, void *hookdata);
75             };
76              
77             struct XSParseInfixInfo {
78             const char *opname;
79             OPCODE opcode;
80              
81             const struct XSParseInfixHooks *hooks;
82             void *hookdata;
83              
84             enum XSParseInfixClassification cls;
85             };
86              
87             static bool (*parse_infix_func)(pTHX_ enum XSParseInfixSelection select, struct XSParseInfixInfo **infop);
88             #define parse_infix(select, infop) S_parse_infix(aTHX_ select, infop)
89             static bool S_parse_infix(pTHX_ enum XSParseInfixSelection select, struct XSParseInfixInfo **infop)
90             {
91             if(!parse_infix_func)
92             croak("Must call boot_xs_parse_infix() first");
93              
94             struct XSParseInfixInfo *infocopy;
95              
96             return (*parse_infix_func)(aTHX_ select, infop);
97             }
98              
99             static OP *(*xs_parse_infix_new_op_func)(pTHX_ const struct XSParseInfixInfo *info, U32 flags, OP *lhs, OP *rhs);
100             #define xs_parse_infix_new_op(info, flags, lhs, rhs) S_xs_parse_infix_new_op(aTHX_ info, flags, lhs, rhs)
101             static OP *S_xs_parse_infix_new_op(pTHX_ const struct XSParseInfixInfo *info, U32 flags, OP *lhs, OP *rhs)
102             {
103 7 50         if(!xs_parse_infix_new_op_func)
104 0           croak("Must call boot_xs_parse_infix() first");
105              
106 7           return (*xs_parse_infix_new_op_func)(aTHX_ info, flags, lhs, rhs);
107             }
108              
109             static void (*register_xs_parse_infix_func)(pTHX_ const char *kw, const struct XSParseInfixHooks *hooks, void *hookdata);
110             #define register_xs_parse_infix(opname, hooks, hookdata) S_register_xs_parse_infix(aTHX_ opname, hooks, hookdata)
111             static void S_register_xs_parse_infix(pTHX_ const char *opname, const struct XSParseInfixHooks *hooks, void *hookdata)
112             {
113 17 50         if(!register_xs_parse_infix_func)
114 0           croak("Must call boot_xs_parse_infix() first");
115              
116 17           return (*register_xs_parse_infix_func)(aTHX_ opname, hooks, hookdata);
117             }
118              
119             #define boot_xs_parse_infix(ver) S_boot_xs_parse_infix(aTHX_ ver)
120 17           static void S_boot_xs_parse_infix(pTHX_ double ver) {
121             SV **svp;
122 17 50         SV *versv = ver ? newSVnv(ver) : NULL;
123              
124             /* XS::Parse::Infix is implemented in XS::Parse::Keyword's .so file */
125 17           load_module(PERL_LOADMOD_NOIMPORT, newSVpvs("XS::Parse::Keyword"), versv, NULL);
126              
127 17           svp = hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MIN", 0);
128 17 50         if(!svp)
129 0           croak("XS::Parse::Infix ABI minimum version missing");
130 17 50         int abi_ver = SvIV(*svp);
131 17 50         if(abi_ver > XSPARSEINFIX_ABI_VERSION)
132 0           croak("XS::Parse::Infix ABI version mismatch - library supports >= %d, compiled for %d",
133             abi_ver, XSPARSEINFIX_ABI_VERSION);
134              
135 17           svp = hv_fetchs(PL_modglobal, "XS::Parse::Infix/ABIVERSION_MAX", 0);
136 17 50         abi_ver = SvIV(*svp);
137 17 50         if(abi_ver < XSPARSEINFIX_ABI_VERSION)
138 0           croak("XS::Parse::Infix ABI version mismatch - library supports <= %d, compiled for %d",
139             abi_ver, XSPARSEINFIX_ABI_VERSION);
140              
141 17 50         parse_infix_func = INT2PTR(bool (*)(pTHX_ enum XSParseInfixSelection, struct XSParseInfixInfo **),
142             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/parse()@2", 0)));
143 17 50         xs_parse_infix_new_op_func = INT2PTR(OP *(*)(pTHX_ const struct XSParseInfixInfo *, U32, OP *, OP *),
144             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/new_op()@0", 0)));
145 17 50         register_xs_parse_infix_func = INT2PTR(void (*)(pTHX_ const char *, const struct XSParseInfixHooks *, void *),
146             SvUV(*hv_fetchs(PL_modglobal, "XS::Parse::Infix/register()@2", 0)));
147 17           }
148              
149             #endif