Skip to content

Commit db9f7a8

Browse files
committed
Group syntax entities by combinator precedence
1 parent 80512fe commit db9f7a8

2 files changed

Lines changed: 54 additions & 27 deletions

File tree

src/parser.ts

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@ export enum Component {
1111
Group,
1212
}
1313

14+
// Higher number is higher precedence
1415
export enum Combinator {
1516
/** Components are mandatory and should appear in that order */
16-
Juxtaposition,
17+
Juxtaposition = 0,
1718
/** Components are mandatory but may appear in any order */
18-
DoubleAmpersand,
19+
DoubleAmpersand = 1,
1920
/** At least one of the components must be present, and they may appear in any order */
20-
DoubleBar,
21+
DoubleBar = 2,
2122
/** Exactly one of the components must be present */
22-
SingleBar,
23+
SingleBar = 3,
2324
}
2425

2526
export enum Multiplier {
@@ -94,7 +95,6 @@ const REGEX_KEYWORD = /^([\w-]+)/g;
9495

9596
export default function parse(syntax: string): EntityType[] {
9697
const levels: EntityType[][] = [[]];
97-
const deepestLevel = () => levels[levels.length - 1];
9898
let previousMatchWasComponent = false;
9999
let entityMatch: RegExpExecArray | null;
100100
while ((entityMatch = REGEX_ENTITY.exec(syntax))) {
@@ -118,12 +118,12 @@ export default function parse(syntax: string): EntityType[] {
118118
} else if (value.indexOf(']') === 0) {
119119
const definitions = levels.pop();
120120
if (definitions) {
121-
deepestLevel().push(componentGroupData(definitions, multiplierData(rawMultiplier)));
121+
deepestLevel().push(componentGroupData(groupByPrecedence(definitions), multiplierData(rawMultiplier)));
122122
}
123123
previousMatchWasComponent = true;
124124
continue;
125125
} else {
126-
if (previousMatchWasComponent === true) {
126+
if (previousMatchWasComponent) {
127127
deepestLevel().push(combinatorData(Combinator.Juxtaposition));
128128
}
129129

@@ -149,7 +149,27 @@ export default function parse(syntax: string): EntityType[] {
149149
deepestLevel().push({ entity: Entity.Unknown, multiplier: multiplierData(rawMultiplier) });
150150
}
151151

152-
return levels[0];
152+
function deepestLevel() {
153+
return levels[levels.length - 1];
154+
}
155+
156+
return groupByPrecedence(levels[0]);
157+
}
158+
159+
export function isFunction(entity: EntityType): entity is IFunction {
160+
return entity.entity === Entity.Function;
161+
}
162+
163+
export function isComponent(entity: EntityType): entity is ComponentType {
164+
return entity.entity === Entity.Component;
165+
}
166+
167+
export function isCombinator(entity: EntityType): entity is ICombinator {
168+
return entity.entity === Entity.Combinator;
169+
}
170+
171+
export function isQurlyBracetMultiplier(multiplier: MultiplierType): multiplier is IMultiplierQurlyBracet {
172+
return multiplier.sign === Multiplier.QurlyBracet;
153173
}
154174

155175
function combinatorData(combinator: Combinator, multiplier: MultiplierType | null = null): ICombinator {
@@ -173,7 +193,7 @@ function componentData(
173193
};
174194
}
175195

176-
function componentGroupData(entities: EntityType[], multiplier: MultiplierType | null): ComponentType {
196+
function componentGroupData(entities: EntityType[], multiplier: MultiplierType | null = null): ComponentType {
177197
return {
178198
entity: Entity.Component,
179199
component: Component.Group,
@@ -203,3 +223,24 @@ function multiplierData(raw: string[]): MultiplierType | null {
203223
return null;
204224
}
205225
}
226+
227+
function groupByPrecedence(entities: EntityType[]): EntityType[] {
228+
for (let i = 0; i < entities.length; i++) {
229+
const entity = entities[i];
230+
if (isCombinator(entity)) {
231+
for (let a = i; a >= 0; a--) {
232+
const adjacentEntity = entities[a];
233+
if (isCombinator(adjacentEntity) && adjacentEntity.combinator < entity.combinator) {
234+
return groupByPrecedence([componentGroupData(entities.slice(0, i)), ...entities.slice(i)]);
235+
}
236+
}
237+
for (let a = i; a < entities.length; a++) {
238+
const subsequentEntity = entities[a];
239+
if (isCombinator(subsequentEntity) && subsequentEntity.combinator < entity.combinator) {
240+
return [...entities.slice(0, i + 1), componentGroupData(groupByPrecedence(entities.slice(i + 1)))];
241+
}
242+
}
243+
}
244+
}
245+
return entities;
246+
}

src/typer.ts

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import parse, {
88
Entity,
99
EntityType,
1010
ICombinator,
11-
IFunction,
12-
IMultiplierQurlyBracet,
11+
isCombinator,
12+
isComponent,
13+
isFunction,
14+
isQurlyBracetMultiplier,
1315
Multiplier,
1416
MultiplierType,
1517
} from './parser';
@@ -265,22 +267,6 @@ export default function typing(entities: EntityType[]): TypeType[] {
265267
return types;
266268
}
267269

268-
function isFunction(entity: EntityType): entity is IFunction {
269-
return entity.entity === Entity.Function;
270-
}
271-
272-
function isComponent(entity: EntityType): entity is ComponentType {
273-
return entity.entity === Entity.Component;
274-
}
275-
276-
function isCombinator(entity: EntityType): entity is ICombinator {
277-
return entity.entity === Entity.Combinator;
278-
}
279-
280-
function isQurlyBracetMultiplier(multiplier: MultiplierType): multiplier is IMultiplierQurlyBracet {
281-
return multiplier.sign === Multiplier.QurlyBracet;
282-
}
283-
284270
function isMultiplied(multiplier: MultiplierType) {
285271
return (
286272
(isQurlyBracetMultiplier(multiplier) && (multiplier.min > 1 || multiplier.max === 1)) ||

0 commit comments

Comments
 (0)