Forráskód Böngészése

Add option to print ast

Signed-off-by: Sean Young <sean@mess.org>
Sean Young 5 éve
szülő
commit
8487f7e17f
4 módosított fájl, 667 hozzáadás és 1 törlés
  1. 3 0
      docs/running.rst
  2. 6 1
      src/bin/solang.rs
  3. 1 0
      src/sema/mod.rs
  4. 657 0
      src/sema/printer.rs

+ 3 - 0
docs/running.rst

@@ -67,6 +67,9 @@ Options:
 
   Phase:
 
+  ast
+    Output Abstract Syntax Tree, the parsed and resolved input
+
   cfg
     Output control flow graph.
 

+ 6 - 1
src/bin/solang.rs

@@ -47,7 +47,7 @@ fn main() {
                 .help("Emit compiler state at early stage")
                 .long("emit")
                 .takes_value(true)
-                .possible_values(&["cfg", "llvm", "bc", "object"]),
+                .possible_values(&["ast", "cfg", "llvm", "bc", "object"]),
         )
         .arg(
             Arg::with_name("OPT")
@@ -192,6 +192,11 @@ fn process_filename(
         codegen(contract_no, &mut ns);
     }
 
+    if let Some("ast") = matches.value_of("EMIT") {
+        println!("{}", ns.print(filename));
+        return;
+    }
+
     // emit phase
     for contract_no in 0..ns.contracts.len() {
         let resolved_contract = &ns.contracts[contract_no];

+ 1 - 0
src/sema/mod.rs

@@ -14,6 +14,7 @@ pub mod eval;
 pub mod expression;
 mod functions;
 mod mutability;
+pub mod printer;
 mod statements;
 pub mod symtable;
 mod types;

+ 657 - 0
src/sema/printer.rs

@@ -0,0 +1,657 @@
+use super::ast::*;
+use hex;
+use parser::pt;
+
+#[derive(Clone)]
+enum Tree {
+    Leaf(String),
+    Branch(String, Vec<Tree>),
+}
+
+fn print_tree(t: &Tree, prefix: &str, field_prefix: &str) -> String {
+    let mut res = String::new();
+
+    match t {
+        Tree::Leaf(s) => {
+            res.push_str(&format!("{}{}\n", prefix, s));
+        }
+        Tree::Branch(s, list) => {
+            res.push_str(&format!("{}{}\n", prefix, s));
+
+            let len = list.len();
+
+            for (i, e) in list.iter().enumerate() {
+                if len != i + 1 {
+                    res.push_str(&format!(
+                        "{}├─ {}",
+                        field_prefix,
+                        print_tree(e, prefix, &format!("{}│  ", field_prefix))
+                    ));
+                } else {
+                    res.push_str(&format!(
+                        "{}└─ {}",
+                        field_prefix,
+                        print_tree(e, prefix, &format!("{}   ", field_prefix))
+                    ));
+                }
+            }
+        }
+    }
+
+    res
+}
+
+fn print_expr(e: &Expression, func: Option<&Function>, ns: &Namespace) -> Tree {
+    match e {
+        Expression::BoolLiteral(_, b) => Tree::Leaf(format!(
+            "literal bool {}",
+            if *b { "true" } else { "false" }
+        )),
+        Expression::BytesLiteral(_, ty, b) => {
+            Tree::Leaf(format!("literal {} {}", ty.to_string(ns), hex::encode(b)))
+        }
+        Expression::CodeLiteral(_, contract_no, true) => {
+            Tree::Leaf(format!("code runtime {}", ns.contracts[*contract_no].name))
+        }
+        Expression::CodeLiteral(_, contract_no, false) => {
+            Tree::Leaf(format!("code deploy {}", ns.contracts[*contract_no].name))
+        }
+        Expression::NumberLiteral(_, ty, b) => {
+            Tree::Leaf(format!("literal {} {}", ty.to_string(ns), b))
+        }
+        Expression::StructLiteral(_, ty, fields) => {
+            let fields = fields.iter().map(|e| print_expr(e, func, ns)).collect();
+
+            Tree::Branch(format!("struct {}", ty.to_string(ns)), fields)
+        }
+        Expression::Add(_, ty, left, right) => Tree::Branch(
+            format!("add {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::Subtract(_, ty, left, right) => Tree::Branch(
+            format!("subtract {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::Multiply(_, ty, left, right) => Tree::Branch(
+            format!("multiply {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::UDivide(_, ty, left, right) => Tree::Branch(
+            format!("unsigned divide {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SDivide(_, ty, left, right) => Tree::Branch(
+            format!("signed divide {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::UModulo(_, ty, left, right) => Tree::Branch(
+            format!("unsigned modulo {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SModulo(_, ty, left, right) => Tree::Branch(
+            format!("signed modulo {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::Power(_, ty, left, right) => Tree::Branch(
+            format!("power {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::BitwiseOr(_, ty, left, right) => Tree::Branch(
+            format!("bitwise or {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::BitwiseAnd(_, ty, left, right) => Tree::Branch(
+            format!("bitwise and {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::BitwiseXor(_, ty, left, right) => Tree::Branch(
+            format!("bitwise xor {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::ShiftLeft(_, ty, left, right) => Tree::Branch(
+            format!("shift left {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::ShiftRight(_, ty, left, right, sign) => Tree::Branch(
+            format!("shift right {}", ty.to_string(ns)),
+            vec![
+                print_expr(left, func, ns),
+                print_expr(right, func, ns),
+                Tree::Leaf(format!("signed: {}", *sign)),
+            ],
+        ),
+        Expression::Variable(_, ty, pos) => Tree::Leaf(format!(
+            "variable {} {}",
+            ty.to_string(ns),
+            func.unwrap().symtable.vars[pos].id.name
+        )),
+        Expression::ConstantVariable(_, ty, base_contract_no, var_no) => Tree::Leaf(format!(
+            "contract variable {} {}",
+            ty.to_string(ns),
+            ns.contracts[*base_contract_no].variables[*var_no].name
+        )),
+        Expression::StorageVariable(_, ty, base_contract_no, var_no) => Tree::Leaf(format!(
+            "storage variable {} {}",
+            ty.to_string(ns),
+            ns.contracts[*base_contract_no].variables[*var_no].name
+        )),
+        Expression::Load(_, ty, expr) => Tree::Branch(
+            format!("load memory {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::StorageLoad(_, ty, expr) => Tree::Branch(
+            format!("load storage {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::ZeroExt(_, ty, expr) => Tree::Branch(
+            format!("zero extend {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::SignExt(_, ty, expr) => Tree::Branch(
+            format!("sign extend {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::Trunc(_, ty, expr) => Tree::Branch(
+            format!("truncate {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::Cast(_, ty, expr) => Tree::Branch(
+            format!("cast {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::PreIncrement(_, ty, expr) => Tree::Branch(
+            format!("pre-increment {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::PreDecrement(_, ty, expr) => Tree::Branch(
+            format!("pre-decrement {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::PostIncrement(_, ty, expr) => Tree::Branch(
+            format!("post-increment {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::PostDecrement(_, ty, expr) => Tree::Branch(
+            format!("post-decrement {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::Assign(_, ty, left, right) => Tree::Branch(
+            format!("asign {}", ty.to_string(ns)),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::UMore(_, left, right) => Tree::Branch(
+            String::from("unsigned more"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::ULess(_, left, right) => Tree::Branch(
+            String::from("unsigned less"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::UMoreEqual(_, left, right) => Tree::Branch(
+            String::from("unsigned more or equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::ULessEqual(_, left, right) => Tree::Branch(
+            String::from("unsigned less or equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SMore(_, left, right) => Tree::Branch(
+            String::from("signed more"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SLess(_, left, right) => Tree::Branch(
+            String::from("signed less"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SMoreEqual(_, left, right) => Tree::Branch(
+            String::from("signed more or equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::SLessEqual(_, left, right) => Tree::Branch(
+            String::from("signed less or equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::Equal(_, left, right) => Tree::Branch(
+            String::from("equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::NotEqual(_, left, right) => Tree::Branch(
+            String::from("not equal"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::Not(_, expr) => {
+            Tree::Branch(String::from("not"), vec![print_expr(expr, func, ns)])
+        }
+        Expression::Complement(_, ty, expr) => Tree::Branch(
+            format!("complement {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::UnaryMinus(_, ty, expr) => Tree::Branch(
+            format!("unary minus {}", ty.to_string(ns)),
+            vec![print_expr(expr, func, ns)],
+        ),
+        Expression::Ternary(_, _, cond, left, right) => Tree::Branch(
+            String::from("ternary"),
+            vec![
+                print_expr(cond, func, ns),
+                print_expr(left, func, ns),
+                print_expr(right, func, ns),
+            ],
+        ),
+        Expression::ArraySubscript(_, ty, array, index) => Tree::Branch(
+            format!("array subscript {}", ty.to_string(ns)),
+            vec![
+                Tree::Branch(String::from("array"), vec![print_expr(array, func, ns)]),
+                Tree::Branch(String::from("index"), vec![print_expr(index, func, ns)]),
+            ],
+        ),
+        Expression::StructMember(_, ty, struct_expr, member) => {
+            if let Type::Struct(struct_no) = struct_expr.ty() {
+                Tree::Branch(
+                    format!("array subscript {}", ty.to_string(ns)),
+                    vec![
+                        Tree::Branch(
+                            String::from("struct"),
+                            vec![print_expr(struct_expr, func, ns)],
+                        ),
+                        Tree::Branch(
+                            String::from("member"),
+                            vec![Tree::Leaf(
+                                ns.structs[struct_no].fields[*member].name.to_owned(),
+                            )],
+                        ),
+                    ],
+                )
+            } else {
+                panic!("struct member on non-struct");
+            }
+        }
+        Expression::Or(_, left, right) => Tree::Branch(
+            String::from("logical or"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        Expression::And(_, left, right) => Tree::Branch(
+            String::from("logical and"),
+            vec![print_expr(left, func, ns), print_expr(right, func, ns)],
+        ),
+        _ => Tree::Leaf(String::from("not implemented")),
+    }
+}
+
+fn print_statement(stmts: &[Statement], func: &Function, ns: &Namespace) -> Vec<Tree> {
+    let mut res = Vec::new();
+
+    for stmt in stmts {
+        res.push(match stmt {
+            Statement::VariableDecl(_, _, p, None) => {
+                Tree::Leaf(format!("declare {} {}", p.ty.to_string(ns), p.name))
+            }
+            Statement::VariableDecl(_, _, p, Some(e)) => Tree::Branch(
+                format!("declare {} {}", p.ty.to_string(ns), p.name),
+                vec![print_expr(e, Some(func), ns)],
+            ),
+            Statement::If(_, _, cond, then_stmt, else_stmt) if else_stmt.is_empty() => {
+                let cond =
+                    Tree::Branch(String::from("cond"), vec![print_expr(cond, Some(func), ns)]);
+                let then = Tree::Branch(String::from("then"), print_statement(then_stmt, func, ns));
+                Tree::Branch(String::from("if"), vec![cond, then])
+            }
+            Statement::If(_, _, cond, then_stmt, else_stmt) => {
+                let cond =
+                    Tree::Branch(String::from("cond"), vec![print_expr(cond, Some(func), ns)]);
+                let then_tree =
+                    Tree::Branch(String::from("then"), print_statement(then_stmt, func, ns));
+                let else_tree =
+                    Tree::Branch(String::from("else"), print_statement(else_stmt, func, ns));
+                Tree::Branch(String::from("if"), vec![cond, then_tree, else_tree])
+            }
+            Statement::While(_, _, cond, body) => {
+                let cond =
+                    Tree::Branch(String::from("cond"), vec![print_expr(cond, Some(func), ns)]);
+                let body = Tree::Branch(String::from("then"), print_statement(body, func, ns));
+                Tree::Branch(String::from("while"), vec![cond, body])
+            }
+            Statement::For {
+                init,
+                cond: None,
+                next,
+                body,
+                ..
+            } => {
+                let init = Tree::Branch(String::from("init"), print_statement(init, func, ns));
+                let body = Tree::Branch(String::from("body"), print_statement(body, func, ns));
+                let next = Tree::Branch(String::from("next"), print_statement(next, func, ns));
+                Tree::Branch(String::from("for"), vec![init, body, next])
+            }
+            Statement::For {
+                init,
+                cond: Some(cond),
+                next,
+                body,
+                ..
+            } => {
+                let init = Tree::Branch(String::from("init"), print_statement(init, func, ns));
+                let cond =
+                    Tree::Branch(String::from("cond"), vec![print_expr(cond, Some(func), ns)]);
+                let body = Tree::Branch(String::from("body"), print_statement(body, func, ns));
+                let next = Tree::Branch(String::from("next"), print_statement(next, func, ns));
+                Tree::Branch(String::from("for"), vec![init, cond, body, next])
+            }
+            Statement::DoWhile(_, _, body, cond) => {
+                let body = Tree::Branch(String::from("then"), print_statement(body, func, ns));
+                let cond =
+                    Tree::Branch(String::from("cond"), vec![print_expr(cond, Some(func), ns)]);
+                Tree::Branch(String::from("do while"), vec![body, cond])
+            }
+            Statement::Expression(_, _, expr) => Tree::Branch(
+                String::from("expression"),
+                vec![print_expr(expr, Some(func), ns)],
+            ),
+            Statement::Delete(_, ty, expr) => {
+                let expr =
+                    Tree::Branch(String::from("expr"), vec![print_expr(expr, Some(func), ns)]);
+                let ty = Tree::Leaf(ty.to_string(ns));
+                Tree::Branch(String::from("delete"), vec![expr, ty])
+            }
+            Statement::Break(_) => Tree::Leaf(String::from("break")),
+            Statement::Continue(_) => Tree::Leaf(String::from("continue")),
+            Statement::Return(_, args) => {
+                if args.is_empty() {
+                    Tree::Leaf(String::from("return"))
+                } else {
+                    let args = args.iter().map(|e| print_expr(e, Some(func), ns)).collect();
+
+                    Tree::Branch(String::from("return"), args)
+                }
+            }
+            Statement::Emit { event_no, args, .. } => {
+                let args = args.iter().map(|e| print_expr(e, Some(func), ns)).collect();
+
+                Tree::Branch(format!("emit {}", ns.events[*event_no].to_string()), args)
+            }
+            Statement::Destructure(_, fields, args) => {
+                let fields = fields
+                    .iter()
+                    .map(|f| match f {
+                        DestructureField::None => Tree::Leaf(String::from("")),
+                        DestructureField::Expression(e) => print_expr(e, Some(func), ns),
+                        DestructureField::VariableDecl(_, p) => {
+                            Tree::Leaf(format!("{} {}", p.ty.to_string(ns), p.name))
+                        }
+                    })
+                    .collect();
+                let args = print_expr(args, Some(func), ns);
+
+                Tree::Branch(
+                    String::from("destructure"),
+                    vec![Tree::Branch(String::from("fields"), fields), args],
+                )
+            }
+            Statement::TryCatch {
+                expr,
+                returns,
+                ok_stmt,
+                error,
+                catch_param,
+                catch_stmt,
+                ..
+            } => {
+                let mut list = Vec::new();
+
+                list.push(Tree::Branch(
+                    String::from("expr"),
+                    vec![print_expr(expr, Some(func), ns)],
+                ));
+
+                if !returns.is_empty() {
+                    let returns = returns
+                        .iter()
+                        .map(|(_, param)| {
+                            Tree::Leaf(format!("{} {}", param.ty.to_string(ns), param.name))
+                        })
+                        .collect();
+
+                    list.push(Tree::Branch(String::from("returns"), returns));
+                }
+
+                list.push(Tree::Branch(
+                    String::from("ok_stmt"),
+                    print_statement(ok_stmt, func, ns),
+                ));
+
+                if let Some((_, param, stmt)) = &error {
+                    list.push(Tree::Leaf(format!(
+                        "error_param: {} {}",
+                        param.ty.to_string(ns),
+                        param.name
+                    )));
+
+                    list.push(Tree::Branch(
+                        String::from("error_statement"),
+                        print_statement(stmt, func, ns),
+                    ));
+                }
+
+                list.push(Tree::Leaf(format!(
+                    "catch_param: {} {}",
+                    catch_param.ty.to_string(ns),
+                    catch_param.name
+                )));
+
+                list.push(Tree::Branch(
+                    String::from("catch_stmt"),
+                    print_statement(catch_stmt, func, ns),
+                ));
+
+                Tree::Branch(String::from("try-catch"), list)
+            }
+        });
+    }
+
+    res
+}
+
+impl Namespace {
+    pub fn print(&self, filename: &str) -> String {
+        // enums
+        let mut t = Vec::new();
+        for e in &self.enums {
+            let mut values = Vec::new();
+            values.resize(e.values.len(), Tree::Leaf(String::new()));
+            for (name, (_, pos)) in &e.values {
+                values[*pos] = Tree::Leaf(name.clone());
+            }
+
+            t.push(Tree::Branch(
+                format!("enum {}", e.print_to_string()),
+                values,
+            ));
+        }
+
+        // structs
+        for s in &self.structs {
+            let fields = s
+                .fields
+                .iter()
+                .map(|p| Tree::Leaf(format!("field {} {}", p.ty.to_string(&self), p.name)))
+                .collect();
+
+            t.push(Tree::Branch(
+                format!("struct {}", s.print_to_string()),
+                fields,
+            ));
+        }
+
+        // events
+        for e in &self.events {
+            let fields = e
+                .fields
+                .iter()
+                .map(|p| {
+                    Tree::Leaf(format!(
+                        "field {} {}{}",
+                        p.ty.to_string(&self),
+                        if p.indexed { "indexed " } else { "" },
+                        p.name
+                    ))
+                })
+                .collect();
+
+            t.push(Tree::Branch(
+                format!("event {} {}", e, if e.anonymous { "anonymous" } else { "" }),
+                fields,
+            ));
+        }
+
+        // contracts
+        for c in &self.contracts {
+            let mut members = Vec::new();
+
+            if !c.bases.is_empty() {
+                let mut list = Vec::new();
+
+                for base in &c.bases {
+                    let name = self.contracts[base.contract_no].name.clone();
+
+                    if let Some((_, args)) = &base.constructor {
+                        list.push(Tree::Branch(
+                            name,
+                            args.iter().map(|e| print_expr(e, None, self)).collect(),
+                        ));
+                    } else {
+                        list.push(Tree::Leaf(name));
+                    }
+                }
+
+                members.push(Tree::Branch(String::from("bases"), list));
+            }
+
+            for var in &c.variables {
+                let name = format!(
+                    "variable {} {} {}",
+                    match var.var {
+                        ContractVariableType::Constant => "constant",
+                        ContractVariableType::Storage => "storage",
+                    },
+                    var.ty.to_string(self),
+                    var.name
+                );
+
+                if let Some(initializer) = &var.initializer {
+                    members.push(Tree::Branch(
+                        name,
+                        vec![print_expr(initializer, None, self)],
+                    ));
+                } else {
+                    members.push(Tree::Leaf(name));
+                }
+            }
+
+            if !c.using.is_empty() {
+                let mut list = Vec::new();
+
+                for (library_no, ty) in &c.using {
+                    if let Some(ty) = ty {
+                        list.push(Tree::Leaf(format!(
+                            "library {} for {}",
+                            self.contracts[*library_no].name,
+                            ty.to_string(self)
+                        )));
+                    } else {
+                        list.push(Tree::Leaf(format!(
+                            "library {}",
+                            self.contracts[*library_no].name
+                        )));
+                    }
+                }
+
+                members.push(Tree::Branch(String::from("using"), list));
+            }
+
+            for func in &c.functions {
+                let mut list = Vec::new();
+
+                list.push(Tree::Leaf(format!("visibility {}", func.visibility)));
+
+                if func.ty == pt::FunctionTy::Constructor && func.ty == pt::FunctionTy::Function {
+                    list.push(Tree::Leaf(format!("signature {}", func.signature)));
+                }
+
+                if let Some(mutability) = &func.mutability {
+                    list.push(Tree::Leaf(format!("mutability {}", mutability)));
+                }
+
+                if func.is_virtual {
+                    list.push(Tree::Leaf(String::from("virtual")));
+                }
+
+                if let Some((_, is_override)) = &func.is_override {
+                    if is_override.is_empty() {
+                        list.push(Tree::Leaf(String::from("override")));
+                    } else {
+                        list.push(Tree::Branch(
+                            String::from("override"),
+                            is_override
+                                .iter()
+                                .map(|contract_no| {
+                                    Tree::Leaf(self.contracts[*contract_no].name.clone())
+                                })
+                                .collect(),
+                        ));
+                    }
+                }
+
+                if !func.bases.is_empty() {
+                    let mut list = Vec::new();
+                    for (base_no, (_, _, args)) in &func.bases {
+                        let name = self.contracts[*base_no].name.clone();
+                        if !args.is_empty() {
+                            list.push(Tree::Branch(
+                                name,
+                                args.iter()
+                                    .map(|e| print_expr(e, Some(func), self))
+                                    .collect(),
+                            ));
+                        } else {
+                            list.push(Tree::Leaf(name));
+                        }
+                    }
+                    members.push(Tree::Branch(String::from("bases"), list));
+                }
+
+                if !func.params.is_empty() {
+                    let params = func
+                        .params
+                        .iter()
+                        .map(|p| Tree::Leaf(format!("{} {}", p.ty.to_string(&self), p.name)))
+                        .collect();
+
+                    list.push(Tree::Branch(String::from("params"), params));
+                }
+
+                if !func.returns.is_empty() {
+                    let returns = func
+                        .returns
+                        .iter()
+                        .map(|p| Tree::Leaf(format!("{} {}", p.ty.to_string(&self), p.name)))
+                        .collect();
+
+                    list.push(Tree::Branch(String::from("returns"), returns));
+                }
+
+                if !func.body.is_empty() {
+                    list.push(Tree::Branch(
+                        String::from("body"),
+                        print_statement(&func.body, func, self),
+                    ));
+                }
+
+                members.push(Tree::Branch(format!("{} {}", func.ty, func.name), list));
+            }
+
+            t.push(Tree::Branch(format!("{} {}", c.ty, c.name), members));
+        }
+
+        print_tree(&Tree::Branch(filename.to_owned(), t), "", "")
+    }
+}