Home Reference Source

scripts/path-controller/toolsys/toolpath.js

import {ToolClasses, ToolOp, ToolFlags, UndoFlags, ToolMacro} from './toolsys.js';
import {tokdef, lexer, parser, PUTLParseError} from '../util/parseutil.js';
import {DataPathError} from '../controller/controller_base.js';
import {cachering} from '../util/util.js';

export let ToolPaths = {};

var initToolPaths_run = false;

export function buildParser() {
  let t = (name, re, func) => new tokdef(name, re, func);

  let tokens = [
    t('ID', /[a-zA-Z_$]+[a-zA-Z0-9_$]*/, (t) => {
      if (t.value == "true" || t.value == "false") {
        t.type = "BOOL";
        t.value = t.value == "true";
      }

      return t;
    }),
    t('LPAREN', /\(/),
    t('RPAREN', /\)/),
    t('LSBRACKET', /\[/),
    t('RSBRACKET', /\]/),
    t('DOT', /\./),
    t('COMMA', /\,/),
    t('EQUALS', /\=/),
    t('STRLIT', /"[^"]*"/, (t) => {
      t.value = t.value.slice(1, t.value.length-1);
      return t;
    }),
    t('STRLIT', /'[^']*'/, (t) => {
      t.value = t.value.slice(1, t.value.length-1);
      return t;
    }),
    t('NUMBER', /-?[0-9]+/, (t) => {
      t.value = parseInt(t.value);
      return t;
    }),
    t('NUMBER', /-?[0-9]+\.[0-9]*/, (t) => {
      t.value = parseFloat(t.value);
      return t;
    }),
    t('WS', /[ \n\r\t]/, (t) => undefined) //ignore whitespace
  ];

  let lexerror = (t) => {
    console.warn("Parse error");
    return true;
  };

  let valid_datatypes = {
    "STRLIT" : 1, "NUMBER" : 1, "BOOL" : 1
  };

  function p_Start(p) {
    let args = {};

    while (!p.at_end()) {
      let keyword = p.expect("ID");

      p.expect("EQUALS");

      let t = p.next();
      if (!(t.type in valid_datatypes)) {
        throw new PUTLParseError("parse error: unexpected " + t.type);
      }

      args[keyword] = t.value;
    }

    return args;
  }

  let lex = new lexer(tokens, lexerror)
  let p = new parser(lex);
  p.start = p_Start;

  return p;
}

export let Parser = buildParser();
/*
let parse_rets = new cachering(() => return {
  toolclass : undefined,
  args : {}
}, 64);
//*/

export function parseToolPath(str, check_tool_exists=true) {
  if (!initToolPaths_run) {
    initToolPaths_run = true;
    initToolPaths();
  }

  let startstr = str;

  let i1 = str.search(/\(/);
  let i2 = str.search(/\)/);
  let args = "";

  if (i1 >= 0 && i2 >= 0) {
    args = str.slice(i1+1, i2).trim();
    str = str.slice(0, i1).trim();
  }

  if (!(str in ToolPaths) && check_tool_exists) {
    throw new DataPathError("unknown tool " + str);
  }

  let ret;

  try {
    ret = Parser.parse(args);
  } catch (error) {
    console.log(error);
    throw new DataPathError(`"${startstr}"\n  ${error.message}`);
  }

  return {
    toolclass : ToolPaths[str],
    args      : ret
  };
}

export function testToolParser() {
  let ret = parseToolPath("view3d.sometool(selectmode=1 str='str' bool=true)", false);

  return ret;
}

window.parseToolPath = parseToolPath;
//window._ToolPaths = ToolPaths;

//tool path parser for simple_toolsys.js
export function initToolPaths() {
  for (let cls of ToolClasses) {
    if (!cls.hasOwnProperty("tooldef")) { //ignore abstract classes
      continue;
    }

    let def = cls.tooldef();
    let path = def.toolpath;

    ToolPaths[path] = cls;
  }
}