Skip to content

Commit 5354667

Browse files
committed
Allow parsing cast expressions.
1 parent c7ccdfb commit 5354667

File tree

5 files changed

+110
-12
lines changed

5 files changed

+110
-12
lines changed

src/expr.rs

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ use std::ops::{
2929
use crate::literal::{self, CChar};
3030
use crate::token::{Kind as TokenKind, Token};
3131
use crate::ToCexprResult;
32-
use nom::branch::alt;
33-
use nom::combinator::{complete, map, map_opt};
32+
use nom::branch::{alt, permutation};
33+
use nom::combinator::{complete, map, map_opt, opt};
3434
use nom::multi::{fold_many0, many0, separated_list0};
3535
use nom::sequence::{delimited, pair, preceded};
3636
use nom::*;
@@ -54,6 +54,7 @@ pub enum EvalResult {
5454
Float(f64),
5555
Char(CChar),
5656
Str(Vec<u8>),
57+
Cast(Vec<Vec<u8>>, Box<Self>),
5758
Invalid,
5859
}
5960

@@ -126,6 +127,10 @@ fn identifier_token(input: &[Token]) -> CResult<'_, &[u8]> {
126127
}
127128
}
128129

130+
fn keyword(c: &'static str) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
131+
exact_token!(Keyword, c.as_bytes())
132+
}
133+
129134
fn p(c: &'static str) -> impl Fn(&[Token]) -> CResult<'_, &[u8]> {
130135
exact_token!(Punctuation, c.as_bytes())
131136
}
@@ -289,6 +294,10 @@ where
289294
nom::combinator::map_opt(f, EvalResult::as_numeric)
290295
}
291296

