1use paste::paste;
12use std::{ffi::c_void, marker::PhantomData};
13
14use crate::raw::{
15 TableGenRecordRef, TableGenRecordValRef, tableGenRecordGetFirstValue, tableGenRecordGetLoc,
16 tableGenRecordGetName, tableGenRecordGetValue, tableGenRecordIsAnonymous,
17 tableGenRecordIsSubclassOf, tableGenRecordPrint, tableGenRecordValGetLoc,
18 tableGenRecordValGetNameInit, tableGenRecordValGetValue, tableGenRecordValNext,
19 tableGenRecordValPrint,
20};
21
22use crate::{
23 error::{Error, SourceLoc, SourceLocation, TableGenError, WithLocation},
24 init::{BitInit, DagInit, ListInit, StringInit, TypedInit},
25 string_ref::StringRef,
26 util::print_callback,
27};
28use std::fmt::{self, Debug, Display, Formatter};
29
30#[derive(Clone, Copy, PartialEq, Eq)]
36pub struct Record<'a> {
37 raw: TableGenRecordRef,
38 _reference: PhantomData<&'a TableGenRecordRef>,
39}
40
41impl Display for Record<'_> {
42 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
43 let mut data = (formatter, Ok(()));
44
45 unsafe {
46 tableGenRecordPrint(
47 self.raw,
48 Some(print_callback),
49 &mut data as *mut _ as *mut c_void,
50 );
51 }
52
53 data.1
54 }
55}
56
57impl Debug for Record<'_> {
58 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
59 writeln!(formatter, "Record(")?;
60 Display::fmt(self, formatter)?;
61 write!(formatter, ")")
62 }
63}
64
65macro_rules! record_value {
66 ($(#[$attr:meta])* $name:ident, $type:ty) => {
67 paste! {
68 $(#[$attr])*
69 pub fn [<$name _value>](self, name: &str) -> Result<$type, Error> {
70 self.value(name)?.try_into()
71 }
72 }
73 };
74}
75
76impl<'a> Record<'a> {
77 pub unsafe fn from_raw(ptr: TableGenRecordRef) -> Record<'a> {
83 Record {
84 raw: ptr,
85 _reference: PhantomData,
86 }
87 }
88
89 pub fn name(self) -> Result<&'a str, Error> {
95 unsafe { StringRef::from_raw(tableGenRecordGetName(self.raw)) }
96 .try_into()
97 .map_err(TableGenError::from)
98 .map_err(|e| e.with_location(self))
99 }
100
101 record_value!(
102 bit,
105 bool
106 );
107 record_value!(
108 bits,
111 Vec<bool>
112 );
113 record_value!(
114 int,
117 i64
118 );
119 record_value!(
120 code,
125 String
126 );
127 record_value!(
128 code_str,
131 &'a str
132 );
133 record_value!(
134 string,
139 String
140 );
141 record_value!(
142 str,
145 &'a str
146 );
147 record_value!(
148 def,
151 Record<'a>
152 );
153 record_value!(
154 list,
157 ListInit<'a>
158 );
159 record_value!(
160 dag,
163 DagInit<'a>
164 );
165
166 pub fn value<'n>(self, name: &'n str) -> Result<RecordValue<'a>, Error> {
168 let value = unsafe { tableGenRecordGetValue(self.raw, StringRef::from(name).to_raw()) };
169 if !value.is_null() {
170 Ok(unsafe { RecordValue::from_raw(value) })
171 } else {
172 Err(TableGenError::MissingValue(String::from(name)).with_location(self))
173 }
174 }
175
176 pub fn anonymous(self) -> bool {
178 unsafe { tableGenRecordIsAnonymous(self.raw) > 0 }
179 }
180
181 pub fn subclass_of(self, class: &str) -> bool {
184 unsafe { tableGenRecordIsSubclassOf(self.raw, StringRef::from(class).to_raw()) > 0 }
185 }
186
187 pub fn values(self) -> RecordValueIter<'a> {
191 RecordValueIter::new(self)
192 }
193}
194
195impl SourceLoc for Record<'_> {
196 fn source_location(self) -> SourceLocation {
197 unsafe { SourceLocation::from_raw(tableGenRecordGetLoc(self.raw)) }
198 }
199}
200
201macro_rules! try_into {
202 ($type:ty) => {
203 impl<'a> TryFrom<RecordValue<'a>> for $type {
204 type Error = Error;
205
206 fn try_from(record_value: RecordValue<'a>) -> Result<Self, Self::Error> {
207 Self::try_from(record_value.init).map_err(|e| e.set_location(record_value))
208 }
209 }
210 };
211}
212
213try_into!(bool);
214try_into!(Vec<bool>);
215try_into!(Vec<BitInit<'a>>);
216try_into!(i64);
217try_into!(ListInit<'a>);
218try_into!(DagInit<'a>);
219try_into!(Record<'a>);
220try_into!(String);
221try_into!(&'a str);
222
223impl<'a> From<RecordValue<'a>> for TypedInit<'a> {
224 fn from(value: RecordValue<'a>) -> Self {
225 value.init
226 }
227}
228
229#[derive(Debug, Clone, Copy, PartialEq, Eq)]
233pub struct RecordValue<'a> {
234 raw: TableGenRecordValRef,
235 pub name: StringInit<'a>,
236 pub init: TypedInit<'a>,
237 _reference: PhantomData<&'a TableGenRecordRef>,
238}
239
240impl Display for RecordValue<'_> {
241 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
242 let mut data = (formatter, Ok(()));
243
244 unsafe {
245 tableGenRecordValPrint(
246 self.raw,
247 Some(print_callback),
248 &mut data as *mut _ as *mut c_void,
249 );
250 }
251
252 data.1
253 }
254}
255
256impl RecordValue<'_> {
257 pub unsafe fn from_raw(ptr: TableGenRecordValRef) -> Self {
263 let name = unsafe { StringInit::from_raw(tableGenRecordValGetNameInit(ptr)) };
264 let value = unsafe { TypedInit::from_raw(tableGenRecordValGetValue(ptr)) };
265 Self {
266 name,
267 init: value,
268 raw: ptr,
269 _reference: PhantomData,
270 }
271 }
272}
273
274impl SourceLoc for RecordValue<'_> {
275 fn source_location(self) -> SourceLocation {
276 unsafe { SourceLocation::from_raw(tableGenRecordValGetLoc(self.raw)) }
277 }
278}
279
280#[derive(Debug, Clone)]
281pub struct RecordValueIter<'a> {
282 record: TableGenRecordRef,
283 current: TableGenRecordValRef,
284 _reference: PhantomData<&'a TableGenRecordRef>,
285}
286
287impl<'a> RecordValueIter<'a> {
288 fn new(record: Record<'a>) -> RecordValueIter<'a> {
289 unsafe {
290 RecordValueIter {
291 record: record.raw,
292 current: tableGenRecordGetFirstValue(record.raw),
293 _reference: PhantomData,
294 }
295 }
296 }
297}
298
299impl<'a> Iterator for RecordValueIter<'a> {
300 type Item = RecordValue<'a>;
301
302 fn next(&mut self) -> Option<RecordValue<'a>> {
303 let res = if self.current.is_null() {
304 None
305 } else {
306 unsafe { Some(RecordValue::from_raw(self.current)) }
307 };
308 self.current = unsafe { tableGenRecordValNext(self.record, self.current) };
309 res
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::TableGenParser;
317
318 #[test]
319 fn record() {
320 let rk = TableGenParser::new()
321 .add_source(
322 r#"
323 class A;
324 class B;
325 class C;
326
327 def D1: A;
328 def D2: A, B;
329 def : B, C;
330 "#,
331 )
332 .unwrap()
333 .parse()
334 .expect("valid tablegen");
335 let d2 = rk.def("D2").expect("D2 exists");
336 assert!(d2.subclass_of("A"));
337 assert!(d2.subclass_of("B"));
338 assert!(!d2.subclass_of("C"));
339 assert!(!d2.subclass_of("D"));
340 let anon = rk
341 .defs()
342 .map(|(_name, def)| def)
343 .find(|d| d.anonymous())
344 .expect("anonymous class exists");
345 assert!(!anon.subclass_of("A"));
346 assert!(anon.subclass_of("B"));
347 assert!(anon.subclass_of("C"));
348 }
349
350 #[test]
351 fn single_value() {
352 let rk = TableGenParser::new()
353 .add_source(
354 r#"
355 def A {
356 int size = 42;
357 }
358 "#,
359 )
360 .unwrap()
361 .parse()
362 .expect("valid tablegen");
363 let a = rk.def("A").expect("def A exists");
364 assert_eq!(a.name(), Ok("A"));
365 assert_eq!(a.int_value("size"), Ok(42));
366 assert_eq!(
367 a.value("size")
368 .and_then(|v| {
369 assert!(v.name.to_str() == Ok("size"));
370 v.init.as_int().map_err(|e| e.set_location(v))
371 })
372 .map(|i| i.into()),
373 Ok(42)
374 );
375 }
376
377 #[test]
378 fn values() {
379 let rk = TableGenParser::new()
380 .add_source(
381 r#"
382 def A {
383 int a = 5;
384 string n = "hello";
385 }
386 "#,
387 )
388 .unwrap()
389 .parse()
390 .expect("valid tablegen");
391 let a = rk.def("A").expect("def A exists");
392 let values = a.values();
393 assert_eq!(values.clone().count(), 2);
394 for v in values {
395 match v.init {
396 TypedInit::Int(i) => {
397 assert_eq!(v.name.to_str(), Ok("a"));
398 assert_eq!(i64::from(i), 5);
399 }
400 TypedInit::String(i) => {
401 assert_eq!(v.name.to_str(), Ok("n"));
402 assert_eq!(i.to_str(), Ok("hello"));
403 }
404 _ => panic!("unexpected type"),
405 }
406 }
407 }
408
409 #[test]
410 fn print_error() {
411 let rk = TableGenParser::new()
412 .add_source(
413 r#"
414 class C<int test> {
415 int a = test;
416 }
417 def A : C<4>;
418 "#,
419 )
420 .unwrap()
421 .parse()
422 .expect("valid tablegen");
423 let a = rk.def("A").expect("def A exists");
424 if let Err(e) = a.string_value("a") {
425 assert_eq!(
427 format!("{}", e.clone().add_source_info(rk.source_info())).trim(),
428 r#"
429 error: invalid conversion from Int to alloc::string::String
430 int a = test;
431 ^
432 "#
433 .trim()
434 );
435
436 drop(rk);
438 assert_eq!(
439 format!("{}", e).trim(),
440 r#"
441 invalid conversion from Int to alloc::string::String
442 "#
443 .trim()
444 );
445
446 let rk = TableGenParser::new()
448 .add_source("def A;")
449 .unwrap()
450 .parse()
451 .expect("valid tablegen");
452 assert_eq!(
453 format!("{}", e.add_source_info(rk.source_info())).trim(),
454 "invalid conversion from Int to alloc::string::String\nfailed to print source information: invalid source location"
455 .trim()
456 );
457 } else {
458 panic!("expected error")
459 }
460 }
461}