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

Support for casts in macros #4

Open
azerupi opened this issue Dec 7, 2016 · 7 comments · May be fixed by #15
Open

Support for casts in macros #4

azerupi opened this issue Dec 7, 2016 · 7 comments · May be fixed by #15

Comments

@azerupi
Copy link

azerupi commented Dec 7, 2016

rust-lang/rust-bindgen#316

Some macro defined constants are written like this:

#define kOfxStatFailed  ((int)1)
#define kOfxStatErrFatal ((int)2)

But currently, they are just ignored. It would be great to support casts.

@jethrogb
Copy link
Owner

jethrogb commented Dec 7, 2016

I agree, this would be great. The current state of the parser is about at my limit of understanding of parser-combinators. I think something like this would work but it'd be nice if someone could chime in on this:

--- expr.rs
+++ expr.rs
@@ -258,9 +258,16 @@
 	($i:expr, $f:expr ) => (map_opt!($i,call!($f),EvalResult::as_numeric));
 );
 
+struct TypeCast { /* ... */ }
+
 impl<'a> PRef<'a> {
+	method!(cast<PRef<'a>,&[Token],TypeCast,::Error>, mut self,
+		delimited!(p!("("),call_m!(self.identifier),p!(")"))
+	);
+
 	method!(unary<PRef<'a>,&[Token],EvalResult,::Error>, mut self,
 		alt!(
+			pair!(call_m!(self.cast),call_m!(self.numeric_expr)) |
 			delimited!(p!("("),call_m!(self.numeric_expr),p!(")")) |
 			numeric!(call_m!(self.literal)) |
 			numeric!(call_m!(self.identifier)) |

Also whether this has the correct precedence, etc. (I know this needs some more fudging with the return types).

@azerupi
Copy link
Author

azerupi commented Dec 8, 2016

I will not be able to help much here, all my attempts at trying nom have resulted in miserable fails 😕

@azerupi
Copy link
Author

azerupi commented Feb 5, 2017

I tried to take a look, but I'm in over my head.
I can just say that:

method!(cast<PRef<'a>,&[Token],TypeCast,::Error>, mut self,
	delimited!(p!("("),call_m!(self.identifier),p!(")"))
);

Has a type error, because self.identifier returns an EvalResult. Even if this method would return the correct type you would get an error in

method!(unary<PRef<'a>,&[Token],EvalResult,::Error>, mut self,
    alt!(
        pair!(call_m!(self.cast),call_m!(self.numeric_expr)) |
 	delimited!(p!("("),call_m!(self.numeric_expr),p!(")")) |
 	numeric!(call_m!(self.literal)) |
 	numeric!(call_m!(self.identifier)) |
        map_opt!(pair!(alt!( p!("+") | p!("-") | p!("~") ),call_m!(self.unary)),unary_op)
    )
);

because pair!(call_m!(self.cast),call_m!(self.numeric_expr)) returns a tuple and not an EvalResult.

I tried to figure out how the code works by following the methods used, but I gave up... It's to complex for me :/

@mash-graz
Copy link

this unpleasant issue still exists.
it would be really helpful. if someone, which is more familiar with this code, could try to solve it.

@crab2313
Copy link

@jethrogb I'm new to nom and trying to implement this feature. Is my approach viable?

diff --git a/src/expr.rs b/src/expr.rs
index ccfac83..40e46e9 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -65,7 +65,7 @@ impl EvalResult {
        result_opt!(fn as_float: Float -> f64);
        result_opt!(fn as_char: Char -> CChar);
        result_opt!(fn as_str: Str -> Vec<u8>);
-       
+
        fn as_numeric(self) -> Option<EvalResult> {
                match self {
                        EvalResult::Int(_) | EvalResult::Float(_) => Some(self),
@@ -130,6 +130,10 @@ macro_rules! p (
        ($i:expr, $c:expr) => (exact_token!($i,Punctuation,$c.as_bytes()))
 );
 
+macro_rules! k (
+       ($i:expr, $c:expr) => (exact_token!($i,Keyword,$c.as_bytes()))
+);
+
 macro_rules! one_of_punctuation (
        ($i:expr, $c:expr) => ({
                if $i.is_empty() {
@@ -298,9 +302,29 @@ macro_rules! numeric (
        ($i:expr, $f:expr ) => (map_opt!($i,call!($f),EvalResult::as_numeric));
 );
 
+enum TypeCast {
+       Int(u32), // bits of the type to cast
+       Float(u32)
+}
+
 impl<'a> PRef<'a> {
+       method!(cast<PRef<'a>,&[Token],TypeCast,::Error>, mut self,
+               delimited!(p!("("), alt!(
+                       do_parse!(opt!(k!("unsigned")) >> k!("int") >> (TypeCast::Int(32))) |
+                       do_parse!(opt!(k!("unsigned")) >> k!("char") >> (TypeCast::Int(8))) |
+                       do_parse!(opt!(k!("unsigned")) >> k!("long") >> (TypeCast::Int(32)))
+               ) ,p!(")"))
+       );
+
        method!(unary<PRef<'a>,&[Token],EvalResult,::Error>, mut self,
                alt!(
+                       map!(pair!(call_m!(self.cast), call_m!(self.numeric_expr)), |r| {
+                               match r {
+                                       (TypeCast::Int(w), EvalResult::Float(f)) => EvalResult::Int(Wrapping(f as i64)),
+                                       (TypeCast::Int(w), EvalResult::Int(Wrapping(i))) => EvalResult::Int(Wrapping(i % 2i64.pow(w))),
+                                       (_, v) => v
+                               }
+                       }) |
                        delimited!(p!("("),call_m!(self.numeric_expr),p!(")")) |
                        numeric!(call_m!(self.literal)) |
                        numeric!(call_m!(self.identifier)) |

@jethrogb
Copy link
Owner

That looks like it's going in the right direction. My main concerns are:

  • Precedence. Is this the correct precedence?
  • Handling type names. The size of a type is dependent on the target architecture, e.g. long is 64 bits on my system. Besides that, I expect to see things like uint8_t and size_t in expressions like these.

@crab2313
Copy link

Thanks for the reply. The precedence is wrong in fact. For example:

#define Float_236p3 (int)233.3 + 3.3          // Int_236 if we are using the patch posted previously

We should not expect a numeric_expr after a (int). We could just assume cast is another unary operation and has the same precedence.

			map!(pair!(call_m!(self.cast), call_m!(self.unary)), |(c, r)| r.cast(c) ) |

Also, uint8_t is an identifier rather than a keyword which requires different treatment. It is really hard for me to handle cast between integers and float points properly. I need more time to figure it out.

@crab2313 crab2313 linked a pull request Jun 22, 2019 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants