import Logger, { levels } from '../logger.js'; import { filename } from '../utils.js'; const log = new Logger(filename(import.meta.url), "DEBUG"); class Target { constructor(channel) { this.channel = channel; } channel; value; } const available_targets = { r: new Target('r'), g: new Target('g'), b: new Target('b'), stack: new Target('stack'), stack2: new Target('stack2'), stack3: new Target('stack3'), stack4: new Target('stack4'), stack5: new Target('stack5'), stack6: new Target('stack6'), stack6: new Target('stackr'), stack6: new Target('stackg'), stack6: new Target('stackb'), tick: new Target('tick'), index: new Target('index'), }; class Instruction { constructor(name, targets, args) { let valid_targets = []; let matched_args = []; targets.forEach((t, i) => { if (t instanceof Target) { let match = Object.keys(available_targets).find((key) => available_targets[key].channel === t.channel); if (match) { if (args[i]) { matched_args.push({ ...t, arg: args[i] }) } else { matched_args.push(t); } } } }); this.name = name; this.targets = valid_targets; this.args = matched_args; } name; targets; args; } export const instructions = [ ]; export function initialize(ctx) { log.s(ctx.log_level); } function parseSingleInstruction(str = '') { let item = { valid: false, instruction: undefined, errors: undefined, }; let split = str.split(' '); let cmd = split[0]; log.debug(cmd); let match = instructions.filter((i) => i.n == cmd.toUpperCase()); log.debug(match); split = split.slice(1); if (match.length) { let inst_targets = []; let inst_args = []; let parsed_args = []; let join_index = -1; let add = true; for (let index in split) { if (split[index].startsWith('[')) { join_index = index; add = false; } if (add) { parsed_args.push(split[index]); } if (split[index].endsWith(']') && join_index != -1) { let joined = split .slice(join_index, index + 1) .join(' ') .replace(/[\[\]]/g, ''); parsed_args.push(joined); add = true; join_index = -1; } } inst_targets = parsed_args[0] .split(',') .map((s) => s.trim()) .map((t) => new Target(t)); if (!inst_targets.length) { item.errors = 'No valid targets.'; } inst_targets.forEach((t) => { let match = Object.keys(available_targets).find((key) => available_targets[key].channel === t.channel); if (!match) { item.errors = `Invalid target: ${t.channel}`; } }); if (match[0].a) { if (parsed_args.length < 2) { item.errors = 'Not enough arguments.'; return item; } inst_args = parsed_args[1] .split(',') .map((s) => s.trim()) .map((s) => (available_targets[s] ? s : parseInt(s))); if (!inst_args.length) { item.errors = 'No valid args.'; } inst_args.forEach((arg) => { if (arg === NaN) { item.errors = 'An argument is null or undefined.'; } }); } if (item.errors) { return item; } item.instruction = new Instruction(match[0].n, inst_targets, inst_args || []); } else { item.errors = 'No command matched.'; return item; } item.valid = true; return item; } export function discover(data) { for (let value of data) { if (value.n != undefined) { let found = instructions.filter((val) => { return val.n == value.n }); if (!found.length) { log.debug(`discovered new keyword ${value.n}`); instructions.push(value); } } } } export default function parse(str) { let parsed = []; let split = str.split('\n').filter((s) => s.length > 0); split.forEach((item) => { let parsedItem = parseSingleInstruction(item); parsed.push(parsedItem); log.debug(item); }); return parsed; }