Merged PR 4509: CppToJson First Version

Added all basic files required for the functionality of CppToJson, including some basic testing
This commit is contained in:
Teo Magnino Chaban 2019-06-07 17:08:06 +00:00
Родитель 007601c4da
Коммит 84d4f9faba
8 изменённых файлов: 475 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,82 @@
import os
import re
import clang.cindex as cindex
import CommonEnvironment.FileSystem as fileSystem
import CommonEnvironment.CallOnExit as callOnExit
import CommonEnvironment.Shell as CE_Shell
def ObtainFunctions(input_filename):
'''
This function will extract return value, name and parameters for every
function given. input_filename can be a file name or a string that is the code
itself.
Return value:
Returns a list of functions, every item in this list is a dictionary that
has information about the function.
'''
is_temp_file = False
# Since clang can only parse from a file, if we are given a string we need to create
# a new temp file and put the string inside.
if not fileSystem.IsFilename(input_filename):
is_temp_file = True
file_content = input_filename
input_filename = CE_Shell.Shell.CreateTempFilename(suffix=".cpp")
with open(input_filename, "w") as file_pointer:
file_pointer.write(file_content)
# ----------------------------------------------------------------------
def DeleteFile():
if is_temp_file:
os.remove(input_filename)
# ----------------------------------------------------------------------
with callOnExit.CallOnExit(DeleteFile):
funcs_list = []
pattern_const = re.compile("^const ")
pattern_star = re.compile(r"( \*)*\**")
pattern_amper = re.compile("( &)*&*")
# ----------------------------------------------------------------------
def SimpleVarType(name):
name = re.sub(pattern_const, "", name)
name = re.sub(pattern_star, "", name)
name = re.sub(pattern_amper, "", name)
return name
# ----------------------------------------------------------------------
index = cindex.Index.create()
args = []
if os.name == 'posix':
args = ['-I{}'.format(v) for v in os.environ['INCLUDE'].split(":") if v.strip()]
translation_unit = index.parse(input_filename, args=args)
cursor = translation_unit.cursor
# ----------------------------------------------------------------------
def Enumerate(node):
if node.kind == cindex.CursorKind.NAMESPACE:
for child in node.get_children():
Enumerate(child)
if node.kind == cindex.CursorKind.FUNCTION_DECL and node.location.file.name == input_filename:
func = {}
func["func_name"] = node.spelling
func["raw_return_type"] = node.result_type.spelling
func["simple_return_type"] = SimpleVarType(node.result_type.spelling)
func["var_names"] = []
func["raw_var_types"] = []
func["simple_var_types"] = []
for arg in node.get_arguments():
func["var_names"].append(arg.displayname)
func["raw_var_types"].append(arg.type.spelling)
func["simple_var_types"].append(SimpleVarType(arg.type.spelling))
funcs_list.append(func)
# ----------------------------------------------------------------------
for child in cursor.get_children():
Enumerate(child)
return funcs_list
# ----------------------------------------------------------------------

Просмотреть файл

