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

157 lines
3.5 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_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 ] }
]
}
]
}
]
*/