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
use std::path::Path;

use lexpr::Value;

use crate::{run_scilla_fmt, Contract, Error, Field, FieldList, Transition};

pub fn parse(contract_path: &Path) -> Result<Contract, Error> {
    let sexp = run_scilla_fmt(&contract_path).unwrap();
    parse_sexp(&sexp, contract_path)
}

pub fn parse_sexp(sexp: &str, contract_path: &Path) -> Result<Contract, Error> {
    let v = lexpr::from_str(sexp)?;
    let name = v["contr"][0]["cname"]["Ident"][0][1].to_string();
    let transitions = extract_transitions(&v["contr"][0]["ccomps"])?;
    let contract_params = parse_fields(&v["contr"][0]["cparams"][0])?;
    let contract_fields = extract_contract_fields(&v["contr"][0]["cfields"])?;
    Ok(Contract {
        path: contract_path.canonicalize()?,
        name,
        transitions,
        init_params: contract_params,
        fields: contract_fields,
    })
}

fn extract_contract_fields(cfields: &Value) -> Result<FieldList, Error> {
    let mut fields = vec![];
    for elem in cfields[0].list_iter().unwrap() {
        let field_name = elem[0]["SimpleLocal"][0].to_string();
        let field_type = elem[1][0].to_string();
        let field_type = match field_type.as_str() {
            "PrimType" => elem[1][1].to_string(),
            _ => elem[1].to_string(),
        };

        fields.push(Field {
            name: field_name,
            r#type: field_type,
        })
    }
    Ok(FieldList(fields))
}

fn extract_transitions(ccomps: &Value) -> Result<Vec<Transition>, Error> {
    let mut transitions = vec![];
    for elem in ccomps[0].list_iter().unwrap() {
        let transition_name = elem["comp_name"][0]["SimpleLocal"][0].to_string();
        transitions.push(Transition {
            name: transition_name,
            params: parse_fields(&elem["comp_params"][0])?,
        })
    }

    Ok(transitions)
}

fn parse_fields(cparams: &Value) -> Result<FieldList, Error> {
    let mut params = vec![];
    for elem in cparams.list_iter().unwrap() {
        let name = elem[0]["SimpleLocal"][0].to_string();
        let r#type = elem[1][1].to_string();
        params.push(Field { name, r#type })
    }

    Ok(FieldList(params))
}