dsdl_parser 0.1.3

A nom parser for the DSDL (Data structure description language) used when transmiting over uavcan
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
use std::str;
use std::str::FromStr;

use *;

use nom::{
    line_ending,
    not_line_ending,
    is_digit,
    is_oct_digit,
    is_hex_digit,
};

named!(whitespace, take_while!(is_whitespace));


named!(pub id<String>, map!(map_res!(verify!(take_while!(is_digit), |x:&[u8]| x.len() > 0), str::from_utf8), String::from));

named!(pub file_name<FileName>, map_res!(map_res!(take_while!(is_allowed_in_file_name), str::from_utf8), FileName::from_str));


named!(comment<Comment>, map!(map_res!(complete!(preceded!(tag!("#"), not_line_ending)), str::from_utf8), Comment::from));

named!(directive<Directive>, map_res!(map_res!(do_parse!(_tag: tag!("@") >> name: take_while!(is_allowed_in_directive_name) >> (name)), str::from_utf8), Directive::from_str));

named!(service_response_marker<ServiceResponseMarker>, do_parse!(_srm: tag!("---") >> (ServiceResponseMarker{})));

named!(constant<Const>, alt!(
    complete!(do_parse!(_value: tag!("true") >> (Const::Bool(true)) )) |
    complete!(do_parse!(_value: tag!("false") >> (Const::Bool(false)) )) |
    complete!(do_parse!(_format: tag!("0x") >> value: map_res!(take_while!(is_hex_digit), str::from_utf8) >> (Const::Hex(String::from("0x") + value)))) |
    complete!(do_parse!(_format: tag!("+0x") >> value: map_res!(take_while!(is_hex_digit), str::from_utf8) >> (Const::Hex(String::from("+0x") + value)))) |
    complete!(do_parse!(_format: tag!("-0x") >> value: map_res!(take_while!(is_hex_digit), str::from_utf8) >> (Const::Hex(String::from("-0x") + value)))) |
    complete!(do_parse!(_format: tag!("0b") >> value: map_res!(take_while!(is_bin_digit), str::from_utf8) >> (Const::Bin(String::from("0b") + value)))) |
    complete!(do_parse!(_format: tag!("+0b") >> value: map_res!(take_while!(is_bin_digit), str::from_utf8) >> (Const::Bin(String::from("+0b") + value)))) |
    complete!(do_parse!(_format: tag!("-0b") >> value: map_res!(take_while!(is_bin_digit), str::from_utf8) >> (Const::Bin(String::from("-0b") + value)))) |
    complete!(do_parse!(_format: tag!("0o") >> value: map_res!(take_while!(is_oct_digit), str::from_utf8) >> (Const::Oct(String::from("0o") + value)))) |
    complete!(do_parse!(_format: tag!("+0o") >> value: map_res!(take_while!(is_oct_digit), str::from_utf8) >> (Const::Oct(String::from("+0o") + value)))) |
    complete!(do_parse!(_format: tag!("-0o") >> value: map_res!(take_while!(is_oct_digit), str::from_utf8) >> (Const::Oct(String::from("-0o") + value)))) |
    complete!(do_parse!(achar: delimited!(tag!("'"), map_res!(take_until!("'"), str::from_utf8), tag!("'")) >> (Const::Char(String::from(achar))))) |
    complete!(do_parse!(_sign: tag!("-") >> value: map_res!(verify!(take_while!(is_allowed_in_const), |x:&[u8]| x.iter().all(|x| is_digit(*x))), str::from_utf8) >> (Const::Dec(String::from("-") + value)))) |
    complete!(do_parse!(_sign: tag!("+") >> value: map_res!(verify!(take_while!(is_allowed_in_const), |x:&[u8]| x.iter().all(|x| is_digit(*x))), str::from_utf8) >> (Const::Dec(String::from("+") + value)))) |
    complete!(do_parse!(value: map_res!(verify!(take_while!(is_allowed_in_const), |x:&[u8]| x.iter().all(|x| is_digit(*x))), str::from_utf8) >> (Const::Dec(String::from(value))))) |
    complete!(do_parse!(value: map_res!(take_while!(is_allowed_in_float), str::from_utf8) >> (Const::Float(String::from(value)))))
));

