summaryrefslogtreecommitdiff
path: root/clformat/src/main/java/bjc/utils/ioutils/format/directives/EscapeDirective.java
blob: 3610bdacaa56b38b5c4af9ae6950b835d4826c68 (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
123
124
125
126
127
128
129
130
131
package bjc.utils.ioutils.format.directives;

import bjc.esodata.*;
import bjc.utils.ioutils.format.*;

/**
 * Implementation for the ^ directive.
 *
 * This directive allows you to escape an iteration directive.
 *
 * @author Ben Culkin
 */
public class EscapeDirective implements Directive {
	@Override
	public Edict compile(CompileContext compCTX) {
		CLParameters params = compCTX.decr.parameters;
		CLModifiers  mods   = compCTX.decr.modifiers;

		CLValue param1 = CLValue.nil();
		CLValue param2 = CLValue.nil();
		CLValue param3 = CLValue.nil();

		EscapeEdict.Mode mode;
		switch (params.length()) {
		case 0:
			mode = EscapeEdict.Mode.END;
			break;
		case 1:
			mode = EscapeEdict.Mode.COUNT;
			
			params.mapIndices("count");
			param1 = params.resolveKey("count");
			break;
		case 2:
			mode = EscapeEdict.Mode.EQUALITY;

			params.mapIndices("lhand", "rhand");
			param1 = params.resolveKey("lhand");
			param2 = params.resolveKey("rhand");
			break;
		case 3:
			mode = EscapeEdict.Mode.RANGE;

			params.mapIndices("lower", "ival", "upper");
			param1 = params.resolveKey("lower");
			param2 = params.resolveKey("ival");
			param3 = params.resolveKey("upper");
			break;
		default:
			throw new IllegalArgumentException("Too many parameters to ^ directive");
		}

		return new EscapeEdict(mods.atMod, mode, mods.colonMod,
				param1, param2, param3, mods.dollarMod);
	}
}

class EscapeEdict implements Edict {
	public static enum Mode {
		END, COUNT, EQUALITY, RANGE
	}

	private Mode mode;

	private boolean isNegated;
	private boolean terminateIteration;

	private CLValue param1;
	private CLValue param2;
	private CLValue param3;

	private boolean advance;

	public EscapeEdict(boolean isNegated, Mode mode, boolean terminateIteration,
			CLValue param1, CLValue param2, CLValue param3, boolean advance) {
		this.mode = mode;

		this.isNegated = isNegated;
		this.terminateIteration = terminateIteration;

		this.param1 = param1;
		this.param2 = param2;
		this.param3 = param3;

		this.advance = advance;
	}

	@Override
	public void format(FormatContext formCTX) {
		boolean shouldExit;

		Tape<Object> items = formCTX.items;

		if (advance) items.right();

		switch (mode) {
		case END:
			shouldExit = items.atEnd();
			break;
		case COUNT: {
			int num = param1.asInt(items, "condition count", "^", 0);

			shouldExit = (num == 0);
		}
			break;
		case EQUALITY: {
			int left  = param1.asInt(items, "left-hand condition", "^", 0);
			int right = param2.asInt(items, "right-hand condition", "^", 0);

			shouldExit = (left == right);
		}
			break;
		case RANGE: {
			int low  = param1.asInt(items, "lower-bound condition", "^", 0);
			int mid  = param2.asInt(items, "interval condition", "^", 0);
			int high = param3.asInt(items, "upper-bound condition", "^", 0);

			shouldExit = (low <= mid) && (mid <= high);
		}
			break;
		default:
			throw new IllegalArgumentException(
					"Escape condition mode " + mode + " isn't supported");
		}

		if (advance)   items.left();
		if (isNegated) shouldExit = !shouldExit;

		if (shouldExit) throw new DirectiveEscape(terminateIteration);
	}
}