-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsyntaxtree.js
126 lines (117 loc) · 4.06 KB
/
syntaxtree.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
var defClass = require('./classgenerator');
SyntaxItem = defClass(null,
function SyntaxItem(args) {
if(!args) return;
this.descriptor = args.descriptor;
this.evaluateFn = args.evaluateFn;
},
{
getType: notImplemented,
getString: notImplemented,
getLength: notImplemented,
getSubordinateDescriptors: notImplemented,
getDescriptor: function() { return this.descriptor },
setDescriptor: function(value) { this.descriptor = value },
getDescriptors: function(isEntry) {
if(isEntry == null) isEntry = true;
if(this.getDescriptor()) {
var ret = {};
ret[this.getDescriptor()] = this;
return ret;
}
else return this.getSubordinateDescriptors(isEntry);
},
evaluate: function() {
if(typeof this.evaluateFn !== 'function') throw new Error('no or invalid evaluate function specified');
return this.evaluateFn.call(this);
}
});
Expression = defClass(SyntaxItem,
function Expression(baseArg, args /* := sequence, explicit */) {
SyntaxItem.call(this, baseArg);
this.sequence = args.sequence;
this.explicit = args.explicit == true;
},
{
getType: function() { return 'expression' },
getLength: function() { return this.getSequence().map(function(el) { return el.getLength() }).reduce(function(red, el) { return red+el },0) },
getSequence: function() { return this.sequence },
getString: function() { return this.getSequence().map(function(el) { return el.getString() }).join('') },
getNthItem: function(n) { return this.sequence[n] },
isExplicit: function() { return this.explicit },
getSubordinateDescriptors: function(isEntry) {
if(isEntry == null) isEntry = true;
if(!isEntry && this.isExplicit()) return {};
return mergeDescriptorTrees(this.getSequence().map(function(el) {
return el.getDescriptors(false);
}));
}
});
function mergeDescriptorTrees(trees) {
var ret = {};
trees.forEach(function(t) {
Object.keys(t).forEach(function(key) {
if(ret[key]) throw new Error('cant assign two values to this descriptor');
ret[key] = t[key];
})
})
return ret;
}
Group = defClass(SyntaxItem,
function Group(baseArg, args /* := inner */) {
SyntaxItem.call(this, baseArg);
this.inner = args.inner;
},
{
getType: function() { return 'group' },
getInner: function() { return this.inner },
getLength: function() { return this.isIgnored() ? 0 : this.inner.getLength() },
getString: function() { return this.inner ? this.inner.getString() : '' },
isIgnored: function() { return this.inner == null },
getSubordinateDescriptors: function() {
if(!this.isIgnored()) return this.inner.getDescriptors();
else return {};
}
});
Repetition = defClass(SyntaxItem,
function Repetition(baseArg, args /* := items */) {
SyntaxItem.call(this, baseArg);
this.items = args.items;
},
{
getType: function() { return 'repetition' },
getLength: function() { return this.getItems().map(function(el) { return el.getLength() }).reduce(function(red, el) { return red+el },0) },
getItems: function() { return this.items },
getSubordinateDescriptors: function() {
return composeDescriptorsToArrays(this.items.map(function(i) { return i.getDescriptors() }));
},
getString: function() {
return this.getItems().map(function(i) { return i.getString() }).join('');
}
});
StringOrChar = defClass(SyntaxItem,
function StringOrChar(baseArg, args /* := value */) {
SyntaxItem.call(this, baseArg);
this.value = args.value;
},
{
getType: function() { return 'string-or-char' },
getValue: function() { return this.value },
getLength: function() { return this.getValue().length },
getSubordinateDescriptors: function() { return {} },
getString: function() { return this.getValue() }
});
function composeDescriptorsToArrays(trees) {
var ret = {};
trees.forEach(function(t, i) {
Object.keys(t).forEach(function(key) {
if(!ret[key]) ret[key] = [];
ret[key][i] = t[key];
})
})
return ret;
}
function notImplemented() {
throw new Error('not implemented');
}
module.exports = { SyntaxItem: SyntaxItem, Expression: Expression, Group: Group, Repetition: Repetition, StringOrChar: StringOrChar };