@bablr/agast-vm 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/evaluate.js +108 -105
- package/lib/index.js +1 -4
- package/lib/state.js +8 -525
- package/package.json +13 -4
- package/lib/facades.js +0 -3
- package/lib/node.js +0 -215
- package/lib/path.js +0 -194
package/lib/evaluate.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* global WeakSet */
|
|
1
2
|
import {
|
|
2
3
|
DoctypeTag,
|
|
3
4
|
OpenNodeTag,
|
|
@@ -6,24 +7,33 @@ import {
|
|
|
6
7
|
ShiftTag,
|
|
7
8
|
GapTag,
|
|
8
9
|
NullTag,
|
|
9
|
-
InitializerTag,
|
|
10
10
|
LiteralTag,
|
|
11
11
|
AttributeDefinition,
|
|
12
12
|
BindingTag,
|
|
13
13
|
Property,
|
|
14
|
-
|
|
14
|
+
TreeNode,
|
|
15
|
+
NullNode,
|
|
16
|
+
GapNode,
|
|
15
17
|
} from '@bablr/agast-helpers/symbols';
|
|
16
18
|
import { State } from './state.js';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
+
import {
|
|
20
|
+
getAttributes,
|
|
21
|
+
getFirstNode,
|
|
22
|
+
isGapNode,
|
|
23
|
+
isNodeTag,
|
|
24
|
+
TagPath,
|
|
25
|
+
} from '@bablr/agast-helpers/path';
|
|
26
|
+
import * as BTree from '@bablr/agast-helpers/btree';
|
|
19
27
|
import * as Tags from '@bablr/agast-helpers/tags';
|
|
20
|
-
import {
|
|
28
|
+
import { isObject } from '@bablr/agast-helpers/object';
|
|
29
|
+
|
|
30
|
+
const validNodes = new WeakSet();
|
|
31
|
+
|
|
32
|
+
export const isKnownValid = (node) => validNodes.has(node);
|
|
21
33
|
|
|
22
34
|
let { isArray } = Array;
|
|
23
35
|
|
|
24
36
|
export const agast = (options = {}) => {
|
|
25
|
-
if (options.held?.tags) throw new Error();
|
|
26
|
-
|
|
27
37
|
let state = State.from(options.held);
|
|
28
38
|
|
|
29
39
|
let vm = __agast(state, options);
|
|
@@ -32,7 +42,14 @@ export const agast = (options = {}) => {
|
|
|
32
42
|
|
|
33
43
|
Object.freeze(options);
|
|
34
44
|
|
|
35
|
-
|
|
45
|
+
let getState = () => ({
|
|
46
|
+
path: state.path,
|
|
47
|
+
node: state.path.node,
|
|
48
|
+
resultPath: state.resultPath,
|
|
49
|
+
held: state.held,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
return Object.freeze({ options, getState, vm });
|
|
36
53
|
};
|
|
37
54
|
|
|
38
55
|
function* __agast(s) {
|
|
@@ -40,24 +57,19 @@ function* __agast(s) {
|
|
|
40
57
|
for (;;) {
|
|
41
58
|
let returnValue = null;
|
|
42
59
|
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
tag.value.node === s.held.node
|
|
57
|
-
)
|
|
58
|
-
) {
|
|
59
|
-
throw new Error('Cannot advance while holding');
|
|
60
|
-
}
|
|
60
|
+
// if (
|
|
61
|
+
// s.held &&
|
|
62
|
+
// ![OpenNodeTag, ReferenceTag, TreeNode, GapNode, BindingTag, Property, GapTag].includes(
|
|
63
|
+
// tag.type,
|
|
64
|
+
// ) &&
|
|
65
|
+
// !(
|
|
66
|
+
// (isNodeTag(tag) &&
|
|
67
|
+
// (Tags.getSize(tag.value.tags) <= 1 || getFirstNode(tag.value) === s.held)) ||
|
|
68
|
+
// tag.value === s.held
|
|
69
|
+
// )
|
|
70
|
+
// ) {
|
|
71
|
+
// throw new Error('Cannot advance while holding');
|
|
72
|
+
// }
|
|
61
73
|
|
|
62
74
|
switch (tag.type) {
|
|
63
75
|
case DoctypeTag: {
|
|
@@ -65,134 +77,125 @@ function* __agast(s) {
|
|
|
65
77
|
throw new Error();
|
|
66
78
|
}
|
|
67
79
|
|
|
68
|
-
s.advance(tag);
|
|
80
|
+
s.path = s.path.advance(tag);
|
|
69
81
|
break;
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
case
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (s.held) {
|
|
78
|
-
throw new Error('Cannot consume input while hold register is full');
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
s.advance(tag);
|
|
84
|
+
case ReferenceTag: {
|
|
85
|
+
s.path = s.path.advance(tag);
|
|
86
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
82
87
|
break;
|
|
83
88
|
}
|
|
84
89
|
|
|
85
|
-
case
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
90
|
+
case LiteralTag: {
|
|
91
|
+
s.path = s.path.advance(tag);
|
|
92
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
91
95
|
|
|
92
|
-
|
|
96
|
+
case AttributeDefinition: {
|
|
97
|
+
s.path = s.path.advance(tag);
|
|
98
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
93
99
|
break;
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
case BindingTag: {
|
|
97
|
-
const {
|
|
98
|
-
|
|
99
|
-
if (languagePath && !isArray(languagePath)) throw new Error();
|
|
103
|
+
const { segments } = tag.value;
|
|
100
104
|
|
|
101
|
-
|
|
105
|
+
if (segments && !isArray(segments)) throw new Error();
|
|
102
106
|
|
|
103
|
-
s.advance(tag);
|
|
107
|
+
s.path = s.path.advance(tag);
|
|
108
|
+
s.resultPath = s.path.tagPathAt(-1, [-1, -1]);
|
|
104
109
|
break;
|
|
105
110
|
}
|
|
106
111
|
|
|
107
112
|
case NullTag:
|
|
108
113
|
case GapTag: {
|
|
109
|
-
s.advance(tag);
|
|
110
|
-
|
|
114
|
+
s.path = s.path.advance(tag);
|
|
115
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
116
|
+
returnValue = s.resultPath.node;
|
|
111
117
|
break;
|
|
112
118
|
}
|
|
113
119
|
|
|
114
120
|
case AttributeDefinition: {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
s.advance(tag);
|
|
121
|
+
s.path = s.path.advance(tag);
|
|
118
122
|
break;
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
case
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
s.
|
|
125
|
+
case ShiftTag: {
|
|
126
|
+
let previousPropertyPath = s.path.tagPathAt(-1);
|
|
127
|
+
s.path = s.path.advance(tag);
|
|
128
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
129
|
+
s.held = previousPropertyPath.inner.node;
|
|
125
130
|
break;
|
|
126
131
|
}
|
|
127
132
|
|
|
128
|
-
case
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
let { path, tagsIndex } = s.resultPath;
|
|
133
|
-
|
|
134
|
-
let prevRef = TagPath.from(path, tagsIndex, 0);
|
|
135
|
-
let refPath = prevRef;
|
|
136
|
-
|
|
137
|
-
if (prevRef.tag.type === ShiftTag) {
|
|
138
|
-
if (prevRef.tag.value.index + 1 !== index) throw new Error('bad shift index');
|
|
133
|
+
case OpenNodeTag: {
|
|
134
|
+
s.path = !s.path ? TagPath.fromTag(tag).path : s.path.advance(tag);
|
|
135
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
139
136
|
|
|
140
|
-
|
|
137
|
+
if (s.path) {
|
|
138
|
+
let queue = [getAttributes(s.node)];
|
|
139
|
+
while (queue.length) {
|
|
140
|
+
for (let value of Object.values(queue[queue.length - 1])) {
|
|
141
|
+
if (value === undefined) {
|
|
142
|
+
} else if (isArray(value) || isObject(value)) {
|
|
143
|
+
queue.push(value);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
queue.pop();
|
|
147
|
+
}
|
|
141
148
|
}
|
|
142
149
|
|
|
143
|
-
|
|
150
|
+
returnValue = s.node || s.resultPath.node;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
144
153
|
|
|
145
|
-
|
|
146
|
-
|
|
154
|
+
case CloseNodeTag: {
|
|
155
|
+
if (!s.path) {
|
|
156
|
+
s.done = true;
|
|
147
157
|
}
|
|
148
158
|
|
|
149
|
-
s.
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
159
|
+
validNodes.add(s.node);
|
|
152
160
|
|
|
153
|
-
|
|
154
|
-
s.advance(tag);
|
|
161
|
+
returnValue = s.node;
|
|
155
162
|
|
|
156
|
-
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
163
|
+
let donePath = s.path;
|
|
159
164
|
|
|
160
|
-
|
|
161
|
-
returnValue = new NodeFacade(s.node);
|
|
165
|
+
s.path = s.path.advance(tag);
|
|
162
166
|
|
|
163
|
-
s.
|
|
167
|
+
s.resultPath = donePath.tagPathAt(-1, -1);
|
|
164
168
|
break;
|
|
165
169
|
}
|
|
166
170
|
|
|
167
|
-
case
|
|
168
|
-
let { tags,
|
|
169
|
-
let { node, reference } = property;
|
|
170
|
-
|
|
171
|
-
if (reference.type === '_') {
|
|
172
|
-
returnValue = node;
|
|
173
|
-
s.node.tags = Tags.push(s.node.tags, node);
|
|
171
|
+
case Property: {
|
|
172
|
+
let { tags, node } = tag.value;
|
|
174
173
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
s.referenceTagPath = TagPath.from(s.path, -1, 0);
|
|
178
|
-
}
|
|
179
|
-
s.held = null;
|
|
180
|
-
} else {
|
|
181
|
-
for (tag of tags) {
|
|
182
|
-
s.advance(tag);
|
|
183
|
-
}
|
|
184
|
-
returnValue = new NodeFacade(node);
|
|
174
|
+
for (tag of Tags.traverse(tags)) {
|
|
175
|
+
s.path = s.path.advance(tag);
|
|
185
176
|
}
|
|
177
|
+
returnValue = node;
|
|
186
178
|
|
|
187
179
|
break;
|
|
188
180
|
}
|
|
189
181
|
|
|
190
|
-
case
|
|
191
|
-
|
|
182
|
+
case NullNode:
|
|
183
|
+
case GapNode:
|
|
184
|
+
case TreeNode: {
|
|
185
|
+
let node = tag;
|
|
192
186
|
|
|
193
|
-
|
|
187
|
+
// let clearedHeld =
|
|
188
|
+
// s.held &&
|
|
189
|
+
// (node.type === GapNode ||
|
|
190
|
+
// BTree.getAt(-BTree.getSize(s.held.value.bounds[0]), node.value.bounds[0]));
|
|
191
|
+
|
|
192
|
+
// if (s.held && !s.path.held) throw new Error();
|
|
193
|
+
|
|
194
|
+
s.path = s.path.advance(s.held && isGapNode(node) ? s.held : tag);
|
|
195
|
+
s.resultPath = s.path.tagPathAt(-1, -1);
|
|
196
|
+
s.held = null;
|
|
194
197
|
|
|
195
|
-
returnValue =
|
|
198
|
+
returnValue = s.path.node;
|
|
196
199
|
break;
|
|
197
200
|
}
|
|
198
201
|
|
package/lib/index.js
CHANGED
package/lib/state.js
CHANGED
|
@@ -1,176 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
addProperty,
|
|
4
|
-
finalizeNode,
|
|
5
|
-
buildStubNode,
|
|
6
|
-
getRange,
|
|
7
|
-
createNode,
|
|
8
|
-
buildNullNode,
|
|
9
|
-
buildOpenNodeTag,
|
|
10
|
-
shiftProperty,
|
|
11
|
-
buildProperty,
|
|
12
|
-
add,
|
|
13
|
-
buildAttributeDefinition,
|
|
14
|
-
buildBinding,
|
|
15
|
-
buildGapTag,
|
|
16
|
-
getOr,
|
|
17
|
-
has as nodeHas,
|
|
18
|
-
buildReferenceTag,
|
|
19
|
-
buildReference,
|
|
20
|
-
buildBounds,
|
|
21
|
-
buildChild,
|
|
22
|
-
buildPropertyWrapper,
|
|
23
|
-
} from '@bablr/agast-helpers/tree';
|
|
24
|
-
import * as Tags from '@bablr/agast-helpers/tags';
|
|
25
|
-
import * as BTree from '@bablr/agast-helpers/btree';
|
|
26
|
-
import {
|
|
27
|
-
getInitializerTagsIndex,
|
|
28
|
-
getOpenTag,
|
|
29
|
-
getOriginalFirstNode,
|
|
30
|
-
getProperty,
|
|
31
|
-
getPropertyTagsIndex,
|
|
32
|
-
isGapNode,
|
|
33
|
-
isStubNode,
|
|
34
|
-
offsetForTag,
|
|
35
|
-
referencesAreEqual,
|
|
36
|
-
TagPath,
|
|
37
|
-
} from '@bablr/agast-helpers/path';
|
|
38
|
-
import {
|
|
39
|
-
DoctypeTag,
|
|
40
|
-
OpenNodeTag,
|
|
41
|
-
CloseNodeTag,
|
|
42
|
-
ReferenceTag,
|
|
43
|
-
ShiftTag,
|
|
44
|
-
GapTag,
|
|
45
|
-
NullTag,
|
|
46
|
-
InitializerTag,
|
|
47
|
-
LiteralTag,
|
|
48
|
-
AttributeDefinition,
|
|
49
|
-
BindingTag,
|
|
50
|
-
Property,
|
|
51
|
-
PropertyWrapper,
|
|
52
|
-
} from '@bablr/agast-helpers/symbols';
|
|
53
|
-
import { facades, actuals } from './facades.js';
|
|
54
|
-
import { Path, PathFacade, TagPathFacade } from './path.js';
|
|
55
|
-
import { get, has, immSet, isObject } from '@bablr/agast-helpers/object';
|
|
56
|
-
import { NodeFacade } from './node.js';
|
|
57
|
-
|
|
58
|
-
const { isArray } = Array;
|
|
59
|
-
|
|
60
|
-
const defineAttribute = (node, tag) => {
|
|
61
|
-
if (tag.type !== AttributeDefinition) throw new Error();
|
|
62
|
-
|
|
63
|
-
let { path, value } = tag.value;
|
|
64
|
-
let openTag = getOpenTag(node);
|
|
65
|
-
let { attributes } = node;
|
|
66
|
-
|
|
67
|
-
if (!has(attributes, path) && get(attributes, path) !== undefined)
|
|
68
|
-
throw new Error('Can only define undefined attributes');
|
|
69
|
-
|
|
70
|
-
if (value === undefined) throw new Error('cannot define attribute to undefined');
|
|
71
|
-
|
|
72
|
-
let { flags, type } = openTag.value;
|
|
73
|
-
attributes = immSet(attributes, path, value);
|
|
74
|
-
let newOpenTag = buildOpenNodeTag(flags, type, attributes);
|
|
75
|
-
|
|
76
|
-
node.attributes = attributes;
|
|
77
|
-
|
|
78
|
-
node.tags = Tags.replaceAt(0, node.tags, newOpenTag);
|
|
79
|
-
node.tags = Tags.push(node.tags, tag);
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export const StateFacade = class AgastStateFacade {
|
|
83
|
-
constructor(state) {
|
|
84
|
-
facades.set(state, this);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
static create() {
|
|
88
|
-
return State.create();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
get resultPath() {
|
|
92
|
-
let { resultPath } = actuals.get(this);
|
|
93
|
-
return resultPath && new TagPathFacade(resultPath);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
get referenceTag() {
|
|
97
|
-
return actuals.get(this).referenceTag;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
get referenceTagPath() {
|
|
101
|
-
let { referenceTagPath } = actuals.get(this);
|
|
102
|
-
return referenceTagPath && new TagPathFacade(referenceTagPath);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
get path() {
|
|
106
|
-
let { path } = actuals.get(this);
|
|
107
|
-
return path && new PathFacade(path);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
get node() {
|
|
111
|
-
let { node } = actuals.get(this);
|
|
112
|
-
return node && new NodeFacade(node);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
get done() {
|
|
116
|
-
return actuals.get(this).done;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
get parentNode() {
|
|
120
|
-
let { parentNode } = actuals.get(this);
|
|
121
|
-
return parentNode && new NodeFacade(parentNode);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
get held() {
|
|
125
|
-
let { held } = actuals.get(this);
|
|
126
|
-
return held && new NodeFacade(held.node);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
get holding() {
|
|
130
|
-
return actuals.get(this).holding;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
get depth() {
|
|
134
|
-
return actuals.get(this).depth;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
get parent() {
|
|
138
|
-
return facades.get(actuals.get(this).parent);
|
|
139
|
-
}
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
export const nodeStates = new WeakMap();
|
|
1
|
+
import { offsetForTag, TagPath } from '@bablr/agast-helpers/path';
|
|
2
|
+
import { DoctypeTag, Property } from '@bablr/agast-helpers/symbols';
|
|
143
3
|
|
|
144
4
|
export const State = class AgastState {
|
|
145
5
|
static create() {
|
|
146
6
|
return new State();
|
|
147
7
|
}
|
|
148
8
|
|
|
9
|
+
static from(held) {
|
|
10
|
+
return new State(held);
|
|
11
|
+
}
|
|
12
|
+
|
|
149
13
|
constructor(held = null, path = null, resultPath = null) {
|
|
150
14
|
this.held = held;
|
|
151
15
|
this.path = path;
|
|
152
16
|
this.resultPath = resultPath;
|
|
153
17
|
this.done = false;
|
|
154
|
-
this.referenceTagPath = null;
|
|
155
18
|
this.doctype = null;
|
|
156
|
-
|
|
157
|
-
new StateFacade(this);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
static from(held) {
|
|
161
|
-
return new State(held);
|
|
162
19
|
}
|
|
163
20
|
|
|
164
|
-
get
|
|
165
|
-
return
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
get atReference() {
|
|
169
|
-
return [ReferenceTag, ShiftTag].includes(this.resultPath?.tag.type);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
get atBinding() {
|
|
173
|
-
return this.resultPath?.tag.type === BindingTag;
|
|
21
|
+
get node() {
|
|
22
|
+
return this.path.node;
|
|
174
23
|
}
|
|
175
24
|
|
|
176
25
|
advance(tag) {
|
|
@@ -192,343 +41,6 @@ export const State = class AgastState {
|
|
|
192
41
|
break;
|
|
193
42
|
}
|
|
194
43
|
|
|
195
|
-
case ReferenceTag: {
|
|
196
|
-
let { type, isArray, name, flags } = tag.value;
|
|
197
|
-
|
|
198
|
-
if (this.atReference) throw new Error('invalid location for reference');
|
|
199
|
-
if (!name && !type) throw new Error();
|
|
200
|
-
if (type && !['.', '#', '@'].includes(type)) throw new Error();
|
|
201
|
-
if (type === '@' && isArray) throw new Error();
|
|
202
|
-
|
|
203
|
-
if (this.held && Tags.getAt(2, this.node.tags)?.type === InitializerTag) {
|
|
204
|
-
if (
|
|
205
|
-
!referencesAreEqual(Tags.getAt(1, this.node.tags).value, tag.value) ||
|
|
206
|
-
Tags.getSize(this.node.tags) > 3
|
|
207
|
-
) {
|
|
208
|
-
throw new Error();
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (tag.value.name) {
|
|
213
|
-
if (
|
|
214
|
-
getOr(null, tag.value.name, this.node) &&
|
|
215
|
-
!referencesAreEqual(tag.value, getProperty(tag.value.name, this.node).reference)
|
|
216
|
-
) {
|
|
217
|
-
throw new Error('mismatched references');
|
|
218
|
-
}
|
|
219
|
-
} else if (tag.value.type === '.') {
|
|
220
|
-
let rootIdx = getPropertyTagsIndex(this.node, '.', null, 0);
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
rootIdx != null &&
|
|
224
|
-
!referencesAreEqual(
|
|
225
|
-
tag.value,
|
|
226
|
-
Tags.getAt(rootIdx, this.node.tags).value.property.reference,
|
|
227
|
-
)
|
|
228
|
-
) {
|
|
229
|
-
throw new Error('mismatched references');
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
let initIndex = getInitializerTagsIndex(this.node, tag);
|
|
234
|
-
if (initIndex != null) {
|
|
235
|
-
let initReferenceTag = Tags.getAt(initIndex, this.node.tags, 0);
|
|
236
|
-
if (!referencesAreEqual(tag.value, initReferenceTag.value)) {
|
|
237
|
-
throw new Error("reference didn't match initializer");
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
let tagProperty = buildProperty(tag.value);
|
|
242
|
-
|
|
243
|
-
this.node.tags = Tags.push(
|
|
244
|
-
this.node.tags,
|
|
245
|
-
buildChild(PropertyWrapper, buildPropertyWrapper([tag], tagProperty)),
|
|
246
|
-
);
|
|
247
|
-
|
|
248
|
-
if (flags.hasGap && !this.node.flags.hasGap) {
|
|
249
|
-
throw new Error('gap reference in gapless node');
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
this.referenceTagPath = TagPath.from(this.path, -1, 0);
|
|
253
|
-
|
|
254
|
-
break;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
case BindingTag: {
|
|
258
|
-
if (!this.atReference && this.parent) {
|
|
259
|
-
throw new Error('Invalid location for BindingTag');
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
let refPath = this.referenceTagPath;
|
|
263
|
-
let propPath = TagPath.from(refPath.path, refPath.tagsIndex);
|
|
264
|
-
|
|
265
|
-
if (refPath.tag.type === ShiftTag) {
|
|
266
|
-
refPath = TagPath.from(refPath.path, refPath.tagsIndex - refPath.tag.value.index, 0);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
let refTag = refPath.tag;
|
|
270
|
-
|
|
271
|
-
let tagProperty = buildProperty(refTag.value, tag.value, undefined);
|
|
272
|
-
let tags = [propPath.tag.value.tags[0], tag];
|
|
273
|
-
|
|
274
|
-
this.node.tags = Tags.replaceAt(
|
|
275
|
-
this.referenceTagPath.tagsIndex,
|
|
276
|
-
this.node.tags,
|
|
277
|
-
buildChild(PropertyWrapper, buildPropertyWrapper(tags, tagProperty)),
|
|
278
|
-
);
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
case OpenNodeTag: {
|
|
283
|
-
let { literalValue } = tag.value;
|
|
284
|
-
let parentNode = this.node;
|
|
285
|
-
|
|
286
|
-
if (!this.atBinding && this.parent) {
|
|
287
|
-
throw new Error('Invalid location for OpenNodeTag');
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
let bindingTag = parentNode && Tags.getAt(-1, parentNode.tags, 1);
|
|
291
|
-
|
|
292
|
-
if (bindingTag && !bindingTag.value.languagePath) throw new Error();
|
|
293
|
-
|
|
294
|
-
let node = createNode(tag);
|
|
295
|
-
|
|
296
|
-
if (!this.path) {
|
|
297
|
-
this.path = Path.create(node);
|
|
298
|
-
} else {
|
|
299
|
-
this.path = this.path.push(node, Tags.getSize(parentNode.tags) - 1);
|
|
300
|
-
add(parentNode, this.referenceTag, node, bindingTag);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (literalValue) {
|
|
304
|
-
finalizeNode(node);
|
|
305
|
-
|
|
306
|
-
let oldPath = this.path;
|
|
307
|
-
this.path = this.path.parent;
|
|
308
|
-
|
|
309
|
-
if (!this.path) {
|
|
310
|
-
this.done = true;
|
|
311
|
-
this.resultPath = TagPath.from(oldPath, 0);
|
|
312
|
-
return tag;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
targetPath = this.path;
|
|
317
|
-
|
|
318
|
-
if (this.path) {
|
|
319
|
-
let undefinedAttributes = 0;
|
|
320
|
-
|
|
321
|
-
let queue = [this.node.attributes];
|
|
322
|
-
while (queue.length) {
|
|
323
|
-
for (let value of Object.values(queue[queue.length - 1])) {
|
|
324
|
-
if (value === undefined) {
|
|
325
|
-
undefinedAttributes++;
|
|
326
|
-
} else if (isArray(value) || isObject(value)) {
|
|
327
|
-
queue.push(value);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
queue.pop();
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
nodeStates.set(this.node, { undefinedAttributes });
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
break;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
case CloseNodeTag: {
|
|
340
|
-
if (this.atReference) throw new Error('invalid location for close tag');
|
|
341
|
-
|
|
342
|
-
if (this.node.type) {
|
|
343
|
-
for (const { 0: key, 1: count } of Tags.getSums(this.node.tags).references) {
|
|
344
|
-
if (count === 1) {
|
|
345
|
-
let property = getProperty(key, this.node);
|
|
346
|
-
if (!property && nodeHas(key, this.node)) {
|
|
347
|
-
let refIndex = getInitializerTagsIndex(this.node, buildReferenceTag(null, key));
|
|
348
|
-
let ref = Tags.getAt(refIndex, this.node.tags, 0);
|
|
349
|
-
if (!ref.value.isArray) {
|
|
350
|
-
let reference = Tags.getAt(refIndex, this.node.tags, 0).value;
|
|
351
|
-
|
|
352
|
-
addProperty(this.node, buildProperty(reference, buildBinding(), buildNullNode()));
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
let list = emptyStack.push(this.node.attributes);
|
|
360
|
-
while (list.size) {
|
|
361
|
-
let item = list.value;
|
|
362
|
-
list = list.pop();
|
|
363
|
-
|
|
364
|
-
for (const value of Object.values(item)) {
|
|
365
|
-
if (isObject(value)) {
|
|
366
|
-
list = list.push(value);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
Object.freeze(item);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
this.node.tags = Tags.push(this.node.tags, tag);
|
|
374
|
-
|
|
375
|
-
if (!this.path) {
|
|
376
|
-
this.done = true;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
finalizeNode(this.node);
|
|
380
|
-
|
|
381
|
-
this.path = this.path.parent;
|
|
382
|
-
break;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
case Property: {
|
|
386
|
-
let target;
|
|
387
|
-
let property = tag.value;
|
|
388
|
-
|
|
389
|
-
if (!this.atBinding && !isStubNode(property.node)) {
|
|
390
|
-
throw new Error('Invalid location for Property');
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
let { node } = this.path;
|
|
394
|
-
let lastTagPath = TagPath.from(this.path, -1, 0);
|
|
395
|
-
let refOrShift = lastTagPath.tag;
|
|
396
|
-
|
|
397
|
-
if (![ShiftTag, ReferenceTag].includes(refOrShift.type)) throw new Error();
|
|
398
|
-
|
|
399
|
-
if (this.held) {
|
|
400
|
-
if (isGapNode(property.node)) {
|
|
401
|
-
property = buildProperty(property.reference, this.held.binding, this.held.node);
|
|
402
|
-
} else {
|
|
403
|
-
let { height } = refOrShift.value;
|
|
404
|
-
let matchesHeld =
|
|
405
|
-
isGapNode(property.node) ||
|
|
406
|
-
this.held.node === property.node ||
|
|
407
|
-
this.held.node === getOriginalFirstNode(property.node, (height ?? 1) - 1);
|
|
408
|
-
if (!matchesHeld) {
|
|
409
|
-
throw new Error();
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
let openStack = node.bounds[0];
|
|
414
|
-
|
|
415
|
-
openStack = BTree.replaceAt(-1, openStack, property);
|
|
416
|
-
openStack = BTree.push(
|
|
417
|
-
openStack,
|
|
418
|
-
buildProperty(buildReference('.'), buildBinding(), buildStubNode(buildGapTag())),
|
|
419
|
-
);
|
|
420
|
-
|
|
421
|
-
node.bounds = buildBounds(openStack, node.bounds[1]);
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
target = this.held ? this.held.node : buildStubNode(buildGapTag());
|
|
425
|
-
|
|
426
|
-
const range = getRange(target);
|
|
427
|
-
|
|
428
|
-
this.resultPath = range ? range[1] : this.resultPath;
|
|
429
|
-
this.referenceTagPath = null;
|
|
430
|
-
|
|
431
|
-
if (refOrShift.type === ShiftTag) {
|
|
432
|
-
shiftProperty(node, property);
|
|
433
|
-
} else {
|
|
434
|
-
addProperty(node, property);
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
this.held = null;
|
|
438
|
-
break;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
case GapTag:
|
|
442
|
-
case NullTag: {
|
|
443
|
-
const { node: parentNode, referenceTag } = this;
|
|
444
|
-
|
|
445
|
-
if (this.held) throw new Error();
|
|
446
|
-
|
|
447
|
-
if (!this.atReference && this.parent) {
|
|
448
|
-
throw new Error('Invalid location for NullTag');
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
let stubNode = buildStubNode(tag);
|
|
452
|
-
|
|
453
|
-
add(parentNode, referenceTag, stubNode);
|
|
454
|
-
|
|
455
|
-
targetPath = this.path.push(stubNode, Tags.getSize(this.node.tags) - 1);
|
|
456
|
-
break;
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
case AttributeDefinition: {
|
|
460
|
-
if (this.held) throw new Error('invalid place for an atrribute binding');
|
|
461
|
-
|
|
462
|
-
let nodeState = nodeStates.get(this.node);
|
|
463
|
-
|
|
464
|
-
nodeState.undefinedAttributes--;
|
|
465
|
-
|
|
466
|
-
// add undefined attributes from value
|
|
467
|
-
|
|
468
|
-
defineAttribute(this.node, tag);
|
|
469
|
-
|
|
470
|
-
break;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
case InitializerTag: {
|
|
474
|
-
const { node, referenceTag } = this;
|
|
475
|
-
|
|
476
|
-
if (!this.atReference && this.parent) {
|
|
477
|
-
throw new Error('Invalid location for InitializerTag');
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
if (this.held && Tags.getAt(1, node.tags, 0)?.type === InitializerTag) {
|
|
481
|
-
throw new Error();
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
if (getInitializerTagsIndex(node, referenceTag) != null) {
|
|
485
|
-
throw new Error();
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
let currentProperty = Tags.getAt(-1, node.tags).value.property;
|
|
489
|
-
|
|
490
|
-
let tags = [referenceTag, tag];
|
|
491
|
-
|
|
492
|
-
let propertyWrapper = buildChild(
|
|
493
|
-
PropertyWrapper,
|
|
494
|
-
buildPropertyWrapper(tags, currentProperty),
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
node.tags = Tags.replaceAt(-1, node.tags, propertyWrapper);
|
|
498
|
-
break;
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
case ShiftTag: {
|
|
502
|
-
if (this.resultPath.tag.type !== Property) throw new Error('invalid location for shift');
|
|
503
|
-
|
|
504
|
-
let heldProperty = this.resultPath.tag.value;
|
|
505
|
-
|
|
506
|
-
if (!this.held) {
|
|
507
|
-
this.held = heldProperty;
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
if (!heldProperty.reference.flags.expression) throw new Error();
|
|
511
|
-
|
|
512
|
-
let tagProperty = buildProperty(heldProperty.reference);
|
|
513
|
-
|
|
514
|
-
this.node.tags = Tags.push(
|
|
515
|
-
this.node.tags,
|
|
516
|
-
buildChild(PropertyWrapper, buildPropertyWrapper([tag], tagProperty)),
|
|
517
|
-
);
|
|
518
|
-
|
|
519
|
-
this.referenceTagPath = TagPath.from(this.path, -1, 0);
|
|
520
|
-
|
|
521
|
-
// this.path = finishedPath;
|
|
522
|
-
targetPath = this.path;
|
|
523
|
-
break;
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
case LiteralTag:
|
|
527
|
-
if (typeof tag.value !== 'string') throw new Error();
|
|
528
|
-
|
|
529
|
-
this.node.tags = Tags.push(this.node.tags, tag);
|
|
530
|
-
break;
|
|
531
|
-
|
|
532
44
|
default:
|
|
533
45
|
throw new Error();
|
|
534
46
|
}
|
|
@@ -538,33 +50,4 @@ export const State = class AgastState {
|
|
|
538
50
|
|
|
539
51
|
return tag;
|
|
540
52
|
}
|
|
541
|
-
|
|
542
|
-
get isGap() {
|
|
543
|
-
return this.tag.type === GapTag;
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
get speculative() {
|
|
547
|
-
return !!this.parent;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
get parentNode() {
|
|
551
|
-
return this.path.parent.node;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
get referenceTag() {
|
|
555
|
-
return this.referenceTagPath?.tag;
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
get bindingPath() {
|
|
559
|
-
let path = this.referenceTagPath.nextSibling;
|
|
560
|
-
return path.tag.type === BindingTag ? path : null;
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
get binding() {
|
|
564
|
-
return this.bindingPath?.tag;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
get node() {
|
|
568
|
-
return this.path?.node;
|
|
569
|
-
}
|
|
570
53
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bablr/agast-vm",
|
|
3
3
|
"description": "A VM providing DOM-like guarantees about agAST trees",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.11.0",
|
|
5
5
|
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -11,21 +11,30 @@
|
|
|
11
11
|
".": "./lib/index.js"
|
|
12
12
|
},
|
|
13
13
|
"sideEffects": false,
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "mocha test/*.test.js"
|
|
16
|
+
},
|
|
14
17
|
"dependencies": {
|
|
15
18
|
"@iter-tools/imm-stack": "1.2.0",
|
|
16
|
-
"@bablr/agast-helpers": "0.
|
|
17
|
-
"@bablr/agast-vm-helpers": "0.
|
|
19
|
+
"@bablr/agast-helpers": "0.10.0",
|
|
20
|
+
"@bablr/agast-vm-helpers": "0.10.0"
|
|
18
21
|
},
|
|
19
22
|
"devDependencies": {
|
|
20
23
|
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#49f5952efed27f94ee9b94340eb1563c440bf64e",
|
|
24
|
+
"@bablr/boot": "*",
|
|
21
25
|
"enhanced-resolve": "^5.12.0",
|
|
26
|
+
"expect": "30.1.2",
|
|
22
27
|
"eslint": "^8.32.0",
|
|
23
28
|
"eslint-import-resolver-enhanced-resolve": "^1.0.5",
|
|
24
29
|
"eslint-plugin-import": "^2.27.5",
|
|
25
30
|
"iter-tools-es": "^7.3.1",
|
|
31
|
+
"mocha": "11.7.2",
|
|
26
32
|
"prettier": "^2.6.2"
|
|
27
33
|
},
|
|
28
|
-
"repository":
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/bablr-lang/agast-vm.git"
|
|
37
|
+
},
|
|
29
38
|
"homepage": "https://github.com/bablr-lang/agast-vm",
|
|
30
39
|
"license": "MIT"
|
|
31
40
|
}
|
package/lib/facades.js
DELETED
package/lib/node.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildPathSegment,
|
|
3
|
-
get,
|
|
4
|
-
has,
|
|
5
|
-
countList,
|
|
6
|
-
getChildPropertyIndex,
|
|
7
|
-
getCloseTag,
|
|
8
|
-
getInitializerTagsIndex,
|
|
9
|
-
getProperty,
|
|
10
|
-
getPropertyTagsIndex,
|
|
11
|
-
relatedNodes,
|
|
12
|
-
getOpenTag,
|
|
13
|
-
} from '@bablr/agast-helpers/path';
|
|
14
|
-
import * as Tags from '@bablr/agast-helpers/tags';
|
|
15
|
-
import * as BTree from '@bablr/agast-helpers/btree';
|
|
16
|
-
import { CloseNodeTag, GapTag, NullTag, OpenNodeTag } from '@bablr/agast-helpers/symbols';
|
|
17
|
-
import { buildReferenceTag, nodeFlags } from '@bablr/agast-helpers/builders';
|
|
18
|
-
import { nodeStates } from './state.js';
|
|
19
|
-
|
|
20
|
-
let { freeze } = Object;
|
|
21
|
-
|
|
22
|
-
export const nodes = new WeakMap();
|
|
23
|
-
|
|
24
|
-
export class BTreeNodeFacade {}
|
|
25
|
-
|
|
26
|
-
export class NodeTagsFacade {
|
|
27
|
-
constructor(node) {
|
|
28
|
-
nodes.set(this, node);
|
|
29
|
-
|
|
30
|
-
if (!Object.isFrozen(node)) throw new Error(); // just a sanity check right now
|
|
31
|
-
|
|
32
|
-
let nodeValues = Tags.getValues(node);
|
|
33
|
-
|
|
34
|
-
this.openTag = nodeValues[0];
|
|
35
|
-
this.childrenNode = nodeValues[1];
|
|
36
|
-
this.closeTag = nodeValues[2];
|
|
37
|
-
|
|
38
|
-
this.size = Tags.getSize(node);
|
|
39
|
-
this.node = node;
|
|
40
|
-
|
|
41
|
-
freeze(this);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
*children() {
|
|
45
|
-
for (const child of this) {
|
|
46
|
-
if (![OpenNodeTag, CloseNodeTag, NullTag, GapTag].includes(child.type)) {
|
|
47
|
-
yield child;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
at(idx, offsetIdx) {
|
|
53
|
-
return Tags.getAt(idx, this.node, offsetIdx);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
find(reference, index) {
|
|
57
|
-
let node = this.node;
|
|
58
|
-
|
|
59
|
-
let idx = this.findIndex(reference, index);
|
|
60
|
-
|
|
61
|
-
return idx == null ? null : Tags.getAt(idx, node);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
findIndex(reference, index) {
|
|
65
|
-
let { type, name } = reference;
|
|
66
|
-
|
|
67
|
-
return getPropertyTagsIndex(this.node, type, name, index);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
[Symbol.iterator]() {
|
|
71
|
-
return Tags.traverse(this.node);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export class ListFacade {
|
|
76
|
-
constructor(tree) {
|
|
77
|
-
nodes.set(this, tree);
|
|
78
|
-
|
|
79
|
-
this.size = BTree.getSize(tree);
|
|
80
|
-
|
|
81
|
-
freeze(this);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
at(idx) {
|
|
85
|
-
return BTree.getAt(idx, nodes.get(this));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
[Symbol.iterator]() {
|
|
89
|
-
return BTree.traverse(nodes.get(this));
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export class NodePropertiesFacade {
|
|
94
|
-
constructor(node) {
|
|
95
|
-
nodes.set(this, node);
|
|
96
|
-
|
|
97
|
-
freeze(this);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
get(name, index = undefined, shiftIndex = undefined) {
|
|
101
|
-
let node = nodes.get(this);
|
|
102
|
-
|
|
103
|
-
let prop = getProperty(buildPathSegment(name, index, shiftIndex), node);
|
|
104
|
-
if (prop) {
|
|
105
|
-
if (Array.isArray(prop.node) && index === undefined) {
|
|
106
|
-
return new ListFacade(prop.node);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (Array.isArray(prop.node)) {
|
|
110
|
-
prop = BTree.getAt(index ?? -1, prop.node);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (!prop) return index === -1 ? prop : null;
|
|
114
|
-
|
|
115
|
-
return NodeFacade.from(prop.node);
|
|
116
|
-
}
|
|
117
|
-
return null;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
referenceAt(name, index = undefined) {
|
|
121
|
-
let path = index == null ? name : buildPathSegment(name, index);
|
|
122
|
-
return getProperty(path, nodes.get(this))?.reference;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
has(name, index = undefined) {
|
|
126
|
-
let path = index == null ? name : buildPathSegment(name, index);
|
|
127
|
-
return (
|
|
128
|
-
!!getProperty(path, nodes.get(this)) ||
|
|
129
|
-
getInitializerTagsIndex(nodes.get(this), buildReferenceTag(null, name)) != null
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
[Symbol.iterator]() {
|
|
134
|
-
return relatedNodes(nodes.get(this));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export class NodeFacade {
|
|
139
|
-
static from(node) {
|
|
140
|
-
return node && new NodeFacade(node);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
constructor(node) {
|
|
144
|
-
let sigilTag = getOpenTag(node);
|
|
145
|
-
|
|
146
|
-
this.sigilTag = sigilTag;
|
|
147
|
-
|
|
148
|
-
if ([NullTag, GapTag].includes(sigilTag.type)) {
|
|
149
|
-
this.flags = nodeFlags;
|
|
150
|
-
this.type = null;
|
|
151
|
-
} else if (sigilTag.type === OpenNodeTag) {
|
|
152
|
-
let { flags, type } = sigilTag.value;
|
|
153
|
-
|
|
154
|
-
this.flags = flags;
|
|
155
|
-
this.type = type;
|
|
156
|
-
} else {
|
|
157
|
-
throw new Error();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
nodes.set(this, node);
|
|
161
|
-
|
|
162
|
-
freeze(this);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
get tags() {
|
|
166
|
-
return new NodeTagsFacade(nodes.get(this).tags);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
get properties() {
|
|
170
|
-
return new NodePropertiesFacade(nodes.get(this));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
get attributes() {
|
|
174
|
-
return nodes.get(this).attributes;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
get undefinedAttributes() {
|
|
178
|
-
return nodeStates.get(nodes.get(this)).undefinedAttributes;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
get node() {
|
|
182
|
-
let node = nodes.get(this);
|
|
183
|
-
|
|
184
|
-
let openTag = getOpenTag(node);
|
|
185
|
-
|
|
186
|
-
return getCloseTag(node) ||
|
|
187
|
-
(openTag && ([NullTag, GapTag].includes(openTag.type) || openTag.value.literalValue))
|
|
188
|
-
? node
|
|
189
|
-
: undefined;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
get(path) {
|
|
193
|
-
return NodeFacade.from(get(path, nodes.get(this)));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
has(path) {
|
|
197
|
-
return NodeFacade.from(has(path, nodes.get(this)));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
countList(path) {
|
|
201
|
-
return countList(path, nodes.get(this));
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
getChildPropertyIndex(tagsIndex) {
|
|
205
|
-
return getChildPropertyIndex(nodes.get(this), tagsIndex);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
getPropertyTagsIndex(type, name) {
|
|
209
|
-
return getPropertyTagsIndex(nodes.get(this), type, name);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
equalTo(node) {
|
|
213
|
-
return nodes.get(this) === nodes.get(node);
|
|
214
|
-
}
|
|
215
|
-
}
|
package/lib/path.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
import { Property } from '@bablr/agast-helpers/symbols';
|
|
2
|
-
import { NodeFacade, nodes } from './node.js';
|
|
3
|
-
import { Path, TagPath } from '@bablr/agast-helpers/path';
|
|
4
|
-
import { buildChild, buildFacadeProperty, buildProperty } from '@bablr/agast-helpers/builders';
|
|
5
|
-
|
|
6
|
-
export { Path, TagPath } from '@bablr/agast-helpers/path';
|
|
7
|
-
|
|
8
|
-
export { allTagPathsFor, ownTagPathsFor } from '@bablr/agast-helpers/path';
|
|
9
|
-
|
|
10
|
-
let { freeze } = Object;
|
|
11
|
-
|
|
12
|
-
let paths = new WeakMap();
|
|
13
|
-
|
|
14
|
-
export class TagPathFacade {
|
|
15
|
-
static from(path, tagsIndex, wrapperIndex) {
|
|
16
|
-
let tagPath = path && TagPath.from(paths.get(path), tagsIndex, wrapperIndex);
|
|
17
|
-
return tagPath && new TagPathFacade(tagPath);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static fromNode(node, tagsIndex, wrapperIndex) {
|
|
21
|
-
let path = node && TagPath.fromNode(nodes.get(node), tagsIndex, wrapperIndex);
|
|
22
|
-
return path && new TagPathFacade(path);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
static wrap(tagPath) {
|
|
26
|
-
return tagPath && new TagPathFacade(tagPath);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
constructor(tagPath) {
|
|
30
|
-
if (!(tagPath instanceof TagPath)) throw new Error();
|
|
31
|
-
paths.set(this, tagPath);
|
|
32
|
-
|
|
33
|
-
let { tag } = tagPath;
|
|
34
|
-
|
|
35
|
-
this.path = new PathFacade(tagPath.path);
|
|
36
|
-
this.node = new NodeFacade(tagPath.node);
|
|
37
|
-
this.tag =
|
|
38
|
-
tag.type === Property
|
|
39
|
-
? buildChild(
|
|
40
|
-
Property,
|
|
41
|
-
buildFacadeProperty(
|
|
42
|
-
tag.value.reference,
|
|
43
|
-
tag.value.binding,
|
|
44
|
-
new NodeFacade(tag.value.node),
|
|
45
|
-
),
|
|
46
|
-
)
|
|
47
|
-
: tag;
|
|
48
|
-
this.tagsIndex = tagPath.tagsIndex;
|
|
49
|
-
this.wrapperIndex = tagPath.wrapperIndex;
|
|
50
|
-
|
|
51
|
-
freeze(this);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
get child() {
|
|
55
|
-
return this.tag;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
siblingAt(index) {
|
|
59
|
-
return TagPathFacade.wrap(paths.get(this).siblingAt(index));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
get nextSibling() {
|
|
63
|
-
return TagPathFacade.wrap(paths.get(this).nextSibling);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
get next() {
|
|
67
|
-
return TagPathFacade.wrap(paths.get(this).next);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
get nextUnshifted() {
|
|
71
|
-
return TagPathFacade.wrap(paths.get(this).nextUnshifted);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
get previousSibling() {
|
|
75
|
-
return TagPathFacade.wrap(paths.get(this).previousSibling);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
get previous() {
|
|
79
|
-
return TagPathFacade.wrap(paths.get(this).previous);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
get previousUnshifted() {
|
|
83
|
-
return TagPathFacade.wrap(paths.get(this).previousUnshifted);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
get inner() {
|
|
87
|
-
return PathFacade.wrap(paths.get(this).inner);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getWrapped() {}
|
|
91
|
-
|
|
92
|
-
equalTo(tagPath) {
|
|
93
|
-
if (tagPath == null) return false;
|
|
94
|
-
|
|
95
|
-
let { path, tagsIndex, wrapperIndex } = paths.get(this);
|
|
96
|
-
let tagPath_ = paths.get(tagPath);
|
|
97
|
-
return (
|
|
98
|
-
path.node === tagPath_.path.node &&
|
|
99
|
-
tagsIndex === tagPath_.tagsIndex &&
|
|
100
|
-
wrapperIndex === tagPath_.wrapperIndex
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export class PathFacade {
|
|
106
|
-
static from(node) {
|
|
107
|
-
return node && new PathFacade(Path.from(nodes.get(node)));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
static wrap(path) {
|
|
111
|
-
return path && new PathFacade(path);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
constructor(path) {
|
|
115
|
-
if (!(path instanceof Path)) throw new Error();
|
|
116
|
-
this.depth = path.depth;
|
|
117
|
-
|
|
118
|
-
this.node = new NodeFacade(path.node);
|
|
119
|
-
this.parentIndex = path.parentIndex;
|
|
120
|
-
|
|
121
|
-
paths.set(this, path);
|
|
122
|
-
|
|
123
|
-
freeze(this);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
get parent() {
|
|
127
|
-
// not a stable reference. can/should it be?
|
|
128
|
-
return PathFacade.wrap(paths.get(this).parent);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
get openTagPath() {
|
|
132
|
-
return TagPathFacade.wrap(paths.get(this).openTagPath);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
get openTag() {
|
|
136
|
-
return paths.get(this).openTag;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
get closeTagPath() {
|
|
140
|
-
return TagPathFacade.wrap(paths.get(this).closeTagPath);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
get closeTag() {
|
|
144
|
-
return paths.get(this).closeTag;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
get bindingTag() {
|
|
148
|
-
return paths.get(this).bindingTag;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
get binding() {
|
|
152
|
-
return paths.get(this).binding;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
get bindingTagPath() {
|
|
156
|
-
return TagPathFacade.wrap(paths.get(this).bindingTagPath);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
get parentProperty() {
|
|
160
|
-
return this.parentPropertyPath.tag;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
get parentPropertyPath() {
|
|
164
|
-
return TagPathFacade.wrap(paths.get(this).parentPropertyPath);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
get referenceTag() {
|
|
168
|
-
return paths.get(this).referenceTag;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
get reference() {
|
|
172
|
-
return paths.get(this).reference;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
get referenceTagPath() {
|
|
176
|
-
return TagPathFacade.wrap(paths.get(this).referenceTagPath);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
get(path, shiftIndex = null) {
|
|
180
|
-
return new PathFacade(paths.get(this).get(path, shiftIndex));
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
tagPathAt(tagsIndex, wrapperIndex) {
|
|
184
|
-
return TagPathFacade.wrap(TagPath.from(paths.get(this), tagsIndex, wrapperIndex));
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
tagAt(tagsIndex, wrapperIndex) {
|
|
188
|
-
return this.tagPathAt(tagsIndex, wrapperIndex).tag;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
atDepth(depth) {
|
|
192
|
-
return new PathFacade(paths.get(this).atDepth(depth));
|
|
193
|
-
}
|
|
194
|
-
}
|