dochy_json5/
jval.rs

1use std::rc::Rc;
2use linked_hash_map::LinkedHashMap;
3//use indexmap::IndexMap;
4//use linked_hash_map::LinkedHashMap;
5
6#[derive(Clone, Debug, PartialEq)]
7pub enum JVal{
8    Null(Span),
9    Undefined(Span),
10    Bool(bool, Span),
11    String(String, Span),
12    Int(i64, Span),
13    Double(f64, Span),
14    Array(Vec<JVal>, Span),
15    Map(LinkedHashMap<String, JVal>, Span)
16}
17
18impl JVal{
19    pub fn as_object(&self) -> Option<&LinkedHashMap<String, JVal>>{
20        return match self {
21            JVal::Map(map, _span) => { Some(map) }
22            _ => { None }
23        }
24    }
25
26    pub fn as_array(&self) -> Option<&Vec<JVal>>{
27        return match self{
28            JVal::Array(a, _) => { Some(a) },
29            _ =>{ None }
30        }
31    }
32
33    pub fn as_str(&self) -> Option<&str>{
34        return match self {
35            JVal::String(s, _span) => { Some(s) }
36            _ => { None }
37        }
38    }
39
40    pub fn as_num(&self) -> Option<f64>{
41        return match self{
42            //JVal::Int(i, _) =>{ Some(*i as f64) },
43            JVal::Double(d, _) =>{ Some(*d) },
44            _ =>{ None }
45        }
46    }
47
48    pub fn as_int(&self) -> Option<i64>{
49        return match self{
50            JVal::Int(i, _) =>{ Some(*i) },
51            _ =>{ None }
52        }
53    }
54
55    pub fn as_bool(&self) -> Option<bool>{
56        return match self{
57            JVal::Bool(b, _) =>{ Some(*b) }
58            _ =>{ None }
59        }
60    }
61
62    pub fn is_null(&self) -> bool{
63        return match self{
64            JVal::Null(_) => true,
65            _ => false,
66        }
67    }
68
69    pub fn is_undefined(&self) -> bool{
70        return match self{
71            JVal::Undefined(_) => true,
72            _ => false,
73        }
74    }
75
76    pub fn span(&self) -> &Span{
77        return match self{
78            JVal::Null(s) => s,
79            JVal::Undefined(s) => s,
80            JVal::Bool(_,s) => s,
81            JVal::String(_, s) => s,
82            JVal::Double(_, s) => s,
83            JVal::Int(_,s) => s,
84            JVal::Array(_, s) => s,
85            JVal::Map(_, s) => s,
86        }
87    }
88
89    pub fn slice(&self) -> &str{
90        self.span().slice()
91    }
92
93    ///くっそ重いので正常系で実行しないように注意
94    pub fn line_str(&self) -> String{
95        self.span().line_str()
96    }
97}
98
99#[derive(Clone, Debug, PartialEq)]
100pub struct Span{
101    pub start : usize,
102    pub end : usize,
103    pub text : Rc<String>,
104}
105
106impl Span{
107    pub fn line_num(&self) -> usize {
108        let input = self.text.as_str();
109        let mut pos = self.start;
110        if pos > input.len() {
111            panic!("position out of bounds");
112        }
113
114        // Position's pos is always a UTF-8 border.
115        let slice = unsafe { std::str::from_utf8_unchecked(&input.as_bytes()[..pos]) };
116        let mut chars = slice.chars().peekable();
117
118        let mut line_col = (1, 1);
119
120        while pos != 0 {
121            match chars.next() {
122                Some('\r') => {
123                    if let Some(&'\n') = chars.peek() {
124                        chars.next();
125
126                        if pos == 1 {
127                            pos -= 1;
128                        } else {
129                            pos -= 2;
130                        }
131
132                        line_col = (line_col.0 + 1, 1);
133                    } else {
134                        pos -= 1;
135                        line_col = (line_col.0, line_col.1 + 1);
136                    }
137                }
138                Some('\n') => {
139                    pos -= 1;
140                    line_col = (line_col.0 + 1, 1);
141                }
142                Some(c) => {
143                    pos -= c.len_utf8();
144                    line_col = (line_col.0, line_col.1 + 1);
145                }
146                None => unreachable!()
147            }
148        }
149
150        line_col.0
151    }
152
153    ///くっそ重いので正常系で実行しないように注意
154    pub fn line_str(&self) -> String{
155        self.line_num().to_string()
156    }
157
158    pub fn slice(&self) -> &str{
159        &self.text.as_str()[self.start..self.end]
160    }
161}
162
163//imp Display for Span{
164//    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165//        let (line, col) = self.line_col();
166//        write!(f, "({}, {})", line, col)
167//    }
168//
169//}