Skip to main content

rib/
variable_id.rs

1// Copyright 2024-2025 Golem Cloud
2//
3// Licensed under the Golem Source License v1.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://license.golem.cloud/LICENSE
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use serde::{Deserialize, Serialize};
16use std::fmt::Display;
17
18#[derive(Hash, Eq, Debug, Clone, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
19pub enum VariableId {
20    Global(String),
21    Local(String, Option<Id>),
22    MatchIdentifier(MatchIdentifier),
23    ListComprehension(ListComprehensionIdentifier),
24    ListReduce(ListAggregationIdentifier),
25}
26
27impl VariableId {
28    pub fn as_instance_variable(&self) -> VariableId {
29        let variable_string = match self {
30            VariableId::Global(name) => name.clone(),
31            VariableId::Local(name, identifier) => {
32                if let Some(id) = identifier {
33                    format!("{}-{}", name, id.0)
34                } else {
35                    name.clone()
36                }
37            }
38            VariableId::MatchIdentifier(m) => format!("{}-{}", m.name, m.match_arm_index),
39            VariableId::ListComprehension(l) => l.name.clone(),
40            VariableId::ListReduce(r) => r.name.clone(),
41        };
42
43        VariableId::global(format!("__instance_{variable_string}"))
44    }
45    pub fn list_comprehension_identifier(name: impl AsRef<str>) -> VariableId {
46        VariableId::ListComprehension(ListComprehensionIdentifier {
47            name: name.as_ref().to_string(),
48        })
49    }
50
51    pub fn list_reduce_identifier(name: impl AsRef<str>) -> VariableId {
52        VariableId::ListReduce(ListAggregationIdentifier {
53            name: name.as_ref().to_string(),
54        })
55    }
56
57    pub fn match_identifier(name: String, match_arm_index: usize) -> VariableId {
58        VariableId::MatchIdentifier(MatchIdentifier {
59            name,
60            match_arm_index,
61        })
62    }
63
64    pub fn name(&self) -> String {
65        match self {
66            VariableId::Global(name) => name.clone(),
67            VariableId::Local(name, _) => name.clone(),
68            VariableId::MatchIdentifier(m) => m.name.clone(),
69            VariableId::ListComprehension(l) => l.name.clone(),
70            VariableId::ListReduce(r) => r.name.clone(),
71        }
72    }
73
74    pub fn is_global(&self) -> bool {
75        match self {
76            VariableId::Global(_) => true,
77            VariableId::Local(_, _) => false,
78            VariableId::MatchIdentifier(_) => false,
79            VariableId::ListComprehension(_) => false,
80            VariableId::ListReduce(_) => false,
81        }
82    }
83
84    pub fn is_local(&self) -> bool {
85        match self {
86            VariableId::Global(_) => false,
87            VariableId::Local(_, _) => true,
88            VariableId::MatchIdentifier(_) => false,
89            VariableId::ListComprehension(_) => false,
90            VariableId::ListReduce(_) => false,
91        }
92    }
93
94    pub fn is_match_binding(&self) -> bool {
95        match self {
96            VariableId::Global(_) => false,
97            VariableId::Local(_, _) => false,
98            VariableId::MatchIdentifier(_) => true,
99            VariableId::ListComprehension(_) => false,
100            VariableId::ListReduce(_) => false,
101        }
102    }
103
104    // Default variable_id could global, but as soon as type inference
105    // identifies them to be local it gets converted to a local with an id
106    pub fn global(variable_name: String) -> VariableId {
107        VariableId::Global(variable_name)
108    }
109
110    pub fn local(variable_name: &str, id: u32) -> VariableId {
111        VariableId::Local(variable_name.to_string(), Some(Id(id)))
112    }
113
114    // A local variable can be directly formed during parsing itself.
115    // For example: all identifiers in the LHS of a pattern-match-arm
116    // don't have a local definition of the variable, yet they are considered to be local
117    pub fn local_with_no_id(name: &str) -> VariableId {
118        VariableId::Local(name.to_string(), None)
119    }
120
121    pub fn increment_local_variable_id(&mut self) -> VariableId {
122        match self {
123            VariableId::Global(name) => VariableId::Local(name.clone(), Some(Id(0))),
124            VariableId::Local(name, id) => {
125                let new_id = id.clone().map_or(Some(Id(0)), |x| Some(Id(x.0 + 1)));
126                *id = new_id.clone();
127                VariableId::Local(name.to_string(), new_id)
128            }
129            VariableId::MatchIdentifier(m) => VariableId::MatchIdentifier(m.clone()),
130            VariableId::ListComprehension(l) => VariableId::ListComprehension(l.clone()),
131            VariableId::ListReduce(l) => VariableId::ListReduce(l.clone()),
132        }
133    }
134}
135
136#[derive(Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
137pub struct ListComprehensionIdentifier {
138    pub name: String,
139}
140
141#[derive(Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
142pub struct ListAggregationIdentifier {
143    pub name: String,
144}
145
146#[derive(Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
147pub struct MatchIdentifier {
148    pub name: String,
149    pub match_arm_index: usize, // Every match arm across the program is identified by a non-sharing index value. Within a match arm the identifier names cannot be reused
150}
151
152impl MatchIdentifier {
153    pub fn new(name: String, match_arm_index: usize) -> MatchIdentifier {
154        MatchIdentifier {
155            name,
156            match_arm_index,
157        }
158    }
159}
160
161impl Display for VariableId {
162    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163        match self {
164            VariableId::Global(name) => write!(f, "{name}"),
165            VariableId::Local(name, _) => write!(f, "{name}"),
166            VariableId::MatchIdentifier(m) => write!(f, "{}", m.name),
167            VariableId::ListComprehension(l) => write!(f, "{}", l.name),
168            VariableId::ListReduce(r) => write!(f, "{}", r.name),
169        }
170    }
171}
172#[derive(Hash, Eq, Debug, Clone, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
173pub struct Id(pub(crate) u32);