Last active
February 3, 2018 23:02
-
-
Save aciidgh/c3553333426cc2680f5e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public func getASTString() -> String { | |
// get the file path for the file "test.json" in the playground bundle | |
// let filePath = NSBundle.mainBundle().pathForResource("FirstTtest", ofType: "ast") | |
// get the contentData | |
let contentData = NSFileManager.defaultManager().contentsAtPath("a.txt") | |
// get the string | |
let content = NSString(data: contentData!, encoding: NSUTF8StringEncoding) as? String | |
return content! | |
} | |
extension String { | |
/** | |
Remove trailing newline characters. By default chomp removes | |
all trailing \n (UNIX) or all trailing \r\n (Windows) (it will | |
not remove mixed occurrences of both separators. | |
*/ | |
public func chomp(separator: String? = nil) -> String { | |
func scrub(separator: String) -> String { | |
var E = endIndex | |
while self[startIndex..<E].hasSuffix(separator) && E > startIndex { | |
E = E.predecessor() | |
} | |
return self[startIndex..<E] | |
} | |
if let separator = separator { | |
return scrub(separator) | |
} else if hasSuffix("\r\n") { | |
return scrub("\r\n") | |
} else if hasSuffix("\n") { | |
return scrub("\n") | |
} else { | |
return self | |
} | |
} | |
/** | |
Trims whitespace from both ends of a string, if the resulting | |
string is empty, returns `nil`.String | |
Useful because you can short-circuit off the result and thus | |
handle “falsy” strings in an elegant way: | |
return userInput.chuzzle() ?? "default value" | |
*/ | |
public func chuzzle() -> String? { | |
var cc = characters | |
loop: while true { | |
switch cc.first { | |
case .None: | |
return nil | |
case .Some("\n"), .Some("\r"), .Some(" "), .Some("\t"), .Some("\r\n"): | |
cc = cc.dropFirst() | |
default: | |
break loop | |
} | |
} | |
loop: while true { | |
switch cc.last { | |
case .None: | |
return nil | |
case .Some("\n"), .Some("\r"), .Some(" "), .Some("\t"), .Some("\r\n"): | |
cc = cc.dropLast() | |
default: | |
break loop | |
} | |
} | |
return String(cc) | |
} | |
} | |
let astString = getASTString() | |
enum Type: String { | |
case Class = "class_decl" | |
case Fn = "func_decl" | |
case Unknown = "" | |
} | |
class Node: CustomStringConvertible { | |
var contents: String = "" | |
var nodes: [Node] = [] | |
init() { | |
} | |
var description: String { | |
if nodes.count > 0 { | |
return "\(contents) \(nodes)" | |
} | |
return "\(contents)" | |
} | |
var type: Type { | |
if contents.hasPrefix(Type.Class.rawValue) { | |
return .Class | |
} | |
if contents.hasPrefix(Type.Fn.rawValue) { | |
return .Fn | |
} | |
return .Unknown | |
} | |
var name: String { | |
switch type { | |
case .Class: fallthrough | |
case .Fn: | |
var str = "" | |
var quoteBegan: Bool = false | |
for char in self.contents.characters { | |
if char == "\"" { | |
if quoteBegan { return str[str.startIndex.successor()..<str.endIndex] } | |
quoteBegan = true | |
} | |
if quoteBegan { str += "\(char)" } | |
} | |
return str | |
default: | |
return "" | |
} | |
} | |
} | |
var stack = Array<Node>() | |
var data = "" | |
var quoteStarted: Bool = false | |
var sources: [Node] = [] | |
for var index in astString.characters.startIndex..<astString.characters.endIndex { | |
let char = astString.characters[index] | |
func peekNext() -> String { | |
return "\(astString.characters[index.successor()])" | |
} | |
if char == "(" && !quoteStarted { | |
let node = Node() | |
if data.characters.count > 0, let lastNode = stack.last, let chuzzed = data.chuzzle() { | |
lastNode.contents = chuzzed | |
if lastNode.contents == "source_file" { sources += [lastNode] } | |
} | |
stack.append(node) | |
data = "" | |
} else if char == ")" && !quoteStarted { | |
if case let poppedNode = stack.removeLast() where stack.count > 0 { | |
if data.characters.count > 0, let chuzzed = data.chuzzle() { | |
poppedNode.contents = chuzzed | |
} | |
stack.last!.nodes += [poppedNode] | |
data = "" | |
} | |
} else { | |
var charToAppend = char | |
data = data + String(char) | |
if char == "\"" || char == "'" { quoteStarted = !quoteStarted } | |
} | |
} | |
// print(sources) | |
print(sources.count) | |
//// | |
for source in sources { | |
for node in source.nodes where node.type == .Class && node.name.characters.count > 3 { | |
// guard let _ = node.name.chuzzle() else { continue } | |
print("----------------") | |
print(node.name) | |
print("----------------") | |
for classNode in node.nodes where classNode.type == .Fn && classNode.name.characters.count > 3 { | |
print(classNode.name) | |
} | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@prabodhprakash
There's a way to spit out swift gramma file if you dig around here
https://github.com/johndpope/ANTLR-Swift-Target
Run time walker here
https://github.com/johndpope/Antlr-Swift-Runtime/tree/master/Test/Test
If you run into issue log to antlr repo.