summaryrefslogtreecommitdiff
path: root/java/pablotron/luigi/Parser.java
blob: 0e415c431fb221a5b0bf52279f0200b84929041c (plain)
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
118
119
120
121
122
package pablotron.luigi;

import java.util.ArrayList;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

import pablotron.luigi.actions.Action;
import pablotron.luigi.actions.FilterAction;
import pablotron.luigi.actions.TextAction;
import pablotron.luigi.FilterReference;
import pablotron.luigi.LuigiError;

public final class Parser {
  private static final Pattern RE_ACTION = Pattern.compile(
    // match opening brace
    "%\\{" + 
      
      // match optional whitespace
      "\\s*" + 

      // match key
      // "(?<key>[^\\s\\|\\}]+)" +
      "([^\\s\\|\\}]+)" +

      // match filter(s)
      // "(?<filters>(\\s*\\|(\\s*[^\\s\\|\\}]+)+)*)" +
      "((\\s*\\|(\\s*[^\\s\\|\\}]+)+)*)" +

      // match optional whitespace
      "\\s*" +
    
    // match closing brace
    "\\}" +
    
    // or match up all non-% chars or a single % char
    // "| (?<text>[^%]* | %)",
    "| ([^%]* | %)",

    Pattern.COMMENTS
  );

  private static final Pattern RE_FILTER = Pattern.compile(
    // match filter name
    // "(?<name>\\S+)" +
    "(\\S+)" +
  
    // match filter arguments (optional)
    // "(?<args>(\\s*\\S+)*)" +
    "((\\s*\\S+)*)" +
  
    // optional trailing whitespace
    "\\s*",

    Pattern.COMMENTS
  );

  private static final Pattern RE_DELIM_FILTERS = Pattern.compile(
    "\\s*\\|\\s*"
  );

  private static final Pattern RE_DELIM_ARGS = Pattern.compile(
    "\\s+"
  );

  public static Action[] parse_template(
    final String template
  ) throws LuigiError {
    final ArrayList<Action> r = new ArrayList<Action>();

    // match on text
    final Matcher m = RE_ACTION.matcher(template);

    while (m.find()) {
      // String key = m.group("key");
      final String key = m.group(1);
      
      if (key != null && key.length() > 0) {
        // r.add(new FilterAction(key, parse_filters(m.group("filters"))));
        r.add(new FilterAction(key, parse_filters(m.group(2))));
      } else {
        // r.add(new TextAction(m.group("text")));
        r.add(new TextAction(m.group(5)));
      }
    }

    // build array of results
    return r.toArray(new Action[r.size()]);
  }

  private static final String[] NO_ARGS = {};

  public static FilterReference[] parse_filters(
    final String filters_str
  ) throws LuigiError {
    final ArrayList<FilterReference> r = new ArrayList<FilterReference>();

    // split string into individual filters and handle each one
    for (String f: RE_DELIM_FILTERS.split(filters_str)) {
      // trim filter string and skip empty filters
      f = f.trim();
      if (f.length() == 0)
        continue;

      // match on filter and check for error
      final Matcher m = RE_FILTER.matcher(f);
      if (!m.find())
        throw new LuigiError("invalid filter: " + f);

      // get arguments string
      final String args = m.group(2).trim();

      // append new filter reference to result
      r.add(new FilterReference(
        m.group(1),
        (args.length() > 0) ? RE_DELIM_ARGS.split(args) : NO_ARGS
      ));
    }

    // return result
    return r.toArray(new FilterReference[r.size()]);
  }
};