Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f0ff8da
feat: add Transpil for type
reneca Mar 6, 2026
0d96508
fix: replace try from for types by from
reneca Mar 6, 2026
b40ebd0
feat: add serde::Deserialize for TypeMapper
reneca Mar 6, 2026
2eafef1
feat: make TypeMapper Debug and Clone
reneca Mar 6, 2026
b128637
feat: introduce transpil trait and implement trait for automatic C++ …
reneca Mar 13, 2026
f15ff64
feat: add transpilation for C++ const and static expression
reneca Mar 20, 2026
1afeef1
fix: fmt
reneca Mar 20, 2026
dd4cd22
feat: improve transpiler errors
reneca Mar 20, 2026
3522edc
feat: improve transpiler errors with their value
reneca Mar 20, 2026
c3d14be
fix: revert transpiler error debug
reneca Mar 20, 2026
468c81a
fix: handle C++ dynamic arrays
reneca Mar 20, 2026
c69123f
feat: implement transpilation for C++ enums
reneca Mar 20, 2026
7a17539
feat: add helper for auto types
reneca Mar 20, 2026
8915150
fix: types with cast if needed
reneca Mar 25, 2026
7d03445
feat: improve type assignment
reneca Mar 26, 2026
d2069f4
fix: remove from for const expr
reneca Mar 26, 2026
21749ea
feat: add helper for ast::Ident and ast::Visibility
reneca Mar 26, 2026
faa0ad1
feat: add config to skip types from transpilation
reneca Mar 26, 2026
4a83248
fix: remove unwanted println
reneca Apr 3, 2026
abf4f76
fix: ast parsing for Verbatim
reneca Apr 3, 2026
cb24f8c
feat: change Verbatim token type for LinkedList
reneca Apr 3, 2026
707445e
fix: clippy
reneca Apr 4, 2026
d756d70
feat: improve ast doc for specific items
reneca Apr 8, 2026
3ffe86e
feat: Type and Field transpilation
reneca Apr 8, 2026
cca63d5
feat: handle static for ast::Field
reneca Apr 10, 2026
5d846b7
feat: add regular ast::Var to fix static
reneca Apr 10, 2026
5b01206
feat: add utils for ast::Ident
reneca Apr 10, 2026
f79abd8
fix: ast::Ident PartialEq
reneca Apr 10, 2026
9052c88
feat: impl helper for default contructor
reneca Apr 10, 2026
0395d95
feat: handle class_name for ast function
reneca Apr 10, 2026
6d5835f
feat: add more helper on ast function
reneca Apr 10, 2026
25305b1
feat: handle member init in constructor definition
reneca Apr 10, 2026
334877d
feat: parse class_path for const and static items
reneca Apr 15, 2026
d571bee
feat: add helper for ExprLit
reneca Apr 16, 2026
b353640
feat: add transpilation for local statement
reneca Apr 17, 2026
80e983e
feat: add transpilation for expr
reneca Apr 17, 2026
6e30d5d
feat: improve error span
reneca Apr 17, 2026
651870b
feat: transpil binary expression
reneca Apr 17, 2026
73da8c4
feat: add fallback setting for Expr transpilation
reneca Apr 21, 2026
45ce390
feat: add SourceCodeSpan trait to improve span for errors
reneca Apr 23, 2026
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
11 changes: 10 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
[package]
name = "cppshift"
version = "0.1.0"
version = "0.1.1"
authors = ["Jérémy HERGAULT", "Enzo PASQUALINI"]
description = "CPP parser and transpiler"
repository = "https://github.com/worldline/cppshift"
edition = "2024"
license = "Apache-2.0"

[features]
default = ["transpiler"]
ast = []
transpiler = ["ast", "dep:serde", "dep:syn", "dep:quote", "dep:proc-macro2"]

[dependencies]
miette = { version = "7", features = ["fancy"] }
thiserror = "2"
serde = { version = "1", features = ["derive"], optional = true }
syn = { version = "2", features = ["full", "extra-traits", "printing"], optional = true }
quote = { version = "1", optional = true }
proc-macro2 = { version = "1", optional = true }

[dev-dependencies]
tokio = { version = "1", features = ["macros"] }
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,11 @@ To parse a C++ source file and inspect the AST decomposition, run the _ast_ exam
```bash
cargo run --example ast -- <source_path>
```

## Transpiler

The transpiler contains all trait implementations for C++ to Rust transpilation.
There are no examples available.

You need to configure all the settings in the `Transpiler`.
After that, you will be able to transpile any C++ structure you have.
134 changes: 133 additions & 1 deletion src/ast/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
//!
//! Analogous to `syn::Expr`.

use crate::SourceSpan;
use std::str::FromStr;

use crate::ast::ty::{FundamentalKind, Type};
use crate::{SourceCodeSpan, SourceSpan};

use super::item::{Ident, Path};
use super::punct::Punctuated;
Expand All @@ -16,6 +19,49 @@ pub enum LitKind {
Char,
}

