summaryrefslogtreecommitdiffstats
path: root/src/CodeParser
diff options
context:
space:
mode:
Diffstat (limited to 'src/CodeParser')
-rw-r--r--src/CodeParser/CParser.ts175
-rw-r--r--src/CodeParser/CParser/CParser.ts387
-rw-r--r--src/CodeParser/CParser/CppParser.ts (renamed from src/CodeParser/CppParser.ts)4
-rw-r--r--src/CodeParser/CParser/ParseTree.ts220
-rw-r--r--src/CodeParser/CParser/Token.ts24
-rw-r--r--src/CodeParser/CodeParserController.ts4
6 files changed, 635 insertions, 179 deletions
diff --git a/src/CodeParser/CParser.ts b/src/CodeParser/CParser.ts
deleted file mode 100644
index f26aa5f..0000000
--- a/src/CodeParser/CParser.ts
+++ /dev/null
@@ -1,175 +0,0 @@
-import { Position, TextDocumentContentChangeEvent, TextEditor, TextLine, workspace } from "vscode";
-import { Config, ConfigType } from "../Config";
-import Generator from "../DocGen/CGen";
-import { IDocGen } from "../DocGen/DocGen";
-import ICodeParser from "./CodeParser";
-
-/**
- *
- * Parses C code for methods and signatures
- *
- * @export
- * @class CParser
- * @implements {ICodeParser}
- */
-export default class CParser implements ICodeParser {
- protected activeEditor: TextEditor;
- protected activeSelection: Position;
-
- /**
- * @inheritdoc
- */
- public Parse(activeEdit: TextEditor, event: TextDocumentContentChangeEvent): IDocGen {
- this.activeEditor = activeEdit;
- this.activeSelection = this.activeEditor.selection.active;
-
- const activeLine: TextLine = this.activeEditor.document.lineAt(this.activeEditor.selection.active.line);
-
- const line: string = this.getLogicalLine();
-
- // Not a method
- if (line.length === 0) {
- return null;
- }
-
- const returnValue: string[] = this.getReturn(line);
-
- const params: string[] = this.getParams(line);
- const tparams: string[] = this.getTemplateParams(line);
-
- const cppGenerator: IDocGen = new Generator(
- this.activeEditor,
- this.activeSelection,
- params,
- tparams,
- returnValue,
- );
- return cppGenerator;
- }
-
- /***************************************************************************
- Implementation
- ***************************************************************************/
- protected getLogicalLine(): string {
- let logicalLine: string = "";
-
- let nextLine: Position = new Position(this.activeSelection.line + 1, this.activeSelection.character);
-
- let nextLineTxt: string = this.activeEditor.document.lineAt(nextLine.line).text.trim();
-
- // VSCode may enter a * on itself, we don't want that in our method
- if (nextLineTxt === "*") {
- nextLineTxt = "";
- }
-
- while (nextLineTxt.length === 0) { // Get first method line
- nextLine = new Position(nextLine.line + 1, nextLine.character);
- nextLineTxt = this.activeEditor.document.lineAt(nextLine.line).text.trim();
- }
-
- logicalLine += nextLineTxt;
-
- // Get method end line
- while (nextLineTxt.indexOf(";") === -1 && nextLineTxt.indexOf("{") === -1) { // Check for method end
- nextLine = new Position(nextLine.line + 1, nextLine.character);
- nextLineTxt = this.activeEditor.document.lineAt(nextLine.line).text.trim();
-
- logicalLine += " " + nextLineTxt;
- }
-
- // Not a method but some code in the file
- if (logicalLine.indexOf(")") === -1) {
- return "";
- }
-
- return logicalLine;
- }
-
- protected getReturn(method: string): string[] {
- const retVals: string[] = [];
-
- // Remove the compiler keywords from the signature
- const sign: string = method.replace(/(static)|(inline)|(friend)|(virtual)|(extern)|(explicit)|(const)/g, "");
- // Remove the parameters from the signature
- const returnSignature = sign.slice(0, sign.indexOf("(")).trim();
-
- if (returnSignature.indexOf(" ") === -1) { // Constructor or similar
- return retVals;
- }
-
- const returnType: string = returnSignature.substr(0, returnSignature.lastIndexOf(" "));
-
- switch (returnType) {
- case "bool":
- retVals.push("true");
- retVals.push("false");
- break;
- case "void":
- break;
- default:
- retVals.push(returnType);
- break;
- }
-
- return retVals;
- }
-
- protected getParams(method: string): string[] {
- const params: string[] = [];
-
- const endOfCtorIdx: number = method.search(/\)\s*:/g);
-
- let func: string = "";
-
- if (endOfCtorIdx !== -1) {
- func = method.substring(0, endOfCtorIdx + 1);
- } else {
- func = method;
- }
-
- // Get parameters from enclosing brackets
- const parameters: string = func.substring(func.indexOf("(") + 1, // Get text after opening bracket
- func.lastIndexOf(")")); // Remove closing bracket
-
- if (parameters.length === 0) { // No parameters
- return params;
- }
-
- let functionPointer: boolean = false;
-
- let paramArr: string[] = parameters.split(",");
- paramArr = paramArr.map((item: string) => {
- // Remove any special C++ characters
- const clean: string = item.trim().replace(/[&*\[\]]/g, "");
-
- // function pointer special case
- if (item.indexOf("(") !== -1) {
- if (item.indexOf(")") !== -1) {
- // Get the name of the function pointer
- const funPtr: string = clean.substring(item.indexOf("("), item.indexOf(")"))
- .replace(/[()]/g, ""); // Remove the brackets
-
- functionPointer = true;
- return funPtr.trim();
- }
- return null;
- }
-
- // Ignore all params until the closing bracket of the function pointer params
- if (item.indexOf(")") !== -1 && functionPointer) {
- functionPointer = false;
- return null;
- }
-
- return clean.split(" ").pop();
- });
-
- return paramArr;
- }
-
- protected getTemplateParams(method: string): string[] {
- // Todo implement parsing of template parameters.
- const tparams: string[] = [];
- return tparams;
- }
-}
diff --git a/src/CodeParser/CParser/CParser.ts b/src/CodeParser/CParser/CParser.ts
new file mode 100644
index 0000000..d0d0dcb
--- /dev/null
+++ b/src/CodeParser/CParser/CParser.ts
@@ -0,0 +1,387 @@
+import { Position, TextDocumentContentChangeEvent, TextEditor, TextLine, workspace } from "vscode";
+import { Config, ConfigType } from "../../Config";
+import Generator from "../../DocGen/CGen";
+import { IDocGen } from "../../DocGen/DocGen";
+import ICodeParser from "../CodeParser";
+import { ParseTree } from "./ParseTree";
+import { Token, TokenType } from "./Token";
+
+/**
+ *
+ * Parses C code for methods and signatures
+ *
+ * @export
+ * @class CParser
+ * @implements {ICodeParser}
+ */
+export default class CParser implements ICodeParser {
+ protected activeEditor: TextEditor;
+ protected activeSelection: Position;
+
+ private keywords: string[];
+ private lexerVocabulary;
+
+ constructor() {
+ this.keywords = [
+ "static",
+ "inline",
+ "friend",
+ "virtual",
+ "extern",
+ "explicit",
+ "const",
+ "struct",
+ "class",
+ "override",
+ ];
+
+ this.lexerVocabulary = {
+ ArraySubscript: (x: string): string => (x.match("^\\[[^\\[]*?\\]") || [])[0],
+ Arrow: (x: string): string => (x.match("^->") || [])[0],
+ Assignment: (x: string): string => (x.match("^=") || [])[0],
+ Attribute: (x: string): string => (x.match("^\\[\\[[^\\[]*?\\]\\]") || [])[0],
+ CloseParenthesis: (x: string): string => (x.match("^\\)") || [])[0],
+ Comma: (x: string): string => (x.match("^,") || [])[0],
+ CurlyBlock: (x: string): string => {
+ if (x.startsWith("{") === false) {
+ return undefined;
+ }
+ const startEndOffset: number[] = this.GetSubExprStartEnd(x, 0, "{", "}");
+ return startEndOffset[1] === 0 ? undefined : x.slice(0, startEndOffset[1]);
+ },
+ Ellipsis: (x: string): string => (x.match("^\\.\\.\\.") || [])[0],
+ OpenParenthesis: (x: string): string => (x.match("^\\(") || [])[0],
+ Pointer: (x: string): string => (x.match("^\\*") || [])[0],
+ Reference: (x: string): string => (x.match("^&") || [])[0],
+ Symbol: (x: string): string => {
+ // Handle operator and decltype special cases.
+ if (x.startsWith("operator") === true) {
+ const startBrace: number = x.indexOf("(");
+ return startBrace === -1 ? undefined : x.slice(0, startBrace);
+ } else if (x.startsWith("decltype") === true) {
+ const startEndOffset: number[] = this.GetSubExprStartEnd(x, 0, "(", ")");
+ return startEndOffset[1] === 0 ? undefined : x.slice(0, startEndOffset[1]);
+ }
+
+ const reMatch: string = (x.match("^[a-z|A-Z|:|_|\\d]+") || [])[0];
+ if (reMatch === undefined) {
+ return undefined;
+ }
+
+ // Check if symbol includes a template for instance Matrix<T, M, N> and include it if so.
+ if (x.slice(reMatch.length, x.length).trim().startsWith("<") === false) {
+ return reMatch;
+ }
+
+ const offsets: number[] = this.GetSubExprStartEnd(x, reMatch.length, "<", ">");
+ return offsets[1] === 0 ? undefined : x.slice(0, offsets[1]);
+ },
+ };
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public Parse(activeEdit: TextEditor, event: TextDocumentContentChangeEvent): IDocGen {
+ this.activeEditor = activeEdit;
+ this.activeSelection = this.activeEditor.selection.active;
+
+ const activeLine: TextLine = this.activeEditor.document.lineAt(this.activeEditor.selection.active.line);
+
+ let line: string = this.getLogicalLine();
+
+ // Not a method
+ if (line.length === 0) {
+ return null;
+ }
+
+ // template parsing is simpler by using heuristics rather then tokenizing first.
+ const template: string = this.GetTemplate(line);
+ const templateArgs: string[] = this.GetArgsFromTemplate(template);
+ let args: string[] = [];
+ let retVals: string[] = [];
+
+ line = line.slice(template.length, line.length + 1).trim();
+
+ try {
+ // Tokenize rest of expression;
+ const tokens: Token[] = this.Tokenize(line);
+ // Create hierarchical tree based on the parenthesis.
+ const tree: ParseTree = ParseTree.CreateTree(tokens).Compact();
+
+ const parsedArgs: ParseTree[] = tree.GetArgTrees();
+ const parsedReturns: ParseTree = tree.GetReturnTree();
+
+ args = parsedArgs
+ .map((a) => this.GetArgNameFromArgTree(a));
+
+ retVals = this.GetArgTypeFromReturnTree(parsedReturns);
+
+ } catch (err) {
+ args = [];
+ retVals = [];
+ }
+
+ const cppGenerator: IDocGen = new Generator(
+ this.activeEditor,
+ this.activeSelection,
+ args,
+ templateArgs,
+ retVals,
+ );
+ return cppGenerator;
+ }
+
+ /***************************************************************************
+ Implementation
+ ***************************************************************************/
+ protected getLogicalLine(): string {
+ let logicalLine: string = "";
+
+ let nextLine: Position = new Position(this.activeSelection.line + 1, this.activeSelection.character);
+
+ let nextLineTxt: string = this.activeEditor.document.lineAt(nextLine.line).text.trim();
+
+ // VSCode may enter a * on itself, we don"t want that in our method
+ if (nextLineTxt === "*") {
+ nextLineTxt = "";
+ }
+
+ while (nextLineTxt.length === 0) { // Get first method line
+ nextLine = new Position(nextLine.line + 1, nextLine.character);
+ nextLineTxt = this.activeEditor.document.lineAt(nextLine.line).text.trim();
+ }
+
+ logicalLine += nextLineTxt;
+
+ // Get method end line
+ while (nextLineTxt.indexOf(";") === -1 && nextLineTxt.indexOf("{") === -1) { // Check for method end
+ nextLine = new Position(nextLine.line + 1, nextLine.character);
+ nextLineTxt = this.activeEditor.document.lineAt(nextLine.line).text.trim();
+
+ logicalLine += " " + nextLineTxt;
+ }
+
+ logicalLine = logicalLine.replace(/[{|;]$/, "").trim();
+
+ return logicalLine;
+ }
+
+ private Tokenize(expression: string): Token[] {
+ const tokens: Token[] = [];
+ expression = expression.trim();
+
+ while (expression.length !== 0) {
+ const matches: Token[] = Object.keys(this.lexerVocabulary)
+ .map((k): Token => new Token(TokenType[k], this.lexerVocabulary[k](expression)))
+ .filter((t) => t.Value !== undefined);
+
+ if (matches.length === 0) {
+ throw new Error("Next token couldn\'t be determined: " + expression);
+ } else if (matches.length > 1) {
+ throw new Error("Multiple matches for next token: " + expression);
+ }
+
+ const match = matches[0];
+ tokens.push(match);
+ expression = expression.slice(match.Value.length, expression.length).trim();
+ }
+
+ return tokens;
+ }
+
+ private GetArgNameFromArgTree(tree: ParseTree): string {
+ const hasEllipsis: boolean = tree.nodes
+ .filter((n) => n instanceof Token && n.Type === TokenType.Ellipsis)
+ .length > 0;
+
+ const indexTrailingReturn: number = tree.nodes
+ .findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
+
+ const isFuncPtr: boolean = tree.nodes
+ .slice(0, indexTrailingReturn === -1 ? tree.nodes.length : indexTrailingReturn)
+ .filter((n) => n instanceof ParseTree)
+ .length === 2;
+
+ // If it is a function pointer the name is in the first tree.
+ if (isFuncPtr === true) {
+ const nestedTokens: Token[] = tree.nodes
+ .filter((n) => n instanceof ParseTree)
+ .map((n) => n as ParseTree)[0]
+ .nodes
+ .filter((n) => n instanceof Token)
+ .map((n) => n as Token)
+ .filter((t) => t.Type === TokenType.Symbol)
+ .filter((t) => this.keywords.find((k) => k === t.Value) === undefined);
+
+ return nestedTokens[0].Value;
+ }
+
+ const tokens: Token[] = tree.nodes
+ .filter((n) => n instanceof Token)
+ .map((n) => n as Token)
+ .filter((t) => t.Type === TokenType.Symbol)
+ .filter((t) => this.keywords.find((k) => k === t.Value) === undefined);
+
+ if (tokens.length === 0 && hasEllipsis === true) {
+ return "...";
+ }
+
+ if (tokens.length < 2) {
+ return "";
+ }
+
+ return tokens[1].Value;
+ }
+
+ private GetArgTypeFromReturnTree(tree: ParseTree): string[] {
+ // First strip out the param name or function name since it's not part of the type.
+ const indexTrailingReturn: number = tree.nodes
+ .findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
+
+ const isFuncPtr: boolean = tree.nodes
+ .slice(0, indexTrailingReturn === -1 ? tree.nodes.length : indexTrailingReturn)
+ .filter((n) => n instanceof ParseTree)
+ .length === 2;
+
+ let treeToModify: ParseTree = tree;
+ let symbolsFound = 0;
+ // If it is a function pointer the name is in the first tree.
+ if (isFuncPtr === true) {
+ treeToModify = tree.nodes
+ .filter((n) => n instanceof ParseTree)
+ .map((n) => n as ParseTree)[0];
+
+ // Function pointer so delete the first symbol in the tree
+ // Fake that one symbol was found.
+ symbolsFound = 1;
+ } else {
+ // Check for special case if return type is boolean or void.
+ for (const token of treeToModify.nodes) {
+ if (token instanceof ParseTree) {
+ break;
+ }
+ if (token.Type !== TokenType.Symbol) {
+ continue;
+ }
+
+ if (token.Value === "bool") {
+ return ["true", "false"];
+ } else if (token.Value === "void") {
+ return [];
+ }
+ }
+ }
+
+ for (let i = 0; i < treeToModify.nodes.length; i++) {
+ const node = treeToModify.nodes[i];
+ if (node instanceof ParseTree) {
+ break;
+ }
+
+ if (node instanceof Token
+ && node.Type === TokenType.Symbol
+ && this.keywords.find((k) => k === node.Value) === undefined
+ ) {
+ symbolsFound++;
+ }
+
+ if (symbolsFound === 2) {
+ treeToModify.nodes.splice(i, 1);
+ break;
+ }
+ }
+
+ return [tree.ToString()];
+ }
+
+ private GetSubExprStartEnd(expression: string, startSearch: number, openExpr: string, closeExpr: string): number[] {
+ let openExprOffset: number = -1;
+ let nestedCount: number = 0;
+ for (let i: number = startSearch; i < expression.length; i++) {
+ if (expression[i] === openExpr && openExprOffset === -1) {
+ openExprOffset = i;
+ }
+
+ if (expression[i] === openExpr) {
+ nestedCount++;
+ } else if (expression[i] === closeExpr && nestedCount > 0) {
+ nestedCount--;
+ }
+
+ if (expression[i] === closeExpr && nestedCount === 0 && openExprOffset !== -1) {
+ return [openExprOffset, i + 1];
+ }
+ }
+
+ return [0, 0];
+ }
+
+ private GetTemplate(expression: string): string {
+ if (expression.startsWith("template") === false) {
+ return "";
+ }
+
+ let startTemplateOffset: number = -1;
+ for (let i: number = "template".length; i < expression.length; i++) {
+ if (expression[i] === "<") {
+ startTemplateOffset = i;
+ break;
+ } else if (expression[i] !== " ") {
+ return "";
+ }
+ }
+
+ if (startTemplateOffset === -1) {
+ return "";
+ }
+
+ const [start, end] = this.GetSubExprStartEnd(expression, startTemplateOffset, "<", ">");
+ return expression.slice(0, end);
+ }
+
+ private GetArgsFromTemplate(template: string): string[] {
+ const args: string[] = [];
+ if (template === "") {
+ return args;
+ }
+
+ // Remove <> and add a comma to the end to remove edge case.
+ template = template.slice(template.indexOf("<") + 1, template.lastIndexOf(">")).trim() + ",";
+
+ const nestedCounts: { [key: string]: number; } = {
+ "(": 0,
+ "<": 0,
+ "{": 0,
+ };
+
+ let lastSeparator: number = 0;
+ for (let i: number = 0; i < template.length; i++) {
+ const notInSubExpr: boolean = nestedCounts["<"] === 0
+ && nestedCounts["("] === 0
+ && nestedCounts["{"] === 0;
+
+ if (notInSubExpr === true && template[i] === ",") {
+ args.push(template.slice(lastSeparator + 1, i).trim());
+ } else if (notInSubExpr === true && (template[i] === " " || template[i] === ".")) {
+ lastSeparator = i;
+ }
+
+ if (template[i] === "(") {
+ nestedCounts["("]++;
+ } else if (template[i] === ")" && nestedCounts["("] > 0) {
+ nestedCounts["("]--;
+ } else if (template[i] === "<") {
+ nestedCounts["<"]++;
+ } else if (template[i] === ">" && nestedCounts["<"] > 0) {
+ nestedCounts["<"]--;
+ } else if (template[i] === "{") {
+ nestedCounts["{"]++;
+ } else if (template[i] === "}" && nestedCounts["{"] > 0) {
+ nestedCounts["{"]--;
+ }
+ }
+
+ return args;
+ }
+}
diff --git a/src/CodeParser/CppParser.ts b/src/CodeParser/CParser/CppParser.ts
index 2d5985b..b3279c6 100644
--- a/src/CodeParser/CppParser.ts
+++ b/src/CodeParser/CParser/CppParser.ts
@@ -1,6 +1,6 @@
import { Position, TextDocumentContentChangeEvent, TextEditor, TextLine } from "vscode";
-import Generator from "../DocGen/CGen";
-import { IDocGen } from "../DocGen/DocGen";
+import Generator from "../../DocGen/CGen";
+import { IDocGen } from "../../DocGen/DocGen";
import CParser from "./CParser";
/**
diff --git a/src/CodeParser/CParser/ParseTree.ts b/src/CodeParser/CParser/ParseTree.ts
new file mode 100644
index 0000000..9090212
--- /dev/null
+++ b/src/CodeParser/CParser/ParseTree.ts
@@ -0,0 +1,220 @@
+import { Token, TokenType } from "./Token";
+
+export class ParseTree {
+
+ /**
+ * Create a tree from tokens. This consumes the tokens.
+ * @param tokens The tokens to create a tree for.
+ * @param inNested If currently allready nesting.
+ */
+ public static CreateTree(tokens: Token[], inNested: boolean = false): ParseTree {
+ const tree: ParseTree = new ParseTree();
+
+ while (tokens.length > 0) {
+ const token: Token = tokens.shift();
+ switch (token.Type) {
+ case TokenType.OpenParenthesis:
+ tree.nodes.push(this.CreateTree(tokens, true));
+ break;
+ case TokenType.CloseParenthesis:
+ if (inNested === false) {
+ throw new Error("Unmatched closing parenthesis.");
+ }
+ return tree;
+ default:
+ tree.nodes.push(token);
+ break;
+ }
+ }
+
+ if (inNested === true) {
+ throw new Error("No match found for an opening parenthesis.");
+ }
+
+ return tree;
+ }
+
+ public nodes: Array<Token | ParseTree> = [];
+
+ /**
+ * Compact empty branches. Example ((foo))(((bar))) will become (foo)(bar)
+ * @param tree The ParseTree to compact. Defaults to the current tree.
+ */
+ public Compact(tree: ParseTree = this): ParseTree {
+ const newTree: ParseTree = new ParseTree();
+ newTree.nodes = tree.nodes.map((n) => n);
+ const isNotCompact = (n) => n instanceof ParseTree && n.nodes.length === 1 && n.nodes[0] instanceof ParseTree;
+
+ // Compact current level of nodes to the maximum amount.
+ while (newTree.nodes.some((n) => isNotCompact(n))) {
+ newTree.nodes = newTree.nodes
+ .map((n) => n instanceof ParseTree && isNotCompact(n) ? n.nodes[0] : n);
+ }
+
+ // Compact all nested parsetrees and filter out empty branches.
+ newTree.nodes = newTree.nodes
+ .map((n) => n instanceof ParseTree ? this.Compact(n) : n);
+
+ return newTree;
+ }
+
+ /**
+ * Create string from the parsetree which is a representation of the original code.
+ */
+ public ToString(tree: ParseTree = this): string {
+ let code: string = "";
+
+ for (const node of tree.nodes) {
+ if (node instanceof ParseTree) {
+ code += "(" + this.ToString(node) + ")";
+ continue;
+ }
+
+ switch (node.Type) {
+ case TokenType.Symbol:
+ code += code === "" ? node.Value : " " + node.Value;
+ break;
+ case TokenType.Pointer:
+ code += node.Value;
+ break;
+ case TokenType.Reference:
+ code += node.Value;
+ break;
+ case TokenType.ArraySubscript:
+ code += node.Value;
+ break;
+ case TokenType.CurlyBlock:
+ code += node.Value;
+ break;
+ case TokenType.Assignment:
+ code += " " + node.Value + " ";
+ break;
+ case TokenType.Comma:
+ code += node.Value;
+ break;
+ case TokenType.Arrow:
+ code += " " + node.Value + " ";
+ break;
+ case TokenType.Ellipsis:
+ code += node.Value;
+ break;
+ case TokenType.Attribute:
+ code += code === "" ? node.Value : " " + node.Value;
+ break;
+ }
+ }
+
+ return code;
+ }
+
+ /**
+ * Get the tree for the return.
+ */
+ public GetReturnTree(): ParseTree {
+ const returnTree: ParseTree = new ParseTree();
+
+ const indexTrailingReturn: number = this.nodes
+ .findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
+
+ const isFuncPtr: boolean = this.nodes
+ .slice(0, indexTrailingReturn === -1 ? this.nodes.length : indexTrailingReturn)
+ .filter((n) => n instanceof ParseTree)
+ .length === 2;
+
+ if (isFuncPtr === true) {
+ const trees: ParseTree[] = this.nodes
+ .filter((n) => n instanceof ParseTree)
+ .map((n) => n as ParseTree);
+
+ // Add left most part to the return tokens.
+ for (const node of this.nodes) {
+ if (node instanceof ParseTree) {
+ break;
+ }
+ returnTree.nodes.push(node);
+ }
+
+ // add left and right parse tree to return tokens
+ const leftTree: ParseTree = new ParseTree();
+ for (const node of trees[0].nodes) {
+ if (node instanceof ParseTree) {
+ break;
+ }
+ leftTree.nodes.push(node);
+ }
+
+ returnTree.nodes.push(leftTree);
+ returnTree.nodes.push(trees[1]);
+ } else if (indexTrailingReturn !== -1) {
+ returnTree.nodes = this.nodes
+ .slice(indexTrailingReturn + 1, this.nodes.length);
+
+ // Don't include the auto so start from index 1.
+ for (let i: number = 1; i < this.nodes.length; i++) {
+ if (this.nodes[i] instanceof ParseTree) {
+ break;
+ }
+ returnTree.nodes.push(this.nodes[i]);
+ }
+ } else {
+ for (const node of this.nodes) {
+ if (node instanceof ParseTree) {
+ break;
+ }
+ returnTree.nodes.push(node);
+ }
+ }
+
+ return returnTree;
+ }
+
+ /**
+ * Get the arguments of the function and create a new ParseTree for each one.
+ */
+ public GetArgTrees(): ParseTree[] {
+ const args: ParseTree[] = [];
+
+ const indexTrailingReturn: number = this.nodes
+ .findIndex((t) => t instanceof Token ? t.Type === TokenType.Arrow : false);
+
+ const isFuncPtr: boolean = this.nodes
+ .slice(0, indexTrailingReturn === -1 ? this.nodes.length : indexTrailingReturn)
+ .filter((n) => n instanceof ParseTree)
+ .length === 2;
+
+ let argsTree: ParseTree = this.nodes
+ .filter((n) => n instanceof ParseTree)
+ .map((t) => t as ParseTree)[0];
+
+ // If it is a func ptr get the nested tree.
+ if (isFuncPtr === true) {
+ argsTree = argsTree.nodes
+ .filter((n) => n instanceof ParseTree)
+ .map((t) => t as ParseTree)[0];
+ }
+
+ if (argsTree === undefined) {
+ throw new Error("Couldn't find arguments tree");
+ }
+
+ // split args at command and create a tree for each one.
+ let lastComma: number = 0;
+ for (let i = 0; i < argsTree.nodes.length; i++) {
+ const node = argsTree.nodes[i];
+ if (node instanceof Token && node.Type === TokenType.Comma) {
+ const tree: ParseTree = new ParseTree();
+ tree.nodes = argsTree.nodes.slice(lastComma, i);
+ args.push(tree);
+ lastComma = i + 1;
+ }
+ }
+
+ const lastArgTree: ParseTree = new ParseTree();
+ lastArgTree.nodes = argsTree.nodes.slice(lastComma, argsTree.nodes.length);
+ if (lastArgTree.nodes.length > 0) {
+ args.push(lastArgTree);
+ }
+
+ return args;
+ }
+}
diff --git a/src/CodeParser/CParser/Token.ts b/src/CodeParser/CParser/Token.ts
new file mode 100644
index 0000000..379fd46
--- /dev/null
+++ b/src/CodeParser/CParser/Token.ts
@@ -0,0 +1,24 @@
+export enum TokenType {
+ Symbol,
+ Pointer,
+ Reference,
+ ArraySubscript,
+ OpenParenthesis,
+ CloseParenthesis,
+ CurlyBlock,
+ Assignment,
+ Comma,
+ Arrow,
+ Ellipsis,
+ Attribute,
+}
+
+export class Token {
+ public Type: TokenType;
+ public Value: string;
+
+ constructor(type: TokenType, value: string) {
+ this.Type = type;
+ this.Value = value;
+ }
+}
diff --git a/src/CodeParser/CodeParserController.ts b/src/CodeParser/CodeParserController.ts
index 70941d0..bd5a60b 100644
--- a/src/CodeParser/CodeParserController.ts
+++ b/src/CodeParser/CodeParserController.ts
@@ -10,8 +10,8 @@ import {
} from "vscode";
import { Config, ConfigType } from "../Config";
import CodeParser from "./CodeParser";
-import CParser from "./CParser";
-import CppParser from "./CppParser";
+import CParser from "./CParser/CParser";
+import CppParser from "./CParser/CppParser";
/**
*