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_Match { constructor(rule, match) { Object.assign(this, { rule, match }); } get action() { return this.rule.handler; } } 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 }); } match(...args) { const match = this.condition.match(...args); if (match) { return new Rule_Match(this, match); } } } class Sub_Scan_Rule_Match { constructor(rule, sub_scan_candidate) { Object.assign(this, { rule, sub_scan_candidate }); } get action() { return this.sub_scan_candidate.match.action; } get match() { return this.sub_scan_candidate.match.match; } } class Sub_Scan_Rule { constructor(sub_system) { Object.assign(this, { sub_system }); } match(...args) { const candidate = this.sub_system.find_reduction_candidate(...args); if (candidate) { return new Sub_Scan_Rule_Match(this, candidate) } } } function sequence_rule(sequence, transform_fn) { return new Rule( new R.Sequence_Condition(sequence), ({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 CARET = new R.Strict_Equality('^'); const CARON = new R.Strict_Equality('ˇ'); const ASTERISK = new R.Strict_Equality('*'); const SLASH = new R.Strict_Equality('/'); const PLUS = new R.Strict_Equality('+'); const MINUS = new R.Strict_Equality('-'); // These are the outer settings const rss = Reduction_Settings.load(); // These are the inner settings const rss_inner = Reduction_Settings.load({ reduction_order: 'POSITION_MAJOR', }); const rs = new Reduction_Scanner(rss); // Local factory for sub system function sub_system(...rules) { const sub_settings = { ...rss_inner, rules }; const scanner = new Reduction_Scanner(sub_settings); return new Sub_Scan_Rule(scanner); } rss.rules.push( sub_system( sequence_rule([N, CARET, N], (left, op, right) => ({ type: 'BINOP', op: 'CARET', operands: [left, right]})), sequence_rule([N, CARON, N], (left, op, right) => ({ type: 'BINOP', op: 'CARON', operands: [left, right]})), ), sub_system( sequence_rule([N, ASTERISK, N], (left, op, right) => ({ type: 'BINOP', op: 'ASTERISK', operands: [left, right]})), sequence_rule([N, SLASH, N], (left, op, right) => ({ type: 'BINOP', op: 'SLASH', operands: [left, right]})), ), sub_system( sequence_rule([N, PLUS, N], (left, op, right) => ({ type: 'BINOP', op: 'PLUS', operands: [left, right]})), sequence_rule([N, MINUS, N], (left, op, right) => ({ type: 'BINOP', op: 'MINUS', operands: [left, right]})), ), ); const arr = [5, '-', 10, '^', 5, 'ˇ', 2, '+', 20, '*', 30]; console.log(inspect(rs.transform(arr), { colors: true, depth: null })); /* [ { type: 'BINOP', op: 'MINUS', operands: [ 5, { type: 'BINOP', op: 'PLUS', operands: [ { type: 'BINOP', op: 'CARON', operands: [ { type: 'BINOP', op: 'CARET', operands: [ 10, 5 ] }, 2 ] }, { type: 'BINOP', op: 'ASTERISK', operands: [ 20, 30 ] } ] } ] } ] */