Monday, 23 August 2021

How to convert nested function call tree to state machine?

Say you have this sort of system:

const input = [0, [1, 2, [3, 4, [8, 9], 6, 7], 4], [5, 6, 7], 3, 4, [8, 9], 6, 7, [1], 9]
const output = parse(input)
console.log(output.join('-'))

function parse(input) {
  const output = []
  iterate(input, value => {
    check(() => isArray(value),
      () => { // yes array
        const children = parse(value)
        output.push(...children)
      },
      () => { // not array
        check(() => isEven(value), () => {
          output.push(value)
        })
      })
  })
  return output
}

function isArray(value) {
  return Array.isArray(value)
}

function isEven(value) {
  return value % 2 == 0
}

function check(condition, success, failure) {
  if (condition()) success()
  else if (failure) failure()
}

function iterate(array, block) {
  array.forEach(block)
}

Essentially this is like a tree grammar:

parse =
  iterate input, value =>
    check isArray(value)
      call parse(value)
    check isNumber(value)
      check isEven(value)
        push(value)

You can imagine this as JSON:

{
  type: 'function',
  name: 'parse',
  children: [
    {
      type: 'iterate',
      children: [
        {
          type: 'check',
          checker: 'isArray',
          children: [
            {
              type: 'call',
              function: 'parse'
            }
          ]
        },
        {
          type: 'check',
          checker: 'isNumber',
          children: [
            {
              type: 'check',
              checker: 'isEven',
              children: [
                {
                  type: 'push',
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Basically my real problem is I have something like this JSON in a custom programming language, and I want to convert it into a state machine rather than the nested/recursive function calls like we started with in this post.

So my question is, how can you rewrite the recursive function system from the beginning of this post, such that it uses a state machine instead? You don't have to go all the way and make the state machine from the JSON (which in this example is incomplete, as I don't have a good example to simplify from). Instead, just if you could show how to rewrite this recursive or nested function system from the beginning of this post as a state machine, that would be all.

What I am imagining is something like this:

let transitions = [
  function1,
  function2,
  ...
]

let transition = transitions[0] // the start function in theory
let currentInput = input
let someStack = []
while (transition) {
  [currentInput, transition] = transition(someStack, currentInput)
}

But I quickly get lost on how I would keep track of the position we are at in the input, as well as how to handle things like iteration (as in the iterator), or "if statements" (as in the check).

function iterate(input) {
  // you can't do the recursive call here,
  // as the original while loop should handle this.
  // but, we should return some reference to the current input,
  // as well as the next transition.
}

If a language must be chosen then doing this in JavaScript would be simplest. But it can even be done in pseudocode to show generally how it's done.



from How to convert nested function call tree to state machine?

No comments:

Post a Comment