297+
fn expr_cast(input: (Vec<Vec<u8>>, EvalResult)) -> EvalResult {
298+
EvalResult::Cast(input.0, Box::new(input.1))
299+
}
300+
292301
impl<'a> PRef<'a> {
293302
fn unary(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
294303
alt((
@@ -473,6 +482,10 @@ impl<'a> PRef<'a> {
473482

474483
fn expr(self, input: &'_ [Token]) -> CResult<'_, EvalResult> {
475484
alt((
485+
map(
486+
pair(|i| self.cast(i), |i| self.expr(i)),
487+
expr_cast
488+
),
476489
|i| self.numeric_expr(i),
477490
delimited(p("("), |i| self.expr(i), p(")")),
478491
|i| self.concat_str(i),
@@ -482,6 +495,88 @@ impl<'a> PRef<'a> {
482495
.to_cexpr_result()
483496
}
484497

498+
fn cast(self, input: &'_ [Token]) -> CResult<'_, Vec<Vec<u8>>> {
499+
delimited(p("("), |i| self.ty(i), p(")"))(input)
500+
}
501+
502+
fn int_ty(input: &'_ [Token]) -> CResult<'_, Vec<&[u8]>> {
503+
fn int_signedness(input: &'_ [Token]) -> CResult<'_, &[u8]> {
504+
alt((
505+
keyword("unsigned"),
506+
keyword("signed"),
507+
))(input)
508+
}
509+
510+
fn int_longness(input: &'_ [Token]) -> CResult<'_, &[u8]> {
511+
alt((
512+
keyword("short"),
513+
keyword("long"),
514+
))(input)
515+
}
516+
517+
alt((
518+
// [const] [(un)signed] long long [int]
519+
map(
520+
permutation((opt(keyword("const")), opt(int_signedness), keyword("long"), keyword("long"), opt(keyword("int")))),
521+
|(_, s, i1, i2, _)| if let Some(s) = s {
522+
if s == b"signed" {
523+
vec![i1, i2]
524+
} else {
525+
vec![s, i1, i2]
526+
}
527+
} else {
528+
vec![i1, i2]
529+
},
530+
),
531+
// [const] [(un)signed] long/short [int]
532+
map(
533+
permutation((opt(keyword("const")), opt(int_signedness), int_longness, opt(keyword("int")))),
534+
|(_, s, i, _)| if let Some(s) = s {
535+
if s == b"signed" {
536+
vec![i]
537+
} else {
538+
vec![s, i]
539+
}
540+
} else {
541+
vec![i]
542+
},
543+
),
544+
// [const] [(un)signed] char/int
545+
map(
546+
permutation((opt(keyword("const")), opt(int_signedness), alt((keyword("char"), keyword("int"))))),
547+
|(_, s, i)| if let Some(s) = s {
548+
if s == b"signed" && i == b"int" {
549+
vec![i]
550+
} else {
551+
vec![s, i]
552+
}
553+
} else {
554+
vec![i]
555+
},
556+
),
557+
))(input)
558+
}
559+
560+
fn ty(self, input: &'_ [Token]) -> CResult<'_, Vec<Vec<u8>>> {
561+
map(
562+
alt((
563+
// [const] <identifier>
564+
map(
565+
permutation((opt(keyword("const")), identifier_token)),
566+
|(_, id)| vec![id],
567+
),
568+
// [const] bool
569+
map(
570+
permutation((opt(keyword("const")), keyword("bool"))),
571+
|(_, b)| vec![b],
572+
),
573+
Self::int_ty,
574+
)),
575+
|v| v.into_iter().map(|t| t.to_vec()).collect(),
576+
)(input)
577+
.to_cexpr_result()
578+
}
579+
485580
fn macro_definition(self, input: &'_ [Token]) -> CResult<'_, (&'_ [u8], EvalResult)> {
486581
pair(identifier_token, |i| self.expr(i))(input)
487582
}

tests/clang.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use std::collections::HashMap;
1212
use std::io::Write;
1313
use std::str::{self, FromStr};
1414
use std::{char, ffi, mem, ptr, slice};
15+
use std::num::Wrapping;
1516

1617
use cexpr::assert_full_parse;
1718
use cexpr::expr::{fn_macro_declaration, EvalResult, IdentifierParser};
@@ -25,18 +26,17 @@ fn test_definition(
2526
tokens: &[Token],
2627
idents: &mut HashMap<Vec<u8>, EvalResult>,
2728
) -> bool {
29+
use cexpr::expr::EvalResult::*;
30+
2831
fn bytes_to_int(value: &[u8]) -> Option<EvalResult> {
29-
str::from_utf8(value)
30-
.ok()
31-
.map(|s| s.replace("n", "-"))
32-
.map(|s| s.replace("_", ""))
33-
.and_then(|v| i64::from_str(&v).ok())
34-
.map(::std::num::Wrapping)
32+
let s = str::from_utf8(value).ok()?;
33+
let s = s.rsplit_once('_').map(|(_, s)| s).unwrap_or(s);
34+
35+
i64::from_str(&s.replace("n", "-")).ok()
36+
.map(Wrapping)
3537
.map(Int)
3638
}
3739

38-
use cexpr::expr::EvalResult::*;
39-
4040
let display_name = String::from_utf8_lossy(&ident).into_owned();
4141

4242
let functional;
@@ -127,6 +127,7 @@ fn test_definition(
127127
return false;
128128
}
129129
}
130+
130131
assert_full_parse(IdentifierParser::new(&fnidents).expr(&expr_tokens))
131132
} else {
132133
IdentifierParser::new(idents)

tests/input/fail.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
#define FAIL_function_like(x) 3
21
#define FAIL_empty
32
#define FAIL_invalid_for_radix 0b2
43
#define FAIL_shift_by_float 3<<1f

tests/input/int_signed.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
#define Int_n3 -(-(-3))
22
#define Int_n5 -3-2
33
#define Int_n9223372036854775808 -9223372036854775808
4+
5+
#define Fn_Int_n9(_3) _3*-3

tests/input/int_unsigned.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#define Int_124 124u
1111
#define Int_125 125uL
1212
#define Int_126 126LuL
13-
#define Int_16 (((1)<<4ULL))/*comment*/
13+
#define Int_16 (((1)<<4ULL))/*comment*/
1414
#define Int_13 1|8^6&2<<1
1515

1616
#define Int_47 32|15
@@ -27,3 +27,4 @@
2727
#define Int_n9223372036854775808 9223372036854775808
2828

2929
#define Fn_Int_9(_3) _3*3
30+
#define Fn_Int_unused_arg_3(x_unused_0) 3

0 commit comments

Comments
 (0)