Files
nodejs.esm-library/experiments/reduction-scanner-2.mjs

77 lines
1.9 KiB
JavaScript

import { Reduction_Scanner, Reduction_Settings } from '@efforting.tech/rule-processing/reduction-scanner';
import * as R from '@efforting.tech/rule-processing/rules';
import { inspect } from 'node:util';
class Rule { //NOTE: This is somewhat of a place holder because we may want to declare specific transformations later rather than always having an opaque handler function
constructor(condition, handler) {
Object.assign(this, { condition, handler });
}
get match() {
return this.condition.match.bind(this.condition);
}
get action() {
return this.handler;
}
}
function sequence_rule(sequence, transform_fn) {
return new Rule(
new R.Sequence_Condition(sequence),
(rs, sequence, match) => {
const MS = match.match_start;
const ME = match.match_end;
sequence.splice(MS, ME - MS + 1, transform_fn(...sequence.slice(MS, ME + 1)));
}
);
}
const N = new R.Predicate((i) => typeof i === 'number' || i.type == 'BINOP' );
const ASTERISK = new R.Strict_Equality('*');
const PLUS = new R.Strict_Equality('+');
const HAT = new R.Strict_Equality('^');
const rss = Reduction_Settings.load({
// Switching this on or off affects whether add comes before mul or not
//reduction_order: 'POSITION_MAJOR',
});
const rs = new Reduction_Scanner(rss);
rss.rules.push(
sequence_rule([N, HAT, N], (left, op, right) => ({ type: 'BINOP', op: 'HAT', operands: [left, right]})),
sequence_rule([N, ASTERISK, N], (left, op, right) => ({ type: 'BINOP', op: 'ASTERISK', operands: [left, right]})),
sequence_rule([N, PLUS, N], (left, op, right) => ({ type: 'BINOP', op: 'PLUS', operands: [left, right]})),
);
const arr = [10, '^', 5, '+', 20, '*', 30];
console.log(inspect(rs.transform(arr), { colors: true, depth: null }));
/* OUTPUT
[
{
type: 'BINOP',
op: 'PLUS',
operands: [
{ type: 'BINOP', op: 'HAT', operands: [ 10, 5 ] },
{ type: 'BINOP', op: 'ASTERISK', operands: [ 20, 30 ] }
]
}
]
*/