diff options
| author | Rowan Goemans <RB.Goemans@student.han.nl> | 2017-10-30 01:46:33 +0100 |
|---|---|---|
| committer | Christoph Schlosser <christophschlosser@users.noreply.github.com> | 2017-11-05 18:45:08 +0100 |
| commit | 666f392bd23574f57689e9a9ea6d6a05a9bd2f97 (patch) | |
| tree | dcad101896db2e2e0867168bd233c97711920a0c /src | |
| parent | d2bda50f26bffd6a56574188704d9df50fecabf8 (diff) | |
| download | doxdocgen-666f392bd23574f57689e9a9ea6d6a05a9bd2f97.tar.gz | |
-- Completely rewritten parser to support all known(to me) C++ constructs, this includes:
- Function pointers as parameters and as returns.
- Template support.
- Trailing return type.
- Variadic templates.
- Variadic parametes, C style and template style.
- Correct parsing of template types with more then 1 template parameter.
Diffstat (limited to 'src')
| -rw-r--r-- | src/CodeParser/CParser.ts | 175 | ||||
| -rw-r--r-- | src/CodeParser/CParser/CParser.ts | 387 | ||||
| -rw-r--r-- | src/CodeParser/CParser/CppParser.ts (renamed from src/CodeParser/CppParser.ts) | 4 | ||||
| -rw-r--r-- | src/CodeParser/CParser/ParseTree.ts | 220 | ||||
| -rw-r--r-- | src/CodeParser/CParser/Token.ts | 24 | ||||
| -rw-r--r-- | src/CodeParser/CodeParserController.ts | 4 | ||||
| -rw-r--r-- | src/DocGen/CGen.ts | 6 |
7 files changed, 638 insertions, 182 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"; /** * diff --git a/src/DocGen/CGen.ts b/src/DocGen/CGen.ts index e333014..d6c45cf 100644 --- a/src/DocGen/CGen.ts +++ b/src/DocGen/CGen.ts @@ -27,21 +27,21 @@ export default class CGen implements IDocGen { /** * @param {TextEditor} actEdit Active editor window * @param {Position} cursorPosition Where the cursor of the user currently is - * @param {string[]} param The parameter names of the method extracted by the parser + * @param {string[]} params The parameter names of the method extracted by the parser * @param {string[]} tparam The template parameter names of the method extracted by the parser. * @param {string[]} returnVals The return values extracted by the parser */ public constructor( actEdit: TextEditor, cursorPosition: Position, - param: string[], + params: string[], tparam: string[], returnVals: string[], ) { this.activeEditor = actEdit; this.templateParamReplace = "{param}"; this.templateTypeReplace = "{type}"; - this.params = param; + this.params = params; this.tparams = tparam; this.retVals = returnVals; } |