Skip to content
Open
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
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ travis-ci = { repository = "jethrogb/rust-cexpr" }
nom = { version = "7", default-features = false, features = ["std"] }

[dev-dependencies]
clang-sys = ">= 0.13.0, < 0.29.0"
clang = { version = "2", features = ["runtime"] }

[patch.crates-io]
clang-sys = { git = "https://github.com/reitermarkus/clang-sys", branch = "load-api" }
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you upstream or remove this? It seems unfortunate not depending on the crates.io version.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An upstream PR is already opened. This is only needed for the last commit in this PR, cleaning up the test setup.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to split the test setup cleanup into its own PR? Seems like there's some push back against making the change to clang-sys since it's a breaking change...

clang = { git = "https://github.com/reitermarkus/clang-rs", branch = "load-api" }
121 changes: 113 additions & 8 deletions src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use std::ops::{
use crate::literal::{self, CChar};
use crate::token::{Kind as TokenKind, Token};
use crate::ToCexprResult;
use nom::branch::alt;
use nom::combinator::{complete, map, map_opt};
use nom::branch::{alt, permutation};
use nom::combinator::{complete, map, map_opt, opt};
use nom::multi::{fold_many0, many0, separated_list0};
use nom::sequence::{delimited, pair, preceded};
use nom::*;
Expand All @@ -54,6 +54,7 @@ pub enum EvalResult {
Float(f64),
Char(CChar),
Str(Vec<u8>),
Cast(Vec<Vec<u8>>, Box<Self>),
Invalid,
}

Expand Down Expand Up @@ -121,11 +122,17 @@ fn identifier_token(input: &[Token]) -> CResult<'_, &[u8]> {
if input[0].kind == TokenKind::Identifier {
Ok((&input[1..], &input[0].raw[..]))
} else {
Err(crate::nom::Err::Error((input, crate::ErrorKind::TypedToken(TokenKind::Identifier)).into()))
Err(crate::nom::Err::Error(
(input, crate::ErrorKind::TypedToken(TokenKind::Identifier)).into(),
))
}
}
}

fn keyword(c: &'static str) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
exact_token!(Keyword, c.as_bytes())
}

fn p(c: &'static str) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
exact_token!(Punctuation, c.as_bytes())
}
Expand Down Expand Up @@ -289,6 +296,10 @@ where
nom::combinator::map_opt(f, EvalResult::as_numeric)
}

fn expr_cast(input: (Vec<Vec<u8>>, EvalResult)) -> EvalResult {
EvalResult::Cast(input.0, Box::new(input.1))
}

impl<'a> PRef<'a> {
fn unary(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
alt((
Expand Down Expand Up @@ -473,6 +484,7 @@ impl<'a> PRef<'a> {

fn expr(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
alt((
map(pair(|i| self.cast(i), |i| self.expr(i)), expr_cast),
|i| self.numeric_expr(i),
delimited(p("("), |i| self.expr(i), p(")")),
|i| self.concat_str(i),
Expand All @@ -482,6 +494,103 @@ impl<'a> PRef<'a> {
.to_cexpr_result()
}

fn cast(self, input: &'_ [Token]) -> CResult<'_, Vec<Vec<u8>>> {
delimited(p("("), |i| self.ty(i), p(")"))(input)
}

fn int_ty(input: &'_ [Token]) -> CResult<'_, Vec<&[u8]>> {
fn int_signedness(input: &'_ [Token]) -> CResult<'_, &[u8]> {
alt((keyword("unsigned"), keyword("signed")))(input)
}

fn int_longness(input: &'_ [Token]) -> CResult<'_, &[u8]> {
alt((keyword("short"), keyword("long")))(input)
}

alt((
// [const] [(un)signed] long long [int]
map(
permutation((
opt(keyword("const")),
opt(int_signedness),
keyword("long"),
keyword("long"),
opt(keyword("int")),
)),
|(_, s, i1, i2, _)| {
if let Some(s) = s {
if s == b"signed" {
vec![i1, i2]
} else {
vec![s, i1, i2]
}
} else {
vec![i1, i2]
}
},
),
// [const] [(un)signed] long/short [int]
map(
permutation((
opt(keyword("const")),
opt(int_signedness),
int_longness,
opt(keyword("int")),
)),
|(_, s, i, _)| {
if let Some(s) = s {
if s == b"signed" {
vec![i]
} else {
vec![s, i]
}
} else {
vec![i]
}
},
),
// [const] [(un)signed] char/int
map(
permutation((
opt(keyword("const")),
opt(int_signedness),
alt((keyword("char"), keyword("int"))),
)),
|(_, s, i)| {
if let Some(s) = s {
if s == b"signed" && i == b"int" {
vec![i]
} else {
vec![s, i]
}
} else {
vec![i]
}
},
),
))(input)
}

fn ty(self, input: &'_ [Token]) -> CResult<'_, Vec<Vec<u8>>> {
map(
alt((
// [const] <identifier>
map(
permutation((opt(keyword("const")), identifier_token)),
|(_, id)| vec![id],
),
// [const] bool
map(
permutation((opt(keyword("const")), keyword("bool"))),
|(_, b)| vec![b],
),
Self::int_ty,
)),
|v| v.into_iter().map(|t| t.to_vec()).collect(),
)(input)
.to_cexpr_result()
}

fn macro_definition(self, input: &'_ [Token]) -> CResult<'_, (&'_ [u8], EvalResult)> {
pair(identifier_token, |i| self.expr(i))(input)
}
Expand Down Expand Up @@ -601,10 +710,6 @@ pub fn macro_definition(input: &[Token]) -> CResult<'_, (&'_ [u8], EvalResult)>
pub fn fn_macro_declaration(input: &[Token]) -> CResult<'_, (&[u8], Vec<&[u8]>)> {
pair(
identifier_token,
delimited(
p("("),
separated_list0(p(","), identifier_token),
p(")"),
),
delimited(p("("), separated_list0(p(","), identifier_token), p(")")),
)(input)
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

pub mod nom {
//! nom's result types, re-exported.
pub use nom::{error::ErrorKind, error::Error, Err, IResult, Needed};
pub use nom::{error::Error, error::ErrorKind, Err, IResult, Needed};
}
pub mod expr;
pub mod literal;
Expand Down
Loading