@effectful/transducers
Version:
JS syntax transformation framework for @effectful/js
306 lines (299 loc) • 8.65 kB
JavaScript
;
exports.__esModule = true;
var _exportNames = {
enter: true,
leave: true,
tok: true,
produce: true,
consume: true,
reproduceNodes: true,
resetFieldInfo: true,
removeNulls: true,
emitConst: true
};
exports.consume = consume;
exports.emitConst = emitConst;
exports.enter = enter;
exports.leave = leave;
exports.produce = produce;
exports.removeNulls = removeNulls;
exports.reproduceNodes = reproduceNodes;
exports.resetFieldInfo = resetFieldInfo;
exports.tok = tok;
var _types = require("./v2/types");
Object.keys(_types).forEach(function (key) {
if (key === "default" || key === "__esModule") return;
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
if (key in exports && exports[key] === _types[key]) return;
exports[key] = _types[key];
});
function enter(pos, type, value) {
(0, _types.invariant)(pos && type && value);
return {
enter: true,
leave: false,
pos,
type,
value
};
}
function leave(pos, type, value) {
return {
enter: false,
leave: true,
pos,
type,
value
};
}
function tok(pos, type, value) {
return {
enter: true,
leave: true,
pos,
type,
value
};
}
/**
* converts AST `node` into a stream of tokens with initial position `pos`
* and intial tag's value - `value`
*/
function* produce(node, pos, value) {
function* _produce(node, pos, value) {
value.node = node;
if (node == null) {
if (pos === _types.Tag.push) yield tok(pos, _types.Tag.Empty, {
node: null
});
} else if (Array.isArray(node)) {
yield enter(pos, _types.Tag.Array, value);
for (const i of node) yield* _produce(i, _types.Tag.push, {});
yield leave(pos, _types.Tag.Array, value);
} else if ((0, _types.isNode)(node)) {
const keys = _types.VISITOR_KEYS[node.type];
const ti = (0, _types.nodeInfo)(node);
const type = ti.sym;
if (keys.length) {
yield enter(pos, type, value);
for (const i of keys) {
const v = node[i];
if (v != null) {
yield* _produce(node[i], _types.Tag[i] || i, {});
}
}
yield leave(pos, type, value);
} else {
yield tok(pos, type, value);
}
}
}
yield* _produce(node, pos || _types.Tag.top, value || {});
}
/**
* converts stream of tokens into AST node
*/
function consume(s) {
const stack = [{}];
for (const i of s) {
const ti = (0, _types.typeInfo)(i);
if (i.type == null || ti.kind === "ctrl") continue;
if (i.enter) {
if (i.type === _types.Tag.Array) stack.unshift([]);
//TODO: another step to handle nulls
else if (i.type === _types.Tag.Null) {
if (i.pos !== _types.Tag.push) stack[0][(0, _types.symName)(i.pos)] = null;
continue;
} else {
if (i.value != null) {
if (ti.esType != null) i.value.node.type = ti.esType;
if (ti.fields) Object.assign(i.value.node, ti.fields);
}
const node = i.type === _types.Tag.Empty ? null : i.value.node;
(0, _types.invariant)(!node || node.type);
stack.unshift(node);
}
}
if (i.leave) {
const node = stack.shift();
if (i.pos === _types.Tag.push) {
stack[0].push(node);
} else stack[0][(0, _types.symName)(i.pos)] = node;
}
}
return stack[0];
}
/**
* unwraps tokens formerly folded into Node sub-token
*/
function* reproduceNodes(s) {
for (const i of s) {
if (i.type === _types.Tag.Node) {
if (i.enter) {
yield* produce(i.value.node, i.pos);
} else yield i;
}
}
}
/**
* Resets `fieldInfo` field in each `value`.
* The field descripts AST node context.
*/
function* resetFieldInfo(s) {
const stack = [];
for (const i of s) {
if (i.enter) {
let f = stack[stack.length - 1];
if (f && f.fieldsMap) {
f = i.value.fieldInfo = f.fieldsMap.get(i.pos);
}
let ti = f && f.ti || (0, _types.typeInfo)(i);
switch (ti.kind) {
case "array":
stack.push(i.value.fieldInfo);
break;
case "node":
// babel validator hacks
// TODO: own model description
switch (i.type) {
case _types.Tag.ArrayPattern:
ti = f && f.declVar ? _types.arrayPattern : _types.arrayAssignmentPattern;
break;
case _types.Tag.ObjectPattern:
ti = f && f.declVar ? _types.objectPattern : _types.objectAssignmentPattern;
break;
case _types.Tag.RestElement:
ti = f && f.declVar ? _types.restElement : _types.restElementAssignment;
break;
case _types.Tag.AssignmentExpression:
ti = i.value.node.operator === "=" ? _types.assignmentOpEq : _types.assignmentOpDefault;
break;
case _types.Tag.ObjectProperty:
if (i.value.node.computed) ti = ti.propAlt;else if (f && f.declVar) ti = _types.assignmentProperty;
break;
case _types.Tag.AssignmentPattern:
if (!f || !f.declVar) ti = (0, _types.symInfo)(_types.Tag.AssignmentExpression);
break;
case _types.Tag.MemberExpression:
case _types.Tag.ObjectMethod:
case _types.Tag.ClassProperty:
case _types.Tag.ClassMethod:
case _types.Tag.ClassPrivateMethod:
case _types.Tag.ClassPrivateProperty:
if (i.value.node.computed) ti = ti.propAlt;
break;
}
stack.push(ti);
break;
default:
stack.push(false);
}
}
if (i.leave) stack.pop();
yield i;
}
}
/** interprets `Tag.Null` tokens by changing AST accordingly */
function* removeNulls(s) {
const stack = [];
for (const i of s) {
if (i.type === _types.Tag.Null && i.pos !== _types.Tag.push) {
if (i.enter && stack[0]) {
stack[0][(0, _types.symName)(i.pos)] = null;
}
continue;
}
yield i;
if (i.enter) stack.unshift(i.value.node);
if (i.leave) stack.shift();
}
}
/** converts compile time constant into a list of tokens */
function* emitConst(pos, ...args) {
for (const value of args) {
switch (typeof value) {
case "number":
yield tok(pos, _types.Tag.NumericLiteral, {
node: {
value
}
});
continue;
case "string":
yield tok(pos, _types.Tag.StringLiteral, {
node: {
value
}
});
continue;
case "boolean":
yield tok(pos, _types.Tag.BooleanLiteral, {
node: {
value
}
});
continue;
case "object":
if (value === null) {
yield tok(pos, _types.Tag.NullLiteral, {
node: {}
});
continue;
}
if (value.emitConstMethod) {
yield* value.emitConstMethod(pos);
continue;
}
if (Array.isArray(value)) {
const ival = {
node: {}
};
const aval = {
node: []
};
yield enter(pos, _types.Tag.ArrayExpression, ival);
yield enter(_types.Tag.elements, _types.Tag.Array, aval);
for (const j of value) yield* emitConst(_types.Tag.push, j);
yield leave(_types.Tag.elements, _types.Tag.Array, aval);
yield leave(pos, _types.Tag.ArrayExpression, ival);
continue;
}
const ival = {
node: {}
};
const aval = {
node: []
};
yield enter(pos, _types.Tag.ObjectExpression, ival);
yield enter(_types.Tag.properties, _types.Tag.Array, aval);
for (const name in value) {
const pval = {
node: {}
};
yield enter(_types.Tag.push, _types.Tag.ObjectProperty, pval);
yield tok(_types.Tag.key, _types.Tag.Identifier, {
node: {
name
}
});
yield* emitConst(_types.Tag.value, value[name]);
yield leave(_types.Tag.push, _types.Tag.ObjectProperty, pval);
}
yield leave(_types.Tag.properties, _types.Tag.Array, aval);
yield leave(pos, _types.Tag.ObjectExpression, ival);
continue;
}
const val = {
node: {
operator: "void"
}
};
yield enter(pos, _types.Tag.UnaryExpression, val);
yield tok(_types.Tag.argument, _types.Tag.NumericLiteral, {
node: {
value: "0"
}
});
yield leave(pos, _types.Tag.UnaryExpression, val);
}
}