Skip to content

Commit

Permalink
feat(cpp): introduce C++ parser
Browse files Browse the repository at this point in the history
  • Loading branch information
Mephistophiles committed Oct 6, 2024
1 parent 9238fc1 commit 47937db
Show file tree
Hide file tree
Showing 34 changed files with 1,220 additions and 0 deletions.
11 changes: 11 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ titlecase = "3.3.0"
tree-sitter = "0.23.0"
tree-sitter-c = "0.23.1"
tree-sitter-c-sharp = "0.23.0"
tree-sitter-cpp = "0.23.0"
tree-sitter-go = "0.23.1"
tree-sitter-python = "0.23.2"
tree-sitter-rust = "0.23.0"
Expand Down
98 changes: 98 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,66 @@ int main(void) {
}
```
###### Rename class.
Try to rename a class:
```cpp file=example.cpp
class OldClass {
}
int main() {
class OldClass newClass;
}
```

with

```bash
cat example.cpp | srgn --cpp 'class' 'OldClass' 'NewClass'
```

will give

```cpp file=output-example.cpp
class NewClass {
}

int main() {
class NewClass newClass;
}
```
###### Rename class.
Try to rename a class:
```cpp file=example.cpp
class OldClass {
}
int main() {
class OldClass newClass;
}
```

with

```bash
cat example.cpp | srgn --cpp 'class' 'OldClass' 'NewClass'
```

will give

```cpp file=output-example.cpp
class NewClass {
}