named!(cast_mode<CastMode>, map_res!(map_res!(
    alt!(
        complete!(tag!("saturated")) |
        complete!(tag!("truncated")) 
    ), str::from_utf8), CastMode::from_str)
);

named!(field_name<Ident>, map!(map_res!(
    verify!(take_while!(is_allowed_in_field_name), |x:&[u8]| x.len() >= 1 && is_lowercase_char(x[0])),
    str::from_utf8), Ident::from)
);

named!(const_name<Ident>, map!(map_res!(
    verify!(take_while!(is_allowed_in_const_name), |x:&[u8]| x.len() >= 1 && is_uppercase_char(x[0])),
    str::from_utf8), Ident::from)
);

named!(composite_type_name<CompositeType>, map_res!(map_res!(
    take_while!(is_allowed_in_composite_type_name),
    str::from_utf8), CompositeType::from_str)
);

named!(primitive_type<PrimitiveType>, map_res!(map_res!(take_while!(is_allowed_in_primitive_type_name), str::from_utf8), PrimitiveType::from_str));

named!(type_name<Ty>, alt!(
    map!(complete!(primitive_type), Ty::from) |
    map!(complete!(composite_type_name), Ty::from)
));

named!(array_info<ArrayInfo>, alt!(
    complete!(do_parse!(intro: tag!("[<=") >> num: map_res!(take_while!(is_digit), str::from_utf8) >> exit: tag!("]") >> (ArrayInfo::DynamicLeq(Size::from_str(num).unwrap())))) |
    complete!(do_parse!(intro: tag!("[<") >> num: map_res!(take_while!(is_digit), str::from_utf8) >> exit: tag!("]") >> (ArrayInfo::DynamicLess(Size::from_str(num).unwrap())))) |
    complete!(do_parse!(intro: tag!("[") >> num: map_res!(take_while!(is_digit), str::from_utf8) >> exit: tag!("]") >> (ArrayInfo::Static(Size::from_str(num).unwrap())))) |
    complete!(do_parse!(empty: tag!("") >> (ArrayInfo::Single)))
));





named!(void_definition<FieldDefinition>, sep!(whitespace, 
                                             do_parse!(
                                                 type_name: verify!(primitive_type, |x:PrimitiveType| x.is_void()) >>
                                                     (FieldDefinition{cast_mode: None, field_type: Ty::Primitive(type_name), array: ArrayInfo::Single, name: None}))
));


named!(field_definition<FieldDefinition>, sep!(whitespace, do_parse!(
    cast_mode: opt!(cast_mode) >>
        field_type: type_name >>
        array: array_info >>
        name: field_name >>
        (FieldDefinition{cast_mode: cast_mode, field_type: field_type, array: array, name: Some(name)})
)));


named!(const_definition<ConstDefinition>, sep!(whitespace, do_parse!(
    cast_mode: opt!(cast_mode) >>
        field_type: type_name >>
        name: const_name >>
        _eq: tag!("=") >>
        constant: constant >>
        (ConstDefinition{cast_mode: cast_mode, field_type: field_type, name: name, constant: constant})
)));





named!(attribute_definition<AttributeDefinition>, complete!(sep!(whitespace, alt!(
    map!(const_definition, AttributeDefinition::from) |
    map!(field_definition, AttributeDefinition::from) |
    map!(void_definition, AttributeDefinition::from)
))));



