///|
pub(all) struct FunctionInfo {
name : String
start_line : Int
end_line : Int
tree : TreeNode
}
///|
pub impl Show for FunctionInfo with output(self, logger) {
logger.write_string("FunctionInfo(")
logger.write_string(self.name)
logger.write_string(", lines=")
logger.write_string(self.start_line.to_string())
logger.write_string("-")
logger.write_string(self.end_line.to_string())
logger.write_string(")")
}
///|
priv struct IdGenerator {
mut next_id : Int
}
///|
fn IdGenerator::new() -> IdGenerator {
{ next_id: 0 }
}
///|
fn IdGenerator::next(self : IdGenerator) -> Int {
let id = self.next_id
self.next_id = self.next_id + 1
id
}
///|
pub fn extract_functions(source : String) -> Array[FunctionInfo] {
let (impls, _) = @parser.parse_string(source)
let functions : Array[FunctionInfo] = []
let id_gen = IdGenerator::new()
for impl_ in impls {
match impl_ {
TopFuncDef(fun_decl~, decl_body~, loc~) => {
let name = fun_decl.name.name
let tree = decl_body_to_tree(decl_body, id_gen)
functions.push({
name,
start_line: loc.start.lnum,
end_line: loc.end.lnum,
tree,
})
}
TopImpl(method_name~, body~, loc~, ..) => {
let name = method_name.name
let tree = decl_body_to_tree(body, id_gen)
functions.push({
name,
start_line: loc.start.lnum,
end_line: loc.end.lnum,
tree,
})
}
TopTest(expr~, name~, loc~, ..) => {
let test_name = match name {
Some((s, _)) => "test:\{s}"
None => "test"
}
let tree = expr_to_tree(expr, id_gen)
functions.push({
name: test_name,
start_line: loc.start.lnum,
end_line: loc.end.lnum,
tree,
})
}
_ => ()
}
}
functions
}
///|
fn decl_body_to_tree(body : @syntax.DeclBody, id_gen : IdGenerator) -> TreeNode {
match body {
DeclNone => TreeNode::new("DeclNone", "", id_gen.next())
DeclBody(expr~, ..) => expr_to_tree(expr, id_gen)
DeclStubs(stubs) =>
match stubs {
Import(module_name~, func_name~, ..) => {
let node = TreeNode::new(
"Import",
"\{module_name}:\{func_name}",
id_gen.next(),
)
node
}
Embedded(..) => TreeNode::new("Embedded", "", id_gen.next())
}
}
}
///|
fn expr_to_tree(expr : @syntax.Expr, id_gen : IdGenerator) -> TreeNode {
match expr {
Apply(func~, args~, ..) => {
let node = TreeNode::new("Apply", "", id_gen.next())
node.add_child(expr_to_tree(func, id_gen))
for arg in args {
node.add_child(expr_to_tree(arg.value, id_gen))
}
node
}
Infix(op~, lhs~, rhs~, ..) => {
let op_name = match op.name {
Ident(name~) => name
Dot(pkg~, id~) => "\{pkg}.\{id}"
}
let node = TreeNode::new("Infix", op_name, id_gen.next())
node.add_child(expr_to_tree(lhs, id_gen))
node.add_child(expr_to_tree(rhs, id_gen))
node
}
Unary(op~, expr~, ..) => {
let op_name = match op.name {
Ident(name~) => name
Dot(pkg~, id~) => "\{pkg}.\{id}"
}
let node = TreeNode::new("Unary", op_name, id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
Array(exprs~, ..) => {
let node = TreeNode::new("Array", "", id_gen.next())
for e in exprs {
node.add_child(expr_to_tree(e, id_gen))
}
node
}
ArraySpread(elems~, ..) => {
let node = TreeNode::new("ArraySpread", "", id_gen.next())
for elem in elems {
match elem {
Regular(e) => node.add_child(expr_to_tree(e, id_gen))
Spread(expr~, ..) => {
let spread_node = TreeNode::new("Spread", "", id_gen.next())
spread_node.add_child(expr_to_tree(expr, id_gen))
node.add_child(spread_node)
}
}
}
node
}
ArrayGet(array~, index~, ..) => {
let node = TreeNode::new("ArrayGet", "", id_gen.next())
node.add_child(expr_to_tree(array, id_gen))
node.add_child(expr_to_tree(index, id_gen))
node
}
ArrayGetSlice(array~, start_index~, end_index~, ..) => {
let node = TreeNode::new("ArrayGetSlice", "", id_gen.next())
node.add_child(expr_to_tree(array, id_gen))
match start_index {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
match end_index {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
ArraySet(array~, index~, value~, ..) => {
let node = TreeNode::new("ArraySet", "", id_gen.next())
node.add_child(expr_to_tree(array, id_gen))
node.add_child(expr_to_tree(index, id_gen))
node.add_child(expr_to_tree(value, id_gen))
node
}
ArrayAugmentedSet(op~, array~, index~, value~, ..) => {
let op_name = match op.name {
Ident(name~) => name
Dot(pkg~, id~) => "\{pkg}.\{id}"
}
let node = TreeNode::new("ArrayAugmentedSet", op_name, id_gen.next())
node.add_child(expr_to_tree(array, id_gen))
node.add_child(expr_to_tree(index, id_gen))
node.add_child(expr_to_tree(value, id_gen))
node
}
Constant(c~, ..) => {
let label = match c {
Bool(_) => "Bool"
Byte(_) => "Byte"
Bytes(_) => "Bytes"
Char(_) => "Char"
Int(_) => "Int"
Int64(_) => "Int64"
UInt(_) => "UInt"
UInt64(_) => "UInt64"
Float(_) => "Float"
Double(_) => "Double"
String(_) => "String"
BigInt(_) => "BigInt"
}
TreeNode::new("Constant", label, id_gen.next())
}
MultilineString(..) => TreeNode::new("MultilineString", "", id_gen.next())
Interp(elems~, ..) => {
let node = TreeNode::new("Interp", "", id_gen.next())
for elem in elems {
match elem {
Expr(expr~, ..) => node.add_child(expr_to_tree(expr, id_gen))
_ => ()
}
}
node
}
Constraint(expr~, ..) => {
let node = TreeNode::new("Constraint", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
Constr(constr~, ..) =>
TreeNode::new("Constr", constr.name.name, id_gen.next())
While(loop_cond~, loop_body~, while_else~, ..) => {
let node = TreeNode::new("While", "", id_gen.next())
node.add_child(expr_to_tree(loop_cond, id_gen))
node.add_child(expr_to_tree(loop_body, id_gen))
match while_else {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
Function(func~, ..) => {
let node = TreeNode::new("Function", "", id_gen.next())
node.add_child(expr_to_tree(func.body, id_gen))
node
}
Ident(id~, ..) => {
let name = match id.name {
Ident(name~) => name
Dot(pkg~, id~) => "\{pkg}.\{id}"
}
TreeNode::new("Ident", name, id_gen.next())
}
If(cond~, ifso~, ifnot~, ..) => {
let node = TreeNode::new("If", "", id_gen.next())
node.add_child(expr_to_tree(cond, id_gen))
node.add_child(expr_to_tree(ifso, id_gen))
match ifnot {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
Guard(cond~, otherwise~, body~, ..) => {
let node = TreeNode::new("Guard", "", id_gen.next())
node.add_child(expr_to_tree(cond, id_gen))
match otherwise {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node.add_child(expr_to_tree(body, id_gen))
node
}
Is(expr~, ..) => {
let node = TreeNode::new("Is", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
IsLexMatch(expr~, ..) => {
let node = TreeNode::new("IsLexMatch", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
Defer(expr~, body~, ..) => {
let node = TreeNode::new("Defer", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node.add_child(expr_to_tree(body, id_gen))
node
}
LetFn(func~, body~, ..) => {
let node = TreeNode::new("LetFn", "", id_gen.next())
node.add_child(expr_to_tree(func.body, id_gen))
node.add_child(expr_to_tree(body, id_gen))
node
}
LetRec(bindings~, body~, ..) => {
let node = TreeNode::new("LetRec", "", id_gen.next())
for binding in bindings {
let (_, func) = binding
node.add_child(expr_to_tree(func.body, id_gen))
}
node.add_child(expr_to_tree(body, id_gen))
node
}
LetAnd(bindings~, body~, ..) => {
let node = TreeNode::new("LetAnd", "", id_gen.next())
for binding in bindings {
let (_, _, func) = binding
node.add_child(expr_to_tree(func.body, id_gen))
}
node.add_child(expr_to_tree(body, id_gen))
node
}
Let(expr~, body~, ..) => {
let node = TreeNode::new("Let", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node.add_child(expr_to_tree(body, id_gen))
node
}
Sequence(exprs~, last_expr~, ..) => {
let node = TreeNode::new("Sequence", "", id_gen.next())
for e in exprs {
node.add_child(expr_to_tree(e, id_gen))
}
node.add_child(expr_to_tree(last_expr, id_gen))
node
}
Tuple(exprs~, ..) => {
let node = TreeNode::new("Tuple", "", id_gen.next())
for e in exprs {
node.add_child(expr_to_tree(e, id_gen))
}
node
}
Record(fields~, ..) => {
let node = TreeNode::new("Record", "", id_gen.next())
for field in fields {
node.add_child(expr_to_tree(field.expr, id_gen))
}
node
}
RecordUpdate(record~, fields~, ..) => {
let node = TreeNode::new("RecordUpdate", "", id_gen.next())
node.add_child(expr_to_tree(record, id_gen))
for field in fields {
node.add_child(expr_to_tree(field.expr, id_gen))
}
node
}
Field(record~, ..) => {
let node = TreeNode::new("Field", "", id_gen.next())
node.add_child(expr_to_tree(record, id_gen))
node
}
Method(..) => TreeNode::new("Method", "", id_gen.next())
DotApply(self~, args~, ..) => {
let node = TreeNode::new("DotApply", "", id_gen.next())
node.add_child(expr_to_tree(self, id_gen))
for arg in args {
node.add_child(expr_to_tree(arg.value, id_gen))
}
node
}
As(expr~, ..) => {
let node = TreeNode::new("As", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
Mutate(record~, field~, ..) => {
let node = TreeNode::new("Mutate", "", id_gen.next())
node.add_child(expr_to_tree(record, id_gen))
node.add_child(expr_to_tree(field, id_gen))
node
}
Match(expr~, cases~, ..) => {
let node = TreeNode::new("Match", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
for case in cases {
node.add_child(expr_to_tree(case.body, id_gen))
}
node
}
LexMatch(expr~, cases~, ..) => {
let node = TreeNode::new("LexMatch", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
for case in cases {
node.add_child(expr_to_tree(case.body, id_gen))
}
node
}
LetMut(expr~, body~, ..) => {
let node = TreeNode::new("LetMut", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node.add_child(expr_to_tree(body, id_gen))
node
}
Pipe(lhs~, rhs~, ..) => {
let node = TreeNode::new("Pipe", "", id_gen.next())
node.add_child(expr_to_tree(lhs, id_gen))
node.add_child(expr_to_tree(rhs, id_gen))
node
}
Assign(expr~, ..) => {
let node = TreeNode::new("Assign", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
Hole(..) => TreeNode::new("Hole", "", id_gen.next())
Return(return_value~, ..) => {
let node = TreeNode::new("Return", "", id_gen.next())
match return_value {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
Raise(err_value~, ..) => {
let node = TreeNode::new("Raise", "", id_gen.next())
node.add_child(expr_to_tree(err_value, id_gen))
node
}
Unit(..) => TreeNode::new("Unit", "", id_gen.next())
Break(arg~, ..) => {
let node = TreeNode::new("Break", "", id_gen.next())
match arg {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
Continue(args~, ..) => {
let node = TreeNode::new("Continue", "", id_gen.next())
for e in args {
node.add_child(expr_to_tree(e, id_gen))
}
node
}
Loop(arg~, body~, ..) => {
let node = TreeNode::new("Loop", "", id_gen.next())
node.add_child(expr_to_tree(arg, id_gen))
for case in body {
node.add_child(expr_to_tree(case.body, id_gen))
}
node
}
For(binders~, condition~, continue_block~, body~, for_else~, ..) => {
let node = TreeNode::new("For", "", id_gen.next())
for binder in binders {
let (_, e) = binder
node.add_child(expr_to_tree(e, id_gen))
}
match condition {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
for cont in continue_block {
let (_, e) = cont
node.add_child(expr_to_tree(e, id_gen))
}
node.add_child(expr_to_tree(body, id_gen))
match for_else {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
ForEach(expr~, body~, else_block~, ..) => {
let node = TreeNode::new("ForEach", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node.add_child(expr_to_tree(body, id_gen))
match else_block {
Some(e) => node.add_child(expr_to_tree(e, id_gen))
None => ()
}
node
}
Try(body~, catch_~, try_else~, ..) => {
let node = TreeNode::new("Try", "", id_gen.next())
node.add_child(expr_to_tree(body, id_gen))
for case in catch_ {
node.add_child(expr_to_tree(case.body, id_gen))
}
match try_else {
Some(cases) =>
for case in cases {
node.add_child(expr_to_tree(case.body, id_gen))
}
None => ()
}
node
}
TryOperator(body~, ..) => {
let node = TreeNode::new("TryOperator", "", id_gen.next())
node.add_child(expr_to_tree(body, id_gen))
node
}
Map(elems~, ..) => {
let node = TreeNode::new("Map", "", id_gen.next())
for elem in elems {
node.add_child(expr_to_tree(elem.expr, id_gen))
}
node
}
Group(expr~, ..) => {
let node = TreeNode::new("Group", "", id_gen.next())
node.add_child(expr_to_tree(expr, id_gen))
node
}
StaticAssert(body~, ..) => {
let node = TreeNode::new("StaticAssert", "", id_gen.next())
node.add_child(expr_to_tree(body, id_gen))
node
}
}
}