Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Directive |
|
| 1.0606060606060606;1.061 | ||||
Directive$ArgDescriptor |
|
| 1.0606060606060606;1.061 | ||||
Directive$AssignmentArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$BlockArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$ConditionArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$ExactlyOneChoice |
|
| 1.0606060606060606;1.061 | ||||
Directive$FormalArgListArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$KeywordArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$LValueArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$LiteralBlockArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$NameArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$OptionChoice |
|
| 1.0606060606060606;1.061 | ||||
Directive$OptionalGroup |
|
| 1.0606060606060606;1.061 | ||||
Directive$OptionalRepeatingSubdirective |
|
| 1.0606060606060606;1.061 | ||||
Directive$OptionalSubdirective |
|
| 1.0606060606060606;1.061 | ||||
Directive$QuotedStringArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$RValueArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$SingleOptionChoice |
|
| 1.0606060606060606;1.061 | ||||
Directive$StringArg |
|
| 1.0606060606060606;1.061 | ||||
Directive$Subdirective |
|
| 1.0606060606060606;1.061 |
1 | /* | |
2 | * Copyright (C) 1998-2000 Semiotek Inc. All Rights Reserved. | |
3 | * | |
4 | * Redistribution and use in source and binary forms, with or without | |
5 | * modification, are permitted under the terms of either of the following | |
6 | * Open Source licenses: | |
7 | * | |
8 | * The GNU General Public License, version 2, or any later version, as | |
9 | * published by the Free Software Foundation | |
10 | * (http://www.fsf.org/copyleft/gpl.html); | |
11 | * | |
12 | * or | |
13 | * | |
14 | * The Semiotek Public License (http://webmacro.org/LICENSE.) | |
15 | * | |
16 | * This software is provided "as is", with NO WARRANTY, not even the | |
17 | * implied warranties of fitness to purpose, or merchantability. You | |
18 | * assume all risks and liabilities associated with its use. | |
19 | * | |
20 | * See www.webmacro.org for more information on the WebMacro project. | |
21 | */ | |
22 | ||
23 | package org.webmacro.directive; | |
24 | ||
25 | import java.io.IOException; | |
26 | ||
27 | import org.slf4j.Logger; | |
28 | import org.slf4j.LoggerFactory; | |
29 | import org.webmacro.Context; | |
30 | import org.webmacro.FastWriter; | |
31 | import org.webmacro.Macro; | |
32 | import org.webmacro.PropertyException; | |
33 | import org.webmacro.TemplateVisitor; | |
34 | import org.webmacro.Visitable; | |
35 | import org.webmacro.engine.BuildContext; | |
36 | import org.webmacro.engine.BuildException; | |
37 | ||
38 | /** | |
39 | * Directive is an abstract class which directives can extend. | |
40 | * Nested within Directive (as static classes) are a host of classes used | |
41 | * for building directive argument lists. | |
42 | * | |
43 | * Directives are Macros, so they must implement the Macro interface. | |
44 | * For convenience, an implementation of evaluate() (written in terms of | |
45 | * write()) is provided in the base class.) | |
46 | * | |
47 | * Directives must implement the following static method: | |
48 | * public DirectiveDescriptor getDescriptor(); | |
49 | * | |
50 | * It is expected that all directives will build a copy of their descriptor | |
51 | * statically, using the various XxxArg() constructors, and return a reference | |
52 | * to that from getDescriptor(). | |
53 | * | |
54 | * @author Brian Goetz | |
55 | */ | |
56 | ||
57 | 1284 | public abstract class Directive implements Macro, Visitable |
58 | { | |
59 | ||
60 | 2 | static Logger _log = LoggerFactory.getLogger(Directive.class); |
61 | public static final int ArgType_CONDITION = 1; | |
62 | public static final int ArgType_LVALUE = 2; | |
63 | public static final int ArgType_RVALUE = 3; | |
64 | public static final int ArgType_KEYWORD = 4; | |
65 | public static final int ArgType_ASSIGN = 5; | |
66 | public static final int ArgType_BLOCK = 6; | |
67 | public static final int ArgType_LITBLOCK = 7; | |
68 | public static final int ArgType_SUBDIRECTIVE = 8; | |
69 | public static final int ArgType_QUOTEDSTRING = 9; | |
70 | public static final int ArgType_STRING = 10; | |
71 | public static final int ArgType_NAME = 11; | |
72 | public static final int ArgType_ARGLIST = 12; | |
73 | ||
74 | public static final int ArgType_GROUP = 50; | |
75 | public static final int ArgType_CHOICE = 51; | |
76 | ||
77 | /** | |
78 | * Directives must implement a build() method. The build method | |
79 | * should examine the directive arguments (available through the | |
80 | * DirectiveBuilder) and return a macro describing the built | |
81 | * directive. In most cases, build() will just set up the | |
82 | * directive's private fields and return 'this', but in some | |
83 | * cases, no macro needs be returned (such as directives with only | |
84 | * side effects on the build context) or some other macro may be | |
85 | * returned (such as in the case of "#if (true) { }" -- no IfDirective | |
86 | * object need be returned, just return the block.) | |
87 | */ | |
88 | ||
89 | public abstract Object build (DirectiveBuilder b, | |
90 | BuildContext bc) | |
91 | throws BuildException; | |
92 | ||
93 | /* Convenience implementation of evaluate() which Directives can inherit */ | |
94 | public Object evaluate (Context context) | |
95 | throws PropertyException | |
96 | { | |
97 | try | |
98 | { | |
99 | 0 | FastWriter fw = FastWriter.getInstance(context.getBroker()); |
100 | 0 | write(fw, context); |
101 | 0 | return fw.toString(); |
102 | } | |
103 | 0 | catch (IOException e) |
104 | { | |
105 | 0 | _log.error( |
106 | "Directive.evaluate: IO exception on write to StringWriter", e); | |
107 | 0 | return ""; |
108 | } | |
109 | } | |
110 | ||
111 | /** | |
112 | * Convenience method for directives to write HTML warnings into the output | |
113 | * stream. Eventually this will be parameterizable so that HTML is not | |
114 | * assumed to be the only underlying language. | |
115 | */ | |
116 | ||
117 | protected static String getWarningText (String warning, Context context) | |
118 | throws IOException, PropertyException | |
119 | { | |
120 | 4 | return context.getEvaluationExceptionHandler() |
121 | .warningString("WARNING: " + warning + | |
122 | " at " + context.getCurrentLocation()); | |
123 | } | |
124 | ||
125 | /** | |
126 | * Convenience method for directives to write HTML warnings into the output | |
127 | * stream. Eventually this will be parameterizable so that HTML is not | |
128 | * assumed to be the only underlying language.<p> | |
129 | * | |
130 | * This method also outputs the same warning message to a log named "directive" | |
131 | */ | |
132 | protected static void writeWarning (String warning, Context context, | |
133 | FastWriter writer) throws IOException, PropertyException | |
134 | { | |
135 | 4 | context.getLog("directive").warn(warning + |
136 | " at " + context.getCurrentLocation()); | |
137 | 4 | writer.write(getWarningText(warning, context)); |
138 | 0 | } |
139 | ||
140 | public void accept (TemplateVisitor v) | |
141 | { | |
142 | 0 | v.visitUnknownMacro(this.getClass().getName(), this); |
143 | 0 | } |
144 | ||
145 | /* Nested static classes */ | |
146 | ||
147 | ||
148 | /** | |
149 | * ArgDescriptor is the base class for all the different types | |
150 | * of argument descriptors, like ConditionalArg, KeywordArg, RValueArg, | |
151 | * etc. | |
152 | * Most ArgDescriptor constructors take an argId parameter, which is | |
153 | * an integer which uniquely identifies the argument which will be passed | |
154 | * to DirectiveBuilder.getArg when retrieving the argument. | |
155 | */ | |
156 | ||
157 | public static abstract class ArgDescriptor | |
158 | { | |
159 | ||
160 | public final int id; | |
161 | public final int type; | |
162 | 208 | public boolean optional = false; |
163 | 208 | public int subordinateArgs = 0, nextArg = 0; |
164 | public int[] children; | |
165 | public String keyword; | |
166 | ||
167 | protected ArgDescriptor (int id, int type) | |
168 | 208 | { |
169 | 208 | this.id = id; |
170 | 208 | this.type = type; |
171 | 208 | } |
172 | ||
173 | protected void setOptional (boolean optional) | |
174 | { | |
175 | 50 | this.optional = optional; |
176 | 50 | } |
177 | ||
178 | protected void setSubordinateArgs (int subordinateArgs) | |
179 | { | |
180 | 46 | this.subordinateArgs = subordinateArgs; |
181 | 46 | } |
182 | } | |
183 | ||
184 | ||
185 | /** | |
186 | * Condition argument type. Accepts a WM expression which evaluates | |
187 | * to a boolean result, evaluated according to Expression.isTrue. | |
188 | */ | |
189 | public static class ConditionArg extends ArgDescriptor | |
190 | { | |
191 | ||
192 | public ConditionArg (int id) | |
193 | { | |
194 | 4 | super(id, ArgType_CONDITION); |
195 | 4 | } |
196 | } | |
197 | ||
198 | /** | |
199 | * Block argument type. Accepts a WM Block. | |
200 | */ | |
201 | public static class BlockArg extends ArgDescriptor | |
202 | { | |
203 | ||
204 | public BlockArg (int id) | |
205 | { | |
206 | 20 | super(id, ArgType_BLOCK); |
207 | 20 | } |
208 | } | |
209 | ||
210 | /** | |
211 | * Literal block argument type. Accepts a WM Block, but does not intepret | |
212 | * any directives or property references contained in the block. | |
213 | */ | |
214 | public static class LiteralBlockArg extends ArgDescriptor | |
215 | { | |
216 | ||
217 | public LiteralBlockArg (int id) | |
218 | { | |
219 | 4 | super(id, ArgType_LITBLOCK); |
220 | 4 | } |
221 | } | |
222 | ||
223 | /** | |
224 | * RValue argument type. Accepts any WM expression. | |
225 | */ | |
226 | public static class RValueArg extends ArgDescriptor | |
227 | { | |
228 | ||
229 | public RValueArg (int id) | |
230 | { | |
231 | 30 | super(id, ArgType_RVALUE); |
232 | 30 | } |
233 | } | |
234 | ||
235 | /** | |
236 | * LValue argument type. Accepts any WM property reference. | |
237 | */ | |
238 | public static class LValueArg extends ArgDescriptor | |
239 | { | |
240 | ||
241 | public LValueArg (int id) | |
242 | { | |
243 | 24 | super(id, ArgType_LVALUE); |
244 | 24 | } |
245 | } | |
246 | ||
247 | /** | |
248 | * Quoted string argument type. Accepts a quoted string with embedded | |
249 | * property references (e.g., "hello $foo") | |
250 | */ | |
251 | public static class QuotedStringArg extends ArgDescriptor | |
252 | { | |
253 | ||
254 | public QuotedStringArg (int id) | |
255 | { | |
256 | 8 | super(id, ArgType_QUOTEDSTRING); |
257 | 8 | } |
258 | } | |
259 | ||
260 | /** | |
261 | * String argument type. Accepts either a quoted string with embedded | |
262 | * property references (e.g., "hello $foo"), or a single property | |
263 | * reference ($something). | |
264 | */ | |
265 | public static class StringArg extends ArgDescriptor | |
266 | { | |
267 | ||
268 | public StringArg (int id) | |
269 | { | |
270 | 0 | super(id, ArgType_STRING); |
271 | 0 | } |
272 | } | |
273 | ||
274 | /** | |
275 | * Keyword argument type. Accepts only the specified keyword. | |
276 | */ | |
277 | public static class KeywordArg extends ArgDescriptor | |
278 | { | |
279 | ||
280 | public KeywordArg (int id, String keyword) | |
281 | { | |
282 | 50 | super(id, ArgType_KEYWORD); |
283 | 50 | this.keyword = keyword; |
284 | 50 | } |
285 | } | |
286 | ||
287 | /** | |
288 | * Assignment. In the standard parser, the parser looks for an = | |
289 | * operator, but other parsers can handle this as they see fit. | |
290 | */ | |
291 | public static class AssignmentArg extends ArgDescriptor | |
292 | { | |
293 | ||
294 | public AssignmentArg () | |
295 | { | |
296 | 14 | super(0, ArgType_ASSIGN); |
297 | 14 | } |
298 | } | |
299 | ||
300 | /** | |
301 | * Implements an argument as a simple name. | |
302 | */ | |
303 | public static class NameArg extends ArgDescriptor | |
304 | { | |
305 | ||
306 | public NameArg (int id) | |
307 | { | |
308 | 2 | super(id, ArgType_NAME); |
309 | 2 | } |
310 | } | |
311 | ||
312 | /** | |
313 | * Argument list. Accepts a ()-delimited list of simple variable names. | |
314 | */ | |
315 | public static class FormalArgListArg extends ArgDescriptor | |
316 | { | |
317 | ||
318 | public FormalArgListArg (int id) | |
319 | { | |
320 | 2 | super(id, ArgType_ARGLIST); |
321 | 2 | } |
322 | } | |
323 | ||
324 | /** | |
325 | * Optional group. An optional group can begin with a Keyword argument. | |
326 | * If the keyword argument is not present in the input text, the entire | |
327 | * group is skipped. Can contain other groups. The argCount parameter | |
328 | * is the number of simple arguments or groups in this argument group. | |
329 | */ | |
330 | public static class OptionalGroup extends ArgDescriptor | |
331 | { | |
332 | ||
333 | public OptionalGroup (int argCount) | |
334 | { | |
335 | 42 | super(0, ArgType_GROUP); |
336 | 42 | setOptional(true); |
337 | 42 | setSubordinateArgs(argCount); |
338 | 42 | } |
339 | } | |
340 | ||
341 | /** | |
342 | * The OptionChoice indicates that several optional groups can be accepted | |
343 | * in any order. The groupCount parameter is the number of OptionalGroup | |
344 | * arguments following. Each group in the choice will be accepted zero | |
345 | * or one time, in any order. | |
346 | * For example, OptionChoice would allow a directive with the optional | |
347 | * groups (Keyword("from"), RValue()) and (Keyword("max"), RValue()) to | |
348 | * accept either "from n max m" or "from n" or "max m from n". | |
349 | */ | |
350 | public static class OptionChoice extends ArgDescriptor | |
351 | { | |
352 | ||
353 | 4 | public boolean repeating = true; |
354 | ||
355 | public OptionChoice (int groupCount) | |
356 | { | |
357 | 4 | super(0, ArgType_CHOICE); |
358 | 4 | setOptional(true); |
359 | 4 | setSubordinateArgs(groupCount); |
360 | 4 | } |
361 | } | |
362 | ||
363 | ||
364 | /** | |
365 | * The SingleOptionChoice indicates that zero or one of several | |
366 | * optional groups can be accepted, but only once. Otherwise works | |
367 | * exactly as OptionChoice. */ | |
368 | public static class SingleOptionChoice extends OptionChoice | |
369 | { | |
370 | ||
371 | public SingleOptionChoice (int groupCount) | |
372 | { | |
373 | 2 | super(groupCount); |
374 | 2 | repeating = false; |
375 | 2 | } |
376 | } | |
377 | ||
378 | ||
379 | /** | |
380 | * The ExactlyOneChoice indicates that exactly one of several | |
381 | * optional groups can be accepted, only once. Otherwise works | |
382 | * exactly as OptionChoice. */ | |
383 | public static class ExactlyOneChoice extends OptionChoice | |
384 | { | |
385 | ||
386 | public ExactlyOneChoice (int groupCount) | |
387 | { | |
388 | 0 | super(groupCount); |
389 | 0 | setOptional(false); |
390 | 0 | repeating = false; |
391 | 0 | } |
392 | } | |
393 | ||
394 | ||
395 | /** | |
396 | * Subdirectives are like directives, except that they do not have their | |
397 | * own class. The directive is responsible for fetching and processing | |
398 | * the subdirective's arguments. Each Subdirective can have its own | |
399 | * argument list. | |
400 | */ | |
401 | public static class Subdirective extends ArgDescriptor | |
402 | { | |
403 | ||
404 | public final static int BREAKING = 1; | |
405 | ||
406 | public final String name; | |
407 | public final ArgDescriptor[] args; | |
408 | 4 | public boolean repeating = false, isBreaking = false; |
409 | ||
410 | public Subdirective (int id, String name, | |
411 | ArgDescriptor[] args) | |
412 | { | |
413 | 4 | super(id, ArgType_SUBDIRECTIVE); |
414 | 4 | this.name = name; |
415 | 4 | this.args = args; |
416 | 4 | } |
417 | ||
418 | public Subdirective (int id, String name, ArgDescriptor[] args, | |
419 | int flags) | |
420 | { | |
421 | 4 | this(id, name, args); |
422 | 4 | isBreaking = ((flags & BREAKING) != 0); |
423 | 4 | } |
424 | } | |
425 | ||
426 | /** | |
427 | * Optional subdirective. This means that the subdirective can appear | |
428 | * zero or one time. | |
429 | */ | |
430 | public static class OptionalSubdirective extends Subdirective | |
431 | { | |
432 | ||
433 | public OptionalSubdirective (int id, String name, | |
434 | ArgDescriptor[] args) | |
435 | { | |
436 | 0 | super(id, name, args); |
437 | 0 | setOptional(true); |
438 | 0 | } |
439 | ||
440 | public OptionalSubdirective (int id, String name, | |
441 | ArgDescriptor[] args, int flags) | |
442 | { | |
443 | 4 | super(id, name, args, flags); |
444 | 4 | setOptional(true); |
445 | 4 | } |
446 | } | |
447 | ||
448 | /** | |
449 | * Optional repeating subdirective. This means that the | |
450 | * subdirective can appear zero or more times. | |
451 | */ | |
452 | public static class OptionalRepeatingSubdirective | |
453 | extends OptionalSubdirective | |
454 | { | |
455 | ||
456 | public OptionalRepeatingSubdirective (int id, String name, | |
457 | ArgDescriptor[] args) | |
458 | { | |
459 | 0 | super(id, name, args); |
460 | 0 | repeating = true; |
461 | 0 | } |
462 | ||
463 | public OptionalRepeatingSubdirective (int id, String name, | |
464 | ArgDescriptor[] args, int flags) | |
465 | { | |
466 | 2 | super(id, name, args, flags); |
467 | 2 | repeating = true; |
468 | 2 | } |
469 | } | |
470 | ||
471 | ||
472 | // Utility exception classes for use by directives | |
473 | ||
474 | /** | |
475 | * Utility exception used by directives to signal that an argument | |
476 | * that was supposed to be a Variable is not a variable. Subclasses | |
477 | * BuildException. | |
478 | */ | |
479 | public static class NotVariableBuildException extends BuildException | |
480 | { | |
481 | ||
482 | /** | |
483 | * | |
484 | */ | |
485 | private static final long serialVersionUID = 1L; | |
486 | ||
487 | public NotVariableBuildException (String directive) | |
488 | { | |
489 | super("#" + directive + ": Argument must be a variable"); | |
490 | } | |
491 | ||
492 | public NotVariableBuildException (String directive, Exception e) | |
493 | { | |
494 | super("#" + directive + ": Argument must be a variable", e); | |
495 | } | |
496 | } | |
497 | ||
498 | /** | |
499 | * Utility exception used by directives to signal that an argument | |
500 | * that was supposed to be a simple Variable (only one term) is not. | |
501 | * Subclasses BuildException. | |
502 | */ | |
503 | 1284 | public static class NotSimpleVariableBuildException extends BuildException |
504 | { | |
505 | private static final long serialVersionUID = 1L; | |
506 | ||
507 | public NotSimpleVariableBuildException (String directive) | |
508 | { | |
509 | super("#" + directive + ": Argument must be a simple variable"); | |
510 | } | |
511 | ||
512 | public NotSimpleVariableBuildException (String directive, Exception e) | |
513 | { | |
514 | super("#" + directive + ": Argument must be a simple variable", e); | |
515 | } | |
516 | } | |
517 | ||
518 | ||
519 | } | |
520 |