named!(line<Line>, sep!(whitespace, alt!(
    do_parse!(
        attribute_definition: attribute_definition >>
            comment: opt!(comment) >>
            _eol: verify!(not_line_ending, |x:&[u8]| x.len() == 0) >>
            (Line::Definition(attribute_definition, comment))
    ) |
    do_parse!(
        directive: directive >>
            comment: opt!(comment) >>
            _eol: verify!(not_line_ending, |x:&[u8]| x.len() == 0) >>
            (Line::Directive(directive, comment))
    ) |
    do_parse!(
        comment: comment >>
            _eol: verify!(not_line_ending, |x:&[u8]| x.len() == 0) >>
            (Line::Comment(comment))
    ) |
    do_parse!(
        _eol: verify!(not_line_ending, |x:&[u8]| x.len() == 0) >>
            (Line::Empty)
    )
)));                       

named!(lines<Vec<Line>>, many0!(sep!(whitespace, do_parse!(line: line >> _eol: opt!(complete!(line_ending)) >> (line)))));

named!(message_definition<MessageDefinition>, do_parse!(lines: lines >> (MessageDefinition(lines))));

named!(service_definition<ServiceDefinition>, sep!(whitespace, do_parse!(
    request: message_definition >>
        _srm: service_response_marker >>
        response: message_definition >>
        (ServiceDefinition{request: request, response: response})
)));

named!(pub type_definition<TypeDefinition>, alt!(
    map!(complete!(service_definition), TypeDefinition::from) |
    map!(complete!(message_definition), TypeDefinition::from)
));




fn is_whitespace(chr: u8) -> bool {
    chr == b' ' || chr == b'\t'
}


fn is_lowercase_char(chr: u8) -> bool {
    chr >= b'a' && chr <= b'z'
}

fn is_uppercase_char(chr: u8) -> bool {
    chr >= b'A' && chr <= b'Z'
}

fn is_bin_digit(chr: u8) -> bool {
    chr == b'0' || chr == b'1'
}

fn is_allowed_in_float(chr: u8) -> bool {
    is_digit(chr) || chr == b'.' || chr == b'E' || chr == b'e' || chr == b'-' || chr == b'+'
}

fn is_allowed_in_const(chr: u8) -> bool {
    is_digit(chr) || is_uppercase_char(chr) || is_lowercase_char(chr) || chr == b'.' || chr == b'E' || chr == b'e' || chr == b'-' || chr == b'+'
}

fn is_allowed_in_field_name(chr: u8) -> bool {
    is_lowercase_char(chr) || is_digit(chr) || chr == b'_'
}
    
fn is_allowed_in_primitive_type_name(chr: u8) -> bool {
    is_lowercase_char(chr) || is_digit(chr)
}
    
fn is_allowed_in_const_name(chr: u8) -> bool {
    is_uppercase_char(chr) || is_digit(chr) || chr == b'_'
}
    
fn is_allowed_in_composite_type_name(chr: u8) -> bool {
    is_uppercase_char(chr) || is_lowercase_char(chr) || is_digit(chr) || chr == b'.'
}
    
fn is_allowed_in_directive_name(chr: u8) -> bool {
    is_lowercase_char(chr)
}
    
fn is_allowed_in_file_name(chr: u8) -> bool {
    is_lowercase_char(chr) || is_uppercase_char(chr) || is_digit(chr) || chr == b'.'
}
    
        


#[cfg(test)]
mod tests {
    use super::*;

    use nom::{
        IResult,
    };

    #[test]
    fn parse_file_name() {
        assert_eq!(file_name(&b"NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: None, namespace: String::from(""), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: None, namespace: String::from(""), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"protocol.NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: None, namespace: String::from("protocol"), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"uavcan.protocol.NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: None, namespace: String::from("uavcan.protocol"), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"protocol.341.NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: Some(String::from("341")), namespace: String::from("protocol"), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"uavcan.protocol.341.NodeStatus.uavcan"[..]), IResult::Done(&b""[..], FileName{id: Some(String::from("341")), namespace: String::from("uavcan.protocol"), name: String::from("NodeStatus"), version: None}));
        assert_eq!(file_name(&b"protocol.341.NodeStatus.0.1.uavcan"[..]), IResult::Done(&b""[..], FileName{id: Some(String::from("341")), namespace: String::from("protocol"), name: String::from("NodeStatus"), version: Some(Version{minor: 1, major: 0})}));
        assert_eq!(file_name(&b"uavcan.protocol.341.NodeStatus.0.1.uavcan"[..]), IResult::Done(&b""[..], FileName{id: Some(String::from("341")), namespace: String::from("uavcan.protocol"), name: String::from("NodeStatus"), version: Some(Version{minor: 1, major: 0})}));
    }
    
