paralegal_compiler/common/
ast.rs

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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// definitions are controller-specific by default, but can be specified to be anywhere in the application
// usually, controller-specific is what you would want
// I added "Everywhere" support for the websubmit deletion policy, which reasons about all sensitive types that are stored anywhere in the application
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DefinitionScope {
    Ctrler,
    Everywhere,
}

#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Definition {
    // quantifier is everywhere "all" bc definitions are over *each* var that satisifes condition
    pub variable: Variable,
    pub scope: DefinitionScope,
    pub declaration: VariableIntro,
    // filter.is_none() iff this is a lifted definition, i.e. not a definition originally but one
    // we derived through optimizations
    pub filter: Option<ASTNode>,
    // if this is a lifted definition, was it lifted from a ForEach or ThereIs clause?
    pub lifted_from: Option<OgClauseIntroType>,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VariableIntro {
    pub variable: Variable,
    pub intro: VariableIntroType,
}

// AST data
#[derive(Clone, Debug, PartialEq, Eq, Hash, strum_macros::Display)]
pub enum VariableIntroType {
    Roots,
    AllNodes,
    Variable,
    VariableMarked { marker: Marker, on_type: bool },
    VariableSourceOf(Variable),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Relation {
    Binary {
        left: Variable,
        right: Variable,
        typ: Binop,
    },
    Negation(Box<Relation>),
    IsMarked(Variable, Marker),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Binop {
    Data,
    Control,
    Both,
    AssociatedCallSite,
}

pub type Variable = String;
pub type Marker = String;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Operator {
    And,
    Or,
}

impl From<&str> for Operator {
    fn from(value: &str) -> Self {
        match value {
            "and" => Operator::And,
            "or" => Operator::Or,
            _ => unimplemented!("invalid operator: valid options are 1) and 2) or"),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct TwoNodeObligation {
    pub op: Operator,
    pub src: ASTNode,
    pub sink: ASTNode,
}

// Only used for optimization logic
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum OgClauseIntroType {
    Conditional,
    ForEach,
    ThereIs,
}

impl From<&ClauseIntro> for OgClauseIntroType {
    fn from(value: &ClauseIntro) -> Self {
        match value {
            ClauseIntro::ForEach(_) => OgClauseIntroType::ForEach,
            ClauseIntro::ThereIs(_) => OgClauseIntroType::ThereIs,
            ClauseIntro::Conditional(_) => OgClauseIntroType::Conditional,
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ClauseIntro {
    ForEach(VariableIntro),
    ThereIs(VariableIntro),
    Conditional(Relation),
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Clause {
    pub intro: ClauseIntro,
    pub body: ASTNode,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum ASTNode {
    Clause(Box<Clause>),
    OnlyVia(
        VariableIntro,
        (Option<Operator>, Vec<VariableIntro>),
        (Option<Operator>, Vec<VariableIntro>),
    ),
    JoinedNodes(Box<TwoNodeObligation>),
    Relation(Relation),
}