13
13
import java .io .InputStreamReader ;
14
14
import java .io .Reader ;
15
15
import java .io .StringReader ;
16
+ import java .io .StringWriter ;
16
17
import java .util .ArrayList ;
18
+ import java .util .HashMap ;
17
19
import java .util .LinkedList ;
18
20
import java .util .List ;
21
+ import java .util .Map ;
19
22
import java .util .concurrent .Callable ;
20
23
import java .util .concurrent .atomic .AtomicInteger ;
21
24
25
+ import static com .sampullara .mustache .Mustache .truncate ;
26
+
22
27
/**
23
28
* A pseudo interpreter / compiler. Instead of compiling to Java code, it compiles to a
24
29
* list of instructions to execute.
@@ -81,7 +86,7 @@ public Mustache parseFile(String path) throws MustacheException {
81
86
if (root == null ) {
82
87
String fullPath = classpathRoot == null ? path : classpathRoot + "/" + path ;
83
88
InputStream resourceAsStream =
84
- MustacheBuilder .class .getClassLoader ().getResourceAsStream (fullPath );
89
+ MustacheBuilder .class .getClassLoader ().getResourceAsStream (fullPath );
85
90
if (resourceAsStream == null ) {
86
91
throw new MustacheException (path + " not found in classpath" );
87
92
}
@@ -184,7 +189,7 @@ protected List<Code> compile(final Mustache m, final Reader br, String tag, fina
184
189
}
185
190
if (!variable .equals (tag )) {
186
191
throw new MustacheException (
187
- "Mismatched start/end tags: " + tag + " != " + variable + " in " + file + ":" + currentLine );
192
+ "Mismatched start/end tags: " + tag + " != " + variable + " in " + file + ":" + currentLine );
188
193
}
189
194
190
195
return list ;
@@ -203,7 +208,7 @@ protected List<Code> compile(final Mustache m, final Reader br, String tag, fina
203
208
} else {
204
209
if (br .read () != '}' ) {
205
210
throw new MustacheException (
206
- "Improperly closed variable in " + file + ":" + currentLine );
211
+ "Improperly closed variable in " + file + ":" + currentLine );
207
212
}
208
213
}
209
214
final String finalName = name ;
@@ -268,7 +273,7 @@ private StringBuilder write(List<Code> list, StringBuilder out, int line) {
268
273
private abstract static class SubCode implements Code {
269
274
protected final Mustache m ;
270
275
protected final String variable ;
271
- private final Code [] codes ;
276
+ protected final Code [] codes ;
272
277
private final int line ;
273
278
private final String file ;
274
279
@@ -325,6 +330,30 @@ public IterableCode(Mustache m, String variable, List<Code> codes, String file,
325
330
public void execute (FutureWriter fw , Scope scope ) throws MustacheException {
326
331
execute (fw , m .iterable (scope , variable ));
327
332
}
333
+
334
+ @ Override
335
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
336
+ // I think we have to make iteration greedy and match until we can't find a match
337
+ List <Scope > results = new ArrayList <Scope >();
338
+ Scope result ;
339
+ do {
340
+ result = new Scope ();
341
+ for (int i = 0 ; i < codes .length && result != null ; i ++) {
342
+ if (Mustache .debug ) {
343
+ Mustache .line .set (codes [i ].getLine ());
344
+ }
345
+ Code [] truncate = truncate (codes , i + 1 );
346
+ result = codes [i ].unparse (result , text , position , truncate );
347
+ }
348
+ if (result != null && result .size () > 0 ) {
349
+ results .add (result );
350
+ } else break ;
351
+ } while (true );
352
+ if (results .size () != 0 ) {
353
+ current .put (variable , results );
354
+ }
355
+ return current ;
356
+ }
328
357
}
329
358
330
359
private static class FunctionCode extends SubCode {
@@ -343,6 +372,46 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
343
372
throw new MustacheException ("Not a function: " + function );
344
373
}
345
374
}
375
+
376
+ static class MapFunction implements Function <String , String > {
377
+ private Map <String , String > map = new HashMap <String , String >();
378
+
379
+ void put (String input , String value ) {
380
+ map .put (input , value );
381
+ }
382
+
383
+ @ Override
384
+ public String apply (String input ) {
385
+ return map .get (input );
386
+ }
387
+
388
+ public String toString () {
389
+ return map .toString ();
390
+ }
391
+ }
392
+
393
+ @ Override
394
+ public Scope unparse (Scope current , final String text , final AtomicInteger position , Code [] next ) throws MustacheException {
395
+ final String value = unparseValueCode (current , text , position , next , false );
396
+ if (value == null ) return null ;
397
+ MapFunction function = (FunctionCode .MapFunction ) current .get (variable );
398
+ if (function == null ) {
399
+ function = new MapFunction ();
400
+ put (current , variable , function );
401
+ }
402
+ StringWriter sw = new StringWriter ();
403
+ FutureWriter fw = new FutureWriter (sw );
404
+ try {
405
+ for (Code code : codes ) {
406
+ code .execute (fw , current );
407
+ }
408
+ fw .flush ();
409
+ } catch (IOException e ) {
410
+ throw new MustacheException ("Failed to evaluate function body" , e );
411
+ }
412
+ function .put (sw .toString (), value );
413
+ return current ;
414
+ }
346
415
}
347
416
348
417
private static class IfIterableCode extends SubCode {
@@ -358,6 +427,23 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
358
427
}
359
428
execute (fw , m .ifiterable (scope , variable ));
360
429
}
430
+
431
+ @ Override
432
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
433
+ // Like the iterable version with only one
434
+ Scope result = new Scope ();
435
+ for (int i = 0 ; i < codes .length && result != null ; i ++) {
436
+ if (Mustache .debug ) {
437
+ Mustache .line .set (codes [i ].getLine ());
438
+ }
439
+ Code [] truncate = truncate (codes , i + 1 );
440
+ result = codes [i ].unparse (result , text , position , truncate );
441
+ }
442
+ if (result != null && result .size () > 0 ) {
443
+ put (current , variable , result );
444
+ }
445
+ return current ;
446
+ }
361
447
}
362
448
363
449
private static class InvertedIterableCode extends SubCode {
@@ -373,6 +459,24 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
373
459
}
374
460
execute (fw , m .inverted (scope , variable ));
375
461
}
462
+
463
+ @ Override
464
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
465
+ // Like the iterable version with only one
466
+ Scope result = new Scope ();
467
+ for (int i = 0 ; i < codes .length && result != null ; i ++) {
468
+ if (Mustache .debug ) {
469
+ Mustache .line .set (codes [i ].getLine ());
470
+ }
471
+ Code [] truncate = truncate (codes , i + 1 );
472
+ result = codes [i ].unparse (result , text , position , truncate );
473
+ }
474
+ if (result != null ) {
475
+ current .putAll (result );
476
+ put (current , variable , false );
477
+ }
478
+ return current ;
479
+ }
376
480
}
377
481
378
482
private static class PartialCode implements Code {
@@ -409,6 +513,14 @@ public Object call() throws Exception {
409
513
public int getLine () {
410
514
return line ;
411
515
}
516
+
517
+ @ Override
518
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
519
+ Scope unparse = m .partial (variable ).unparse (text , position );
520
+ if (unparse == null ) return null ;
521
+ put (current , variable , unparse );
522
+ return current ;
523
+ }
412
524
}
413
525
414
526
private static class WriteValueCode implements Code {
@@ -433,6 +545,59 @@ public void execute(FutureWriter fw, Scope scope) throws MustacheException {
433
545
public int getLine () {
434
546
return line ;
435
547
}
548
+
549
+ @ Override
550
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
551
+ String value = unparseValueCode (current , text , position , next , encoded );
552
+ if (value != null ) {
553
+ put (current , name , value );
554
+ return current ;
555
+ }
556
+ return null ;
557
+ }
558
+
559
+ }
560
+
561
+ private static String unparseValueCode (Scope current , String text , AtomicInteger position , Code [] next , boolean encoded ) throws MustacheException {
562
+ AtomicInteger probePosition = new AtomicInteger (position .get ());
563
+ Code [] truncate = truncate (next , 1 );
564
+ Scope result = null ;
565
+ int lastposition = position .get ();
566
+ while (next .length != 0 && probePosition .get () < text .length ()) {
567
+ lastposition = probePosition .get ();
568
+ result = next [0 ].unparse (current , text , probePosition , truncate );
569
+ if (result == null ) {
570
+ probePosition .incrementAndGet ();
571
+ } else {
572
+ break ;
573
+ }
574
+ }
575
+ if (result != null ) {
576
+ String value = text .substring (position .get (), lastposition );
577
+ if (encoded ) {
578
+ // Decode
579
+ }
580
+ position .set (lastposition );
581
+ return value ;
582
+ }
583
+ return null ;
584
+ }
585
+
586
+ private static void put (Scope result , String name , Object value ) {
587
+ String [] splits = name .split ("[.]" );
588
+ Scope depth = result ;
589
+ for (int i = 0 ; i < splits .length ; i ++) {
590
+ if (i < splits .length - 1 ) {
591
+ Scope tmp = (Scope ) result .get (splits [i ]);
592
+ if (tmp == null ) {
593
+ tmp = new Scope ();
594
+ }
595
+ depth .put (splits [i ], tmp );
596
+ depth = tmp ;
597
+ } else {
598
+ depth .put (splits [i ], value );
599
+ }
600
+ }
436
601
}
437
602
438
603
private static class WriteCode implements Code {
@@ -457,9 +622,27 @@ public int getLine() {
457
622
return line ;
458
623
}
459
624
625
+ <<<<<<< HEAD
626
+ @ Override
627
+ public Scope unparse (Scope current , String text , AtomicInteger position , Code [] next ) throws MustacheException {
628
+ if (position .get () + rest .length () <= text .length ()) {
629
+ String substring = text .substring (position .get (), position .get () + rest .length ());
630
+ if (rest .toString ().equals (substring )) {
631
+ position .addAndGet (rest .length ());
632
+ return current ;
633
+ }
634
+ }
635
+ return null ;
636
+ }
637
+
638
+ public void append (String append ) {
639
+ rest .append (append );
640
+ }
641
+ =======
460
642
public void append (String append ) {
461
643
rest .append (append );
462
644
}
463
645
646
+ >>>>>>> master
464
647
}
465
648
}
0 commit comments