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
use crate::{
atoms::{if_take, list, none_of, one_of, opt, seq, seq_no_ws, space, sym},
transform::{collect, to_string},
Parser,
};
use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
pub fn alpha() -> Parser<char> {
if_take(|ch| ch.is_ascii_alphabetic())
% "a letter"
}
pub fn numeral() -> Parser<char> {
if_take(|ch| ch.is_numeric())
% "a digit"
}
pub fn alphanumeric() -> Parser<char> {
alpha() | numeral()
% "an alphanumeric character"
}
pub fn punctuation() -> Parser<char> {
if_take(|ch| ch.is_ascii_punctuation())
% "one of ! \" # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \\ ] ^ _ ` { | } ~"
}
pub fn token() -> Parser<String> {
(space()
>> (string()
| number()
| identifier()
| (punctuation() - to_string))
<< space())
% "pne of string, number, identifier, or punctuation"
}
pub fn identifier() -> Parser<String> {
(alpha().is() >> (((alphanumeric() | sym('_')) * (1..31)) - collect))
% "an identifier"
}
pub fn string() -> Parser<String> {
let special_char = sym('\\')
| sym('/')
| sym('"')
| sym('\'')
| (sym('b') - |_| '\x08')
| (sym('f') - |_| '\x0C')
| (sym('n') - |_| '\n')
| (sym('r') - |_| '\r')
| (sym('t') - |_| '\t');
let escape_sequence = sym('\\') >> special_char;
((sym('"') >> ((none_of(b"\\\"") | escape_sequence).repeat(0..)) << sym('"'))
- |v| v.iter().collect::<String>())
% "a string"
}
pub fn number() -> Parser<String> {
let integer =
(one_of(b"0123456789").repeat(1..) - |cons| cons.iter().collect::<String>()) | seq("0");
let frac = sym('.') >> integer.clone();
let number = (space() >> opt(sym('-'))) & (space() >> integer) & (opt(frac) << space());
(number
- |v: ((Option<char>, String), Option<String>)| {
let mut result = String::new();
if let Some(ch) = (v.0).0 {
result.push(ch);
}
result += &(v.0).1;
if let Some(s) = v.1 {
result += &(".".to_owned() + &s);
}
result
})
% "a number"
}
pub fn array<T: 'static + Clone>(
begin: &'static str,
item: Parser<T>,
end: &'static str,
) -> Parser<Vec<T>> {
seq_no_ws(begin) >> list(item.clone(), seq_no_ws(",")) << seq_no_ws(end)
% format!("An array of 0 or more {}(s)", item.expectation)
}