UNPKG

walt-compiler

Version:

Alternative syntax for WebAssembly text format

79 lines (77 loc) 2.32 kB
/** * Unary operator plugin. * * @flow */ import Syntax from 'walt-syntax'; import type { SemanticPlugin } from '../flow/types'; const shifts = { i64: 63, f64: 63, i32: 31, f32: 31, }; const masks = { i64: '0xffffffffffff', f64: '0xffffffffffff', i32: '0xffffff', f32: '0xffffff', }; // Unary expressions need to be patched so that the LHS type matches the RHS export default function(): SemanticPlugin { return { semantics({ stmt }) { return { [Syntax.UnaryExpression]: _ignore => (args, transform) => { const [unaryNode, context] = args; // While it's counter-intuitive that an unary operation would have two operands // it is simpler to always parse them as pseudo-binary and then simplify them here. const [lhs, rhs] = unaryNode.params.map(p => transform([p, context])); switch (unaryNode.value) { // Transform bang case '!': const shift = shifts[lhs.type]; return transform([ stmt`(((${lhs} >> ${shift}) | ((~${lhs} + 1) >> ${shift})) + 1);`, context, ]); case '~': const mask = masks[transform([lhs, context]).type]; return transform([stmt`(${lhs} ^ ${mask});`, context]); case '-': // Fold negation into a single opcode (a negative constant). // The parser _currently_ generates 0 - <const> node pairs instead if (rhs.Type === Syntax.Constant) { return { ...rhs, meta: { ...rhs.meta, // Hint for generator SIGN: -1, }, }; } // fallthrough // eslint-disable-next-line default: return transform([ { ...unaryNode, type: rhs.type, params: [ { ...lhs, type: rhs.type, }, rhs, ], Type: Syntax.BinaryExpression, }, context, ]); } }, }; }, }; }