1use std::rc::Rc;
2use linked_hash_map::LinkedHashMap;
3#[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::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 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 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 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