|
1 | 1 | package io.github.noncat_lang;
|
2 | 2 |
|
3 |
| -import java.util.HashMap; |
4 | 3 | import java.util.Map;
|
5 |
| -import java.util.Map.Entry; |
6 |
| -import java.util.regex.Matcher; |
7 |
| -import java.util.regex.Pattern; |
8 |
| -import java.util.stream.Collectors; |
9 | 4 |
|
10 |
| -import org.antlr.v4.runtime.CharStreams; |
11 |
| -import org.antlr.v4.runtime.CommonTokenStream; |
| 5 | +import io.github.noncat_lang.internal.TemplateImpl; |
12 | 6 |
|
13 |
| -import io.github.noncat_lang.TemplateParser.ArgContext; |
14 |
| -import io.github.noncat_lang.TemplateParser.ElementContext; |
15 |
| -import io.github.noncat_lang.TemplateParser.TemplateContext; |
16 |
| -import io.github.noncat_lang.exceptions.MissingTokenException; |
17 |
| -import io.github.noncat_lang.exceptions.MissingValueException; |
18 |
| -import lombok.AccessLevel; |
19 |
| -import lombok.AllArgsConstructor; |
20 |
| -import lombok.NonNull; |
21 |
| -import lombok.experimental.FieldDefaults; |
| 7 | +public interface Template { |
22 | 8 |
|
23 |
| -@AllArgsConstructor(access = AccessLevel.PRIVATE) |
24 |
| -@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) |
25 |
| -public class Template { |
26 |
| - TemplateContext parseTree; |
27 |
| - Map<String, Token> tokens = new HashMap<>(); |
28 |
| - |
29 |
| - public static Template of(@NonNull String templateString) { |
30 |
| - TemplateLexer lexer = new TemplateLexer(CharStreams.fromString(templateString)); |
31 |
| - TemplateParser parser = new TemplateParser(new CommonTokenStream(lexer)); |
32 |
| - return new Template(parser.template()); |
33 |
| - } |
34 |
| - |
35 |
| - public Template withToken(@NonNull String field, @NonNull Token token) { |
36 |
| - if (field.isBlank()) { |
37 |
| - throw new IllegalArgumentException("Token field should not be blank/empty"); |
38 |
| - } |
39 |
| - if (!field.matches("[a-zA-Z0-9]+")) { |
40 |
| - throw new IllegalArgumentException("Token field does not match pattern [a-zA-Z0-9]+"); |
41 |
| - } |
42 |
| - tokens.put(field, token); |
43 |
| - return this; |
44 |
| - } |
45 |
| - |
46 |
| - public String format(@NonNull Map<String, String> values) { |
47 |
| - return unparse(values); |
| 9 | + static Template of(String templateString) { |
| 10 | + return TemplateImpl.of(templateString); |
48 | 11 | }
|
49 | 12 |
|
50 |
| - public String unparse(@NonNull Map<String, String> values) { |
51 |
| - return parseTree.element().stream().map(element -> unparseElement(element, values)).collect(Collectors.joining()); |
52 |
| - } |
| 13 | + Template withToken(String field, Token token); |
53 | 14 |
|
54 |
| - private String unparseElement(ElementContext element, Map<String, String> values) { |
55 |
| - ArgContext arg = element.arg(); |
56 |
| - return arg == null ? element.TEXT().getText() : unparseArg(arg, values); |
57 |
| - } |
| 15 | + String format(Map<String, String> values); |
58 | 16 |
|
59 |
| - private String unparseArg(ArgContext arg, @NonNull Map<String, String> values) { |
60 |
| - String id = getId(arg); |
61 |
| - Token token = tokens.get(id); |
62 |
| - if (token == null) { |
63 |
| - throw new MissingTokenException(String.format("Token for field '%s' is missing", id)); |
64 |
| - } |
65 |
| - String value = values.get(id); |
66 |
| - if (value == null) { |
67 |
| - throw new MissingValueException(String.format("Value for field '%s' is missing", id)); |
68 |
| - } |
69 |
| - value = token.encode(value); |
70 |
| - return value; |
71 |
| - } |
72 |
| - |
73 |
| - public Map<String, String> parse(@NonNull String value) { |
74 |
| - String pattern = parseTree.element().stream().map(this::parseElement).collect(Collectors.joining()); |
75 |
| - Matcher matcher = Pattern.compile(pattern).matcher(value); |
76 |
| - if (!matcher.matches()) { |
77 |
| - throw new IllegalArgumentException( |
78 |
| - String.format("Error during parsing: value '%s' does not match pattern '%s'", value, pattern)); |
79 |
| - } |
80 |
| - return decodeAllToken(matcher); |
81 |
| - } |
| 17 | + String unparse(Map<String, String> values); |
82 | 18 |
|
83 |
| - private Map<String, String> decodeAllToken(Matcher matcher) { |
84 |
| - return tokens.entrySet().stream().collect(Collectors.toMap(Entry::getKey, entry -> decodeToken(entry, matcher))); |
85 |
| - } |
86 |
| - |
87 |
| - private String decodeToken(Entry<String, Token> entry, Matcher matcher) { |
88 |
| - return entry.getValue().decode(matcher.group("x" + entry.getKey())); |
89 |
| - } |
90 |
| - |
91 |
| - private String parseElement(ElementContext element) { |
92 |
| - ArgContext id = element.arg(); |
93 |
| - return id == null ? Pattern.quote(element.TEXT().getText()) : parseArg(id); |
94 |
| - } |
95 |
| - |
96 |
| - private String parseArg(ArgContext arg) { |
97 |
| - String id = getId(arg); |
98 |
| - Token token = tokens.get(id); |
99 |
| - if (token == null) { |
100 |
| - throw new MissingTokenException(String.format("Token for field '%s' is missing", id)); |
101 |
| - } |
102 |
| - return String.format("(?<x%s>%s)", id, token.getRegex()); |
103 |
| - } |
104 |
| - |
105 |
| - private String getId(ArgContext arg) { |
106 |
| - String id = arg.ID().getText(); |
107 |
| - return id.substring(2, id.length() - 1); |
108 |
| - } |
| 19 | + Map<String, String> parse(String value); |
109 | 20 |
|
110 | 21 | }
|
0 commit comments