import Logger, { levels } from '../logger.js'; import { filename } from '../utils.js'; const log = new Logger(filename(import.meta.url), levels.PANIC); 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'), }; class Instruction { constructor(name, targets, args) { let valid_targets = []; targets.forEach((t) => { if (t instanceof Target) { let match = Object.keys(available_targets).find((key) => available_targets[key].channel === t.channel); if (match) { valid_targets.push(t); } } }); this.name = name; this.targets = valid_targets; this.args = args; } name; targets; args; } export const instructions = [ { n: 'CONSTANT', a: true }, { n: 'ADD', a: true }, { n: 'SUB', a: true }, { n: 'RAND', a: false }, ]; 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]; let match = instructions.filter((i) => i.n == cmd.toUpperCase()); 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 == 'stack' ? 'stack' : parseInt(s.trim()))); if (!inst_args.length) { item.errors = 'No valid args.'; } inst_args.forEach((arg) => { if (!arg) { 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 default function parse(str) { let parsed = []; let split = str.split('\n'); split.forEach((item) => { let parsedItem = parseSingleInstruction(item); parsed.push(parsedItem); log.debug(item); }); return parsed; }