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
use std::str::from_utf8;
use handle::Handle;
pub fn digit(b: u8) -> bool {
b <= b'9' && b >= b'0'
}
pub fn sign(b: u8) -> bool { b == b'+' || b == b'-' }
pub fn valid_name_start(s: &[u8]) -> bool {
let a = s[0];
if digit(a) || a == b':' || a == b'#' || a == b'\'' {
return false;
}
if s.len() == 1 { return true; }
if digit(s[1]) && (sign(a) || a == b'.') {
return false;
}
true
}
pub fn valid_name(s: &[u8]) -> bool {
if !valid_name_start(s) {
return false;
}
if s.len() > 1 && slash_index(s).is_some() {
return false;
}
true
}
pub fn slash_index(s: &[u8]) -> Option<usize> {
for i in 0..s.len() {
if s[i] == b'/' {
return Some(i);
}
}
None
}
pub fn prefix_slash(s: &[u8]) -> Option<usize> {
if s.len() == 1 {
return None;
} else {
slash_index(s)
}
}
pub fn parse_symbol_keyword(s: &[u8], default: Option<&[u8]>) -> Result<Handle, String> {
let solidus = if let Some(solidus) = prefix_slash(s) {
let prefix_len = solidus - if s[0] == b':' { 1 } else { 0 };
let name_len = s.len() - solidus - 1;
if prefix_len == 0 || name_len == 0 {
return Err(format!("Can't have a symbol/keyword with an empty prefix or name ({})",
from_utf8(s).unwrap()))
}
if !valid_name(&s[(solidus + 1)..]) {
return Err(format!("Name component (after /) of symbol/keyword is invalid ({})",
from_utf8(s).unwrap()))
}
solidus
} else { 0 };
if s[0] == b':' {
if !valid_name_start(&s[1..]) {
return Err(format!("Keyword has invalid starting characters ({})",
from_utf8(s).unwrap()))
}
use keyword;
if let Some(d) = default {
if solidus == 0 {
return Ok(keyword::new_prefix_name(d, &s[1..]).handle())
}
if solidus == 2 && s[1] == b'_' {
return Ok(keyword::new_from_name(&s[3..]).handle())
}
}
return Ok(keyword::new(s, solidus as u32).handle())
} else {
if s.len() < 6 {
if s == b"nil" { return Ok(Handle::nil()) }
if s == b"true" { return Ok(Handle::tru()) }
if s == b"false" { return Ok(Handle::fals()) }
}
if s.len() > 1 {
let after_sign = if sign(s[0]) { 1 } else { 0 };
if s[after_sign] == b'.' && after_sign + 1 < s.len() && digit(s[after_sign + 1]) {
return Err(format!("Not a valid token ({}). Floating point numbers must \
have a digit before the point, like 0.1 or +1.42.",
from_utf8(s).unwrap()))
}
}
use symbol;
if let Some(d) = default {
if solidus == 0 {
return Ok(symbol::new_prefix_name(d, s).handle())
}
if solidus == 1 && s[0] == b'_' {
return Ok(symbol::new(&s[2..], 0).handle())
}
}
return Ok(symbol::new(s, solidus as u32).handle())
}
}