UNPKG

@effectful/transducers

Version:

JS syntax transformation framework for @effectful/js

306 lines (299 loc) 8.65 kB
"use strict"; 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); } }