I'm trying to represent a function call so that I can make a little scripting language for creating games. Right now I'm just trying to set up the interfaces between all the protocols and classes that I need. I have a class, FunctionCall<T>. It has a method execute() that executes the current function and returns an instance of type T?. FunctionCall also has a an array of instances of type FunctionCall to represent any parameters. It also has a field, stringRepresentation, which is a string representation of the function call, which the user will enter. This string might be something like createNode(named: myCircle) or, in the base case, it might be just a literal, like myCircle. To be clear, myCircle in this case is a String. I'm probably going to choose not to use quotation marks around Strings in my little scripting language.
My problem is with the execute() method. I want to return an instance of type T. So far, I've thought of enforcing that T conforms to a protocol (let's call it Parseable) that enforces that it has a method that takes a String and returns an instance of type T. The problem I found with that approach is that I have no way of creating such a method, because I don't have a way to reference the type that will be implementing the protocol from within the protocol. In other words, if T is SKShapeNode, I have no way or referencing SKShapeNode from within Parseable, so that I can indicate that the return type must be an SKShapeNode. The other approach I found is to make Parseable have a required initializer that takes a String. This works when structs implement the protocol, but not with classes. The problem I get when I try to implement the protocol in a class is that the class wants me to make the initializer required, but I can't do that because I can't put a required initializer in an extension.
I want the FunctionCall class to look something like this
class FunctionCall<T: Parseable> {
var parameters = [FunctionCall]()
var stringRepresentation: String!
init(stringRepresentation: String) {
self.stringRepresentation = stringRepresentation
}
func execute() -> T? {
guard let indexOfFirstLeftParen = stringRepresentation.firstIndex(of: "("),
let indexOfLastRightParen = stringRepresentation.lastIndex(of: ")") else {
// then this is a literal value, because no function is being called
return T(string: stringRepresentation)
}
// TODO: implement
return nil
}
}