|
| 1 | +# Environment Module Documentation |
| 2 | + |
| 3 | +The environment module provides a lexically-scoped symbol table implementation for the R-Python language. It supports both variable and function bindings, with proper scope chain resolution. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The module implements two main structures: |
| 8 | +- `Scope<A>`: Represents a single scope with its variable and function bindings |
| 9 | +- `Environment<A>`: Manages a stack of scopes with a global scope at the bottom |
| 10 | + |
| 11 | +The generic parameter `A` allows the environment to be used for different purposes: |
| 12 | +- Type checking: `Environment<Type>` |
| 13 | +- Interpretation: `Environment<Expression>` |
| 14 | + |
| 15 | +## Structures |
| 16 | + |
| 17 | +### Scope<A> |
| 18 | + |
| 19 | +A single scope containing mappings for variables and functions. |
| 20 | + |
| 21 | +```rust |
| 22 | +pub struct Scope<A> { |
| 23 | + pub variables: HashMap<Name, A>, |
| 24 | + pub functions: HashMap<Name, Function>, |
| 25 | +} |
| 26 | +``` |
| 27 | + |
| 28 | +#### Methods |
| 29 | + |
| 30 | +- `new() -> Scope<A>`: Creates a new empty scope |
| 31 | +- `map_variable(var: Name, value: A)`: Binds a variable in the current scope |
| 32 | +- `map_function(function: Function)`: Binds a function in the current scope |
| 33 | +- `lookup_var(var: &Name) -> Option<&A>`: Looks up a variable in this scope |
| 34 | +- `lookup_function(name: &Name) -> Option<&Function>`: Looks up a function in this scope |
| 35 | + |
| 36 | +### Environment<A> |
| 37 | + |
| 38 | +Manages a stack of scopes with lexical scoping rules. |
| 39 | + |
| 40 | +```rust |
| 41 | +pub struct Environment<A> { |
| 42 | + pub globals: Scope<A>, |
| 43 | + pub stack: LinkedList<Scope<A>>, |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +#### Methods |
| 48 | + |
| 49 | +- `new() -> Environment<A>`: Creates a new environment with empty global scope |
| 50 | +- `map_variable(var: Name, value: A)`: Maps a variable in the current scope |
| 51 | +- `map_function(function: Function)`: Maps a function in the current scope |
| 52 | +- `lookup(var: &Name) -> Option<&A>`: Looks up a variable through the scope chain |
| 53 | +- `lookup_function(name: &Name) -> Option<&Function>`: Looks up a function through the scope chain |
| 54 | +- `push()`: Creates a new scope at the top of the stack |
| 55 | +- `pop()`: Removes the topmost scope |
| 56 | +- `scoped_function() -> bool`: Checks if we're in a function scope |
| 57 | + |
| 58 | +## Scoping Rules |
| 59 | + |
| 60 | +1. **Variable Resolution**: |
| 61 | + - First checks the local scopes from innermost to outermost |
| 62 | + - Falls back to global scope if not found in any local scope |
| 63 | + - Returns None if the variable is not found anywhere |
| 64 | + |
| 65 | +2. **Function Resolution**: |
| 66 | + - Follows the same rules as variable resolution |
| 67 | + - Functions can be defined in any scope |
| 68 | + - Inner functions can shadow outer functions |
| 69 | + |
| 70 | +3. **Scope Management**: |
| 71 | + - New scopes are pushed when entering a function or block |
| 72 | + - Scopes are popped when exiting their block |
| 73 | + - Global scope always remains at the bottom |
| 74 | + |
| 75 | +## Usage Examples |
| 76 | + |
| 77 | +### Type Checking |
| 78 | + |
| 79 | +```rust |
| 80 | +let mut type_env: Environment<Type> = Environment::new(); |
| 81 | + |
| 82 | +// In global scope |
| 83 | +type_env.map_variable("x".to_string(), Type::TInteger); |
| 84 | + |
| 85 | +// In function scope |
| 86 | +type_env.push(); |
| 87 | +type_env.map_variable("y".to_string(), Type::TReal); |
| 88 | +``` |
| 89 | + |
| 90 | +### Interpretation |
| 91 | + |
| 92 | +```rust |
| 93 | +let mut runtime_env: Environment<Expression> = Environment::new(); |
| 94 | + |
| 95 | +// In global scope |
| 96 | +runtime_env.map_variable("x".to_string(), Expression::CInt(42)); |
| 97 | + |
| 98 | +// In function scope |
| 99 | +runtime_env.push(); |
| 100 | +runtime_env.map_variable("y".to_string(), Expression::CReal(3.14)); |
| 101 | +``` |
| 102 | + |
| 103 | +### Nested Scopes |
| 104 | + |
| 105 | +```rust |
| 106 | +let mut env: Environment<i32> = Environment::new(); |
| 107 | + |
| 108 | +// Global scope |
| 109 | +env.map_variable("x".to_string(), 1); |
| 110 | + |
| 111 | +// Outer function scope |
| 112 | +env.push(); |
| 113 | +env.map_variable("y".to_string(), 2); |
| 114 | + |
| 115 | +// Inner function scope |
| 116 | +env.push(); |
| 117 | +env.map_variable("z".to_string(), 3); |
| 118 | + |
| 119 | +// Variables from all scopes are accessible |
| 120 | +assert!(env.lookup(&"x".to_string()).is_some()); // from global |
| 121 | +assert!(env.lookup(&"y".to_string()).is_some()); // from outer |
| 122 | +assert!(env.lookup(&"z".to_string()).is_some()); // from inner |
| 123 | + |
| 124 | +// Pop scopes to clean up |
| 125 | +env.pop(); // removes inner scope |
| 126 | +env.pop(); // removes outer scope |
| 127 | +``` |
| 128 | + |
| 129 | +## Implementation Notes |
| 130 | + |
| 131 | +1. The environment uses a `LinkedList` for the scope stack to efficiently push/pop scopes |
| 132 | +2. All lookups traverse the entire scope chain for proper lexical scoping |
| 133 | +3. The generic parameter `A` must implement `Clone` for the environment to work |
| 134 | +4. Functions are treated similarly to variables but stored in a separate map |
| 135 | +5. The global scope is always accessible, regardless of the current scope depth |
0 commit comments