-
Notifications
You must be signed in to change notification settings - Fork 0
/
execinside.sty
117 lines (95 loc) · 3.38 KB
/
execinside.sty
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
\ProvidesExplPackage{execinside}{2022/06/14}{0.0.4}{Convenience functions for executing some macro deep inside a token list}
\RequirePackage{filecontentsdef}
\RequirePackage{tlanalysispatch}
\ExplSyntaxOn
\cs_generate_variant:Nn \EI_append:n {x}
\cs_generate_variant:Nn \int_compare:nNnTF {VNnTF}
\cs_generate_variant:Nn \tl_set:Nn {Nx}
\cs_generate_variant:Nn \int_compare:nNnT {VNnT}
\cs_generate_variant:Nn \cs_if_exist_use:NT {cT}
% ======== define handler functions.
% a few things it can do:
% • \tl_build_gput_right:Nn to \_EIresult (content being put there must be wrapped in \unexpanded i.e. x-expand to the desired result
\cs_set_protected:Npn \EI_append_raw:n #1 {
\tl_build_gput_right:Nn \_EIresult {#1}
}
\cs_set_protected:Npn \EI_append:n #1 {
\EI_append_raw:n {\exp_not:n {#1}}
}
\int_new:N \_EIbalance_level
\int_new:N \_EIcollecting_balanced
% handler can call this to collect following tokens in the input stream as argument.
% #1: the function to pass argument in. (arguments are passed as brace-hack-included)
% #2: number of arguments
\cs_set_protected:Npn \EI_collect_arg:Nn #1 #2 {
\int_set:Nn \_EIcollecting_balanced {#2}
\int_zero:N \_EIbalance_level
\tl_build_gbegin:N \_EIbalanced_content
\tl_build_gput_right:Nn \_EIbalanced_content {\noexpand #1}
}
\cs_set_protected:Npn \EIhandler_EIexpand {
\EI_collect_arg:Nn \EI_append:x {1}
}
\cs_set_protected:Npn \EIhandler_EIexecute {
\EI_collect_arg:Nn \use:n {1}
}
\cs_set_protected:Npn \execinsideprepare:n #1 {
\tl_build_gbegin:N \_EIresult
\int_zero:N \_EIcollecting_balanced
\tl_analysis_map_inline:nn {#1} {
% reminder: ##1: token, ##2: char code (int), ##3: cat code (hex digit)
\int_compare:nNnTF \_EIcollecting_balanced > 0 {
% collecting content.
\tl_build_gput_right:Nn \_EIbalanced_content {##1}
\int_case:nn {"##3} {
{1} { \int_incr:N \_EIbalance_level }
{2} { \int_decr:N \_EIbalance_level }
}
% we check this every time instead of only after egroup tokens...
% so that if there's exactly one token to be collected it's still correctly passed through
% disadvantage: function might get a space
\int_compare:nNnT \_EIbalance_level = 0 {
% done, call handler function and revert to normal mode.
\int_decr:N \_EIcollecting_balanced
\int_compare:nNnT \_EIcollecting_balanced = 0 {
\tl_build_gend:N \_EIbalanced_content
\tl_set:Nx \_EIbalanced_content {\_EIbalanced_content}
%\pretty:V \_EIbalanced_content
\_EIbalanced_content % ← the handler function is embedded in here
%\pretty:n {done}
}
}
} {
\let \_EIprocessed \c_false_bool
% check for \EIexecute etc. and handle accordingly.
\int_compare:nNnT {##2} = {-1} {
\cs_if_exist_use:cT {
EIhandler_ \expandafter \cs_to_str:N ##1
} {
\let \_EIprocessed \c_true_bool
}
}
% if not, just append to result.
\bool_if:NF \_EIprocessed {
\tl_build_gput_right:Nn \_EIresult {##1}
}
}
}
\tl_build_gend:N \_EIresult
\tl_set:Nx \_EIresult {\_EIresult}
}
\cs_set_protected:Npn \execinside:n #1 {
\execinsideprepare:n {#1}
\_EIresult
}
\let\execinside\execinside:n % normal-catcode alias
\cs_set_protected:Npn \execinside_set:Nn #1 #2 {
\execinsideprepare:n {#2}
\let #1 \_EIresult
}
\let\execinsideSet\execinside_set:Nn
\cs_set_protected:Npn \execinside_gset:Nn #1 #2 {
\execinsideprepare:n {#2}
\global \let #1 \_EIresult
}
\let\execinsideGset\execinside_gset:Nn