Skip to content

Commit

Permalink
feat: [cxx-parser] ParseResult.resolveNodeByType extension (#37)
Browse files Browse the repository at this point in the history
Add `ParseResult.resolveNodeByType` extension function to simplify the
find node operation by `SimpleType`
  • Loading branch information
littleGnAl authored Nov 20, 2023
1 parent 882dc24 commit 9be9693
Show file tree
Hide file tree
Showing 4 changed files with 245 additions and 19 deletions.
166 changes: 166 additions & 0 deletions cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
import '../../src/cxx_parser_ext';
import { ParseResult } from '@agoraio-extensions/terra-core';

import {
Clazz,
Enumz,
SimpleType,
SimpleTypeKind,
Struct,
} from '../../src/cxx_terra_node';

describe('ParseResult', () => {
describe('resolveNodeByType', () => {
it('can find Clazz when the SimpleType ref to a class', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.pointer_t;
simpleType.name = 'A::B::MyClass';
simpleType.source = 'MyClass*';

const clazz = new Clazz();
clazz.name = 'MyClass';
clazz.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [clazz],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(clazz);
});

it('can find Struct when the SimpleType ref to a struct', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.pointer_t;
simpleType.name = 'A::B::MyStruct';
simpleType.source = 'MyStruct*';

const struct = new Struct();
struct.name = 'MyStruct';
struct.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [struct],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(struct);
});

it('can find Enum, when the SimpleType ref to a enum', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.pointer_t;
simpleType.name = 'A::B::MyEnum';
simpleType.source = 'MyEnum*';

const enumz = new Enumz();
enumz.name = 'MyEnum';
enumz.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [enumz],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(enumz);
});

it('return type if it is built-in type', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.value_t;
simpleType.name = 'int';
simpleType.source = 'int';

const returnType = parseResult.resolveNodeByType(simpleType);
expect(returnType).toBe(simpleType);
});

it('can find Clazz when the SimpleType is template_t and template_arguments ref to a class', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.template_t;
simpleType.name = 'TemplateType';
simpleType.source = 'TemplateType<MyClass>';
simpleType.template_arguments = ['A::B::MyClass'];

const clazz = new Clazz();
clazz.name = 'MyClass';
clazz.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [clazz],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(clazz);
});

it('can find Struct when the SimpleType is template_t and template_arguments ref to a struct', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.template_t;
simpleType.name = 'TemplateType';
simpleType.source = 'TemplateType<MyStruct>';
simpleType.template_arguments = ['A::B::MyStruct'];

const struct = new Struct();
struct.name = 'MyStruct';
struct.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [struct],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(struct);
});

it('can find Enum, when the SimpleType is template_t and template_arguments ref to a enum', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.template_t;
simpleType.name = 'TemplateType';
simpleType.source = 'TemplateType<MyEnum>';
simpleType.template_arguments = ['A::B::MyEnum'];

const enumz = new Enumz();
enumz.name = 'MyEnum';
enumz.namespaces = ['A', 'B'];

parseResult.nodes = [
{
nodes: [enumz],
},
];

const node = parseResult.resolveNodeByType(simpleType);
expect(node).toBe(enumz);
});

it('return type if the SimpleType is template_t and template_arguments not ref to any nodes', () => {
let parseResult = new ParseResult();
const simpleType = new SimpleType();
simpleType.kind = SimpleTypeKind.template_t;
simpleType.name = 'TemplateType';
simpleType.source = 'TemplateType<int>';
simpleType.template_arguments = ['int'];

const returnType = parseResult.resolveNodeByType(simpleType);
expect(returnType).toBe(simpleType);
});
});
});
79 changes: 78 additions & 1 deletion cxx-parser/src/cxx_parser_ext.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,40 @@
import './cxx_terra_node_string_ext';

import { ParseResult } from '@agoraio-extensions/terra-core';

import { CXXFile, CXXTYPE, Clazz, Enumz } from './cxx_terra_node';
import {
CXXFile,
CXXTYPE,
CXXTerraNode,
Clazz,
Enumz,
SimpleType,
SimpleTypeKind,
} from './cxx_terra_node';

export {};

declare module '@agoraio-extensions/terra-core' {
export interface ParseResult {
/**
* Find a `Clazz` by its name.
* @deprecated Use `resolveNodeByType` instead.
*/
findClazz(clazzName: string): Clazz | undefined;

/**
* Find a `Enumz` by its name.
* @deprecated Use `resolveNodeByType` instead.
*/
findEnumz(enumzName: string): Enumz | undefined;

/**
* Resolves a `CXXTerraNode` based on the given `SimpleType`. If none is found, the `SimpleType` is returned.
*
* @param type - The `SimpleType` to resolve.
* @returns The resolved `CXXTerraNode`.
*/
resolveNodeByType(type: SimpleType): CXXTerraNode;
}
}

Expand Down Expand Up @@ -88,3 +108,60 @@ ParseResult.prototype.findEnumz = function (

return undefined;
};

/**
* Resolves a `CXXTerraNode` based on the given `SimpleType`. If none is found, the `SimpleType` is returned.
*
* @param type - The `SimpleType` to resolve.
* @returns The resolved `CXXTerraNode`.
*/
ParseResult.prototype.resolveNodeByType = function (
type: SimpleType
): CXXTerraNode {
function _match(ns: string, namespace_string: string): boolean {
return (
ns == namespace_string ||
namespace_string == '' ||
ns.includes(namespace_string)
);
}
let name = type.name;
if (name.length === 0) {
return type;
}

if (type.is_builtin_type) {
return type;
}

if (
type.kind == SimpleTypeKind.template_t &&
type.template_arguments.length
) {
// Only support the first template argument at this time
name = type.template_arguments[0];
}

const namespaceInString = name.getNamespace();
const nameWithoutNS = name.trimNamespace();

for (const f of this.nodes) {
let cxxFile = f as CXXFile;
for (const node of cxxFile.nodes) {
if (node.name === nameWithoutNS) {
let ns = node.namespaces.join('::');
let found = _match(ns, namespaceInString);
if (!found && node.parent_name) {
ns = [...node.namespaces, node.parent_name].join('::');
found = _match(ns, namespaceInString);
}

if (found) {
return node;
}
}
}
}

return type;
};
17 changes: 0 additions & 17 deletions cxx-parser/src/cxx_terra_node_ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,6 @@ import { SimpleType, SimpleTypeKind } from './cxx_terra_node';

export {};

declare global {
export interface String {
/**
* This function removes the namespace from a fully qualified name.
* For example, "foo::bar" becomes "bar".
*/
trimNamespace(): string;

/**
* Returns the namespace of the class name.
*
* Example: "std::vector::size_type" returns "std::vector"
*/
getNamespace(): string;
}
}

declare module '@agoraio-extensions/cxx-parser' {
export interface SimpleType {
/**
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es6",
"target": "es2021",
"module": "commonjs",
"strict": true,
"sourceMap": true,
Expand Down

0 comments on commit 9be9693

Please sign in to comment.