1use crate::{
7 atoms::{if_take, list, none_of, one_of, opt, seq, seq_no_ws, space, sym},
8 transform::{collect, to_string},
9 Parser,
10};
11
12use alloc::borrow::ToOwned;
13use alloc::string::String;
14use alloc::vec::Vec;
16
17pub fn alpha() -> Parser<char> {
19 if_take(|ch| ch.is_ascii_alphabetic())
20 % "a letter"
21}
22
23pub fn numeral() -> Parser<char> {
25 if_take(|ch| ch.is_numeric())
26 % "a digit"
27}
28
29pub fn alphanumeric() -> Parser<char> {
31 alpha() | numeral()
32 % "an alphanumeric character"
33}
34
35pub fn punctuation() -> Parser<char> {
38 if_take(|ch| ch.is_ascii_punctuation())
39 % "one of ! \" # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \\ ] ^ _ ` { | } ~"
40}
41
42pub fn token() -> Parser<String> {
48 (space()
49 >> (string() | number() | identifier() | (punctuation() - to_string))
53 << space())
54 % "pne of string, number, identifier, or punctuation"
55}
56
57pub fn identifier() -> Parser<String> {
59 (alpha().is() >> (((alphanumeric() | sym('_')) * (1..31)) - collect))
60 % "an identifier"
61}
62
63pub fn string() -> Parser<String> {
65 let special_char = sym('\\')
66 | sym('/')
67 | sym('"')
68 | sym('\'')
69 | (sym('b') - |_| '\x08')
70 | (sym('f') - |_| '\x0C')
71 | (sym('n') - |_| '\n')
72 | (sym('r') - |_| '\r')
73 | (sym('t') - |_| '\t');
74 let escape_sequence = sym('\\') >> special_char;
75
76 ((sym('"') >> ((none_of(b"\\\"") | escape_sequence).repeat(0..)) << sym('"'))
77 - |v| v.iter().collect::<String>())
78 % "a string"
79}
80
81pub fn number() -> Parser<String> {
83 let integer =
84 (one_of(b"0123456789").repeat(1..) - |cons| cons.iter().collect::<String>()) | seq("0");
85
86 let frac = sym('.') >> integer.clone();
87 let number = (space() >> opt(sym('-'))) & (space() >> integer) & (opt(frac) << space());
88
89 (number
90 - |v: ((Option<char>, String), Option<String>)| {
91 let mut result = String::new();
92
93 if let Some(ch) = (v.0).0 {
95 result.push(ch);
96 }
97
98 result += &(v.0).1;
100
101 if let Some(s) = v.1 {
104 result += &(".".to_owned() + &s);
105 }
106
107 result
108 })
109 % "a number"
110}
111
112pub fn array<T: 'static + Clone>(
114 begin: &'static str,
115 item: Parser<T>,
116 end: &'static str,
117) -> Parser<Vec<T>> {
118 seq_no_ws(begin) >> list(item.clone(), seq_no_ws(",")) << seq_no_ws(end)
119 % format!("An array of 0 or more {}(s)", item.expectation)
120}