This repository has been archived by the owner on May 31, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
QuakeMapParser.js
129 lines (105 loc) · 4.44 KB
/
QuakeMapParser.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
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
// @flow
import QuakeBrush from "./QuakeBrush";
import QuakeBrushHalfSpaceParser from "./QuakeBrushHalfSpaceParser";
import QuakeEntity from "./QuakeEntity";
import QuakeEntityProperties from "./QuakeEntityProperties";
import QuakeEntityPropertyParser from "./QuakeEntityPropertyParser";
import { default as QuakeMapParserException } from "./Exception/QuakeMap/Parser";
import type { LoggerBreadcrumbs } from "../interfaces/LoggerBreadcrumbs";
import type { QuakeBrush as QuakeBrushInterface } from "../interfaces/QuakeBrush";
import type { QuakeBrushHalfSpace } from "../interfaces/QuakeBrushHalfSpace";
import type { QuakeEntity as QuakeEntityInterface } from "../interfaces/QuakeEntity";
import type { QuakeEntityProperty } from "../interfaces/QuakeEntityProperty";
import type { QuakeMapParser as QuakeMapParserInterface } from "../interfaces/QuakeMapParser";
const REGEXP_NEWLINE = /\r?\n/;
export default class QuakeMapParser implements QuakeMapParserInterface {
+content: string;
+loggerBreadcrumbs: LoggerBreadcrumbs;
constructor(loggerBreadcrumbs: LoggerBreadcrumbs, content: string) {
this.content = content;
this.loggerBreadcrumbs = loggerBreadcrumbs;
}
brushHalfSpace(breadcrumbs: LoggerBreadcrumbs, line: string): QuakeBrushHalfSpace {
return new QuakeBrushHalfSpaceParser(breadcrumbs.add("brushHalfSpace"), line).parse();
}
entityProperty(breadcrumbs: LoggerBreadcrumbs, line: string): QuakeEntityProperty {
return new QuakeEntityPropertyParser(breadcrumbs.add("entityProperty"), line).parse();
}
*parse(): Generator<QuakeEntityInterface, void, void> {
const loggerBreadcrumbs = this.loggerBreadcrumbs.add("parse");
const lines: $ReadOnlyArray<string> = this.splitLines(this.content);
let currentBrushSketch: ?(QuakeBrushHalfSpace[]) = null;
let currentEntitySketch: ?{|
brushes: QuakeBrushInterface[],
props: QuakeEntityProperty[],
|} = null;
for (let lineno = 0; lineno < lines.length; lineno += 1) {
const line = lines[lineno];
const breadcrumbs = loggerBreadcrumbs.addVariable(String(lineno + 1));
if (this.isComment(line) || this.isEmpty(line)) {
continue;
}
if (this.isOpeningBracket(line)) {
if (currentEntitySketch) {
currentBrushSketch = [];
continue;
} else if (!currentEntitySketch) {
currentEntitySketch = {
brushes: [],
props: [],
};
continue;
} else {
throw new QuakeMapParserException(breadcrumbs, "Unexpected opening bracket.");
}
}
if (this.isClosingBracket(line)) {
if (currentBrushSketch) {
if (!currentEntitySketch) {
throw new QuakeMapParserException(breadcrumbs, "Expected brush to be nested inside entity");
}
currentEntitySketch.brushes.push(new QuakeBrush(breadcrumbs.add("QuakeBrush"), currentBrushSketch));
currentBrushSketch = null;
continue;
} else if (currentEntitySketch) {
const quakeEntityProperties = new QuakeEntityProperties(breadcrumbs.add("QuakeEntityProperties"), currentEntitySketch.props);
yield new QuakeEntity(breadcrumbs.add("QuakeEntity"), quakeEntityProperties, currentEntitySketch.brushes);
currentEntitySketch = null;
continue;
} else {
throw new QuakeMapParserException(breadcrumbs, "Unexpected closing bracket.");
}
}
if (currentBrushSketch) {
currentBrushSketch.push(this.brushHalfSpace(breadcrumbs, line));
continue;
}
if (currentEntitySketch) {
currentEntitySketch.props.push(this.entityProperty(breadcrumbs, line));
continue;
}
throw new QuakeMapParserException(breadcrumbs, "Unexpected line.");
}
if (currentBrushSketch) {
throw new QuakeMapParserException(loggerBreadcrumbs, "Unexpected end of brush data.");
}
if (currentEntitySketch) {
throw new QuakeMapParserException(loggerBreadcrumbs, "Unexpected end of entity data.");
}
}
isClosingBracket(line: string): boolean {
return line.startsWith("}");
}
isComment(line: string): boolean {
return line.startsWith("//");
}
isEmpty(line: string): boolean {
return line.trim().length < 1;
}
isOpeningBracket(line: string): boolean {
return line.startsWith("{");
}
splitLines(content: string): $ReadOnlyArray<string> {
return content.split(REGEXP_NEWLINE).map(line => line.trim());
}
}