diff --git a/.gitignore b/.gitignore
index 9e290bc..97e6d83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,3 @@
/target
Cargo.lock
-.vscode/launch.json
+.vscode/
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..f5f3c9a
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/source-code-parser.iml b/.idea/source-code-parser.iml
new file mode 100644
index 0000000..495c100
--- /dev/null
+++ b/.idea/source-code-parser.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/lang/go/class_def.rs b/src/lang/go/class_def.rs
new file mode 100644
index 0000000..14b06d6
--- /dev/null
+++ b/src/lang/go/class_def.rs
@@ -0,0 +1,145 @@
+use crate::go::util::identifier::parse_identifier;
+use crate::go::util::vartype::find_type;
+use crate::parse::AST;
+use crate::prophet::*;
+
+pub(crate) fn parse_type(
+ ast: &AST,
+ package: &str,
+ path: &str,
+) -> Option {
+ let node = match ast.find_child_by_type(&["type_spec"]) {
+ Some(type_node) => type_node,
+ None => ast,
+ };
+
+ parse_type_internal(node, &package, path)
+}
+
+pub(crate) fn parse_type_internal(
+ ast: &AST,
+ package: &str,
+ path: &str,
+) -> Option {
+
+ //determine the type of the instance
+ let instance_type = match ast.find_child_by_type(&["struct_type", "interface_type"]) {
+ Some(node) => match &*node.r#type {
+ "interface_type" => InstanceType::InterfaceComponent,
+ _ => InstanceType::ClassComponent,
+ },
+ None => InstanceType::ClassComponent,
+ };
+
+ //find the name of the type
+ let instance_name = match ast.find_child_by_type(&["type_identifier"]) {
+ Some(identifier) => identifier.value.clone(),
+ None => "".into(),
+ };
+
+ //determine what type the instance is
+ let declaration_type = match instance_type {
+ InstanceType::InterfaceComponent => ContainerType::Interface,
+ _ => ContainerType::Class,
+ };
+
+ //get the component information using the path, package, instance name, and instance type
+ let component = ComponentInfo {
+ language: Language::Go,
+ path: path.into(),
+ package_name: package.into(),
+ instance_name: format!(
+ "{}::{}",
+ instance_name,
+ match instance_type {
+ InstanceType::InterfaceComponent => "InterfaceComponent",
+ _ => "ClassComponent",
+ }
+ ),
+ instance_type: instance_type,
+ };
+
+ // Find bounds
+ let (start, end) = match ast.span {
+ Some(span) => (span.0 as i32, span.2 as i32),
+ None => (0, 0),
+ };
+
+ // Define default values
+ let stereotype = ContainerStereotype::Entity; // TODO determine properly
+ let mut fields = vec![];
+ let constructors = vec![];
+ let mut methods = vec![];
+ //let mut modifier = Modifier::new();
+
+ for child in ast.children.iter() {
+ match &*child.r#type {
+ "struct_type" => {
+ parse_struct_body(child, &component, &mut methods, &mut fields);
+ }
+ _ => {}
+ }
+ }
+
+ Some(ClassOrInterfaceComponent {
+ component: ContainerComponent {
+ component: component,
+ accessor: AccessorType::Public,
+ stereotype: stereotype,
+ methods: methods,
+ container_name: instance_name,
+ line_count: (end - start) + 1,
+ },
+ declaration_type: declaration_type,
+ annotations: vec![],
+ constructors: constructors,
+ field_components: fields,
+ })
+}
+
+fn parse_struct_body(
+ ast: &AST,
+ component: &ComponentInfo,
+ _methods: &mut Vec,
+ fields: &mut Vec,
+) {
+ for node in ast.children.iter() {
+ match &*node.r#type {
+ "field_declaration_list" => fields.append(&mut parse_fields(node, component)),
+ _ => {}
+ }
+ }
+}
+
+fn parse_fields(ast: &AST, component: &ComponentInfo) -> Vec {
+ let mut fields = vec![];
+ for node in ast.children.iter() {
+ match &*node.r#type {
+ "field_declaration" => {
+ let field_identifier = parse_identifier(node);
+ let type_identifier = find_type(node);
+
+ fields.push(FieldComponent {
+ component: ComponentInfo {
+ language: Language::Go,
+ path: component.path.clone(),
+ package_name: component.package_name.clone(),
+ instance_name: field_identifier.clone(),
+ instance_type: InstanceType::FieldComponent,
+ },
+ annotations: vec![],
+ variables: vec![],
+ field_name: field_identifier,
+ accessor: AccessorType::Public,
+ is_static: false,
+ is_final: false,
+ default_value: String::new(),
+ r#type: type_identifier,
+ expression: None,
+ })
+ }
+ _ => {}
+ }
+ }
+ fields
+}
diff --git a/src/lang/go/function_body/expr.rs b/src/lang/go/function_body/expr.rs
new file mode 100644
index 0000000..8f06f0f
--- /dev/null
+++ b/src/lang/go/function_body/expr.rs
@@ -0,0 +1,193 @@
+use crate::Language;
+use crate::go::util::identifier::parse_identifier;
+
+use crate::ast::*;
+use crate::ComponentInfo;
+use crate::AST;
+
+use super::is_common_junk_tag;
+
+pub(crate) fn parse_expr(ast: &AST, component: &ComponentInfo) -> Option {
+ match &*ast.r#type {
+ // Variables and initialization
+ "identifier" | "field_identifier" => parse_ident(ast, component),
+ "int_literal" |
+ "interpreted_string_literal" | "nil" | "true" | "false" => Some(Expr::Literal(Literal::new(ast.value.clone(), Language::Go))),
+ "assignment_statement" => parse_assignment(ast, component),
+
+ //language specific
+ "binary_expression" => parse_binary(ast, component),
+ "expression_list" => parse_expr_stmt(ast, component),
+ "inc_statement" | "dec_statement" => parse_inc_dec(ast, component),
+
+ //function and method calls
+ "call_expression" => parse_function(ast, component),
+ "selector_expression" => Some(parse_dot_expr(ast, component)?.into()),
+
+ _ => None,
+ }
+}
+
+pub(crate) fn parse_expr_stmt(ast: &AST, component: &ComponentInfo) -> Option {
+ let mut expr = None;
+ for comp in ast.children.iter() {
+ expr = parse_expr(comp, component);
+ if expr.is_some() {
+ break;
+ }
+ }
+ expr
+}
+
+fn parse_ident(ast: &AST, _component: &ComponentInfo) -> Option {
+ let ident: Expr = Ident::new(ast.value.clone(), Language::Go).into();
+ Some(ident.into())
+}
+
+/// Parse an assignment expression. May contain a variable declaration
+pub(crate) fn parse_assignment(ast: &AST, component: &ComponentInfo) -> Option {
+ // Define attributes
+ let mut lhs = None;
+ let mut rhs = None;
+
+ // Find values
+ for node in ast.children.iter() {
+
+ let unknown = &*node.r#type;
+ if unknown == "=" {
+ continue;
+ }
+
+ let result = parse_expr(node, component);
+
+ if result.is_some() {
+ if lhs.is_none() {
+ lhs = result;
+ } else if rhs.is_none() {
+ rhs = result;
+ } else {
+ eprintln!(
+ "Extra parsable tag {} encountered while parsing assignment",
+ unknown
+ );
+ }
+ } else {
+ //log_unknown_tag(unknown, "parse_assignment");
+ }
+ }
+
+ // Assemble
+ if let Some(lhs) = lhs {
+ if let Some(rhs) = rhs {
+ let bin: Expr = BinaryExpr::new(Box::new(lhs.into()), "=".into(), Box::new(rhs), Language::Go).into();
+ Some(bin.into())
+ } else {
+ Some(lhs.into())
+ }
+ } else {
+ eprintln!("Assignment with no lefthand side!");
+ None
+ }
+}
+
+//parse increment or decrement statments
+fn parse_inc_dec(ast: &AST, component: &ComponentInfo) -> Option {
+ let name = if ast.children[0].r#type == "identifier" {
+ 0
+ } else {
+ 1
+ };
+ let op = (name + 1) % 2;
+
+ Some(
+ IncDecExpr::new(
+ op < name,
+ ast.children[op].r#type == "++",
+ Box::new(parse_expr(&ast.children[name], component)?),
+ Language::Go,
+ )
+ .into(),
+ )
+}
+
+fn parse_binary(ast: &AST, component: &ComponentInfo) -> Option {
+ let mut lhs = None;
+ let mut op = None;
+ let mut rhs = None;
+ for child in ast.children.iter() {
+ if !is_common_junk_tag(&child.r#type) {
+ let res = Some(child);
+ if lhs.is_none() {
+ lhs = res;
+ } else if op.is_none() {
+ op = res;
+ } else if rhs.is_none() {
+ rhs = res;
+ break;
+ }
+ }
+ }
+
+ if let Some(lhs) = lhs {
+ if let Some(op) = op {
+ if let Some(rhs) = rhs {
+ return Some(
+ BinaryExpr::new(
+ Box::new(parse_expr(lhs, component)?),
+ op.value.as_str().into(),
+ Box::new(parse_expr(rhs, component)?),
+ Language::Go
+ )
+ .into(),
+ );
+ }
+ }
+ }
+ eprintln!("Malformed binary expression detected!");
+ None
+}
+
+fn parse_function(ast: &AST, component: &ComponentInfo) -> Option {
+ let selector = match ast.find_child_by_type(&["selector_expression"]) {
+ Some(node) => node,
+ None => ast
+ };
+
+ let argument_list = match ast.find_child_by_type(&["argument_list"]) {
+ Some(node) => node,
+ None => ast
+ };
+
+ let args: Vec = argument_list
+ .children
+ .iter()
+ .map(|arg| parse_expr(arg, component))
+ .flat_map(|arg| arg)
+ .collect();
+
+
+ //determine the type of function call
+ if selector.find_child_by_type(&["."]).is_some() {
+ //member functions
+ let function_name = parse_dot_expr(selector, component)?;
+
+ Some(CallExpr::new(Box::new(function_name.into()), args, Language::Go).into())
+ } else {
+ //regular functions
+ let name = Ident::new(parse_identifier(&selector.children[0]), Language::Go);
+ Some(CallExpr::new(Box::new(name.into()), args, Language::Go).into())
+ }
+}
+
+fn parse_dot_expr(node: &AST, component: &ComponentInfo) -> Option{
+ //get the name of what called the function
+ //let lhs = Ident::new(parse_identifier(&node.children[0]), Language::Go);
+ let lhs = parse_expr(&node.children[0], component)?;
+ //let rhs = Ident::new(parse_identifier(&node.children[2]), Language::Go);
+ let rhs = parse_expr(&node.children[2], component)?;
+
+ Some(DotExpr::new(Box::new(lhs), Box::new(rhs), Language::Go))
+}
+
+
+
diff --git a/src/lang/go/function_body/mod.rs b/src/lang/go/function_body/mod.rs
new file mode 100644
index 0000000..2cec44f
--- /dev/null
+++ b/src/lang/go/function_body/mod.rs
@@ -0,0 +1,36 @@
+use crate::{AST, ComponentInfo, Language, ast::Block};
+
+use self::node::parse_child_nodes;
+
+mod expr;
+mod node;
+mod stmt;
+
+/// Parse the body of a method, static block, constructor, etc.
+pub(crate) fn parse_block(ast: &AST, component: &ComponentInfo) -> Block {
+ Block::new(parse_child_nodes(ast, component), Language::Go)
+
+}
+
+/*
+/// Logs an unknown tag was encountered. You better not think too much about that.
+/// It does not, however, log well-known "filler tags", to keep from cluttering output.
+pub(crate) fn log_unknown_tag(tag: &str, parent: &str) {
+ if !is_common_junk_tag(tag) {
+ eprintln!("Unknown tag {} encountered while parsing {}!", tag, parent);
+ }
+}
+*/
+
+/// Catch all for standard-issue junk tags from treesitter, to allow easy blanket-silencing of
+/// false alarms, to focus on the tags that are actually important
+pub(crate) fn is_common_junk_tag(tag: &str) -> bool {
+ // TECHNICALLY should just be 2 match arms. I split it up by the class of tag, so its easy to
+ // if a case is handled already. The compiler's gotta be smart enough to figure it out.
+ match tag {
+ "if" | "else" | "for" | "while" | "do" | "switch" | "try" | "catch" | "finally" => true,
+ "class" | "interface" | "enum" => true,
+ "(" | ")" | "{" | "}" | "->" | ";" | "," | "." | "..." => true,
+ _ => false,
+ }
+}
diff --git a/src/lang/go/function_body/node.rs b/src/lang/go/function_body/node.rs
new file mode 100644
index 0000000..41cfea6
--- /dev/null
+++ b/src/lang/go/function_body/node.rs
@@ -0,0 +1,35 @@
+use crate::ast::*;
+use crate::ComponentInfo;
+use crate::AST;
+
+use crate::go::function_body::stmt::*;
+
+use super::parse_block;
+use crate::go::function_body::expr::parse_expr;
+
+pub(crate) fn parse_child_nodes(ast: &AST, component: &ComponentInfo) -> Vec {
+ ast.children
+ .iter()
+ .map(|member| parse_node(member, component))
+ .flat_map(|some| some)
+ .collect()
+}
+
+pub(crate) fn parse_node(ast: &AST, component: &ComponentInfo) -> Option {
+ match &*ast.r#type {
+ "var_declaration" => Some(Node::Stmt(parse_decl(ast, component).into())),
+ "short_var_declaration" => Some(Node::Stmt(parse_short_decl(ast, component)?.into())),
+ "if_statement" => parse_if(ast, component),
+ "block" => Some(parse_block(ast, component).into()),
+
+ "for_statement" => parse_for(ast, component),
+
+ _ => {
+ let expr: Stmt = parse_expr(ast, component)?.into();
+ Some(expr.into())
+ },
+
+ }
+}
+
+
diff --git a/src/lang/go/function_body/stmt.rs b/src/lang/go/function_body/stmt.rs
new file mode 100644
index 0000000..a151232
--- /dev/null
+++ b/src/lang/go/function_body/stmt.rs
@@ -0,0 +1,309 @@
+use crate::ast::{to_block, DeclStmt, Expr, ExprStmt, ForStmt, IfStmt, Node, Stmt, VarDecl, Ident};
+use crate::ComponentInfo;
+use crate::AST;
+use crate::Language;
+use crate::go::util::identifier::parse_identifier;
+
+use super::{expr::parse_expr, is_common_junk_tag, node::parse_node, parse_block};
+use crate::go::function_body::node::parse_child_nodes;
+use crate::go::util::vartype::find_type;
+
+/// Parse an AST section containing a variable declaration
+pub(crate) fn parse_decl(ast: &AST, component: &ComponentInfo) -> DeclStmt {
+ // Extract informtion about the variable
+ let ast = match ast.find_child_by_type(&["var_spec"]) {
+ Some(var) => var,
+ None => ast,
+ };
+ let r#type = find_type(ast);
+
+ // Determine the value it was set to
+ let rhs = parse_child_nodes(ast, component);
+
+ let mut decl = DeclStmt::new(vec![], vec![], Language::Go);
+ for var in rhs.iter() {
+ // Extract expression from the hierarchy
+ let base = match var {
+ Node::Stmt(Stmt::ExprStmt(ExprStmt { expr, .. })) | Node::Expr(expr) => expr,
+ _ => {
+ eprintln!("Unable to interpret as variable: {:#?}", var);
+ continue;
+ }
+ };
+
+ // Parse variable
+ match base {
+ Expr::BinaryExpr(expr) => match expr.lhs.as_ref() {
+ Expr::Ident(lhs) => {
+ decl.variables
+ .push(VarDecl::new(Some(r#type.clone()), lhs.clone(), Language::Go));
+ decl.expressions.push(Some(expr.rhs.as_ref().clone()));
+ }
+ unknown => eprintln!("Expected Ident got {:#?}", unknown),
+ },
+ Expr::Ident(id) => {
+ decl.variables
+ .push(VarDecl::new(Some(r#type.clone()), id.clone(), Language::Go));
+ decl.expressions.push(None);
+ }
+ Expr::Literal(lit) => decl.expressions.push(Some(lit.clone().into())),
+ unknown => {
+ eprintln!("Expected BinaryExpr or Ident, got {:#?}", unknown);
+ }
+ }
+ }
+
+ for var_decl in decl.variables.iter_mut() {
+ var_decl.is_final = None; //Go does not have final variables
+ var_decl.is_static = None; //Go does not have static variables
+ var_decl.var_type = Some(r#type.clone());
+ }
+ decl.into()
+}
+
+pub(crate) fn parse_short_decl(ast: &AST, component: &ComponentInfo) -> Option {
+ //let mut r#type = "N/A".to_string();
+ //let mut i = 0;
+
+ /*
+ for expr in ast.find_all_children_by_type(&["expression_list"]).get_or_insert(vec![]).iter() {
+ if i == 0 {
+ i+= 1;
+ }
+ else {
+ r#type = determine_var_type(expr);
+ }
+ }
+ */
+
+ let expr_lists = ast.find_all_children_by_type(&["expression_list"]).unwrap_or_default();
+ let lhs = *expr_lists.first()?;
+ let rhs = *expr_lists.last()?;
+
+
+ //println!("{:#?}", ast);
+
+ // Determine the value it was set to
+ let var_names = lhs.children.iter()
+ .filter(|child| child.r#type == "identifier")
+ .map(|node| parse_identifier(node))
+ .map(|variable| VarDecl::new(None, Ident::new(variable, Language::Go), Language::Go))
+ .collect::>();
+
+
+ // let rhs_vals = parse_child_nodes(rhs, component).into_iter().map(|node| match node {
+ // Node::Expr(expr) => Some(expr),
+ // var_name => {
+ // println!("{:#?}", var_name);
+ // None
+ // }
+ // }).collect::>();
+
+
+ let rhs_vals = rhs.children.iter()
+ .map(|child| parse_expr(child, component))
+ .collect();
+
+ println!("{:#?}", rhs_vals);
+
+ Some(DeclStmt::new(var_names, rhs_vals, Language::Go))
+
+ /*
+ ///FIX ME!!!! need base to hold a vector of Ident, right now it is only getting the first var!
+ for var in lhs.iter() {
+ // Extract expression from the hierarchy
+ /*
+ let base = match var {
+ Node::Stmt(Stmt::ExprStmt(ExprStmt { expr, .. })) | Node::Expr(expr) => expr,
+ _ => {
+ eprintln!("Unable to interpret as variable: {:#?}", var);
+ continue;
+ }
+ };
+ */
+
+ //println!("{:#?}", base);
+ //println!("{:#?}", lhs);
+
+ // Parse variable
+ /*
+ match base {
+ Expr::BinaryExpr(expr) => match expr.lhs.as_ref() {
+ Expr::Ident(lhs) => {
+ decl.variables
+ .push(VarDecl::new(Some(r#type.clone()), lhs.clone(), Language::Go));
+ decl.expressions.push(Some(expr.rhs.as_ref().clone()));
+ }
+ unknown => eprintln!("Expected Ident got {:#?}", unknown),
+ },
+ Expr::Ident(id) => {
+ decl.variables
+ .push(VarDecl::new(Some(r#type.clone()), id.clone(), Language::Go));
+ decl.expressions.push(None);
+ }
+ Expr::Literal(lit) => decl.expressions.push(Some(lit.clone().into())),
+
+ //Expr::DotExpr()
+ unknown => {
+ eprintln!("Expected BinaryExpr, Ident or Literal, got {:#?}", unknown);
+ }
+ }
+ */
+
+
+ //decl.expressions.push(Some(base.clone()));
+ }
+
+ for var_decl in decl.variables.iter_mut() {
+ var_decl.is_final = None; //Go does not have final variables
+ var_decl.is_static = None; //Go does not have static variables
+ var_decl.var_type = Some(r#type.clone());
+ }
+ decl.into()
+ */
+
+
+}
+
+pub(crate) fn parse_if(ast: &AST, component: &ComponentInfo) -> Option {
+ let mut guard = None;
+ let mut if_stmt = None;
+ let mut else_stmt = None;
+
+ for child in ast.children.iter().filter(|node| node.r#type != "else") {
+ match &*child.r#type {
+
+ "binary_expression" => {
+ guard = parse_expr(child, component)
+ },
+
+ _ => {
+ if let Some(stmt) = parse_node(child, component) {
+ let stmt = to_block(stmt, Language::Go);
+ if if_stmt.is_none() {
+ if_stmt = Some(stmt);
+ } else {
+ else_stmt = Some(stmt);
+ break;
+ }
+ }
+ }
+ }
+ }
+ let ret_node = Some(Node::Stmt(IfStmt::new(guard?, if_stmt?, else_stmt, Language::Go).into()));
+ ret_node
+}
+
+
+pub(crate) fn parse_for(ast: &AST, component: &ComponentInfo) -> Option {
+ let mut for_clauses: Vec> = vec![vec![], vec![], vec![]];
+ let mut i = 0;
+
+ //find the node containing the for clauses of the statement
+ let clause_node = match ast.find_child_by_type(&["for_clause", "range_clause"]) {
+ Some(node) => node,
+ None => ast,
+ };
+
+ //Coerce an Option to an Expr, if it can be
+ let to_expr = |parts: &Vec| -> Vec {
+ parts
+ .into_iter()
+ .flat_map(|part| match part.clone() {
+ Node::Expr(node) => Some(node),
+ Node::Stmt(Stmt::ExprStmt(ExprStmt { expr, .. })) => Some(expr),
+ _ => None,
+ })
+ .collect()
+ };
+
+ //get all the clauses in the for_clauses vector
+ for node in clause_node.children.iter() {
+ if !is_common_junk_tag(&*node.r#type) {
+ for_clauses[i].push(node);
+ }
+ else {
+ i = i + 1;
+ }
+ }
+
+ //prepare clauses for parsing
+ let parts: Vec