    #[test]
    fn parse_directive() {
        assert_eq!(directive(&b"@union"[..]), IResult::Done(&b""[..], Directive::Union));
    }
    
    #[test]
    fn parse_comment() {
        assert_eq!(comment(&b"#This is a comment\n"[..]), IResult::Done(&b"\n"[..], Comment(String::from("This is a comment"))));
        assert_eq!(comment(&b"#This is a comment"[..]), IResult::Done(&b""[..], Comment(String::from("This is a comment"))));
        assert_eq!(comment(&b"#This is a comment\r\n"[..]), IResult::Done(&b"\r\n"[..], Comment(String::from("This is a comment"))));
        assert_eq!(comment(&b"#This is a longer comment"[..]), IResult::Done(&b""[..], Comment(String::from("This is a longer comment"))));
        assert_eq!(comment(&b"# This is a comment"[..]), IResult::Done(&b""[..], Comment(String::from(" This is a comment"))));
        assert_eq!(comment(&b"#"[..]), IResult::Done(&b""[..], Comment(String::from(""))));   
    }

    #[test]
    fn parse_constant() {
        assert_eq!(constant(&b"12354"[..]), IResult::Done(&b""[..], Const::Dec(String::from("12354"))));
        assert_eq!(constant(&b"-12"[..]), IResult::Done(&b""[..], Const::Dec(String::from("-12"))));
        assert_eq!(constant(&b"+12"[..]), IResult::Done(&b""[..], Const::Dec(String::from("+12"))));
        
        assert_eq!(constant(&b"0x123"[..]), IResult::Done(&b""[..], Const::Hex(String::from("0x123"))));
        assert_eq!(constant(&b"-0x12"[..]), IResult::Done(&b""[..], Const::Hex(String::from("-0x12"))));
        assert_eq!(constant(&b"+0x123"[..]), IResult::Done(&b""[..], Const::Hex(String::from("+0x123"))));
        
        assert_eq!(constant(&b"0b1101"[..]), IResult::Done(&b""[..], Const::Bin(String::from("0b1101"))));
        assert_eq!(constant(&b"-0b101101"[..]), IResult::Done(&b""[..], Const::Bin(String::from("-0b101101"))));
        assert_eq!(constant(&b"+0b101101"[..]), IResult::Done(&b""[..], Const::Bin(String::from("+0b101101"))));
        
        assert_eq!(constant(&b"0o123"[..]), IResult::Done(&b""[..], Const::Oct(String::from("0o123"))));
        assert_eq!(constant(&b"-0o777"[..]), IResult::Done(&b""[..], Const::Oct(String::from("-0o777"))));
        assert_eq!(constant(&b"+0o777"[..]), IResult::Done(&b""[..], Const::Oct(String::from("+0o777"))));
        
        assert_eq!(constant(&b"15.75"[..]), IResult::Done(&b""[..], Const::Float(String::from("15.75"))));
        assert_eq!(constant(&b"1.575E1"[..]), IResult::Done(&b""[..], Const::Float(String::from("1.575E1"))));
        assert_eq!(constant(&b"1575e-2"[..]), IResult::Done(&b""[..], Const::Float(String::from("1575e-2"))));
        assert_eq!(constant(&b"-2.5e-3"[..]), IResult::Done(&b""[..], Const::Float(String::from("-2.5e-3"))));
        assert_eq!(constant(&b"+25e-4"[..]), IResult::Done(&b""[..], Const::Float(String::from("+25e-4"))));
        
        assert_eq!(constant(&b"true"[..]), IResult::Done(&b""[..], Const::Bool(true)));
        assert_eq!(constant(&b"false"[..]), IResult::Done(&b""[..], Const::Bool(false)));
        
        assert_eq!(constant(&b"'a'"[..]), IResult::Done(&b""[..], Const::Char(String::from("a"))));
        assert_eq!(constant(&[39,92,b'x',b'6',b'1', 39]), IResult::Done(&b""[..], Const::Char(String::from("\\x61"))));
        assert_eq!(constant(&[39,92,b'n', 39]), IResult::Done(&b""[..], Const::Char(String::from("\\n"))));
    }

