jsode/
core.rs

1use std::{collections::HashMap, fmt::Display, hash::Hash};
2
3use jsode_macro::reflection;
4
5use crate::{common::Arrice, error::JsonError, parser::JsonParser};
6
7#[derive(PartialEq, PartialOrd, Debug)]
8pub enum JsonType {
9    Ident,
10    // a string will start and end with symbol \' or \"
11    Str(Vec<StrType>),
12    // continuously numbers, end when reaching symbol space or comma
13    Num(NumType),
14    // true | false literal, end with comma
15    Bool(bool),
16    // null
17    Null,
18}
19
20impl JsonType {
21    pub const fn get_type_name(&self) -> &str {
22        match self {
23            Self::Bool(_) => "boolean",
24            Self::Ident => "ident",
25            Self::Num(num) => num.get_type_name(),
26            Self::Str(_) => "string",
27            Self::Null => "null",
28        }
29    }
30}
31
32#[derive(PartialEq, PartialOrd, Debug, Clone)]
33pub enum StrType {
34    Str(Span),
35    // \xXX (U+0000 through U+00FF)
36    Ascii(Span),
37    // \uXXXX (U+0000 through U+FFFF)
38    Unicode(Span),
39    // \X
40    Escape(Span),
41    // \'	Apostrophe	    U+0027
42    // \"	Quotation mark	U+0022
43    // \\	Reverse solidus	U+005C
44    // \b	Backspace	    U+0008
45    // \f	Form feed	    U+000C
46    // \n	Line feed	    U+000A
47    // \r	Carriage return	U+000D
48    // \t	Horizontal tab	U+0009
49    // \v	Vertical tab	U+000B
50    // \0	Null	        U+0000
51    Special(Span),
52}
53
54impl StrType {
55    pub const fn get_type_name(&self) -> &str {
56        match self {
57            Self::Ascii(_) => "ascii",
58            Self::Escape(_) => "escape",
59            Self::Special(_) => "special",
60            Self::Unicode(_) => "unicode",
61            Self::Str(_) => "normal str",
62        }
63    }
64}
65
66#[derive(PartialEq, PartialOrd, Debug, Clone)]
67pub enum NumType {
68    // 123
69    // -123
70    // 123e10
71    // 123e+10
72    // 123e-10
73    Integer(Integer),
74    // 123.456
75    // -123.456
76    // 12.3e456
77    // -12.3e-456
78    // .456
79    // 0.456e2
80    Decimal(Decimal),
81    // 0xdecaf
82    // -0xC0FFEE
83    Hex(Heximal),
84    // Infinity
85    Infinity(Span),
86    // NaN
87    NaN(Span),
88}
89
90impl NumType {
91    pub const fn get_type_name(&self) -> &str {
92        match self {
93            Self::Integer(_) => "integer",
94            Self::Decimal(_) => "decimal",
95            Self::Hex(_) => "hexadecimal",
96            Self::Infinity(_) => "infinity",
97            Self::NaN(_) => "NaN",
98        }
99    }
100}
101
102#[derive(PartialEq, PartialOrd, Debug, Clone)]
103pub enum Integer {
104    // given integer -123e-456
105    // 1: -123
106    // 2: -456 (exponent)
107    Positive(Span, Option<Span>),
108    Negative(Span, Option<Span>),
109}
110
111#[derive(PartialEq, PartialOrd, Debug, Clone)]
112pub enum Heximal {
113    // given hexa 0x2E
114    // 1: 0x
115    // 2: 2E
116    Positive(Span, Span),
117    Negative(Span, Span),
118}
119
120#[derive(PartialEq, PartialOrd, Debug, Clone)]
121pub enum Decimal {
122    // given decimal -123.456e-789
123    // 1: -123
124    // 2: 456 (fracment)
125    // 3: -789 (exponent)
126    Positive(Option<Span>, Option<Span>, Option<Span>),
127    Negative(Option<Span>, Option<Span>, Option<Span>),
128}
129
130impl From<Decimal> for NumType {
131    fn from(value: Decimal) -> Self {
132        NumType::Decimal(value)
133    }
134}
135
136impl From<Integer> for NumType {
137    fn from(value: Integer) -> Self {
138        NumType::Integer(value)
139    }
140}
141
142impl From<Heximal> for NumType {
143    fn from(value: Heximal) -> Self {
144        NumType::Hex(value)
145    }
146}
147
148#[derive(PartialEq, PartialOrd, Debug, Clone)]
149pub enum Sign {
150    Plus,
151    Minus,
152    None,
153}
154
155impl Sign {
156    pub const fn detect(sign: u8) -> Self {
157        match sign {
158            43 => Self::Plus,
159            45 => Self::Minus,
160            _ => Self::None,
161        }
162    }
163
164    #[rustfmt::skip]
165    pub const fn compute_start_pos(&self, start: usize) -> usize {
166        // given a number ?123 (? is '+' or '-')
167        // if number has a prefix, move the position backward
168        match self {
169            // +123
170            Self::Plus  => start - 1,
171            // -123
172            Self::Minus => start - 1,
173            // 123
174            _           => start,
175        }
176    }
177
178    pub const fn to_hexadecimal(&self, prefix: Span, suffix: Span) -> NumType {
179        match self {
180            Self::Plus => NumType::Hex(Heximal::Positive(prefix.expand_left(1), suffix)),
181            Self::Minus => NumType::Hex(Heximal::Negative(prefix.expand_left(1), suffix)),
182            _ => NumType::Hex(Heximal::Positive(prefix, suffix)),
183        }
184    }
185
186    pub const fn to_integer(&self, start: usize, end: usize, expo_span: Option<Span>) -> NumType {
187        match self {
188            Self::Plus => NumType::Integer(Integer::Positive(Span::new(start - 1, end), expo_span)),
189            Self::Minus => NumType::Integer(Integer::Negative(Span::new(start - 1, end), expo_span)),
190            _ => NumType::Integer(Integer::Positive(Span::new(start, end), expo_span)),
191        }
192    }
193
194    pub const fn to_decimal(&self, int_span: Option<Span>, frac_span: Option<Span>, expo_span: Option<Span>) -> NumType {
195        let new_int_span = if let Some(integer_span) = int_span { Some(integer_span.expand_left(1)) } else { None };
196        match self {
197            Self::Plus => NumType::Decimal(Decimal::Positive(new_int_span, frac_span, expo_span)),
198            Self::Minus => NumType::Decimal(Decimal::Negative(new_int_span, frac_span, expo_span)),
199            _ => NumType::Decimal(Decimal::Positive(new_int_span, frac_span, expo_span)),
200        }
201    }
202}
203
204impl StrType {
205    pub(crate) fn parse_str<'a>(&'a self, parser: &'a JsonParser<'a>) -> Result<&'a str> {
206        match self {
207            Self::Str(span) => Ok(parser.take_slice(Span::new(span.start, span.end))?),
208            Self::Ascii(span) => Ok(parser.take_slice(Span::new(span.start + 2, span.end))?),
209            Self::Unicode(span) => Ok(parser.take_slice(Span::new(span.start + 2, span.end))?),
210            Self::Escape(span) => Ok(parser.take_slice(Span::new(span.start + 1, span.end))?),
211            Self::Special(span) => {
212                let raw = parser.take_raw(span.clone());
213                let item = map_special_char(raw[0]);
214                Ok(item)
215            },
216        }
217    }
218}
219
220const fn map_special_char<'a>(c: u8) -> &'a str {
221    match c {
222        b'\'' => "\'",
223        b'\"' => "\"",
224        b'\\' => "\\",
225        b'b'  => "\u{08}",
226        b'f'  => "\u{0C}",
227        b'n'  => "\u{0A}",
228        b'r'  => "\u{0D}",
229        b't'  => "\u{09}",
230        b'v'  => "\u{0B}",
231        b'0'  => "\u{00}",
232        _ => "\u{00}",
233    }
234}
235
236#[derive(PartialEq, PartialOrd, Debug)]
237pub enum Punct {
238    DoubleQuote,
239    SingleQuote,
240    Comma      ,
241    Colon      ,
242    OpenSquare ,
243    CloseSquare,
244    OpenCurly  ,
245    CloseCurly ,
246    WhiteSpace ,
247    Plus       ,
248    Minus      ,
249}
250
251#[derive(Default, PartialEq, Eq, PartialOrd, Hash, Clone, Debug)]
252pub struct Span {
253    pub start: usize,
254    pub end: usize,
255    pub col: usize,
256    pub row: usize,
257}
258
259impl Span {
260    #[inline(always)]
261    pub const fn new(start: usize, end: usize) -> Self {
262        Self { start, end, col: 0, row: 0 }
263    }
264
265    #[inline(always)]
266    pub const fn with_counter(start: usize, counter: usize) -> Self {
267        Self { start, end: start + counter, col: 0, row: 0 }
268    }
269
270    #[inline(always)]
271    pub const fn gap(&self) -> usize {
272        self.end - self.start
273    }
274
275    #[inline]
276    pub const fn extend(&self, other: Span) -> Self {
277        Span::new(self.start, other.end)
278    }
279
280    #[inline(always)]
281    pub const fn collapse(mut self, size: usize) -> Self {
282        self.start += size;
283        self.end -= size;
284        self
285    }
286
287    #[inline(always)]
288    pub const fn shrink_left(mut self, size: usize) -> Self {
289        self.start += size;
290        self
291    }
292
293    #[inline(always)]
294    pub const fn shrink_right(mut self, size: usize) -> Self {
295        self.end -= size;
296        self
297    }
298
299    #[inline(always)]
300    pub const fn expand_left(mut self, size: usize) -> Self {
301        self.start -= size;
302        self
303    }
304
305    #[inline(always)]
306    pub const fn expand_right(mut self, size: usize) -> Self {
307        self.end += size;
308        self
309    }
310}
311
312#[derive(PartialEq, PartialOrd, Debug)]
313pub enum JsonToken {
314    Punct(Punct, Span),
315    Data(JsonType, Span),
316    Error(String, Span),
317    Comment(Span),
318}
319
320impl JsonToken {
321    #[inline(always)]
322    pub const fn ident(start: usize, end: usize) -> Self { Self::Data(JsonType::Ident, Span::new(start, end)) }
323    #[inline(always)]
324    pub const fn str(str_tokens: Vec<StrType>, start: usize, end: usize) -> Self { Self::Data(JsonType::Str(str_tokens), Span::new(start, end)) }
325    #[inline(always)]
326    pub const fn number(ty: NumType, start: usize, end: usize) -> Self { Self::Data(JsonType::Num(ty), Span::new(start, end)) }
327    #[inline(always)]
328    pub const fn boolean(value: bool, start: usize) -> Self { Self::Data(JsonType::Bool(value), Span::new(start, start + if value { 4 } else { 5 })) }
329    #[inline(always)]
330    pub const fn null(at: usize) -> Self { Self::Data(JsonType::Null, Span::new(at, at + 1)) }
331    #[inline(always)]
332    pub const fn open_curly(at: usize) -> Self { Self::Punct(Punct::OpenCurly, Span::new(at, at + 1)) }
333    #[inline(always)]
334    pub const fn close_curly(at: usize) -> Self { Self::Punct(Punct::CloseCurly, Span::new(at, at + 1)) }
335    #[inline(always)]
336    pub const fn open_square(at: usize) -> Self { Self::Punct(Punct::OpenSquare, Span::new(at, at + 1)) }
337    #[inline(always)]
338    pub const fn close_square(at: usize) -> Self { Self::Punct(Punct::CloseSquare, Span::new(at, at + 1)) }
339    #[inline(always)]
340    pub const fn single_quote(at: usize) -> Self { Self::Punct(Punct::SingleQuote, Span::new(at, at + 1)) }
341    #[inline(always)]
342    pub const fn double_quote(at: usize) -> Self { Self::Punct(Punct::DoubleQuote, Span::new(at, at + 1)) }
343    #[inline(always)]
344    pub const fn colon(at: usize) -> Self { Self::Punct(Punct::Colon, Span::new(at, at + 1)) }
345    #[inline(always)]
346    pub const fn comma(at: usize) -> Self { Self::Punct(Punct::Comma, Span::new(at, at + 1)) }
347    #[inline(always)]
348    pub const fn whitespace(at: usize, end: usize) -> Self { Self::Punct(Punct::WhiteSpace, Span::new(at, end)) }
349    #[inline(always)]
350    pub const fn plus(at: usize, end: usize) -> Self { Self::Punct(Punct::Plus, Span::new(at, end)) }
351    #[inline(always)]
352    pub const fn minus(at: usize, end: usize) -> Self { Self::Punct(Punct::Minus, Span::new(at, end)) }
353    #[inline(always)]
354    pub const fn comment(at: usize, end: usize) -> Self { Self::Comment(Span::new(at, end)) }
355
356    #[inline(always)]
357    pub fn error(msg: impl Into<String>, start: usize, end: usize) -> Self { Self::Error(msg.into(), Span::new(start, end)) }
358}
359
360impl From<JsonError> for JsonToken {
361    fn from(value: JsonError) -> Self {
362        JsonToken::Error(value.to_string(), value.span)
363    }
364}
365
366impl JsonToken {
367    pub fn parse_keyword(src: &str, start: usize, end: usize) -> JsonToken {
368        match &src[start..start + end] {
369            "true"      => JsonToken::boolean(true, start),
370            "false"     => JsonToken::boolean(false, start),
371            _           => JsonToken::ident(start, end),
372        }
373    }
374
375    pub const fn get_span(&self) -> Span {
376        match self {
377            Self::Data(_, span) => Span::new(span.start, span.end),
378            Self::Punct(_, span) => Span::new(span.start, span.end),
379            Self::Error(_, span) => Span::new(span.start, span.end),
380            Self::Comment(span) => Span::new(span.start, span.end),
381        }
382    }
383}
384
385#[derive(PartialEq, Debug)]
386pub struct JsonBlock {
387    pub(crate) level: usize,
388    pub(crate) value: JsonValue,
389}
390
391impl Default for JsonBlock {
392    fn default() -> Self {
393        Self { level: 0, value: JsonValue::Array(Vec::with_capacity(10), Span::default()) }
394    }
395}
396
397impl JsonBlock {
398    pub fn new(level: usize, value: JsonValue) -> Self {
399        Self { level, value }
400    }
401
402    #[inline]
403    pub(crate) fn parse_type<T: std::str::FromStr>(&self, parser: &JsonParser<'_>) -> Result<T>
404        where T::Err: Display {
405        let span = self.value.get_span();
406        let slice = parser.take_slice(span.clone())?;
407        slice.parse::<T>().map_err(|err| JsonError::custom(format!("{err}"), span))
408    }
409
410    #[inline]
411    pub(crate) fn parse_type_span<T: std::str::FromStr>(&self, parser: &JsonParser<'_>, span: Span) -> Result<T>
412        where T::Err: Display {
413        let slice = parser.take_slice(span.clone())?;
414        slice.parse::<T>().map_err(|err| JsonError::custom(format!("{err}"), span))
415    }
416
417    #[inline]
418    pub fn to_slice<'a>(&'a self, parser: &'a JsonParser<'a>) -> Result<&str> {
419        let span = self.value.get_span();
420        parser.take_slice(span)
421    }
422
423    pub const fn to_bytes<'a>(&'a self, parser: &'a JsonParser<'a>) -> &[u8] {
424        let span = self.value.get_span();
425        parser.take_raw(span)
426    }
427}
428
429#[derive(PartialEq, Debug)]
430pub struct JsonOutput<'out> {
431    pub(crate) parser: &'out JsonParser<'out>,
432    pub(crate) ast: Arrice<'out, JsonBlock>,
433}
434
435impl <'out> JsonOutput<'out> {
436    pub fn new(parser: &'out JsonParser<'out>, ast: impl Into<Arrice<'out, JsonBlock>>) -> Self {
437        Self { parser, ast: ast.into(), }
438    }
439
440    #[inline]
441    #[reflection]
442    pub(crate) fn parse_type<T: std::str::FromStr>(&self) -> Result<T>
443        where T::Err: Display {
444        self.ast.as_slice().first()
445            .map(|it| it.parse_type(self.parser))
446            .ok_or(JsonError::custom(format!("[{__fn_ident}] Soon EOF"), Span::default()))?
447    }
448
449    #[inline]
450    #[reflection]
451    pub(crate) fn parse_type_span<T: std::str::FromStr>(&self, span: Span) -> Result<T>
452        where T::Err: Display {
453        self.ast.as_slice().first()
454            .map(|it| it.parse_type_span(self.parser, span))
455            .ok_or(JsonError::custom(format!("[{__fn_ident}] Soon EOF"), Span::default()))?
456    }
457
458    #[inline]
459    #[reflection]
460    pub fn to_slice(&self) -> Result<&str> {
461        self.ast.as_slice().first()
462            .map(|it| it.to_slice(self.parser))
463            .ok_or(JsonError::custom(format!("[{__fn_ident}] Soon EOF"), Span::default()))?
464    }
465
466    #[inline]
467    pub fn to_slice_span(&self, span: Span) -> Result<&str> {
468        self.parser.take_slice(span)
469    }
470
471    pub fn to_bytes(&self) -> Result<&[u8]> {
472        self.ast.as_slice().first()
473            .map(|it| Ok(it.to_bytes(self.parser)))
474            .ok_or(JsonError::custom("msg", Span::default()))?
475    }
476}
477
478#[derive(PartialEq, Debug)]
479pub enum JsonValue {
480    Object(HashMap<usize,usize>, Span),
481    Array(Vec<usize>, Span),
482    // given prop `year: 2024`
483    // JsonType - type of value (Number in this example)
484    // Span - span of value (span of `2024` in this example)
485    // Span - span of whole property
486    Prop(JsonType, Span, Span),
487    Value(JsonType, Span),
488}
489
490impl JsonValue {
491    #[inline]
492    pub const fn get_span(&self) -> Span {
493        match self {
494            Self::Object(_, span) => Span::new(span.start, span.end),
495            Self::Array(_, span) => Span::new(span.start, span.end),
496            Self::Prop(_, span, _) => Span::new(span.start, span.end),
497            Self::Value(_, span) => Span::new(span.start, span.end),
498        }
499    }
500
501    #[inline(always)]
502    pub const fn get_type_name(&self) -> &str {
503        match self {
504            Self::Object(_,_) => "object",
505            Self::Array(_,_) => "array",
506            Self::Prop(data_ty,_,_) => data_ty.get_type_name(),
507            Self::Value(data_ty, _) => data_ty.get_type_name()
508        }
509    }
510}
511
512pub type Result<T> = core::result::Result<T, JsonError>;