Idea: If axiom is a string: just use string operations (because they are faster), but once a production tries to return an object, transform axiom into list of objects so it can work without errors.
Vice versa, when the axiom is a list of objects, any productions result that is only strings would be auto-transformed into list of objects.
This makes it possible to write shorter productions in productions where you eg. don't need parameters, while maintaining flexibility when you want to use a more complex (context sensitive, parametric) production.
Instead of writing
let lsystem = new LSystem({
axiom: [{symbol: 'A'}, {symbol: 'B', myParameter: 23}, {symbol: 'C'}],
productions: {
'A': [{symbol: 'B'}, {symbol: 'A'}, {symbol: 'B'}, {symbol: 'A'}, {symbol: 'A'}]
'B': ({part, myParameter}) => {return (myParameter === 23) ? {symbol: 'C'} : part},
'C': [{symbol: 'B'}, {symbol: 'A'}]
}
})
You could write:
let lsystem = new LSystem({
axiom: [{symbol: 'B'}, {symbol: 'B', myParameter: 23}, {symbol: 'C'}],
productions: {
'A': 'BABAA'
'B': ({part, myParameter}) => {return (myParameter === 23) ? {symbol: 'C'} : part},
'C': 'AB'
}
})
Should then also mixed iterables be allowed? like:
'B': ['BC', {symbol: 'B', myParameter: 23}, 'C']
Or would it create too much oerhead in general?