Code Generation
extension Expression {
func parenthesize(_ s: String) -> String { return "(\(s))" }
var isOperatorCall: Bool {
switch kind {
case .call:
guard let funcName = args.first else { return false }
switch funcName {
case "+", "-", "*", "%", "/", "||", "&&", "&", "|", "==", ">", "<", ">=", "<=", "[]", "..":
return true
default:
return false
}
default:
return false
}
}
func asRuby(depth: Int = 0) -> String {
let indent = String(repeating: " ", count: 2 * depth)
switch kind {
case .bare:
return args.joined(separator: " ")
case .call:
if isOperatorCall {
let op = args.first!
let rec = children.first!
let opArgs = children.dropFirst()
return parenthesize(rec.asRuby(depth: depth + 1)) + ".\(op)" + parenthesize(opArgs.map { $0.asRuby(depth: depth + 1) }.joined(separator: ", "))
}
else {
return args.joined(separator: " ") + "(" + children.map { "(\($0.asRuby(depth: depth + 1)))" }.joined(separator: ",\n\(indent)") + ")"
}
case .functionDefinition:
let name = args.first!
let argNames = args.dropFirst()
return "def \(name)(\(argNames.joined(separator: ", ")))\n" + children.map { indent + $0.asRuby(depth: depth + 1) }.joined(separator: "\n") + "\nend"
case .empty:
return ""
case .variableDeclaration:
let varName = args.joined(separator: " ")
return "\(varName) = (\(children.map {$0.asRuby(depth: depth + 1)}.joined(separator: ", ")))"
case .conditional:
guard children.count == 3 else {
fatalError("a conditional must have exactly three arguments")
}
let conditional = children[0]
let positive = children[1]
let negative = children[2]
return "if \(conditional.asRuby(depth: depth + 1))\n\(indent) \(positive.asRuby(depth: depth + 1))\nelse\n\(indent) \(negative.asRuby(depth: depth + 1))\nend"
}
}
}