feat: Add assignment operator and recursive scope assignment
Introduces the `Assign` AST node and a corresponding `assign` method on the `Scope` struct. This allows for updating existing variables within the current scope or any parent scope. The `assign` method recursively traverses the scope chain until it finds the variable or determines it's undefined. This enables reassigning variables defined in outer scopes.
This commit is contained in:
+47
-3
@@ -28,6 +28,7 @@ impl<'a> Parser<'a> {
|
||||
match self.peek() {
|
||||
TokenKind::LeftParen => self.parse_list(),
|
||||
TokenKind::LeftBracket => self.parse_vector_literal(),
|
||||
TokenKind::LeftBrace => self.parse_map_literal(),
|
||||
TokenKind::Quote => {
|
||||
let identity = Arc::new(NodeIdentity { location: self.current_token.location });
|
||||
self.advance()?; // consume '
|
||||
@@ -82,6 +83,7 @@ impl<'a> Parser<'a> {
|
||||
"if" => self.parse_if(identity),
|
||||
"fn" => self.parse_fn(identity),
|
||||
"def" => self.parse_def(identity),
|
||||
"assign" => self.parse_assign(identity),
|
||||
"do" => self.parse_do(identity),
|
||||
_ => self.parse_call(head, identity),
|
||||
}
|
||||
@@ -109,7 +111,6 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn parse_def(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
// (def name value)
|
||||
let name_node = self.parse_expression()?;
|
||||
let name = match name_node.kind {
|
||||
UntypedKind::Identifier(s) => s,
|
||||
@@ -124,6 +125,17 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_assign(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
// (assign target value)
|
||||
let target = Box::new(self.parse_expression()?);
|
||||
let value = Box::new(self.parse_expression()?);
|
||||
|
||||
Ok(Node {
|
||||
identity,
|
||||
kind: UntypedKind::Assign { target, value },
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_do(&mut self, identity: Identity) -> Result<Node<UntypedKind>, String> {
|
||||
let mut exprs = Vec::new();
|
||||
while *self.peek() != TokenKind::RightParen && *self.peek() != TokenKind::EOF {
|
||||
@@ -152,7 +164,7 @@ impl<'a> Parser<'a> {
|
||||
if *self.peek() != TokenKind::LeftBracket {
|
||||
return Err(format!("Expected parameter vector [...] for fn, found {:?}", self.peek()));
|
||||
}
|
||||
self.advance()?; // consume '['
|
||||
self.advance()?;
|
||||
|
||||
let mut params = Vec::new();
|
||||
while *self.peek() != TokenKind::RightBracket {
|
||||
@@ -180,7 +192,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
|
||||
fn parse_vector_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?; // consume '['
|
||||
let token = self.advance()?;
|
||||
let mut elements = Vec::new();
|
||||
let mut temp_ctx = Context::new();
|
||||
|
||||
@@ -200,6 +212,38 @@ impl<'a> Parser<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_map_literal(&mut self) -> Result<Node<UntypedKind>, String> {
|
||||
let token = self.advance()?;
|
||||
let mut map = std::collections::HashMap::new();
|
||||
let mut temp_ctx = Context::new();
|
||||
|
||||
while *self.peek() != TokenKind::RightBrace {
|
||||
if *self.peek() == TokenKind::EOF {
|
||||
return Err("Unexpected EOF in map literal".to_string());
|
||||
}
|
||||
|
||||
let key_node = self.parse_expression()?;
|
||||
let key = match key_node.eval(&mut temp_ctx)? {
|
||||
Value::Keyword(k) => k,
|
||||
_ => return Err("Map keys must be keywords".to_string()),
|
||||
};
|
||||
|
||||
if *self.peek() == TokenKind::RightBrace {
|
||||
return Err("Map literal must have even number of forms".to_string());
|
||||
}
|
||||
let val_node = self.parse_expression()?;
|
||||
let val = val_node.eval(&mut temp_ctx)?;
|
||||
|
||||
map.insert(key, val);
|
||||
}
|
||||
self.expect(TokenKind::RightBrace)?;
|
||||
|
||||
Ok(Node {
|
||||
identity: Arc::new(NodeIdentity { location: token.location }),
|
||||
kind: UntypedKind::Constant(Value::Record(Arc::new(map))),
|
||||
})
|
||||
}
|
||||
|
||||
fn expect(&mut self, kind: TokenKind) -> Result<(), String> {
|
||||
let token = self.advance()?;
|
||||
if token.kind == kind {
|
||||
|
||||
Reference in New Issue
Block a user