Skip to content

Commit

Permalink
Allow parsing cast expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
reitermarkus committed Sep 8, 2022
1 parent c7ccdfb commit 5354667
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 12 deletions.
99 changes: 97 additions & 2 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 @@ -126,6 +127,10 @@ fn identifier_token(input: &[Token]) -> CResult<'_, &[u8]> {
}
}

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 +294,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 +482,10 @@ 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 +495,88 @@ 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
17 changes: 9 additions & 8 deletions tests/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use std::collections::HashMap;
use std::io::Write;
use std::str::{self, FromStr};
use std::{char, ffi, mem, ptr, slice};
use std::num::Wrapping;

use cexpr::assert_full_parse;
use cexpr::expr::{fn_macro_declaration, EvalResult, IdentifierParser};
Expand All @@ -25,18 +26,17 @@ fn test_definition(
tokens: &[Token],
idents: &mut HashMap<Vec<u8>, EvalResult>,
) -> bool {
use cexpr::expr::EvalResult::*;

fn bytes_to_int(value: &[u8]) -> Option<EvalResult> {
str::from_utf8(value)
.ok()
.map(|s| s.replace("n", "-"))
.map(|s| s.replace("_", ""))
.and_then(|v| i64::from_str(&v).ok())
.map(::std::num::Wrapping)
let s = str::from_utf8(value).ok()?;
let s = s.rsplit_once('_').map(|(_, s)| s).unwrap_or(s);

i64::from_str(&s.replace("n", "-")).ok()
.map(Wrapping)
.map(Int)
}

use cexpr::expr::EvalResult::*;

let display_name = String::from_utf8_lossy(&ident).into_owned();

let functional;
Expand Down Expand Up @@ -127,6 +127,7 @@ fn test_definition(
return false;
}
}

assert_full_parse(IdentifierParser::new(&fnidents).expr(&expr_tokens))
} else {
IdentifierParser::new(idents)
Expand Down
1 change: 0 additions & 1 deletion tests/input/fail.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#define FAIL_function_like(x) 3
#define FAIL_empty
#define FAIL_invalid_for_radix 0b2
#define FAIL_shift_by_float 3<<1f
Expand Down
2 changes: 2 additions & 0 deletions tests/input/int_signed.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#define Int_n3 -(-(-3))
#define Int_n5 -3-2
#define Int_n9223372036854775808 -9223372036854775808

#define Fn_Int_n9(_3) _3*-3
3 changes: 2 additions & 1 deletion tests/input/int_unsigned.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#define Int_124 124u
#define Int_125 125uL
#define Int_126 126LuL
#define Int_16 (((1)<<4ULL))/*comment*/
#define Int_16 (((1)<<4ULL))/*comment*/
#define Int_13 1|8^6&2<<1

#define Int_47 32|15
Expand All @@ -27,3 +27,4 @@
#define Int_n9223372036854775808 9223372036854775808

#define Fn_Int_9(_3) _3*3
#define Fn_Int_unused_arg_3(x_unused_0) 3

0 comments on commit 5354667

Please sign in to comment.