-
Notifications
You must be signed in to change notification settings - Fork 21
Python Implementation of Ubisoft's Clever-Initiative coding challenge #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
andykdy
wants to merge
11
commits into
MathieuNls:master
Choose a base branch
from
andykdy:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
c13d71c
Initial Python commit
andykdy 1c36624
Deleting Go files
andykdy 95cc23c
regex for Regions and corrected diff results
andykdy 5da7be3
addline and deleteline
andykdy 6b7c1c9
files regex partial
andykdy 160e8e7
part 1 complete TODO refactor for SOLID principles
andykdy 4d6bb13
changes for Feb 4th and addition of thoughts.md
andykdy d4db937
ASTParser start
andykdy 9c0c070
Final Commit
andykdy f95e4d7
added documentation and included array in astParser
andykdy f3f8853
Addressing code review. Fixed duplicate filelist. Code adheres to PEP…
andykdy File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| A place to convey my thoughts. | ||
|
|
||
| Feb 4th 2019\ | ||
| DiffParser is mostly "complete" functionally speaking but some of the regex are hard coded and untested.\ | ||
| Before moving to ASTParser I will do a small check. Then once both AST and Diff are complete, I will do another sweep to refactor the code.\ | ||
| - I tried allowing users to input a flag they wanted to log information on, but allowing users to manipulate the regex seems to be opening up the program a bit too much, instead the information should be kept within\ | ||
| - Is there any way I can group the list of "if" statements? \ | ||
| - I think I have misunderstood what functionCalls is asking for.\ | ||
| - Commas are optional for regions\ | ||
| - Replaced [^n]* with .* | ||
| - For some reason it catches 196480 in * (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80). as a function call.\ | ||
|
|
||
| Feb 16th 2019\ | ||
| DiffParser FunctionCall is still incorrect, but I have moved on to ASTParser.\ | ||
| ASTParser seems relatively simple, because we are only looking for declared variables. | ||
| - Recursive traversal of AST should return a node instead of variable_declaration | ||
| - Should variable_declaration be in ast_result? Would a tuple suffice? | ||
|
|
||
| Feb 21st 2019\ | ||
| DiffParser is complete, but functionCall captures "8" as a functional when parsing assembly offset such as 8(%rdi). | ||
| ASTParser is complete, not sure if the tree traversal is too hardcoded. |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import json | ||
| from ast_result import ASTResult | ||
|
|
||
| # *Goal* | ||
| # Parse an AST to return all the declared variables in the following format | ||
| # {int}{myInt} | ||
| # {string}{myInt} | ||
| # {Foo}{myFooObject} | ||
|
|
||
|
|
||
| class ASTParser: | ||
| def __init__(self): | ||
| print("ASTParser created") | ||
|
|
||
| def parse(self, file): | ||
| """ Load JSON file into dictionary and parse """ | ||
| tree_json = json.load(file) | ||
| ast_res = ASTResult() | ||
| root = tree_json['Root'] | ||
| var_nodes = [] | ||
| # Returns a list of nodes from the AST that are variables | ||
| traverse_search(root, 'VariableDeclaration', var_nodes) | ||
| # Parses each variable node to a variable tuple and returns a list of tuples | ||
| ast_res.variableDeclarations = node_to_var(var_nodes) | ||
| return ast_res | ||
|
|
||
|
|
||
| def node_to_var(var_nodes): | ||
| """Converts each variable node to a variable tuple""" | ||
| var_array = [] | ||
| for node in var_nodes: | ||
| array_variables = [] | ||
| traverse_search(node, 'ArrayCreationExpression', array_variables) | ||
| var_type = find_val(node, 'PredefinedType') | ||
| var_name = find_val(node, 'VariableDeclarator') | ||
| if array_variables: | ||
| var_type += "[]" | ||
| var_array.append((var_type, var_name)) | ||
| return var_array | ||
|
|
||
|
|
||
| def traverse_search(root, look_for, result_list): | ||
| """ | ||
| Recursive traversal of AST to find a node with Type == lookfor | ||
| Appends all nodes that match to resultList which is maintained because python is pass by reference | ||
| """ | ||
| for child in root['Children']: | ||
| if child['Type'] == look_for: | ||
| result_list.append(child) | ||
| else: | ||
| traverse_search(child, look_for, result_list) | ||
|
|
||
|
|
||
| def find_val(var_node, look_for): | ||
| """ | ||
| Use traverseSearch() to find... | ||
| Variable Name found under node VariableDeclarator | ||
| Variable Type found under node PredefinedType | ||
| """ | ||
| found = [] | ||
| traverse_search(var_node, look_for, found) | ||
| if found: | ||
| return found[0]['Children'][0]['ValueText'] | ||
andykdy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| class ASTResult: | ||
| def __init__(self): | ||
| self.variableDeclarations = [] | ||
|
|
||
| def to_text(self): | ||
| with open('astResult.txt', 'w') as output: | ||
| for variable in self.variableDeclarations: | ||
| output.write("{" + variable[0] + "}{" + variable[1] + "}\n") |
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| import re | ||
| from diff_result import DiffResult | ||
| from difflib import SequenceMatcher | ||
|
|
||
| # *Goal* | ||
| # Parse a diff files in the most efficient way possible. | ||
| # Keep these in mind, speed, maintainability, evolvability, etc.... | ||
| # Compute the following | ||
| # - List of files in the diffs | ||
| # - number of regions | ||
| # - number of lines added | ||
| # - number of lines deleted | ||
| # - list of function calls seen in the diffs and their number of calls | ||
|
|
||
|
|
||
| class DiffParser: | ||
|
|
||
| def __init__(self): | ||
| print("DiffParser created") | ||
|
|
||
| def parse(self, file): | ||
| # Regex Patterns | ||
| filelist_rgx = r'^diff --[^\s]* (.*)' | ||
| region_rgx = r'^@@ -\d+(,\d+)? \+\d+(,\d+)? @@.*' | ||
| added_rgx = r'^(\+).*' | ||
| deleted_rgx = r'^(\-).*' | ||
| fnlist_rgx = r'(?<=(?:\s|\.))([\w]+)(?=\()' | ||
|
|
||
| # Object holding results | ||
| diff_res = DiffResult() | ||
|
|
||
| lines = file.readlines() | ||
| # Lines such as | ||
| # +++ <filename> | ||
| # --- <filename> | ||
| # are caught in the regex for added lines | ||
| # having a "bubble" after a region starts allows us to manually filter those out. | ||
| area_start = 0 | ||
| for line in lines: | ||
| if re.search(filelist_rgx, line): | ||
| path_a = re.search(filelist_rgx, line).group(1).split(" ")[0] | ||
| path_b = re.search(filelist_rgx, line).group(1).split(" ")[1] | ||
| if len(path_a) is 0 or len(path_b) is 0: | ||
| raise ValueError | ||
| match = SequenceMatcher(None, path_a, path_b).find_longest_match(0, len(path_a), 0, len(path_b)) | ||
| diff_res.files.append(path_a[match.a: match.a + match.size]) | ||
|
|
||
| area_start = 4 | ||
| if re.search(region_rgx, line): | ||
| diff_res.regions += 1 | ||
| if re.search(added_rgx, line) and area_start < 0: | ||
| diff_res.lineAdded += 1 | ||
| if re.search(deleted_rgx, line) and area_start < 0: | ||
| diff_res.lineDeleted += 1 | ||
| if re.search(fnlist_rgx, line): | ||
| diff_res.functionCalls[re.search(fnlist_rgx, line).group(1)] += 1 | ||
| area_start -= 1 | ||
| return diff_res | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| from collections import defaultdict | ||
|
|
||
| class DiffResult: | ||
| def __init__(self): | ||
| self.files = [] | ||
| self.regions = 0 | ||
| self.lineAdded = 0 | ||
| self.lineDeleted = 0 | ||
| self.functionCalls = defaultdict(int) | ||
|
|
||
| def to_text(self): | ||
| with open('diffResult.txt', 'w') as output: | ||
andykdy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| output.write("Files: \n") | ||
andykdy marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| for file in self.files: | ||
| output.write(" - ") | ||
| output.write(file) | ||
| output.write("\n") | ||
| output.write("Regions: " + str(self.regions) + "\n") | ||
| output.write("Lines Added: " + str(self.lineAdded) + "\n") | ||
| output.write("Lines Deleted: " + str(self.lineDeleted) + "\n") | ||
| output.write("Function Calls: \n") | ||
| for key,value in self.functionCalls.items(): | ||
| output.write(" - ") | ||
| output.write(key + ": " + str(value)) | ||
| output.write("\n") | ||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.