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

Allow parsing cast expressions. #33

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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
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
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.

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