File: json.rs

package info (click to toggle)
rust-scanlex 0.1.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 144 kB
  • sloc: makefile: 4
file content (92 lines) | stat: -rw-r--r-- 2,464 bytes parent folder | download
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
// A Simple, toy JSON parser.
// Remember there are Crates for This
extern crate scanlex;
use scanlex::{Scanner,Token,ScanError};

use std::collections::HashMap;

type JsonArray = Vec<Box<Value>>;
type JsonObject = HashMap<String,Box<Value>>;

#[derive(Debug, Clone, PartialEq)]
pub enum Value {
   Str(String),
   Num(f64),
   Bool(bool),
   Arr(JsonArray),
   Obj(JsonObject),
   Null
}

fn scan_json(scan: &mut Scanner) -> Result<Value,ScanError> {
    use Value::*;
    match scan.get() {
        Token::Str(s) => Ok(Str(s)),
        Token::Num(x) => Ok(Num(x)),
        Token::Int(n) => Ok(Num(n as f64)),
        Token::End => Err(scan.scan_error("unexpected end of input",None)),
        Token::Error(e) => Err(e),
        Token::Iden(s) =>
            if s == "null"    {Ok(Null)}
            else if s == "true" {Ok(Bool(true))}
            else if s == "false" {Ok(Bool(false))}
            else {Err(scan.scan_error(&format!("unknown identifier '{}'",s),None))},
        Token::Char(c) =>
            if c == '[' {
                let mut ja = Vec::new();
                let mut ch = c;
                while ch != ']' {
                    let o = scan_json(scan)?;
                    ch = scan.get_ch_matching(&[',',']'])?;
                    ja.push(Box::new(o));
                }
                Ok(Arr(ja))
            } else
            if c == '{' {
                let mut jo = HashMap::new();
                let mut ch = c;
                while ch != '}' {
                    let key = scan.get_string()?;
                    scan.get_ch_matching(&[':'])?;
                    let o = scan_json(scan)?;
                    ch = scan.get_ch_matching(&[',','}'])?;
                    jo.insert(key,Box::new(o));
                }
                Ok(Obj(jo))
            } else {
                Err(scan.scan_error(&format!("bad char '{}'",c),None))
            }
    }
}

fn parse_json(txt: &str) -> Value {
    let mut scan = Scanner::new(txt);
    scan_json(&mut scan).expect("bad json")
}

use Value::*;

#[test]
fn array() {
	let s = parse_json("[10,20]");
    assert_eq!(s, Arr(vec![Box::new(Num(10.0)),Box::new(Num(20.0))]));
}


#[test]
fn array2() {
	let s = parse_json("[null,true]");
    assert_eq!(s, Arr(vec![Box::new(Null),Box::new(Bool(true))]));
}

#[test]
fn map() {
	let s = parse_json("{'bonzo':10}");
    let mut m = HashMap::new();
    m.insert("bonzo".to_string(),Box::new(Num(10.0)));
	assert_eq!(s, Obj(m));
}