summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/parserutils/RuleBasedConfigReader.java
blob: d07d725619b61d4ea5bfe8060adfa2059d654ba0 (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
package bjc.utils.parserutils;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import bjc.utils.data.Pair;
import bjc.utils.funcdata.FunctionalStringTokenizer;

/**
 * This class parses a rules based config file, and uses it to drive a
 * provided set of actions
 * 
 * @author ben
 *
 * @param <E>The
 *            type of the state object to use
 */
public class RuleBasedConfigReader<E> {
	private BiConsumer<FunctionalStringTokenizer, Pair<String, E>>	startRule;
	private BiConsumer<FunctionalStringTokenizer, E>				continueRule;
	private Consumer<E>												endRule;

	private Map<String, BiConsumer<FunctionalStringTokenizer, E>>	pragmas;

	/**
	 * Create a new rule-based config reader
	 * 
	 * @param startRule
	 *            The action to fire when starting a rule
	 * @param continueRule
	 *            The action to fire when continuing a rule
	 * @param endRule
	 *            The action to fire when ending a rule
	 */
	public RuleBasedConfigReader(
			BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule,
			BiConsumer<FunctionalStringTokenizer, E> continueRule,
			Consumer<E> endRule) {
		this.startRule = startRule;
		this.continueRule = continueRule;
		this.endRule = endRule;

		this.pragmas = new HashMap<>();
	}

	public void addPragma(String pragName,
			BiConsumer<FunctionalStringTokenizer, E> pragAct) {
		pragmas.put(pragName, pragAct);
	}

	public E fromStream(InputStream is, E initState) {
		Scanner scn = new Scanner(is);

		E stat = initState;

		while (scn.hasNextLine()) {
			String ln = scn.nextLine();

			if (ln.equals("")) {
				endRule.accept(stat);
				continue;
			} else if (ln.startsWith("\t")) {
				continueRule.accept(new FunctionalStringTokenizer(
						ln.substring(1), " "), stat);
			} else {
				FunctionalStringTokenizer stk = new FunctionalStringTokenizer(
						ln, " ");

				String nxtToken = stk.nextToken();
				if (nxtToken.equals("#")) {
					// Do nothing, this is a comment
				} else if (nxtToken.equals("pragma")) {
					String tk = stk.nextToken();

					pragmas.getOrDefault(tk, (strk, ras) -> {
						throw new UnknownPragmaException(
								"Unknown pragma " + tk);
					}).accept(stk, stat);
				} else {
					startRule.accept(stk,
							new Pair<String, E>(nxtToken, stat));
				}
			}
		}

		scn.close();

		return stat;
	}

	public void setContinueRule(
			BiConsumer<FunctionalStringTokenizer, E> continueRule) {
		this.continueRule = continueRule;
	}

	public void setEndRule(Consumer<E> endRule) {
		this.endRule = endRule;
	}

	public void setStartRule(
			BiConsumer<FunctionalStringTokenizer, Pair<String, E>> startRule) {
		this.startRule = startRule;
	}
}