Variable handling methods
(&mut self, name: Token<'gc>, can_assign: bool)
| 1619 | |
| 1620 | // Variable handling methods |
| 1621 | fn named_variable(&mut self, name: Token<'gc>, can_assign: bool) -> Result<(), VmError> { |
| 1622 | let (get_op, set_op) = |
| 1623 | if let Some((pos, depth, mutability)) = self.resolve_local(name.lexeme) { |
| 1624 | if depth == UNINITIALIZED_LOCAL_DEPTH { |
| 1625 | self.error_at(name, "Can't read local variable in its own initializer."); |
| 1626 | } |
| 1627 | |
| 1628 | if can_assign && mutability == Mutability::Immutable { |
| 1629 | self.error_at(name, "Cannot assign to constant variable."); |
| 1630 | } |
| 1631 | (OpCode::GetLocal(pos), OpCode::SetLocal(pos)) |
| 1632 | } else if let Some((pos, _, mutability)) = self |
| 1633 | .resolve_upvalue(name.lexeme) |
| 1634 | .inspect_err(|err| self.error_at(name, err)) |
| 1635 | .ok() |
| 1636 | .flatten() |
| 1637 | { |
| 1638 | if can_assign && mutability == Mutability::Immutable { |
| 1639 | self.error_at(name, "Cannot assign to constant variable."); |
| 1640 | } |
| 1641 | (OpCode::GetUpvalue(pos), OpCode::SetUpvalue(pos)) |
| 1642 | } else { |
| 1643 | if can_assign && self.const_globals.contains(name.lexeme) { |
| 1644 | self.error_at(name, "Cannot assign to constant variable."); |
| 1645 | } |
| 1646 | let pos = self.identifier_constant(name.lexeme) as u8; |
| 1647 | (OpCode::GetGlobal(pos), OpCode::SetGlobal(pos)) |
| 1648 | }; |
| 1649 | |
| 1650 | if can_assign { |
| 1651 | self.emit(set_op); |
| 1652 | } else { |
| 1653 | self.emit(get_op); |
| 1654 | } |
| 1655 | Ok(()) |
| 1656 | } |
| 1657 | |
| 1658 | // Resolve a local variable by name, return its index and depth. |
| 1659 | fn resolve_local(&mut self, name: &str) -> Option<(u8, isize, Mutability)> { |
no test coverage detected