summaryrefslogtreecommitdiff
path: root/chomp-bench/src/json/lalr.lalrpop
blob: b5a8401592eafcc474cc8446e11e616e407be895 (plain)
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
use super::{decode_pair, Value};

use std::{collections::HashMap, convert::TryInto, str::FromStr};

grammar;

pub Value: Value = {
    "null" => Value::Null,
    "true" => Value::Bool(true),
    "false" => Value::Bool(false),
    Num => Value::Number(<>),
    Str => Value::String(<>),
    "[" "]" => Value::Array(Vec::new()),
    "[" <v : (<Value> ",")*> <e: Value> "]" => {
        let mut v = v;
        v.push(e);
        Value::Array(v)
    },
    "{" "}" => Value::Object(HashMap::new()),
    "{" <v : (<Str> ":" <Value> ",")*> <e : (<Str> ":" <Value>)> "}" => {
        let mut v = v;
        v.push(e);
        Value::Object(v.into_iter().collect())
    },
};

pub Num: f64 = r"-?(0|[1-9][0-9]*)(\.[0-9]*)?([eE][-+]?[0-9]+)?" => f64::from_str(<>).unwrap();

pub Str: String = r#""([^\\"]|\\.)*""# => {
    let mut out = String::new();
    let mut iter = <>.chars();
    iter.next();
    iter.next_back();
    while let Some(c) = iter.next() {
        let c = match c {
            c @ '\x20'..='\x21' | c @ '\x23'..='\x5B' | c @ '\x5D'..='\u{10FFFF}' => c,
            '\\' => match iter.next().unwrap() {
                '\"' => '\x22',
                '\\' => '\x5C',
                '/' => '\x2F',
                'b' => '\x08',
                'f' => '\x0C',
                'n' => '\x0A',
                'r' => '\x0D',
                't' => '\x09',
                'u' => {
                    let v = iter.by_ref().take(4).collect::<String>();
                    assert_eq!(v.len(), 4);
                    let v = u16::from_str_radix(&v, 16).unwrap();
                    let codepoint = if (0xD800..=0xDFFF).contains(&v) {
                        let skipped = iter.by_ref().take(2).collect::<String>();
                        assert_eq!(skipped, "\\u");
                        let o = iter.by_ref().take(4).collect::<String>();
                        assert_eq!(o.len(), 4);
                        let o = u16::from_str_radix(&o, 16).unwrap();
                        decode_pair(v, o)
                    } else {
                        u32::from(v)
                    };
                    codepoint.try_into().unwrap()
                }
                c => panic!("bad escape sequence {}", c),
            }
            c => panic!("invalid character {}", c),
        };
        out.push(c);
    }
    out
};