This problem breaks down into:
Parsing the string
Evaluating the resulting function graph
Dispatching to each function (as part of #2 above)
Parsing the string
Unfortunately, with the requirements you have, parsing the {{...}}
string is quite complex. You have at least these issues to deal with:
Functions can be nested {{function1(function2(), 2, 3)}}
.
Strings can contain (escaped) quotes, and can contain commas, so even without requirement #1 above the trivial approach to finding the discrete arguments (splitting on a comma) won't work.
So...you need a proper parser. You could try to cobble one together ad hoc, but this is where parser generators come into the picture, like PEG.js or Jison (those are just examples, not necessarily recommendations — I did happen to notice one of the Jison examples is a JSON parser, which would be about half the battle). Writing a parser is out of scope for answering a question on SO I'm afraid. :-)
Evaluating the resulting function graph
Depending on what tool you use, your parser generator may handle this for you. (I'm pretty sure PEG.js and Jison both would, for instance.)
If not, then after parsing you'll presumably end up with an object graph of some sort, which gives you the functions and their arguments (which might be functions with arguments...which might be...).
- functionA
- 1
- "two"
- functionB
- functionD
- 27
functionA there has five arguments, the third of which is functionB with two arguments, and so on.
Your next task, then, is to evaluate those functions deepest first (and at the same depth, left-to-right) and replace them in the relevant arguments list with their result, so you'll need a depth-first traversal algorithm. By deepest first and left-to-right (top-to-bottom in the bullet list above) I mean that in the list above, you have to call functionC first, then functionB, then functionD, and finally functionA.
Dispatching to each function
Depending again on the tool you use, it may handle this bit too. Again I suspect PEG.js does, and I wouldn't be surprised if Jison did as well.
At the point where you're ready to call a function that (no longer) has function calls as arguments, you'll presumably have the function name and an array of arguments. Assuming you store your functions in a map:
var functions = {
index: function() { /* ... */ },
firstName: function() { /* ... */ },
// ...
};
...calling them is the easy bit:
functionResult = functions[functionName].apply(undefined, functionArguments);
I'm sorry not to be able to say "Just do X, and you're there," but it really isn't a trivial problem. I would throw tools at it, I wouldn't invent this wheel myself.