the set of options at any point are determined by the methods available on the class at that point. the class returned by that method determines the next set of methods.
so the rules for the grammar that generates the chain is a right regular grammar where the start symbols are classes, the symbols are methods, and the non-terminals are the classes returned by the methods:
class Car:
configure: Configurator
class Configurator:
with: Configurator // noise method
and: Configurator // noise method
wheels: int -> Configurator
windows: int -> WindowDetails
class WindowDetails:
transparent -> Configurator
tinted -> Configurator
ignoring the method args (int):
Car -> "configure" Configurator
Configurator -> "with" Configurator
Configurator -> "and" Configurator
Configurator -> "wheels" Configurator
Configurator -> "windows" WindowDetails
WindowDetails -> "transparent" Configurator
WindowDetails -> "tinted" Configurator
but what this fails to capture is the argument to wheels (the number of wheels). and a regular grammar can't handle that because different integer arguments might lead to different classes (eg after "(2)" do you have a Configurator or a WindowDetails?):
Configurator -> "wheels" Integer
Configurator -> "windows" Integer
Integer -> ?
so it depends what you want. the chain of methods can be described by a regular grammar. but a regular grammar cannot also describe the arguments passed to the methods. afaict.
you can handle arguments by adding the complexity of context free grammars, because then you can do something like:
Configurator -> "wheels" Integer Configurator
Configurator -> "windows" Integer WindowDetails
which has the extra info needed to continue correctly after the integer argument.
NOTE: the above assumes that method names are unique across all classes. if you have two different classes with the same method name then you are going to have problems, obviously (i hope) (and this might not so rare if you are using things like "with" and "and"....)