-
Notifications
You must be signed in to change notification settings - Fork 0
/
sgfparser.js
72 lines (64 loc) · 2.31 KB
/
sgfparser.js
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
(function (root, undefined) {
var grammar = {
collection : [ ["gametree", "+", "gametrees"] ],
gametree : [ "(", ["sequence", 1, "sequence"], ["gametree", "*", "gametrees"], ")" ],
sequence : [ ["node", "+", "nodes"] ],
node : [ ";", ["property", "*", "properties"] ],
property : [ ["propertyIdentifier", 1, "identifier"], ["propertyValue", "+", "values"] ],
propertyIdentifier : /^([A-Z]+)/,
propertyValue : [ "[", ["cValueType", 1, "value"], "]" ],
cValueType : /^((?:\\]|[^\]])*)/
},
parseSGF = function (sgf) {
var r = parseRule("collection", sgf);
if (!r) return false;
if (r[1] !== "") return false;
return r[0];
},
parseRule = function (rulename, str) {
var rule = grammar[rulename];
str = str.replace(/^\s*/, "");
if (str === "") return false;
if (rule instanceof RegExp) {
var m = str.match(rule);
if (!m) return false;
return [ m[1], str.slice(m[0].length) ];
}
var node = {};
for (var i = 0, seg; (i < rule.length) && (seg = rule[i]); i++) {
if (typeof seg === "string") {
if (str.slice(0, seg.length) === seg) {
str = str.slice(seg.length);
continue;
} else {
return false;
}
} else {
var subrulename = seg[0],
num = seg[1],
name = seg[2],
r;
if (num === 1) {
r = parseRule(subrulename, str);
if (!r) {
// implicit backtracking will occur this way..
return false;
}
str = r[1];
node[name] = r[0];
} else {
node[name] = [];
while (r = parseRule(subrulename, str)) {
num = "*";
str = r[1];
node[name].push(r[0]);
}
if (num === "+")
return false;
}
}
}
return [ node, str ];
};
root.parseSGF = parseSGF;
}(this));