-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommand.java
145 lines (126 loc) · 4.62 KB
/
Command.java
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* Skeleton code copyright (C) 2008, 2022 Paul N. Hilfinger and the
* Regents of the University of California. Do not distribute this or any
* derivative work without permission. */
package ataxx;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import static ataxx.PieceColor.*;
import static ataxx.GameException.*;
/** All things to do with parsing commands.
* @author P. N. Hilfinger
*/
class Command {
/** A list of all commands. */
private static final String[] COMMAND_NAMES = {
"auto", "block", "board", "dump", "help", "manual",
"new", "q", "quiet", "quit", "seed", "undo", "verbose",
};
/** Command types. PIECEMOVE indicates a move of the form
* c0r0-c1r1. ERROR indicates a parse error in the command.
* All other commands are upper-case versions of what the
* programmer writes. */
enum Type {
COMMENT("#.*|$"),
AUTO("auto\\s+(red|blue)"),
BLOCK("block\\s+([a-g][1-7])"),
MANUAL("manual\\s+(red|blue)"),
SEED("seed\\s+(\\d+)"),
START,
/* Regular moves. */
PIECEMOVE("(-|[a-g][1-7]-[a-g][1-7])"),
QUIT("q|quit"),
NEW, DUMP, HELP,
/* Extra commands. */
BOARD, VERBOSE, QUIET, UNDO,
/* Special "commands" internally generated. */
/** Syntax error in command. */
ERROR(".*"),
/** End of input stream. */
EOF;
/** PATTERN is a regular expression string giving the syntax of
* a command of the given type. It matches the entire command,
* assuming no leading or trailing whitespace. The groups in
* the pattern capture the operands (if any). */
Type(String pattern) {
_pattern = Pattern.compile(pattern + "$");
}
/** A Type whose pattern is the lower-case version of its name. */
Type() {
_pattern = Pattern.compile(this.toString().toLowerCase() + "$");
}
/** The Pattern descrbing syntactically correct versions of this
* type of command. */
private final Pattern _pattern;
}
/** A new Command of type TYPE with OPERANDS as its operands. */
Command(Type type, String... operands) {
_type = type;
_operands = operands;
}
/** Return the type of this Command. */
Type commandType() {
return _type;
}
/** Returns this Command's operands. */
String[] operands() {
return _operands;
}
/** Parse COMMAND, returning the command and its operands. */
static Command parseCommand(String command) {
if (command == null) {
return new Command(Type.EOF);
}
command = canonicalizeCommand(command);
for (Type type : Type.values()) {
Matcher mat = type._pattern.matcher(command);
if (mat.matches()) {
String[] operands = new String [mat.groupCount()];
for (int i = 1; i <= operands.length; i += 1) {
operands[i - 1] = mat.group(i);
}
return new Command(type, operands);
}
}
throw new Error("Internal failure: error command did not match.");
}
/** Return COMMAND with the full command name that uniquely fits
* substituted for the command name. COMMAND may start with any
* prefix of a valid command name, as long as that name is unique.
* If the name is not unique or no command name matches,
* returns COMMAND. */
private static String canonicalizeCommand(String command) {
command = command.trim();
if (command.length() == 0) {
return "";
} else if (command.startsWith("#")) {
return "#";
}
command = command.toLowerCase();
int prefixLen = Math.max(command.indexOf(" "), command.length());
String prefix = command.substring(0, prefixLen);
String fullName;
fullName = null;
for (String name : COMMAND_NAMES) {
if (name.equals(prefix)) {
fullName = prefix;
break;
}
if (name.startsWith(prefix)) {
if (fullName != null) {
throw error("%s is not a unique prefix abbreviation",
prefix);
}
fullName = name;
}
}
if (fullName != null) {
return fullName + command.substring(prefixLen);
} else {
return command;
}
}
/** The command name. */
private final Type _type;
/** Command arguments. */
private final String[] _operands;
}