    #[test]
    fn parse_field_name() {
        assert_eq!(field_name(&b"variable23"[..]), IResult::Done(&b""[..], Ident(String::from("variable23"))));
        assert_eq!(field_name(&b"var_iable23"[..]), IResult::Done(&b""[..], Ident(String::from("var_iable23"))));
        assert!(field_name(&b"2variable23"[..]).is_err());
    }

    #[test]
    fn parse_const_name() {
        assert_eq!(const_name(&b"CONST"[..]), IResult::Done(&b""[..], Ident(String::from("CONST"))));
        assert_eq!(const_name(&b"CONST23"[..]), IResult::Done(&b""[..], Ident(String::from("CONST23"))));
        assert_eq!(const_name(&b"CON_ST"[..]), IResult::Done(&b""[..], Ident(String::from("CON_ST"))));
        assert_eq!(const_name(&b"CON_ST1_2345"[..]), IResult::Done(&b""[..], Ident(String::from("CON_ST1_2345"))));
        assert!(const_name(&b"2CON"[..]).is_err());
    }

    #[test]
    fn parse_composite_type_name() {
        assert_eq!(composite_type_name(&b"TypeName"[..]), IResult::Done(&b""[..], CompositeType{namespace: None, name: Ident(String::from("TypeName")) } ));
        assert_eq!(composite_type_name(&b"TypeName1234"[..]), IResult::Done(&b""[..], CompositeType{namespace: None, name: Ident(String::from("TypeName1234")) } ));

        assert_eq!(composite_type_name(&b"uavcan.protocol.TypeName"[..]), IResult::Done(&b""[..], CompositeType{namespace: Some(Ident(String::from("uavcan.protocol"))), name: Ident(String::from("TypeName"))}));
        assert_eq!(composite_type_name(&b"uavcan.protocol.TypeName1234"[..]), IResult::Done(&b""[..], CompositeType{namespace: Some(Ident(String::from("uavcan.protocol"))), name: Ident(String::from("TypeName1234"))}));
    }

    #[test]
    fn parse_primitive_type() {
        assert_eq!(primitive_type(&b"uint2"[..]), IResult::Done(&b""[..], PrimitiveType::Uint2));
        assert_eq!(primitive_type(&b"uint3"[..]), IResult::Done(&b""[..], PrimitiveType::Uint3));
        assert_eq!(primitive_type(&b"uint16"[..]), IResult::Done(&b""[..], PrimitiveType::Uint16));
        assert_eq!(primitive_type(&b"uint32"[..]), IResult::Done(&b""[..], PrimitiveType::Uint32));
        
        assert!(primitive_type(&b"2variable23"[..]).is_err());
    }