@ -0,0 +1,65 @@
'''Integration tests for CppToJson.py
'''
import sys
import os
import json
import unittest
import CommonEnvironment
from DataPipelines import CppToJson
# ----------------------------------------------------------------------
_script_fullpath = CommonEnvironment.ThisFullpath()
_script_dir, _script_name = os.path.split(_script_fullpath)
# ----------------------------------------------------------------------
class FileTest(unittest.TestCase):
'''
The purpose of this function is to verify the file-based capabilities of the ObtainFunctions method. It will make sure
that the files are being opened and the information inside is being correctly processed.
'''
def test_basic_file(self):
func_list = CppToJson.ObtainFunctions(os.path.join(_script_dir, "basicFunc.cpp"))
self.assertEqual(func_list[0], {'func_name': 'add', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': ['a', 'b'], 'raw_var_types': ['int', 'int'], 'simple_var_types': ['int', 'int']})
self.assertEqual(func_list[1], {'func_name': 'sub', 'raw_return_type': 'float', 'simple_return_type': 'float', 'var_names': ['a', 'b'], 'raw_var_types': ['float', 'float'], 'simple_var_types': ['float', 'float']})
self.assertEqual(func_list[2], {'func_name': 'isPos', 'raw_return_type': 'bool', 'simple_return_type': 'bool', 'var_names': ['x'], 'raw_var_types': ['bool'], 'simple_var_types': ['bool']})
self.assertEqual(func_list[3], {'func_name': 'three', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
self.assertEqual(func_list[4], {'func_name': 'nothing', 'raw_return_type': 'void', 'simple_return_type': 'void', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
self.assertEqual(func_list[5], {'func_name': 'main', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
def test_medium_file(self):
func_list = CppToJson.ObtainFunctions(os.path.join(_script_dir, "mediumFunc.cpp"))
self.assertEqual(func_list[0], {'func_name': 'add', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': ['a', 'b'], 'raw_var_types': ['float', 'int'], 'simple_var_types': ['float', 'int']})
self.assertEqual(func_list[1], {'func_name': 'mult', 'raw_return_type': 'float', 'simple_return_type': 'float', 'var_names': ['a', 'b', 'signal'], 'raw_var_types': ['int', 'float', 'bool'], 'simple_var_types': ['int', 'float', 'bool']})
self.assertEqual(func_list[2], {'func_name': 'toUp', 'raw_return_type': 'std::string', 'simple_return_type': 'std::string', 'var_names': ['s'], 'raw_var_types': ['std::string'], 'simple_var_types': ['std::string']})
self.assertEqual(func_list[3], {'func_name': 'fat', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': ['curr', 'at'], 'raw_var_types': ['int', 'int'], 'simple_var_types': ['int', 'int']})
self.assertEqual(func_list[4], {'func_name': 'main', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
def test_hard_file(self):
func_list = CppToJson.ObtainFunctions(os.path.join(_script_dir, "hardFunc.cpp"))
self.assertEqual(func_list[0], {'func_name': 'add', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': ['a'], 'raw_var_types': ['int'], 'simple_var_types': ['int']})
self.assertEqual(func_list[1], {'func_name': 'main', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
self.assertEqual(func_list[2], {'func_name': 'bubbleSort', 'raw_return_type': 'vector<int>', 'simple_return_type': 'vector<int>', 'var_names': ['v'], 'raw_var_types': ['vector<int>'], 'simple_var_types': ['vector<int>']})
self.assertEqual(func_list[3], {'func_name': 'sizeOfMap', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': ['mp'], 'raw_var_types': ['map<int, bool>'], 'simple_var_types': ['map<int, bool>']})
self.assertEqual(func_list[4], {'func_name': 'keys', 'raw_return_type': 'vector<int>', 'simple_return_type': 'vector<int>', 'var_names': ['mp'], 'raw_var_types': ['map<int, int>'], 'simple_var_types': ['map<int, int>']})
self.assertEqual(func_list[5], {'func_name': 'goCount', 'raw_return_type': 'map<float, int>', 'simple_return_type': 'map<float, int>', 'var_names': ['v', 'signal'], 'raw_var_types': ['vector<float>', 'bool'], 'simple_var_types': ['vector<float>', 'bool']})
def test_convoluted_file(self):
func_list = CppToJson.ObtainFunctions(os.path.join(_script_dir, "convolutedFunc.cpp"))
self.assertEqual(func_list[0], {'func_name': 'matrix', 'raw_return_type': 'vector<vector<int> >', 'simple_return_type': 'vector<vector<int> >', 'var_names': ['n'], 'raw_var_types': ['int'], 'simple_var_types': ['int']})
self.assertEqual(func_list[1], {'func_name': 'nonsense', 'raw_return_type': 'map<map<int, vector<bool> >, vector<float> >', 'simple_return_type': 'map<map<int, vector<bool> >, vector<float> >', 'var_names': ['n'], 'raw_var_types': ['int'], 'simple_var_types': ['int']})
self.assertEqual(func_list[2], {'func_name': 'vectorLine', 'raw_return_type': 'vector<vector<vector<vector<float> > > >', 'simple_return_type': 'vector<vector<vector<vector<float> > > >', 'var_names': ['mp'], 'raw_var_types': ['map<bool, int>'], 'simple_var_types': ['map<bool, int>']})
self.assertEqual(func_list[3], {'func_name': 'countVector', 'raw_return_type': 'map<int, int>', 'simple_return_type': 'map<int, int>', 'var_names': ['v'], 'raw_var_types': ['vector<vector<int> >'], 'simple_var_types': ['vector<vector<int> >']})
self.assertEqual(func_list[4], {'func_name': 'main', 'raw_return_type': 'int', 'simple_return_type': 'int', 'var_names': [], 'raw_var_types': [], 'simple_var_types': []})
if __name__ == '__main__':
unittest.main()

Просмотреть файл

@ -0,0 +1,30 @@
#include <iostream>
#include <stdio.h>
using namespace std;
int add(int a, int b){
return a + b;
}
float sub(float a, float b){
return a + b;
}
bool isPos(bool x){
return x;
}
int three(){
return 3;
}
void nothing(){
return;
}
int main(){
cout << "Hello World" << endl;
return 0;
}

Просмотреть файл

@ -0,0 +1,61 @@
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <vector>
using namespace std;
vector<vector<int>> matrix(int n){
vector<vector<int>> ret(n);
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
ret[i].push_back(i*4 + j);
}
}
return ret;
}
map<map<int, vector<bool>>, vector<float>> nonsense(int n){
map<map<int, vector<bool>>, vector<float>> ret;
map<int, vector<bool>> mpv;
mpv[32].push_back(0);
mpv[347].push_back(1);
ret[mpv].push_back(3.1415926);
return ret;
}
vector<vector<vector<vector<float>>>> vectorLine(map<bool, int> mp){
vector<vector<vector<vector<float>>>> ret;
vector<float> v = {3.4, 7.231321, 5, 0, -10};
vector<vector<float>> vv = {v, v};
vector<vector<vector<float>>> vvv = {vv, vv, vv, vv, vv};
ret.push_back(vvv);
vvv.clear();
ret.push_back(vvv);
return ret;
}
map<int, int> countVector(vector<vector<int>> v){
map<int, int>ret;
for(int i = 0; i < v.size(); i++){
ret[i] = v[i].size();
}
return ret;
}
int main(){
cout << "Hello World" << endl;
vector<vector<int>>v;
v = matrix(4);
for(int i=0; i<4; i++){
for(int j=0; j<4; j++){
cout << v[i][j] << " ";
}
cout << endl;
}
return 0;
}

Просмотреть файл

@ -0,0 +1,51 @@
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <vector>
using namespace std;
int add(int a){
return 2;
}
int n;
vector<int>x;
int main(){
cout << "Hello World" << endl;
return 0;
}
vector<int> bubbleSort(vector<int> v){
for(int i = 0; i < v.size(); i++){
for(int j = i + 1; j < v.size() ; j++){
if(v[i] > v[j])
swap(v[i], v[j]);
}
}
return v;
}
int sizeOfMap(map<int, bool> mp){
return mp.size();
}
vector<int> keys(map<int, int> mp){
vector<int> ret;
for(auto it : mp){
ret.push_back(it.first);
}
return ret;
}
map<float, int> goCount(vector<float> v, bool signal){
map<float, int> ret;
for(int i = 0; i < v.size(); i++){
ret[i] = v[i] * (2*signal - 1);
}
return ret;
}

Просмотреть файл

@ -0,0 +1,27 @@
#include <iostream>#include <stdio.h>#include <string>
using namespace std;
int add(float a, int b){
return a + b;
}
float mult(int a, float b, bool signal){
return a * b * (2*signal - 1);
}
string toUp(string s){
if(s[0] <= 'a' and s[0]<='z')
s[0] = s[0] - 'a' + 'A';
return s;
}
int fat(int curr, int at = 3){
if(at == 0)return 1;
return curr * fat(curr - 1, at - 1);
}
int main(){
cout << "Hello World" << endl;
return 0;
}

Просмотреть файл

@ -0,0 +1,135 @@
'''Unit test for CppToJson.py
'''
import sys
import json
import unittest
import textwrap
from DataPipelines import CppToJson
class FuncTest(unittest.TestCase):
def test_add_func(self):
s = textwrap.dedent('''
int add(int a, int b){
return a+b;
}
int main(){
return 0;
}
''')
func_list = CppToJson.ObtainFunctions(s)
self.assertEqual(func_list[0]['func_name'], 'add')
self.assertEqual(func_list[0]['raw_return_type'], 'int')
self.assertEqual(func_list[0]['simple_return_type'], 'int')
self.assertEqual(func_list[0]['var_names'], ['a', 'b'])
self.assertEqual(func_list[0]['raw_var_types'], ['int', 'int'])
self.assertEqual(func_list[0]['simple_var_types'], ['int', 'int'])
self.assertEqual(func_list[1]['func_name'], 'main')
self.assertEqual(func_list[1]['raw_return_type'], 'int')
self.assertEqual(func_list[1]['simple_return_type'], 'int')
self.assertEqual(func_list[1]['var_names'], [])
self.assertEqual(func_list[1]['raw_var_types'], [])
self.assertEqual(func_list[1]['simple_var_types'], [])
def test_vector_func(self):
s = textwrap.dedent('''
#include <vector>
std::vector<int> counting(std::vector<float> v, float x){
std::vector<int>ret;
for(int i = 0; i < v.size(); i++){
if(v[i]==x)
ret.push_back(i);
}
return ret;
}
int main(){
return 0;
}
''')
func_list = CppToJson.ObtainFunctions(s)
self.assertEqual(func_list[0]['func_name'], 'counting')
self.assertEqual(func_list[0]['raw_return_type'], 'std::vector<int>')
self.assertEqual(func_list[0]['simple_return_type'], 'std::vector<int>')
self.assertEqual(func_list[0]['var_names'], ['v', 'x'])
self.assertEqual(func_list[0]['raw_var_types'], ['std::vector<float>', 'float'])
self.assertEqual(func_list[0]['simple_var_types'], ['std::vector<float>', 'float'])
self.assertEqual(func_list[1]['func_name'], 'main')
self.assertEqual(func_list[1]['raw_return_type'], 'int')
self.assertEqual(func_list[1]['simple_return_type'], 'int')
self.assertEqual(func_list[1]['var_names'], [])
self.assertEqual(func_list[1]['raw_var_types'], [])
self.assertEqual(func_list[1]['simple_var_types'], [])
def test_vector_using_std_func(self):
s = textwrap.dedent('''
#include <vector>
using namespace std;
vector<int> counting(vector<float> v, float x){
vector<int>ret;for(int i = 0; i < v.size(); i++){
if(v[i]==x)
ret.push_back(i);
}
return ret;
}
int main(){
return 0;
}
''')
func_list = CppToJson.ObtainFunctions(s)
self.assertEqual(func_list[0]['func_name'], 'counting')
self.assertEqual(func_list[0]['raw_return_type'], 'vector<int>')
self.assertEqual(func_list[0]['simple_return_type'], 'vector<int>')
self.assertEqual(func_list[0]['var_names'], ['v', 'x'])
self.assertEqual(func_list[0]['raw_var_types'], ['vector<float>', 'float'])
self.assertEqual(func_list[0]['simple_var_types'], ['vector<float>', 'float'])
self.assertEqual(func_list[1]['func_name'], 'main')
self.assertEqual(func_list[1]['raw_return_type'], 'int')
self.assertEqual(func_list[1]['simple_return_type'], 'int')
self.assertEqual(func_list[1]['var_names'], [])
self.assertEqual(func_list[1]['raw_var_types'], [])
self.assertEqual(func_list[1]['simple_var_types'], [])
def test_vector_map(self):
s = textwrap.dedent('''
#include <vector>
#include <map>
using namespace std;
vector<vector<int>> counting(vector<map<float,int>> v, float x){
vector<vector<int>>ret;
for(int i=0; i<v.size(); i++){
if(v[i][x])ret.push_back({1, 2, 3, 4});
}
return ret;
}
int main(){
return 0;
}
''')
func_list = CppToJson.ObtainFunctions(s)
self.assertEqual(func_list[0]['func_name'], 'counting')
self.assertEqual(func_list[0]['raw_return_type'], 'vector<vector<int> >')
self.assertEqual(func_list[0]['simple_return_type'], 'vector<vector<int> >')
self.assertEqual(func_list[0]['var_names'], ['v', 'x'])
self.assertEqual(func_list[0]['raw_var_types'], ['vector<map<float, int> >', 'float'])
self.assertEqual(func_list[0]['simple_var_types'], ['vector<map<float, int> >', 'float'])
self.assertEqual(func_list[1]['func_name'], 'main')
self.assertEqual(func_list[1]['raw_return_type'], 'int')
self.assertEqual(func_list[1]['simple_return_type'], 'int')
self.assertEqual(func_list[1]['var_names'], [])
self.assertEqual(func_list[1]['raw_var_types'], [])
self.assertEqual(func_list[1]['simple_var_types'], [])
if __name__ == '__main__':
unittest.main()

24
Scripts/CppToJson.py Normal file
Просмотреть файл

@ -0,0 +1,24 @@
import sys
import json
from DataPipelines import CppToJson
from CommonEnvironment import CommandLine
@CommandLine.EntryPoint
@CommandLine.Constraints(
input_filename=CommandLine.FilenameTypeInfo(
arity="+",
),
)
def EntryPoint(
input_filename,
):
file_dict = {}
for file_name in input_filename:
file_dict[file_name] = CppToJson.ObtainFunctions(file_name)
sys.stdout.write("{}\n".format(json.dumps(file_dict)))
return 0
if __name__ == "__main__":
try: sys.exit(CommandLine.Main())
except KeyboardInterrupt: pass