0

I have a PEG -based parser, processing text input. In addition to regular macros, it supports nesting - macro within a macro.

My code peg processor function - async macroBuilder() wraps every visit() - method used to process a specific type macro in a Promise as:

dateMath(obj) {
  const dateAttribs = { format: obj.format };
  switch (dateAttribs.format) {
    ...
    default:
      fragments.push(
        new Promise((resolve, reject) => {
          resolve(moment(now).format(dateAttribs.format));
        });
      );
      break;
  }
}

To process nested macros, I do:

nestedSnippet(obj) {
  fragments.push(
    processSingleShortcut(constants.SHORTCUT_PREFIX.concat(obj.name), true)
    .then(res => {
      let result = macroBuilder(res, { retainWhitespace: true, nestedLevel: nestedLevel+1 }, clipboard, window.now);
      return result;
    })
    .catch(() => {
      console.log(`couldn't find match for nested snippet: ${obj.name}`);
    })
  );
}

At the end, I do Promise.all() and join all the pieces into a string.

However, it appears that the nested part is not working, like I want to. The idea is to push into fragments a Promise that when being resolved will:

  1. call processSingleShortcut()
  2. use result of the previous call as an argument for an async function macroBuilder()
  3. return the result of macroBuilder()

I need this because in addition to returning strings as a result, macro processing may have side-effects and I need those from all previous macros to correctly process the next one in the fragments array.

Hence, I need nested already processed before the macro following it is being evaluated. It does not seem to wrap a promise around nested macros, I need to.

Moshe Shmukler
  • 1,270
  • 2
  • 21
  • 43
  • "*a promise that when being resolved will call `processSingleShortcut()`*" - that's not how promises work. You are calling `processSingleShortcut()` immediately, and it returns a promise that will resolve (by itself!) when its done. – Bergi Dec 12 '17 at 15:31
  • If you want to iterate sequentially, you cannot use `Promise.all`. Instead you need to chain your function calls for every macro onto each other – Bergi Dec 12 '17 at 15:34
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all Takes an iterable (that is, an object that supports the Iterator interface) as a parameter and later on calls PerformPromiseAll( iterator, constructor, resultCapability) with it, where the latter loops over iterable using IteratorStep(iterator). This means that if if the iterable you pass in to Promise.all() is strictly ordered, they will still be ordered once passed in. – Moshe Shmukler Dec 12 '17 at 16:01
  • So what does that have to do with your question? – Bergi Dec 12 '17 at 16:04
  • @Bergi just helping you to understand how `Promise.all()` works, so you know. – Moshe Shmukler Dec 12 '17 at 16:06
  • Thanks, I know perfectly fine how `Promise.all` works, that's why I'm suggesting that it doesn't fit your problem. – Bergi Dec 12 '17 at 16:10
  • No, you don't. Since `fragments` is an array, the promises will be resolved in the same order as they are in the array. I thought that you could understand this from the documentation. – Moshe Shmukler Dec 12 '17 at 16:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/161045/discussion-between-moshe-shmukler-and-bergi). – Moshe Shmukler Dec 12 '17 at 16:15
  • All what that documentation is trying to get across is that [the results array is in the same order as the original promises](https://stackoverflow.com/a/28066825/1048572) - independent from the temporal order in which the resolutions happened. And no, `Promise.all` does not "resolve" the promises, and not in a particular order. It just waits for them to resolve (on their own). – Bergi Dec 12 '17 at 16:17

0 Answers0