impl LitKind {
/// Check if the fundamental kind matches the literal kind
pub fn match_fundamental(&self, kind: FundamentalKind) -> bool {
match self {
LitKind::Integer => matches!(
kind,
FundamentalKind::Short
| FundamentalKind::Int
| FundamentalKind::Long
| FundamentalKind::LongLong
| FundamentalKind::SignedChar
| FundamentalKind::UnsignedChar
| FundamentalKind::UnsignedShort
| FundamentalKind::UnsignedInt
| FundamentalKind::UnsignedLong
| FundamentalKind::UnsignedLongLong
),
LitKind::Float => matches!(
kind,
FundamentalKind::Float | FundamentalKind::Double | FundamentalKind::LongDouble
),
LitKind::Char => matches!(
kind,
FundamentalKind::Char
| FundamentalKind::Wchar
| FundamentalKind::Char8
| FundamentalKind::Char16
| FundamentalKind::Char32
),
_ => false,
}
}

/// Check if the literal kind matches the type
pub fn match_type(&self, ty: &Type) -> bool {
match ty {
Type::Fundamental(fund) => self.match_fundamental(fund.kind),
Type::Qualified(qualified) => self.match_type(&qualified.ty),
_ => false,
}
}
}

/// Unary operator.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum UnaryOp {
Expand Down Expand Up @@ -143,13 +189,44 @@ pub enum Expr<'de> {
InitList(ExprInitList<'de>),
}

impl<'de> SourceCodeSpan<'de> for Expr<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
match self {
Expr::Lit(ExprLit { span, .. })
| Expr::Bool(ExprBool { span, .. })
| Expr::Nullptr(ExprNullptr { span, .. })
| Expr::This(ExprThis { span, .. }) => Some(*span),
Expr::Ident(ExprIdent { ident }) => Some(ident.span),
Expr::Paren(expr_paren) => expr_paren.expr.span(),
Expr::Unary(expr_unary) => expr_unary.span(),
Expr::Binary(expr_binary) => expr_binary.span(),
Expr::Conditional(expr_conditional) => expr_conditional.span(),
Expr::Call(expr_call) => expr_call.span(),
Expr::Sizeof(expr_sizeof) => expr_sizeof.operand.span(),
Expr::Alignof(expr_alignof) => expr_alignof.ty.span(),
Expr::Typeid(expr_typeid) => expr_typeid.operand.span(),
_ => None,
}
}
}

/// Literal expression: numbers, strings, chars.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ExprLit<'de> {
pub span: SourceSpan<'de>,
pub kind: LitKind,
}

impl<'de> ExprLit<'de> {
/// Parse the literal value from the source span as the specified type.
pub fn parse<F>(&self) -> Result<F, F::Err>
where
F: FromStr,
{
self.span.src().parse::<F>()
}
}

/// Simple identifier expression.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct ExprIdent<'de> {
Expand Down Expand Up @@ -194,6 +271,12 @@ pub struct ExprUnary<'de> {
pub operand: Box<Expr<'de>>,
}

impl<'de> SourceCodeSpan<'de> for ExprUnary<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
self.operand.span()
}
}

/// Binary expression: `lhs op rhs`.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprBinary<'de> {
Expand All @@ -202,6 +285,18 @@ pub struct ExprBinary<'de> {
pub rhs: Box<Expr<'de>>,
}

impl<'de> SourceCodeSpan<'de> for ExprBinary<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
self.lhs.span().map(|l| {
if let Some(r) = self.rhs.span() {
l.extend(r)
} else {
l
}
})
}
}

/// Ternary conditional: `condition ? then_expr : else_expr`.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprConditional<'de> {
Expand All @@ -210,6 +305,20 @@ pub struct ExprConditional<'de> {
pub else_expr: Box<Expr<'de>>,
}

impl<'de> SourceCodeSpan<'de> for ExprConditional<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
self.condition.span().map(|c| {
if let Some(e) = self.else_expr.span() {
c.extend(e)
} else if let Some(t) = self.then_expr.span() {
c.extend(t)
} else {
c
}
})
}
}

/// Function call: `callee(args...)`.
///
/// Analogous to `syn::ExprCall`.
Expand All @@ -219,6 +328,20 @@ pub struct ExprCall<'de> {
pub args: Punctuated<'de, Expr<'de>>,
}

impl<'de> SourceCodeSpan<'de> for ExprCall<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
if let Some(func_span) = self.func.span() {
if let Some(args_span) = self.args.span() {
Some(func_span.extend(args_span))
} else {
Some(func_span)
}
} else {
self.args.span()
}
}
}

/// Method call: `receiver.method(args...)`.
///
/// Analogous to `syn::ExprMethodCall`.
Expand Down Expand Up @@ -347,6 +470,15 @@ pub enum TypeidOperand<'de> {
Expr(Box<Expr<'de>>),
}

impl<'de> SourceCodeSpan<'de> for TypeidOperand<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
match &self {
TypeidOperand::Type(op_type) => op_type.span(),
TypeidOperand::Expr(op_expr) => op_expr.span(),
}
}
}

/// Braced initializer list: `{1, 2, 3}`.
#[derive(Debug, Clone, PartialEq)]
pub struct ExprInitList<'de> {
Expand Down
Loading
Loading