int main() {
class NewClass newClass;
}
```
##### Custom queries
Custom queries allow you to create ad-hoc scopes. These might be useful, for example, to
Expand Down Expand Up @@ -1565,6 +1625,44 @@ Language scopes:
[env: C_QUERY=]

--cpp <CPP>
Scope C++ code using a prepared query.
[env: CPP=]

Possible values:
- comments: Comments (single- and multi-line)
- strings: Strings
- includes: Includes
- type-def: Type definitions
- enum: `enum` definitions
- struct: `struct` type definitions
- class: `class` definitions
- namespace: `namespace` definitions
- using-namespace: `using` namespace declarations
- template: `template` declarations
- field-decl: Field declarations
- variable: Variable definitions
- function: All functions usages (declarations and calls)
- function-def: Function definitions
- function-decl: Function declaration
- lambda: Lambda
- switch: `switch` blocks
- if: `if` blocks
- for: `for` blocks
- while: `while` blocks
- do: `do` blocks
- union: `union` blocks
- try: `try` blocks
- identifier: Identifier
- declaration: Declaration
- call-expression: Call expression

--cpp-query <TREE-SITTER-QUERY>
Scope C++ code using a custom tree-sitter query.
[env: CPP_QUERY=]

--csharp <CSHARP>
Scope C# code using a prepared query.
Expand Down
17 changes: 17 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use srgn::actions::{
#[cfg(feature = "symbols")]
use srgn::actions::{Symbols, SymbolsInversion};
use srgn::scoping::langs::c::{CQuery, C};
use srgn::scoping::langs::cpp::{Cpp, CppQuery};
use srgn::scoping::langs::csharp::{CSharp, CSharpQuery};
use srgn::scoping::langs::go::{Go, GoQuery};
use srgn::scoping::langs::hcl::{Hcl, HclQuery};
Expand Down Expand Up @@ -832,6 +833,7 @@ fn get_language_scopers(args: &cli::Cli) -> Vec<Box<dyn LanguageScoper>> {
}

handle_language_scope!(c, c_query, CQuery, C);
handle_language_scope!(cpp, cpp_query, CppQuery, Cpp);
handle_language_scope!(csharp, csharp_query, CSharpQuery, CSharp);
handle_language_scope!(hcl, hcl_query, HclQuery, Hcl);
handle_language_scope!(go, go_query, GoQuery, Go);
Expand Down Expand Up @@ -939,6 +941,7 @@ mod cli {
use clap::{ArgAction, Command, CommandFactory, Parser};
use clap_complete::{generate, Generator, Shell};
use srgn::scoping::langs::c::{CustomCQuery, PreparedCQuery};
use srgn::scoping::langs::cpp::{CustomCppQuery, PreparedCppQuery};
use srgn::scoping::langs::csharp::{CustomCSharpQuery, PreparedCSharpQuery};
use srgn::scoping::langs::go::{CustomGoQuery, PreparedGoQuery};
use srgn::scoping::langs::hcl::{CustomHclQuery, PreparedHclQuery};
Expand Down Expand Up @@ -1230,6 +1233,8 @@ mod cli {
#[command(flatten)]
pub c: Option<CScope>,
#[command(flatten)]
pub cpp: Option<CppScope>,
#[command(flatten)]
pub csharp: Option<CSharpScope>,
#[command(flatten)]
pub go: Option<GoScope>,
Expand All @@ -1255,6 +1260,18 @@ mod cli {
pub c_query: Vec<CustomCQuery>,
}

#[derive(Parser, Debug, Clone)]
#[group(required = false, multiple = false)]
pub struct CppScope {
/// Scope C++ code using a prepared query.
#[arg(long, env, verbatim_doc_comment)]
pub cpp: Vec<PreparedCppQuery>,

/// Scope C++ code using a custom tree-sitter query.
#[arg(long, env, verbatim_doc_comment, value_name = TREE_SITTER_QUERY_VALUE_NAME)]
pub cpp_query: Vec<CustomCppQuery>,
}

#[derive(Parser, Debug, Clone)]
#[group(required = false, multiple = false)]
pub struct CSharpScope {
Expand Down
151 changes: 151 additions & 0 deletions src/scoping/langs/cpp.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use std::fmt::Debug;
use std::str::FromStr;

use clap::ValueEnum;
use tree_sitter::QueryError;

use super::{CodeQuery, Language, LanguageScoper, TSLanguage, TSQuery};
use crate::find::Find;

/// The C++ language.
pub type Cpp = Language<CppQuery>;
/// A query for C++.
pub type CppQuery = CodeQuery<CustomCppQuery, PreparedCppQuery>;

/// Prepared tree-sitter queries for C++.
#[derive(Debug, Clone, Copy, ValueEnum)]
pub enum PreparedCppQuery {
/// Comments (single- and multi-line).
Comments,
/// Strings.
Strings,
/// Includes.
Includes,
/// Type definitions.
TypeDef,
/// `enum` definitions.
Enum,
/// `struct` type definitions.
Struct,
/// `class` definitions.
Class,
/// `namespace` definitions.
Namespace,
/// `using` namespace declarations.
UsingNamespace,
/// `template` declarations.
Template,
/// Field declarations.
FieldDecl,
/// Variable definitions.
Variable,
/// All functions usages (declarations and calls).
Function,
/// Function definitions.
FunctionDef,
/// Function declaration.
FunctionDecl,
/// Lambda
Lambda,
/// `switch` blocks.
Switch,
/// `if` blocks.
If,
/// `for` blocks.
For,
/// `while` blocks.
While,
/// `do` blocks.
Do,
/// `union` blocks.
Union,
/// `try` blocks.
Try,
/// Identifier.
Identifier,
/// Declaration.
Declaration,
/// Call expression.
CallExpression,
}

impl From<PreparedCppQuery> for TSQuery {
fn from(value: PreparedCppQuery) -> Self {
Self::new(
&Cpp::lang(),
match value {
PreparedCppQuery::Comments => "(comment) @comment",
PreparedCppQuery::Strings => "[(string_literal) (system_lib_string)] @string",
PreparedCppQuery::Includes => "(preproc_include) @include",
PreparedCppQuery::TypeDef => "(type_definition) @typedef",
PreparedCppQuery::Enum => "(enum_specifier) @enum",
PreparedCppQuery::Struct => "(struct_specifier) @struct",
PreparedCppQuery::Class => "(class_specifier) @class",
PreparedCppQuery::Namespace => "(namespace_definition) @namespace",
PreparedCppQuery::UsingNamespace => "(using_declaration) @using",
PreparedCppQuery::Template => "(template_declaration) @template",
PreparedCppQuery::FieldDecl => "(field_declaration) @field_decl",
PreparedCppQuery::Variable => "(declaration) @var",
PreparedCppQuery::Function => {
"[(function_declarator (identifier)) (call_expression (identifier))] @function"
}
PreparedCppQuery::FunctionDef => "(function_definition) @function_definition",
PreparedCppQuery::FunctionDecl => "(function_declarator) @function_decl",
PreparedCppQuery::Lambda => "(lambda_expression) @lambda",
PreparedCppQuery::Switch => "(switch_statement) @switch",
PreparedCppQuery::If => "(if_statement) @if",
PreparedCppQuery::For => "[(for_statement) (for_range_loop)] @for",
PreparedCppQuery::While => "(while_statement) @while",
PreparedCppQuery::Union => "(union_specifier) @union",
PreparedCppQuery::Try => "(try_statement) @try",
PreparedCppQuery::Do => "(do_statement) @do",
PreparedCppQuery::Identifier => "(identifier) @ident",
PreparedCppQuery::Declaration => "(declaration) @decl",
PreparedCppQuery::CallExpression => "(call_expression) @call",
},
)
.expect("Prepared queries to be valid")
}
}

/// A custom tree-sitter query for C++.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CustomCppQuery(String);

impl FromStr for CustomCppQuery {
type Err = QueryError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match TSQuery::new(&Cpp::lang(), s) {
Ok(_) => Ok(Self(s.to_string())),
Err(e) => Err(e),
}
}
}

impl From<CustomCppQuery> for TSQuery {
fn from(value: CustomCppQuery) -> Self {
Self::new(&Cpp::lang(), &value.0)
.expect("Valid query, as object cannot be constructed otherwise")
}
}

impl LanguageScoper for Cpp {
fn lang() -> TSLanguage {
tree_sitter_cpp::LANGUAGE.into()
}

fn pos_query(&self) -> &TSQuery {
&self.positive_query
}

fn neg_query(&self) -> Option<&TSQuery> {
self.negative_query.as_ref()
}
}

impl Find for Cpp {
fn extensions(&self) -> &'static [&'static str] {
&["cpp", "hpp"]
}
}
2 changes: 2 additions & 0 deletions src/scoping/langs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use crate::scoping::{

/// C.
pub mod c;
/// C++.
pub mod cpp;
/// C#.
pub mod csharp;
/// Go.
Expand Down
Loading

0 comments on commit 47937db

Please sign in to comment.