Skip to content
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

feat: [cxx-parser] ParseResult.resolveNodeByType extension #37

Merged
merged 1 commit into from
Nov 20, 2023
Merged
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
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
Loading