File Coverage

blib/lib/Syntax/Keyword/Match.pm
Criterion Covered Total %
statement 18 20 90.0
branch 7 10 70.0
condition n/a
subroutine 4 4 100.0
pod n/a
total 29 34 85.2


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2021-2023 -- leonerd@leonerd.org.uk
5              
6             package Syntax::Keyword::Match 0.11;
7              
8 13     13   2934091 use v5.14;
  13         162  
9 13     13   88 use warnings;
  13         31  
  13         343  
10              
11 13     13   63 use Carp;
  13         30  
  13         4527  
12              
13             require XSLoader;
14             XSLoader::load( __PACKAGE__, our $VERSION );
15              
16             =head1 NAME
17              
18             C - a C syntax for perl
19              
20             =head1 SYNOPSIS
21              
22             use v5.14;
23             use Syntax::Keyword::Match;
24              
25             my $n = ...;
26              
27             match($n : ==) {
28             case(1) { say "It's one" }
29             case(2) { say "It's two" }
30             case(3) { say "It's three" }
31             case(4), case(5)
32             { say "It's four or five" }
33             default { say "It's something else" }
34             }
35              
36             =head1 DESCRIPTION
37              
38             This module provides a syntax plugin that implements a control-flow block
39             called C, which executes at most one of a choice of different
40             blocks depending on the value of its controlling expression.
41              
42             This is similar to C's C syntax (copied into many other
43             languages), or syntax provided by L.
44              
45             This is an initial, experimental implementation. Furthermore, it is built as
46             a non-trivial example use-case on top of L, which is also
47             experimental. No API or compatibility guarantees are made at this time.
48              
49             =head1 Experimental Features
50              
51             Some of the features of this module are currently marked as experimental (even
52             within the context that the module itself is experimental). They will provoke
53             warnings in the C category, unless silenced.
54              
55             use Syntax::Keyword::Match qw( match :experimental(dispatch) );
56              
57             use Syntax::Keyword::Match qw( match :experimental ); # all of the above
58              
59             =cut
60              
61             my @EXPERIMENTAL = qw( dispatch );
62              
63             sub import
64             {
65 10     10   71 shift;
66 10         31 my @syms = @_;
67              
68 10 100       66 @syms or @syms = ( "match" );
69              
70 10         30 my %syms = map { $_ => 1 } @syms;
  13         49  
71              
72 10 50       109 $^H{"Syntax::Keyword::Match/match"}++ if delete $syms{match};
73              
74 10         32 foreach ( @EXPERIMENTAL ) {
75 10 100       85 $^H{"Syntax::Keyword::Match/experimental($_)"}++ if delete $syms{":experimental($_)"};
76             }
77              
78 10 50       44 if( delete $syms{":experimental"} ) {
79 0         0 $^H{"Syntax::Keyword::Match/experimental($_)"}++ for @EXPERIMENTAL;
80             }
81              
82 10 50       16974 croak "Unrecognised import symbols @{[ keys %syms ]}" if keys %syms;
  0            
83             }
84              
85             =head1 KEYWORDS
86              
87             =head2 match
88              
89             match( EXPR : OP ) {
90             ...
91             }
92              
93             A C statement provides the controlling expression, comparison operator,
94             and sequence of C statements for a match operation. The expression is
95             evaluated to yield a scalar value, which is then compared, using the
96             comparison operator, against each of the C labels in the order they are
97             written, topmost first. If a match is found then the body of the labelled
98             block is executed. If no label matches but a C block is present, that
99             will be executed instead. After a single inner block has been executed, no
100             further tests are performed and execution continues from the statement
101             following the C statement.
102              
103             The braces following the C block must only contain C or
104             C statements. Arbitrary code is not supported here.
105              
106             Even though a C statement is a full statement and not an expression, it
107             can still yield a value if it appears as the final statment in its containing
108             C or C block. For example:
109              
110             my $result = do {
111             match( $topic : == ) {
112             case(1) { ... }
113             }
114             };
115              
116             =head3 Comparison Operators
117              
118             The comparison operator must be either C (to compare cases as strings) or
119             C<==> (to compare them as numbers), or C<=~> (to compare cases using regexps).
120              
121             I, or previous versions on Perl
122             releases 5.32 onwards, the C operator is also supported, allowing
123             dispatch based on what type of object the controlling expression gives.
124              
125             match( $obj : isa ) {
126             case(A::Package) { ... }
127             case(Another::Package) { ... }
128             }
129              
130             Remember that comparisons are made in the order they are written, from the top
131             downwards. Therefore, if you list a derived class as well as a base class,
132             make sure to put the derived class B the base class, or instances of
133             that type will also match the base class C block and the derived one
134             will never match.
135              
136             class TheBase {}
137             class Derived :isa(TheBase) {}
138              
139             match( $obj : isa ) {
140             case(TheBase) { ... }
141             case(Derived) {
142             # This case will never match as the one above will always happen first
143             }
144             }
145              
146             I the operator syntax is parsed using L,
147             meaning that custom infix operators can be recognised, even on versions of
148             perl that do not support the full C mechanism.
149              
150             =head2 case
151              
152             case(VAL) { STATEMENTS... }
153              
154             case(VAL), case(VAL), ... { STATEMENTS... }
155              
156             A C statement must only appear inside the braces of a C. It
157             provides a block of code to run if the controlling expression's value matches
158             the value given in the C statement, according to the comparison
159             operator.
160              
161             Multiple C statements are permitted for a single block. A value matching
162             any of them will run the code inside the block.
163              
164             If the value is a non-constant expression, such as a variable or function
165             call, it will be evaluated as part of performing the comparison every time the
166             C statement is executed. For best performance it is advised to extract
167             values that won't need computing again into a variable or C that
168             can be calculated just once at program startup; for example:
169              
170             use constant CONDITION => a_function("with", "arguments");
171              
172             match( $var : eq ) {
173             case(CONDITION) { ... }
174             ...
175             }
176              
177             The C<:experimental(dispatch)> feature selects a more efficient handling of
178             sequences of multiple C blocks with constant expressions. This handling
179             is implemented with a custom operator that will entirely confuse modules like
180             C or optree inspectors like coverage tools so is not selected by
181             default, but can be enabled for extra performance in critical sections.
182              
183             =head2 default
184              
185             A C statement must only appear inside the braces of a C. If
186             present, it must be the final choice, and there must only be one of them. It
187             provides a block of code to run if the controlling expression's value did not
188             match any of the given C labels.
189              
190             =cut
191              
192             =head1 COMPARISONS
193              
194             As this syntax is fairly similar to a few other ideas, the following
195             comparisons may be useful.
196              
197             =head2 Core perl's given/when syntax
198              
199             Compared to core perl's C syntax (available with
200             C), this syntax is initially visually very similar but
201             actually behaves very differently. Core's C uses the smartmatch
202             (C<~~>) operator for its comparisons, which is complex, subtle, and hard to
203             use correctly - doubly-so when comparisons against values stored in variables
204             rather than literal constants are involved. It can be unpredictable whether
205             string or numerical comparison are being used, for example. By comparison,
206             this module requires the programmer to specify the comparison operator. The
207             choice of string or numerical comparison is given in the source code - there
208             can be no ambiguity.
209              
210             Additionally, the C operator is also permitted, which has no equivalent
211             ability in smartmatch.
212              
213             Also, the C syntax permits mixed code within a C block
214             which is run unconditionally, or at least, until the first successful C
215             statement is encountered. The syntax provided by this module requires that the
216             only code inside a C block be a sequence of C statements. No
217             other code is permitted.
218              
219             =head2 Switch::Plain
220              
221             Like this module, L also provides a syntax where the programmer
222             specifies whether the comparison is made using stringy or numerical semantics.
223             C also permits additional conditions to be placed on C
224             blocks, whereas this module does not.
225              
226             Additionally, the C operator is also permitted, which has no equivalent
227             ability in C.
228              
229             =head2 C's switch/case
230              
231             The C programming language provides a similar sort of syntax, using keywords
232             named C and C. One key difference between that and the syntax
233             provided for Perl by this module is that in C the C labels really are
234             just labels. The C part of the statement effectively acts as a sort of
235             computed C. This often leads to bugs caused by forgetting to put a
236             C at the end of a sequence of statements before the next C label;
237             a situation called "fallthrough". Such a mistake is impossible with this
238             module, because every C is provided by a block. Once execution has
239             finished with the block, the entire C statement is finished. There is
240             no possibility of accidental fallthrough.
241              
242             C's syntax only permits compiletime constants for C labels, whereas this
243             module will also allow the result of any runtime expression.
244              
245             Code written in C will perform identically even if any of the C labels
246             and associated code are moved around into a different order. The syntax
247             provided by this module notionally performs all of its tests in the order they
248             are written in, and any changes of that order might cause a different result.
249              
250             =head1 TODO
251              
252             This is clearly an early experimental work. There are many features to add,
253             and design decisions to make. Rather than attempt to list them all here it
254             would be best to check the RT bug queue at
255              
256             L
257              
258             =head1 AUTHOR
259              
260             Paul Evans
261              
262             =cut
263              
264             0x55AA;