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