Scoping and Symbol Binding
Purpose
The ARES Scoping system is the mechanism that manages variable names and their properties within a program. It is a system that keeps track of every identifier you create (like x or my_list) and stores important information about them, such as their data type and their current state. This information is what allows the compiler to make smart decisions, like automatically sorting a list before you search it.
Why it exists
When you write a program, the computer needs to remember exactly what every name stands for. If you use the name x in two different places, the computer must know if they are the same thing or two different things. The scoping system exists to provide this organization. It also tracks the "logic state" of your variables. For example, it remembers if you have already sorted a list, so it doesn't waste time sorting it again. It ensures that your program's logic is consistent and efficient throughout its entire lifecycle.
How it works
ARES uses a central record-keeping system called a Symbol Table.
- Recording names. Every time you create a new variable (using
read,let, oris), the system adds a new entry to the table. - Storing metadata. For every name, the system stores a set of properties (called metadata). These include:
- Type: Is it a number, a line of text, or a list?
- Sorted State: If it's a list, has it been sorted yet?
- Initialization: Has a value been assigned to it?
- Container Status: Is it a single item or a group of items?
- Variable lookups. When you use a name later in your code, the system quickly looks it up in the table to find its properties and ensure you are using it correctly.
- State updates. When you perform an operation on a variable, like sorting it, the system updates the record in the table. This tells all future parts of the program that the variable is now in a new state.
Intuition
Think of the scoping system like a library's filing system. Every time a new book (a variable) arrives, the librarian creates a card for it in the catalog (the Symbol Table). The card lists the book's title, its category (its type), and whether it's currently on the shelf or checked out (its state). When you want to find a book, you check the catalog first. If you move the book to a different section, the librarian updates the card so everyone else knows exactly where it is. Correct organization is what keeps the library (your program) running smoothly.
Implementation details
The core logic for symbol tracking is in src/semantics/analyzer.ts. It uses a standard Map to store the information for every unique name in your program.
- Case Sensitivity: The system treats
dataandDataas two completely different names. - Binding Triggers: Names are "bound" (added to the table) the moment they first appear in your code.
complexity
Managing these names is incredibly fast. Looking up a name or adding a new one takes a constant amount of time (), no matter how large your program gets. This ensures that the compiler stays fast even for very long scripts.
Trace example
This is what happens when you write read my_list as vector<int>; use sort on my_list:
- Binding: The system sees
read my_list. It creates a new record formy_listand marks it as avector<int>that is not sorted. - Updating: The system sees
use sort on my_list. It looks upmy_listin the table and confirms it's a list. - State Change: After the sort command is processed, the system updates the record for
my_listto mark it as sorted. - Future use: If you try to search the list next, the system checks the table, sees it is already sorted, and proceeds immediately.
Related entities
src/semantics/analyzer.ts: The actual code that implements the symbol table and binding logic.3_standard_library/01_primitives.md: Explains the data types that are stored in the symbol table.