Prepares global variables injected from outside of the compiled program. Pre-defined scalar globals are initialized to their default values (0 for numeric types, empty string for text). Pre-defined array globals are allocated with all elements set to their default values. The compiled program may read or write any of these globals. After execution, use `Vm::get_global*` methods to query the va
(
ctx: &mut Context,
symtable: &mut GlobalSymtable,
global_defs: &[GlobalDef],
)
| 1245 | /// After execution, use `Vm::get_global*` methods to query the values of these globals (and |
| 1246 | /// any globals declared via `DIM SHARED` in the program itself). |
| 1247 | pub(super) fn prepare_globals( |
| 1248 | ctx: &mut Context, |
| 1249 | symtable: &mut GlobalSymtable, |
| 1250 | global_defs: &[GlobalDef], |
| 1251 | ) -> Result<()> { |
| 1252 | let preamble_pos = LineCol { line: 0, col: 0 }; |
| 1253 | |
| 1254 | // Register all global defs in the symbol table and collect array globals for the preamble. |
| 1255 | let mut max_ndims: u8 = 0; |
| 1256 | let mut array_globals: Vec<(Register, &GlobalDef)> = vec![]; |
| 1257 | for def in global_defs { |
| 1258 | let key = SymbolKey::from(&def.name); |
| 1259 | match &def.kind { |
| 1260 | GlobalDefKind::Array { subtype, dimensions } => { |
| 1261 | let ndims = |
| 1262 | u8::try_from(dimensions.len()).expect("Array must have at most 255 dimensions"); |
| 1263 | let info = syms::ArrayInfo { subtype: *subtype, ndims: usize::from(ndims) }; |
| 1264 | let reg = symtable |
| 1265 | .put_global(key, SymbolPrototype::Array(info)) |
| 1266 | .map_err(|e| Error::from_syms(e, preamble_pos))?; |
| 1267 | max_ndims = max(max_ndims, ndims); |
| 1268 | array_globals.push((reg, def)); |
| 1269 | } |
| 1270 | |
| 1271 | GlobalDefKind::Scalar { etype, initial_value } => { |
| 1272 | let reg = symtable |
| 1273 | .put_global(key, SymbolPrototype::Scalar(*etype)) |
| 1274 | .map_err(|e| Error::from_syms(e, preamble_pos))?; |
| 1275 | match initial_value { |
| 1276 | Some(datum) => { |
| 1277 | if datum.etype() != *etype { |
| 1278 | return Err(Error::TypeMismatch(preamble_pos, datum.etype(), *etype)); |
| 1279 | } |
| 1280 | ctx.codegen.emit_value(reg, datum.clone(), preamble_pos)?; |
| 1281 | } |
| 1282 | None => ctx.codegen.emit_default(reg, *etype, preamble_pos), |
| 1283 | } |
| 1284 | } |
| 1285 | } |
| 1286 | } |
| 1287 | |
| 1288 | // Emit the array initialization preamble, but only if any arrays were defined. |
| 1289 | // |
| 1290 | // We use a short-lived `ENTER/LEAVE` scope to borrow local registers for the dimension |
| 1291 | // temporaries without permanently consuming global register slots. |
| 1292 | if array_globals.is_empty() { |
| 1293 | // `compile` starts by popping an EOF, so make sure there is one. |
| 1294 | ctx.codegen.emit(bytecode::make_eof(), preamble_pos); |
| 1295 | return Ok(()); |
| 1296 | } |
| 1297 | for (reg, def) in array_globals { |
| 1298 | let GlobalDefKind::Array { subtype, dimensions } = &def.kind else { |
| 1299 | unreachable!("array_globals only contains array defs per the loop above") |
| 1300 | }; |
| 1301 | |
| 1302 | let ndims = u8::try_from(dimensions.len()).unwrap(); |
| 1303 | for (i, &dim) in dimensions.iter().enumerate() { |
| 1304 | let dim_u16 = |
no test coverage detected