Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
"gpt-tokenizer": "^2.1.2",
"groq-sdk": "^0.8.0",
"octokit": "^3.1.1",
"tree-sitter": "^0.22.1",
"tree-sitter-python": "^0.23.4",
"xml2js": "^0.6.2"
},
"devDependencies": {
Expand Down
16 changes: 14 additions & 2 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,21 @@ export const processGitFilepath = (filepath: string) => {
};

export interface EnclosingContext {
enclosingContext: Node | null;
enclosingContext: Node | TreeSitterNode | null;
}
export interface TreeSitterNode {
type: string;
loc: {
start: {
line: number;
column: number;
};
end: {
line: number;
column: number;
};
};
}

export interface AbstractParser {
findEnclosingContext(
file: string,
Expand Down
118 changes: 115 additions & 3 deletions src/context/language/python-parser.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,127 @@
import { AbstractParser, EnclosingContext } from "../../constants";
import {
AbstractParser,
EnclosingContext,
TreeSitterNode,
} from "../../constants";
import Parser from "tree-sitter";
import Python from "tree-sitter-python";
import * as fs from "fs";

/**
* Utility function to process AST node and check if it fully encloses a given line range.
*/
const processNode = (
node: Parser.SyntaxNode,
lineStart: number,
lineEnd: number,
largestSize: number,
largestEnclosingContext: Parser.SyntaxNode | null
) => {
const { startPosition, endPosition } = node;

//Check if node fully encloses the target line range
if (startPosition.row + 1 <= lineStart && lineEnd <= endPosition.row + 1) {
const size = endPosition.row - startPosition.row;
if (size > largestSize) {
largestSize = size;
largestEnclosingContext = node;
}
}
return { largestSize, largestEnclosingContext };
};

/**
* Convert a Tree0sitter 'syntax node to a TreeSitternode
*/
const convertSyntaxNodeToTreeSitterNode = (
syntaxNode: Parser.SyntaxNode
): TreeSitterNode => {
return {
type: syntaxNode.type,
loc: {
start: {
line: syntaxNode.startPosition.row + 1,
column: syntaxNode.startPosition.column,
},
end: {
line: syntaxNode.endPosition.row + 1,
column: syntaxNode.endPosition.column,
},
},
};
};

/**
* Python parser: A parser for python code that identifies syntatic contexts
* and validates code as part of teh AI agents's code review system.
*/
export class PythonParser implements AbstractParser {
private parser: Parser;

constructor() {
this.parser = new Parser();
this.parser.setLanguage(Python);
}
/**
*
* @param file - Content of the python file
* @param lineStart - Starting line number (1-based)
* @param lineEnd - Ending line number (1-based)
* @returns An EnclosingContext object with the type of the the enclosing node
*/
findEnclosingContext(
file: string,
lineStart: number,
lineEnd: number
): EnclosingContext {
// TODO: Implement this method for Python
return null;
const tree = this.parser.parse(file);

let largestEnclosingContext: Parser.SyntaxNode | null = null;
let largestSize = 0;
/**
* Recursive fucntion to traverse AST nodes
*/
const traverseNodes = (node: Parser.SyntaxNode) => {
({ largestSize, largestEnclosingContext } = processNode(
node,
lineStart,
lineEnd,
largestSize,
largestEnclosingContext
));
//Recursice inspect child nodes
for (let i = 0; i < node.childCount; i++) {
traverseNodes(node.child(i));
}
};

//Start of the traversal from root node
traverseNodes(tree.rootNode);

return {
enclosingContext: largestEnclosingContext
? convertSyntaxNodeToTreeSitterNode(largestEnclosingContext)
: null,
};
}
dryRun(file: string): { valid: boolean; error: string } {
// TODO: Implement this method for Python
return { valid: false, error: "Not implemented yet" };
try {
const tree = this.parser.parse(file);

if (tree.rootNode.hasError) {
return {
valid: false,
error: "Syntax error in Python code",
};
}
return { valid: true, error: "" };
} catch (err) {
return {
valid: false,
error: `Error parsing pyhton code: ${err.message}`,
};
}
}
}
18 changes: 9 additions & 9 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"compilerOptions": {
"outDir": "./dist",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es6"
"allowSyntheticDefaultImports": true, //Addion 1 neccesary for tree sitter
"esModuleInterop": true, //Addition 2 for tree sitter and implmentation of python parser
"outDir": "./dist",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es6"
},
"include": [
"./src/**/*"
]
}
"include": ["./src/**/*"]
}