1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use std::borrow::Cow; 6 use std::collections::HashMap; 7 use std::io::Write; 8 9 use syn::{self, UnOp}; 10 11 use crate::bindgen::config::{Config, Language}; 12 use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; 13 use crate::bindgen::dependencies::Dependencies; 14 use crate::bindgen::ir::{ 15 AnnotationSet, Cfg, ConditionWrite, Documentation, GenericParams, Item, ItemContainer, Path, 16 Struct, ToCondition, Type, 17 }; 18 use crate::bindgen::library::Library; 19 use crate::bindgen::writer::{Source, SourceWriter}; 20 use crate::bindgen::Bindings; 21 22 #[derive(Debug, Clone)] 23 pub enum Literal { 24 Expr(String), 25 Path(String), 26 PostfixUnaryOp { 27 op: &'static str, 28 value: Box<Literal>, 29 }, 30 BinOp { 31 left: Box<Literal>, 32 op: &'static str, 33 right: Box<Literal>, 34 }, 35 Struct { 36 path: Path, 37 export_name: String, 38 fields: HashMap<String, Literal>, 39 }, 40 Cast { 41 ty: Type, 42 value: Box<Literal>, 43 }, 44 } 45 46 impl Literal { replace_self_with(&mut self, self_ty: &Path)47 fn replace_self_with(&mut self, self_ty: &Path) { 48 match *self { 49 Literal::PostfixUnaryOp { ref mut value, .. } => { 50 value.replace_self_with(self_ty); 51 } 52 Literal::BinOp { 53 ref mut left, 54 ref mut right, 55 .. 56 } => { 57 left.replace_self_with(self_ty); 58 right.replace_self_with(self_ty); 59 } 60 Literal::Struct { 61 ref mut path, 62 ref mut export_name, 63 ref mut fields, 64 } => { 65 if path.replace_self_with(self_ty) { 66 *export_name = self_ty.name().to_owned(); 67 } 68 for ref mut expr in fields.values_mut() { 69 expr.replace_self_with(self_ty); 70 } 71 } 72 Literal::Cast { 73 ref mut ty, 74 ref mut value, 75 } => { 76 ty.replace_self_with(self_ty); 77 value.replace_self_with(self_ty); 78 } 79 Literal::Expr(..) | Literal::Path(..) => {} 80 } 81 } 82 is_valid(&self, bindings: &Bindings) -> bool83 fn is_valid(&self, bindings: &Bindings) -> bool { 84 match *self { 85 Literal::Expr(..) => true, 86 Literal::Path(..) => true, 87 Literal::PostfixUnaryOp { ref value, .. } => value.is_valid(bindings), 88 Literal::BinOp { 89 ref left, 90 ref right, 91 .. 92 } => left.is_valid(bindings) && right.is_valid(bindings), 93 Literal::Struct { ref path, .. } => bindings.struct_exists(path), 94 Literal::Cast { ref value, .. } => value.is_valid(bindings), 95 } 96 } 97 uses_only_primitive_types(&self) -> bool98 pub fn uses_only_primitive_types(&self) -> bool { 99 match self { 100 Literal::Expr(..) => true, 101 Literal::Path(..) => true, 102 Literal::PostfixUnaryOp { ref value, .. } => value.uses_only_primitive_types(), 103 Literal::BinOp { 104 ref left, 105 ref right, 106 .. 107 } => left.uses_only_primitive_types() & right.uses_only_primitive_types(), 108 Literal::Struct { .. } => false, 109 Literal::Cast { ref value, ref ty } => { 110 value.uses_only_primitive_types() && ty.is_primitive_or_ptr_primitive() 111 } 112 } 113 } 114 } 115 116 impl Literal { rename_for_config(&mut self, config: &Config)117 pub fn rename_for_config(&mut self, config: &Config) { 118 match self { 119 Literal::Struct { 120 ref mut export_name, 121 fields, 122 .. 123 } => { 124 config.export.rename(export_name); 125 for lit in fields.values_mut() { 126 lit.rename_for_config(config); 127 } 128 } 129 Literal::Path(ref mut name) => { 130 config.export.rename(name); 131 } 132 Literal::PostfixUnaryOp { ref mut value, .. } => { 133 value.rename_for_config(config); 134 } 135 Literal::BinOp { 136 ref mut left, 137 ref mut right, 138 .. 139 } => { 140 left.rename_for_config(config); 141 right.rename_for_config(config); 142 } 143 Literal::Expr(_) => {} 144 Literal::Cast { 145 ref mut ty, 146 ref mut value, 147 } => { 148 ty.rename_for_config(config, &GenericParams::default()); 149 value.rename_for_config(config); 150 } 151 } 152 } 153 154 // Translate from full blown `syn::Expr` into a simpler `Literal` type load(expr: &syn::Expr) -> Result<Literal, String>155 pub fn load(expr: &syn::Expr) -> Result<Literal, String> { 156 match *expr { 157 // Match binary expressions of the form `a * b` 158 syn::Expr::Binary(ref bin_expr) => { 159 let l = Self::load(&bin_expr.left)?; 160 let r = Self::load(&bin_expr.right)?; 161 let op = match bin_expr.op { 162 syn::BinOp::Add(..) => "+", 163 syn::BinOp::Sub(..) => "-", 164 syn::BinOp::Mul(..) => "*", 165 syn::BinOp::Div(..) => "/", 166 syn::BinOp::Rem(..) => "%", 167 syn::BinOp::And(..) => "&&", 168 syn::BinOp::Or(..) => "||", 169 syn::BinOp::BitXor(..) => "^", 170 syn::BinOp::BitAnd(..) => "&", 171 syn::BinOp::BitOr(..) => "|", 172 syn::BinOp::Shl(..) => "<<", 173 syn::BinOp::Shr(..) => ">>", 174 syn::BinOp::Eq(..) => "==", 175 syn::BinOp::Lt(..) => "<", 176 syn::BinOp::Le(..) => "<=", 177 syn::BinOp::Ne(..) => "!=", 178 syn::BinOp::Ge(..) => ">=", 179 syn::BinOp::Gt(..) => ">", 180 syn::BinOp::AddEq(..) => "+=", 181 syn::BinOp::SubEq(..) => "-=", 182 syn::BinOp::MulEq(..) => "*=", 183 syn::BinOp::DivEq(..) => "/=", 184 syn::BinOp::RemEq(..) => "%=", 185 syn::BinOp::BitXorEq(..) => "^=", 186 syn::BinOp::BitAndEq(..) => "&=", 187 syn::BinOp::BitOrEq(..) => "|=", 188 syn::BinOp::ShlEq(..) => ">>=", 189 syn::BinOp::ShrEq(..) => "<<=", 190 }; 191 Ok(Literal::BinOp { 192 left: Box::new(l), 193 op, 194 right: Box::new(r), 195 }) 196 } 197 198 // Match literals like true, 'a', 32 etc 199 syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => { 200 match lit { 201 syn::Lit::Byte(ref value) => Ok(Literal::Expr(format!("{}", value.value()))), 202 syn::Lit::Char(ref value) => Ok(Literal::Expr(match value.value() as u32 { 203 0..=255 => format!("'{}'", value.value().escape_default()), 204 other_code => format!(r"U'\U{:08X}'", other_code), 205 })), 206 syn::Lit::Int(ref value) => { 207 if value.base10_parse::<i64>().is_err() { 208 Ok(Literal::Expr(format!("{}ULL", value.base10_digits()))) 209 } else { 210 Ok(Literal::Expr(value.base10_digits().to_string())) 211 } 212 } 213 syn::Lit::Float(ref value) => { 214 Ok(Literal::Expr(value.base10_digits().to_string())) 215 } 216 syn::Lit::Bool(ref value) => Ok(Literal::Expr(format!("{}", value.value))), 217 // TODO: Add support for byte string and Verbatim 218 _ => Err(format!("Unsupported literal expression. {:?}", *lit)), 219 } 220 } 221 222 syn::Expr::Struct(syn::ExprStruct { 223 ref path, 224 ref fields, 225 .. 226 }) => { 227 let struct_name = path.segments[0].ident.to_string(); 228 let mut field_map = HashMap::<String, Literal>::default(); 229 for field in fields { 230 let ident = match field.member { 231 syn::Member::Named(ref name) => name.to_string(), 232 syn::Member::Unnamed(ref index) => format!("_{}", index.index), 233 }; 234 let key = ident.to_string(); 235 let value = Literal::load(&field.expr)?; 236 field_map.insert(key, value); 237 } 238 Ok(Literal::Struct { 239 path: Path::new(struct_name.clone()), 240 export_name: struct_name, 241 fields: field_map, 242 }) 243 } 244 245 syn::Expr::Unary(syn::ExprUnary { 246 ref op, ref expr, .. 247 }) => match *op { 248 UnOp::Neg(_) => { 249 let val = Self::load(expr)?; 250 Ok(Literal::PostfixUnaryOp { 251 op: "-", 252 value: Box::new(val), 253 }) 254 } 255 _ => Err(format!("Unsupported Unary expression. {:?}", *op)), 256 }, 257 258 // Match identifiers, like `5 << SHIFT` 259 syn::Expr::Path(syn::ExprPath { 260 path: syn::Path { ref segments, .. }, 261 .. 262 }) => { 263 // Handle only the simplest identifiers and error for anything else. 264 if segments.len() == 1 { 265 Ok(Literal::Path(format!("{}", segments.last().unwrap().ident))) 266 } else { 267 Err(format!("Unsupported path expression. {:?}", *segments)) 268 } 269 } 270 271 syn::Expr::Paren(syn::ExprParen { ref expr, .. }) => Self::load(expr), 272 273 syn::Expr::Cast(syn::ExprCast { 274 ref expr, ref ty, .. 275 }) => { 276 let val = Self::load(expr)?; 277 match Type::load(ty)? { 278 Some(ty) => Ok(Literal::Cast { 279 ty, 280 value: Box::new(val), 281 }), 282 None => Err("Cannot cast to zero sized type.".to_owned()), 283 } 284 } 285 286 _ => Err(format!("Unsupported expression. {:?}", *expr)), 287 } 288 } 289 write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>)290 pub(crate) fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { 291 match self { 292 Literal::Expr(v) => match (&**v, config.language) { 293 ("true", Language::Cython) => write!(out, "True"), 294 ("false", Language::Cython) => write!(out, "False"), 295 (v, _) => write!(out, "{}", v), 296 }, 297 Literal::Path(v) => write!(out, "{}", v), 298 Literal::PostfixUnaryOp { op, ref value } => { 299 write!(out, "{}", op); 300 value.write(config, out); 301 } 302 Literal::BinOp { 303 ref left, 304 op, 305 ref right, 306 } => { 307 write!(out, "("); 308 left.write(config, out); 309 write!(out, " {} ", op); 310 right.write(config, out); 311 write!(out, ")"); 312 } 313 Literal::Cast { ref ty, ref value } => { 314 out.write(if config.language == Language::Cython { 315 "<" 316 } else { 317 "(" 318 }); 319 ty.write(config, out); 320 out.write(if config.language == Language::Cython { 321 ">" 322 } else { 323 ")" 324 }); 325 value.write(config, out); 326 } 327 Literal::Struct { 328 export_name, 329 fields, 330 path, 331 } => { 332 match config.language { 333 Language::C => write!(out, "({})", export_name), 334 Language::Cxx => write!(out, "{}", export_name), 335 Language::Cython => write!(out, "<{}>", export_name), 336 } 337 338 write!(out, "{{ "); 339 let mut is_first_field = true; 340 // In C++, same order as defined is required. 341 let ordered_fields = out.bindings().struct_field_names(path); 342 for ordered_key in ordered_fields.iter() { 343 if let Some(lit) = fields.get(ordered_key) { 344 if !is_first_field { 345 write!(out, ", "); 346 } else { 347 is_first_field = false; 348 } 349 match config.language { 350 Language::Cxx => write!(out, "/* .{} = */ ", ordered_key), 351 Language::C => write!(out, ".{} = ", ordered_key), 352 Language::Cython => {} 353 } 354 lit.write(config, out); 355 } 356 } 357 write!(out, " }}"); 358 } 359 } 360 } 361 } 362 363 #[derive(Debug, Clone)] 364 pub struct Constant { 365 pub path: Path, 366 pub export_name: String, 367 pub ty: Type, 368 pub value: Literal, 369 pub cfg: Option<Cfg>, 370 pub annotations: AnnotationSet, 371 pub documentation: Documentation, 372 pub associated_to: Option<Path>, 373 } 374 375 impl Constant { load( path: Path, mod_cfg: Option<&Cfg>, ty: &syn::Type, expr: &syn::Expr, attrs: &[syn::Attribute], associated_to: Option<Path>, ) -> Result<Constant, String>376 pub fn load( 377 path: Path, 378 mod_cfg: Option<&Cfg>, 379 ty: &syn::Type, 380 expr: &syn::Expr, 381 attrs: &[syn::Attribute], 382 associated_to: Option<Path>, 383 ) -> Result<Constant, String> { 384 let ty = Type::load(ty)?; 385 let mut ty = match ty { 386 Some(ty) => ty, 387 None => { 388 return Err("Cannot have a zero sized const definition.".to_owned()); 389 } 390 }; 391 392 let mut lit = Literal::load(expr)?; 393 394 if let Some(ref associated_to) = associated_to { 395 ty.replace_self_with(associated_to); 396 lit.replace_self_with(associated_to); 397 } 398 399 Ok(Constant::new( 400 path, 401 ty, 402 lit, 403 Cfg::append(mod_cfg, Cfg::load(attrs)), 404 AnnotationSet::load(attrs)?, 405 Documentation::load(attrs), 406 associated_to, 407 )) 408 } 409 new( path: Path, ty: Type, value: Literal, cfg: Option<Cfg>, annotations: AnnotationSet, documentation: Documentation, associated_to: Option<Path>, ) -> Self410 pub fn new( 411 path: Path, 412 ty: Type, 413 value: Literal, 414 cfg: Option<Cfg>, 415 annotations: AnnotationSet, 416 documentation: Documentation, 417 associated_to: Option<Path>, 418 ) -> Self { 419 let export_name = path.name().to_owned(); 420 Self { 421 path, 422 export_name, 423 ty, 424 value, 425 cfg, 426 annotations, 427 documentation, 428 associated_to, 429 } 430 } 431 uses_only_primitive_types(&self) -> bool432 pub fn uses_only_primitive_types(&self) -> bool { 433 self.value.uses_only_primitive_types() && self.ty.is_primitive_or_ptr_primitive() 434 } 435 } 436 437 impl Item for Constant { path(&self) -> &Path438 fn path(&self) -> &Path { 439 &self.path 440 } 441 add_dependencies(&self, library: &Library, out: &mut Dependencies)442 fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { 443 self.ty.add_dependencies(library, out); 444 } 445 export_name(&self) -> &str446 fn export_name(&self) -> &str { 447 &self.export_name 448 } 449 cfg(&self) -> Option<&Cfg>450 fn cfg(&self) -> Option<&Cfg> { 451 self.cfg.as_ref() 452 } 453 annotations(&self) -> &AnnotationSet454 fn annotations(&self) -> &AnnotationSet { 455 &self.annotations 456 } 457 annotations_mut(&mut self) -> &mut AnnotationSet458 fn annotations_mut(&mut self) -> &mut AnnotationSet { 459 &mut self.annotations 460 } 461 container(&self) -> ItemContainer462 fn container(&self) -> ItemContainer { 463 ItemContainer::Constant(self.clone()) 464 } 465 rename_for_config(&mut self, config: &Config)466 fn rename_for_config(&mut self, config: &Config) { 467 if self.associated_to.is_none() { 468 config.export.rename(&mut self.export_name); 469 } 470 self.value.rename_for_config(config); 471 self.ty.rename_for_config(config, &GenericParams::default()); // FIXME: should probably propagate something here 472 } 473 resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver)474 fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { 475 self.ty.resolve_declaration_types(resolver); 476 } 477 } 478 479 impl Constant { write_declaration<F: Write>( &self, config: &Config, out: &mut SourceWriter<F>, associated_to_struct: &Struct, )480 pub fn write_declaration<F: Write>( 481 &self, 482 config: &Config, 483 out: &mut SourceWriter<F>, 484 associated_to_struct: &Struct, 485 ) { 486 debug_assert!(self.associated_to.is_some()); 487 debug_assert!(config.language == Language::Cxx); 488 debug_assert!(!associated_to_struct.is_transparent); 489 debug_assert!(config.structure.associated_constants_in_body); 490 debug_assert!(config.constant.allow_static_const); 491 492 if let Type::Ptr { is_const: true, .. } = self.ty { 493 out.write("static "); 494 } else { 495 out.write("static const "); 496 } 497 self.ty.write(config, out); 498 write!(out, " {};", self.export_name()) 499 } 500 write<F: Write>( &self, config: &Config, out: &mut SourceWriter<F>, associated_to_struct: Option<&Struct>, )501 pub fn write<F: Write>( 502 &self, 503 config: &Config, 504 out: &mut SourceWriter<F>, 505 associated_to_struct: Option<&Struct>, 506 ) { 507 if let Some(assoc) = associated_to_struct { 508 if assoc.is_generic() { 509 return; // Not tested / implemented yet, so bail out. 510 } 511 } 512 513 if !self.value.is_valid(out.bindings()) { 514 return; 515 } 516 517 let associated_to_transparent = associated_to_struct.map_or(false, |s| s.is_transparent); 518 519 let in_body = associated_to_struct.is_some() 520 && config.language == Language::Cxx 521 && config.structure.associated_constants_in_body 522 && config.constant.allow_static_const 523 && !associated_to_transparent; 524 525 let condition = self.cfg.to_condition(config); 526 condition.write_before(config, out); 527 528 let name = if in_body { 529 Cow::Owned(format!( 530 "{}::{}", 531 associated_to_struct.unwrap().export_name(), 532 self.export_name(), 533 )) 534 } else if self.associated_to.is_none() { 535 Cow::Borrowed(self.export_name()) 536 } else { 537 let associated_name = match associated_to_struct { 538 Some(s) => Cow::Borrowed(s.export_name()), 539 None => { 540 let mut name = self.associated_to.as_ref().unwrap().name().to_owned(); 541 config.export.rename(&mut name); 542 Cow::Owned(name) 543 } 544 }; 545 546 Cow::Owned(format!("{}_{}", associated_name, self.export_name())) 547 }; 548 549 let value = match self.value { 550 Literal::Struct { 551 ref fields, 552 ref path, 553 .. 554 } if out.bindings().struct_is_transparent(path) => fields.iter().next().unwrap().1, 555 _ => &self.value, 556 }; 557 558 self.documentation.write(config, out); 559 560 let allow_constexpr = if let Type::Primitive(..) = self.ty { 561 config.constant.allow_constexpr 562 } else { 563 false 564 }; 565 566 match config.language { 567 Language::Cxx if config.constant.allow_static_const || allow_constexpr => { 568 if allow_constexpr { 569 out.write("constexpr ") 570 } 571 572 if config.constant.allow_static_const { 573 out.write(if in_body { "inline " } else { "static " }); 574 } 575 576 if let Type::Ptr { is_const: true, .. } = self.ty { 577 // Nothing. 578 } else { 579 out.write("const "); 580 } 581 582 self.ty.write(config, out); 583 write!(out, " {} = ", name); 584 value.write(config, out); 585 write!(out, ";"); 586 } 587 Language::Cxx | Language::C => { 588 write!(out, "#define {} ", name); 589 value.write(config, out); 590 } 591 Language::Cython => { 592 out.write("const "); 593 self.ty.write(config, out); 594 // For extern Cython declarations the initializer is ignored, 595 // but still useful as documentation, so we write it as a comment. 596 write!(out, " {} # = ", name); 597 value.write(config, out); 598 } 599 } 600 601 condition.write_after(config, out); 602 } 603 } 604