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
use crate::ply::{ PropertyDef, PropertyType, ScalarType, Encoding, Version, Comment, ObjInfo,ElementDef };
#[derive(Debug, PartialEq, Clone)]
pub enum Line {
    MagicNumber,
    Format((Encoding, Version)),
    Comment(Comment),
    ObjInfo(ObjInfo),
    Element(ElementDef),
    Property(PropertyDef),
    EndHeader
}

peg::parser!{pub grammar grammar() for str {

/// Grammar for PLY header

pub rule number() -> String
	= n:$(['0'..='9']+) { n.to_string() }

rule space() = [' '|'\t']+

rule uint() -> u64
	= n:$(['0'..='9']+) { n.parse().unwrap() }

rule ident() -> String
	= s:$(['a'..='z'|'A'..='Z'|'_']['a'..='z'|'A'..='Z'|'0'..='9'|'_'|'-']*) { s.to_string() }

rule text() -> String
	= s:$((!['\n'|'\r'][_])+) { s.to_string() }

rule line_break()
	= "\r\n" / ['\n'|'\r']

rule scalar() -> ScalarType
	= "char"    { ScalarType::Char }
	/ "int8"    { ScalarType::Char }
	/ "uchar"   { ScalarType::UChar }
	/ "uint8"   { ScalarType::UChar }
	/ "short"   { ScalarType::Short }
	/ "int16"   { ScalarType::Short }
	/ "uint16"  { ScalarType::UShort }
	/ "ushort"  { ScalarType::UShort }
	/ "int32"   { ScalarType::Int }
	/ "int"     { ScalarType::Int }
	/ "uint32"  { ScalarType::UInt }
	/ "uint"    { ScalarType::UInt }
	/ "float32" { ScalarType::Float }
	/ "float64" { ScalarType::Double }
	/ "float"   { ScalarType::Float }
	/ "double"  { ScalarType::Double }

rule data_type() -> PropertyType
	= s:scalar()   { PropertyType::Scalar(s) }
	/ "list" space() it:scalar() space() t:scalar() {
		PropertyType::List(it, t)
	}

pub rule magic_number()
	= "ply"

pub rule format() -> (Encoding, Version)
	= "format" space() "ascii" space() v:version() { (Encoding::Ascii, v) }
	/ "format" space() "binary_big_endian" space() v:version() { (Encoding::BinaryBigEndian, v) }
	/ "format" space() "binary_little_endian" space() v:version() { (Encoding::BinaryLittleEndian, v) }

rule version() -> Version
	= maj:uint() "." min:uint() {
		Version {
			major: maj as u16,
			minor: min as u8,
		}
	}

pub rule comment() -> Comment
	= "comment" space() c:text() {
		c.to_string()
	}
	/ "comment" space()? {
		String::new()
	}

pub rule obj_info() -> ObjInfo
	= "obj_info" space() c:text() {
	    c.to_string()
	}
	/ "obj_info" space()? {
	    String::new()
	}

pub rule element() -> ElementDef
	= "element" space() id:$(ident()) space() n:uint() {
		let mut e = ElementDef::new(id.to_string());
		e.count = n as usize;
		e
	}

pub rule property() -> PropertyDef
	= "property" space() data_type:data_type() space() id:ident() {
		PropertyDef::new(id, data_type)
	}

pub rule end_header()
	= "end_header"

pub rule line() -> Line
	= l:trimmed_line() space()? line_break()? { l }

rule trimmed_line() -> Line
	= magic_number() { Line::MagicNumber }
	/ end_header() { Line::EndHeader }
	/ v:format() { Line::Format(v) }
	/ v:obj_info() { Line::ObjInfo(v) }
	/ v:comment() { Line::Comment(v) }
	/ v:element() { Line::Element(v) }
	/ v:property() { Line::Property(v) }

rule any_number() -> String
	= s:$(['-'|'+']? ['0'..='9']+("."['0'..='9']+)?("e"['-'|'+']?['0'..='9']+)?) { s.to_string() }

rule trimmed_data_line() -> Vec<String>
	= any_number() ** space()

pub rule data_line() -> Vec<String>
	= space()? l:trimmed_data_line() space()? line_break()? {l}

}}