    #[test]
    fn parse_type_name() {
        assert_eq!(type_name(&b"uint2"[..]), IResult::Done(&b""[..], Ty::Primitive(PrimitiveType::Uint2)));
        assert_eq!(type_name(&b"uint3"[..]), IResult::Done(&b""[..], Ty::Primitive(PrimitiveType::Uint3)));
        assert_eq!(type_name(&b"uint16"[..]), IResult::Done(&b""[..], Ty::Primitive(PrimitiveType::Uint16)));
        assert_eq!(type_name(&b"uint32"[..]), IResult::Done(&b""[..], Ty::Primitive(PrimitiveType::Uint32)));

        assert_eq!(type_name(&b"TypeName"[..]), IResult::Done(&b""[..], Ty::Composite(CompositeType{namespace: None, name: Ident(String::from("TypeName"))})));
        assert_eq!(type_name(&b"TypeName1234"[..]), IResult::Done(&b""[..], Ty::Composite(CompositeType{namespace: None, name: Ident(String::from("TypeName1234"))})));

        assert_eq!(type_name(&b"uavcan.protocol.TypeName"[..]), IResult::Done(&b""[..], Ty::Composite(CompositeType{namespace: Some(Ident(String::from("uavcan.protocol"))), name: Ident(String::from("TypeName"))})));
        assert_eq!(type_name(&b"uavcan.protocol.TypeName1234"[..]), IResult::Done(&b""[..], Ty::Composite(CompositeType{namespace: Some(Ident(String::from("uavcan.protocol"))), name: Ident(String::from("TypeName1234"))})));
        
    }

    #[test]
    fn parse_cast_mode() {
        assert_eq!(cast_mode(&b"saturated"[..]), IResult::Done(&b""[..], CastMode::Saturated));
        assert_eq!(cast_mode(&b"truncated"[..]), IResult::Done(&b""[..], CastMode::Truncated));
        
        assert!(cast_mode(&b"2variable23"[..]).is_err());
        assert!(cast_mode(&b""[..]).is_err());
    }

    #[test]
    fn parse_array_info() {
        assert_eq!(array_info(&b""[..]), IResult::Done(&b""[..], ArrayInfo::Single));
        assert_eq!(array_info(&b"[<=4]"[..]), IResult::Done(&b""[..], ArrayInfo::DynamicLeq(Size::from_str("4").unwrap())));
        assert_eq!(array_info(&b"[<5]"[..]), IResult::Done(&b""[..], ArrayInfo::DynamicLess(Size::from_str("5").unwrap())));
        
        assert_eq!(array_info(&b"[<=128]"[..]), IResult::Done(&b""[..], ArrayInfo::DynamicLeq(Size::from_str("128").unwrap())));
        assert_eq!(array_info(&b"[<129]"[..]), IResult::Done(&b""[..], ArrayInfo::DynamicLess(Size::from_str("129").unwrap())));

        assert_eq!(array_info(&b"[4]"[..]), IResult::Done(&b""[..], ArrayInfo::Static(Size::from_str("4").unwrap())));
        assert_eq!(array_info(&b"[5]"[..]), IResult::Done(&b""[..], ArrayInfo::Static(Size::from_str("5").unwrap())));
        assert_eq!(array_info(&b"[128]"[..]), IResult::Done(&b""[..], ArrayInfo::Static(Size::from_str("128").unwrap())));
        assert_eq!(array_info(&b"[129]"[..]), IResult::Done(&b""[..], ArrayInfo::Static(Size::from_str("129").unwrap())));
        
    }







