Skip to main content

atmos/os_lib/
json.rs

1// src/json.rs - Lightweight JSON parser and serializer for AtmOS
2#![allow(dead_code)]
3
4extern crate alloc;
5use alloc::collections::BTreeMap;
6use alloc::string::String;
7use alloc::vec::Vec;
8use core::iter::Peekable;
9use core::str::Chars;
10
11#[derive(Debug, Clone, PartialEq)]
12pub enum JsonValue {
13    Null,
14    Bool(bool),
15    Number(f64),
16    String(String),
17    Array(Vec<JsonValue>),
18    Object(BTreeMap<String, JsonValue>),
19}
20
21pub fn parse(input: &str) -> Result<JsonValue, String> {
22    let mut chars = input.chars().peekable();
23    parse_value(&mut chars, 0)
24}
25
26pub use parse as parse_json;
27
28fn skip_whitespace(chars: &mut Peekable<Chars>) {
29    while let Some(&c) = chars.peek() {
30        if c.is_whitespace() {
31            chars.next();
32        } else {
33            break;
34        }
35    }
36}
37
38// `depth` はRustのネイティブ再帰(`parse_value`→`parse_array`/`parse_object`→
39// `parse_value`…の相互再帰)による呼出しの深さを追跡する。この処理系はブート時点の
40// 初期コアスタックがわずか64KB(`boot.S`の`(CoreID+1)*64KB`)しか無く、`structuredClone`
41// の深いネスト保護テストで一度実際にRustコールスタックオーバーフローによる無応答を
42// 起こしている(2026-07-18、walkthrough.md参照)。同じ危険性が`JSON.parse`(この関数の
43// JS側入口)にも及ぶため、同じ閾値30で打ち切る。
44fn parse_value(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
45    if depth > 30 {
46        return Err(String::from("Maximum nesting depth exceeded"));
47    }
48    skip_whitespace(chars);
49    match chars.peek() {
50        Some(&'n') => parse_null(chars),
51        Some(&'t') | Some(&'f') => parse_bool(chars),
52        Some(&'"') => parse_string(chars).map(JsonValue::String),
53        Some(&'[') => parse_array(chars, depth),
54        Some(&'{') => parse_object(chars, depth),
55        Some(&c) if c == '-' || c.is_ascii_digit() => parse_number(chars),
56        Some(c) => Err(alloc::format!("Unexpected character: {}", c)),
57        None => Err(String::from("Unexpected end of input")),
58    }
59}
60
61fn parse_null(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
62    let expected = "null";
63    for ec in expected.chars() {
64        if chars.next() != Some(ec) {
65            return Err(String::from("Expected null"));
66        }
67    }
68    Ok(JsonValue::Null)
69}
70
71fn parse_bool(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
72    let is_true = chars.peek() == Some(&'t');
73    let expected = if is_true { "true" } else { "false" };
74    for ec in expected.chars() {
75        if chars.next() != Some(ec) {
76            return Err(String::from("Expected bool"));
77        }
78    }
79    Ok(JsonValue::Bool(is_true))
80}
81
82fn parse_string(chars: &mut Peekable<Chars>) -> Result<String, String> {
83    chars.next(); // consume '"'
84    let mut s = String::new();
85    while let Some(&c) = chars.peek() {
86        if c == '"' {
87            chars.next();
88            return Ok(s);
89        } else if c == '\\' {
90            chars.next();
91            if let Some(ec) = chars.next() {
92                match ec {
93                    '"' => s.push('"'),
94                    '\\' => s.push('\\'),
95                    '/' => s.push('/'),
96                    'b' => s.push('\x08'),
97                    'f' => s.push('\x0C'),
98                    'n' => s.push('\n'),
99                    'r' => s.push('\r'),
100                    't' => s.push('\t'),
101                    _ => s.push(ec), // simplisitc fallback
102                }
103            } else {
104                return Err(String::from("Unexpected end of input in escape sequence"));
105            }
106        } else {
107            s.push(c);
108            chars.next();
109        }
110    }
111    Err(String::from("Unterminated string"))
112}
113
114fn parse_number(chars: &mut Peekable<Chars>) -> Result<JsonValue, String> {
115    let mut buf = [0u8; 64];
116    let mut len = 0usize;
117    while let Some(&c) = chars.peek() {
118        if c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E' || c.is_ascii_digit() {
119            if len < buf.len() && c.is_ascii() {
120                buf[len] = c as u8;
121                len += 1;
122            }
123            chars.next();
124        } else {
125            break;
126        }
127    }
128    if let Ok(s) = core::str::from_utf8(&buf[..len]) {
129        match s.parse::<f64>() {
130            Ok(n) => Ok(JsonValue::Number(n)),
131            Err(_) => Err(alloc::format!("Invalid number: {}", s)),
132        }
133    } else {
134        Err(String::from("Invalid UTF-8 in number"))
135    }
136}
137
138fn parse_array(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
139    chars.next(); // consume '['
140    let mut arr = Vec::new();
141    skip_whitespace(chars);
142    if chars.peek() == Some(&']') {
143        chars.next();
144        return Ok(JsonValue::Array(arr));
145    }
146    loop {
147        arr.push(parse_value(chars, depth + 1)?);
148        skip_whitespace(chars);
149        match chars.next() {
150            Some(',') => continue,
151            Some(']') => break,
152            _ => return Err(String::from("Expected ',' or ']' in array")),
153        }
154    }
155    Ok(JsonValue::Array(arr))
156}
157
158fn parse_object(chars: &mut Peekable<Chars>, depth: usize) -> Result<JsonValue, String> {
159    chars.next(); // consume '{'
160    let mut obj = BTreeMap::new();
161    skip_whitespace(chars);
162    if chars.peek() == Some(&'}') {
163        chars.next();
164        return Ok(JsonValue::Object(obj));
165    }
166    loop {
167        skip_whitespace(chars);
168        if chars.peek() != Some(&'"') {
169            return Err(String::from("Expected string key in object"));
170        }
171        let key = parse_string(chars)?;
172        skip_whitespace(chars);
173        if chars.next() != Some(':') {
174            return Err(String::from("Expected ':' after key"));
175        }
176        let val = parse_value(chars, depth + 1)?;
177        obj.insert(key, val);
178        skip_whitespace(chars);
179        match chars.next() {
180            Some(',') => continue,
181            Some('}') => break,
182            _ => return Err(String::from("Expected ',' or '}' in object")),
183        }
184    }
185    Ok(JsonValue::Object(obj))
186}
187
188pub fn to_string(value: &JsonValue) -> String {
189    let mut out = String::new();
190    stringify_to(value, &mut out);
191    out
192}
193
194pub fn stringify_to(value: &JsonValue, out: &mut String) {
195    match value {
196        JsonValue::Null => out.push_str("null"),
197        JsonValue::Bool(true) => out.push_str("true"),
198        JsonValue::Bool(false) => out.push_str("false"),
199        JsonValue::Number(n) => {
200            use core::fmt::Write;
201            let _ = write!(out, "{}", n);
202        }
203        JsonValue::String(s) => {
204            out.push('"');
205            for c in s.chars() {
206                match c {
207                    '"' => out.push_str("\\\""),
208                    '\\' => out.push_str("\\\\"),
209                    '\n' => out.push_str("\\n"),
210                    '\r' => out.push_str("\\r"),
211                    '\t' => out.push_str("\\t"),
212                    c => out.push(c),
213                }
214            }
215            out.push('"');
216        }
217        JsonValue::Array(arr) => {
218            out.push('[');
219            for (i, v) in arr.iter().enumerate() {
220                if i > 0 {
221                    out.push_str(", ");
222                }
223                stringify_to(v, out);
224            }
225            out.push(']');
226        }
227        JsonValue::Object(obj) => {
228            out.push('{');
229            let mut first = true;
230            for (k, v) in obj.iter() {
231                if !first {
232                    out.push_str(", ");
233                }
234                first = false;
235                out.push('"');
236                out.push_str(k);
237                out.push_str("\": ");
238                stringify_to(v, out);
239            }
240            out.push('}');
241        }
242    }
243}