blob: 428ca9ea10dfa3a367d227f74a4279c742123f57 [file] [log] [blame]
/*
* Copyright 2015-2016 IBM Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import Foundation
public struct ActionToken {
var actionName: String
var actionCode: String
}
enum TokenState {
case InStarComment
case InSlashComment
case Initial
case inClass
case inClassName
case inClassQualifier
case skippingBlock
case parseAction
}
public class WhiskTokenizer {
var atPath: String!
var toPath: String!
public var actions = [ActionToken]()
public init(from: String, to: String) {
atPath = from
toPath = to
}
public func readXCodeProjectDirectory() throws {
let dir: FileManager = FileManager.default
if let enumerator: FileManager.DirectoryEnumerator = dir.enumerator(atPath: atPath) {
while let item = enumerator.nextObject() as? NSString {
var isDir = ObjCBool(false)
let fullPath = atPath+"/\(item)"
//print("===== inspecting \(fullPath)")
if dir.fileExists(atPath: fullPath, isDirectory: &isDir) == true {
if isDir.boolValue == true {
} else if item.hasSuffix(".swift") {
do {
let fileStr = try String(contentsOfFile: fullPath)
if let actionArray = getActions(str: fileStr) {
for action in actionArray {
print("action: \(action.actionName), code: \(action.actionCode)")
actions.append(action)
do {
let fileUrl = URL(fileURLWithPath: toPath+"/\(action.actionName).swift")
try action.actionCode.write(to: fileUrl, atomically: false, encoding: String.Encoding.utf8)
} catch {
print("Error writing actions from Xcode \(error)")
}
}
}
} catch {
print("Error \(error)")
}
}
}
}
}
}
func getActions(str: String) -> [ActionToken]? {
let scanner = Scanner(string: str)
var line: NSString?
var state = TokenState.Initial
var actionArray: [ActionToken]? = [ActionToken]()
var actionName = ""
var actionCode = ""
var leftBracketCount = 0
var rightBracketCount = 0
while scanner.scanUpToCharacters(from: CharacterSet.newlines, into: &line) {
// print("Scan location is \(scanner.scanLocation)")
guard let line = line else {
print("Line is somehow null, quitting")
return nil
}
var trimmedLine = line.trimmingCharacters(in: CharacterSet.whitespaces)
//print("Inspecting line \(trimmedLine)")
if trimmedLine.hasPrefix("//") {
//print("Skipping comment")
} else if trimmedLine.hasPrefix("/*") {
state = TokenState.InStarComment
} else {
switch state {
case .Initial:
if trimmedLine.hasPrefix("class") {
let classStr = trimmedLine.components(separatedBy: ":")
if classStr.count > 1 {
if classStr[1].range(of: "WhiskAction") != nil {
// get actionName
let classIndex = classStr[0].characters.index(classStr[0].startIndex, offsetBy: 6)
actionName = classStr[0].substring(from: classIndex).trimmingCharacters(in: CharacterSet.whitespaces)
state = TokenState.parseAction
var tok = trimmedLine.components(separatedBy: "{")
leftBracketCount = tok.count - 1
tok = trimmedLine.components(separatedBy: "}")
rightBracketCount = tok.count - 1
}
}
} else {
//print("Don't care, looking for class")
}
case .parseAction:
print("ParseAction: \(trimmedLine)")
var lookingForLeftBracket = false
if leftBracketCount == 0 {
lookingForLeftBracket = true
}
var tok = trimmedLine.components(separatedBy: "{")
leftBracketCount = leftBracketCount + (tok.count - 1)
tok = trimmedLine.components(separatedBy: "}")
rightBracketCount = rightBracketCount + (tok.count - 1)
if leftBracketCount == rightBracketCount {
// drop extra bracket
let lastLine = String(trimmedLine.characters.dropLast())
if lookingForLeftBracket == false {
actionCode = actionCode + "\n" + lastLine
}
let newAction = ActionToken(actionName: actionName, actionCode: actionCode)
actionArray?.append(newAction)
state = TokenState.Initial
actionName = ""
actionCode = ""
leftBracketCount = 0
rightBracketCount = 0
state = TokenState.Initial
} else {
let range = trimmedLine.range(of: "func run(")
if range != nil {
trimmedLine.replaceSubrange(range!, with: "func main(")
}
if lookingForLeftBracket == false {
actionCode = actionCode + "\n"+trimmedLine
}
}
case .InStarComment:
if trimmedLine.hasSuffix("*/") {
state = TokenState.Initial
}
default:
//print("Don't care")
break
}
}
}
if state == .parseAction {
let code = String(actionCode.characters.dropLast())
let newAction = ActionToken(actionName: actionName, actionCode: code)
actionArray?.append(newAction)
}
return actionArray
}
}