    #[test]
    fn parse_void_definition() {
        assert_eq!(
            void_definition(&b"void2"[..]),
            IResult::Done(&b""[..], FieldDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Void2),
                array: ArrayInfo::Single,
                name: None,
            })
        );        
    }

    #[test]
    fn parse_field_definition() {
        assert_eq!(
            field_definition(&b"uint32 uptime_sec"[..]),
            IResult::Done(&b""[..], FieldDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Uint32),
                array: ArrayInfo::Single,
                name: Some(Ident(String::from("uptime_sec"))),
            })
        );

        
    }

    #[test]
    fn parse_const_definition() {
        assert_eq!(
            const_definition(&b"uint2 HEALTH_OK              = 0"[..]),
            IResult::Done(&b""[..], ConstDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Uint2),
                name: Ident(String::from("HEALTH_OK")),
                constant: Const::Dec(String::from("0")),
            })
        );

        
    }





    #[test]
    fn parse_attribute_definition() {
        assert_eq!(
            attribute_definition(&b"void2"[..]),
            IResult::Done(&b""[..], AttributeDefinition::Field(FieldDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Void2),
                array: ArrayInfo::Single,
                name: None,
            }))
        );

        assert_eq!(
            attribute_definition(&b"uint32 uptime_sec"[..]),
            IResult::Done(&b""[..], AttributeDefinition::Field(FieldDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Uint32),
                array: ArrayInfo::Single,
                name: Some(Ident(String::from("uptime_sec"))),
            }))
        );
        
        assert_eq!(
            attribute_definition(&b"uint2 HEALTH_OK              = 0"[..]),
            IResult::Done(&b""[..], AttributeDefinition::Const(ConstDefinition{
                cast_mode: None,
                field_type: Ty::Primitive(PrimitiveType::Uint2),
                name: Ident(String::from("HEALTH_OK")),
                constant: Const::Dec(String::from("0")),
            }))
        );

        
    }





    #[test]
    fn parse_line() {
        assert_eq!(
            line(&b"# Test comment"[..]),
            IResult::Done(&b""[..], Line::Comment(
                Comment(String::from(" Test comment"))
            ))
        );
        
        assert_eq!(
            line(&b"void2\n"[..]),
            IResult::Done(&b"\n"[..], Line::Definition(
                AttributeDefinition::Field(FieldDefinition{
                    cast_mode: None,
                    field_type: Ty::Primitive(PrimitiveType::Void2),
                    array: ArrayInfo::Single,
                    name: None,
                }),
                None
            ))
        );
        
        assert_eq!(
            line(&b"void3"[..]),
            IResult::Done(&b""[..], Line::Definition(
                AttributeDefinition::Field(FieldDefinition{
                    cast_mode: None,
                    field_type: Ty::Primitive(PrimitiveType::Void3),
                    array: ArrayInfo::Single,
                    name: None,
                }),
                None
            ))
        );

        assert_eq!(
            line(&b"void2 # test comment\n"[..]),
            IResult::Done(&b"\n"[..], Line::Definition(
                AttributeDefinition::Field(FieldDefinition{
                    cast_mode: None,
                    field_type: Ty::Primitive(PrimitiveType::Void2),
                    array: ArrayInfo::Single,
                    name: None
                }),
                Some(Comment(String::from(" test comment")))
            ))
        );

        assert_eq!(
            line(&b"uint32 uptime_sec"[..]),
            IResult::Done(&b""[..], Line::Definition(
                AttributeDefinition::Field(FieldDefinition{
                    cast_mode: None,
                    field_type: Ty::Primitive(PrimitiveType::Uint32),
                    array: ArrayInfo::Single,
                    name: Some(Ident(String::from("uptime_sec"))),
                }),
                None,
            ))
        );
        
        assert_eq!(
            line(&b"uint2 HEALTH_OK              = 0"[..]),
            IResult::Done(&b""[..], Line::Definition(
                AttributeDefinition::Const(ConstDefinition{
                    cast_mode: None,
                    field_type: Ty::Primitive(PrimitiveType::Uint2),
                    name: Ident(String::from("HEALTH_OK")),
                    constant: Const::Dec(String::from("0")),
                }),
                None,
            ))
        );
        
    }

    
    #[test]
    fn parse_lines() {
        assert_eq!(
            lines(&b"void2
# test comment
void3

void2 # test comment"[..]),
            IResult::Done(&b""[..], vec!(
                Line::Definition(AttributeDefinition::Field(FieldDefinition{cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Void2), array: ArrayInfo::Single, name: None}), None),
                Line::Comment(Comment(String::from(" test comment"))),
                Line::Definition(AttributeDefinition::Field(FieldDefinition{cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Void3), array: ArrayInfo::Single, name: None}), None),
                Line::Empty,
                Line::Definition(AttributeDefinition::Field(FieldDefinition{cast_mode: None, field_type: Ty::Primitive(PrimitiveType::Void2), array: ArrayInfo::Single, name: None}), Some(Comment(String::from(" test comment")))),
            ))  
        );
        
        
    }
    
    
    
}