///|
fn field(node : Json, name : String) -> Json? {
match node {
Object(fields) => fields.get(name)
_ => None
}
}
///|
fn text_field(node : Json, name : String) -> String? {
match field(node, name) {
Some(String(value)) => Some(value)
_ => None
}
}
///|
fn int_field(node : Json, name : String) -> Int? {
match field(node, name) {
Some(Number(value, ..)) => Some(value.to_int())
_ => None
}
}
///|
fn array_field(node : Json, name : String) -> Array[Json] {
match field(node, name) {
Some(Array(items)) => items
_ => []
}
}
///|
fn type_spelling(node : Json) -> String? {
match field(node, "type") {
Some(ty) => text_field(ty, "qualType")
None => None
}
}
///|
fn canonical_type_spelling(node : Json) -> String? {
match field(node, "type") {
Some(ty) =>
match text_field(ty, "desugaredQualType") {
Some(value) => Some(value)
None => text_field(ty, "qualType")
}
None => None
}
}
///|
fn source_file(node : Json) -> String? {
match field(node, "loc") {
Some(loc) => text_field(loc, "file")
None => None
}
}
///|
priv struct SourceLocation {
file : String
line : Int
}
///|
priv struct LocatedNode {
node : Json
source : SourceLocation
}
///|
fn located_nodes(ast : Json) -> Array[LocatedNode] {
let result : Array[LocatedNode] = []
let mut current_file = ""
for node in array_field(ast, "inner") {
match source_file(node) {
Some(path) => current_file = path
None => ()
}
let line = match field(node, "loc") {
Some(loc) => int_field(loc, "line").unwrap_or(0)
None => 0
}
result.push({ node, source: { file: current_file, line, }, })
}
result
}
///|
fn normalized_path(path : String) -> String {
path.replace_all(old="\\", new="/").to_lower()
}
///|
fn same_header(source : String, header : String) -> Bool {
let source = normalized_path(source)
let header = normalized_path(header)
source == header ||
header.has_suffix("/" + source) ||
source.has_suffix("/" + header)
}