feat: support bare name assignments in interactive and function scopes
This commit is contained in:
@@ -114,6 +114,11 @@ pub fn analyze(root: &AstRoot, options: &CompileOptions) -> Result<SymbolTable,
|
||||
globals.insert(binding.name.text.clone());
|
||||
root_scope.intern(&binding.name.text);
|
||||
}
|
||||
StmtKind::Assignment(assignment) => {
|
||||
root_scope.expression(&assignment.value, &globals)?;
|
||||
globals.insert(assignment.name.text.clone());
|
||||
root_scope.intern(&assignment.name.text);
|
||||
}
|
||||
StmtKind::Declaration(_) => {}
|
||||
StmtKind::Expression(expression) => {
|
||||
root_scope.expression(expression, &globals)?
|
||||
@@ -164,6 +169,15 @@ fn function_scope(function: &Function, globals: &BTreeSet<String>) -> Result<Sco
|
||||
declare(&mut locals, &binding.name.text, binding.name.span)?;
|
||||
builder.scope.layout.locals.push(binding.name.text.clone());
|
||||
}
|
||||
StmtKind::Assignment(assignment) => {
|
||||
if locals.insert(assignment.name.text.clone()) {
|
||||
builder
|
||||
.scope
|
||||
.layout
|
||||
.locals
|
||||
.push(assignment.name.text.clone());
|
||||
}
|
||||
}
|
||||
StmtKind::Declaration(_) => {
|
||||
return Err(error(
|
||||
statement.span,
|
||||
@@ -186,6 +200,10 @@ fn function_scope(function: &Function, globals: &BTreeSet<String>) -> Result<Sco
|
||||
builder.expression(&binding.value, globals)?;
|
||||
builder.initialized.insert(binding.name.text.clone());
|
||||
}
|
||||
StmtKind::Assignment(assignment) => {
|
||||
builder.expression(&assignment.value, globals)?;
|
||||
builder.initialized.insert(assignment.name.text.clone());
|
||||
}
|
||||
StmtKind::Return(statement) => {
|
||||
if let Some(value) = &statement.value {
|
||||
builder.expression(value, globals)?;
|
||||
|
||||
@@ -179,22 +179,28 @@ impl<'a> Emitter<'a> {
|
||||
self.emit(Opcode::StoreGlobal, self.name_index(&function.name.text))
|
||||
}
|
||||
|
||||
fn store_binding(&mut self, name: &str, value: &Expr) -> Result<(), Diagnostic> {
|
||||
self.expression(value)?;
|
||||
if self.scope.kind == ScopeKind::Function {
|
||||
let index = self
|
||||
.scope
|
||||
.layout
|
||||
.locals
|
||||
.iter()
|
||||
.position(|local| local == name)
|
||||
.expect("analysis allocates binding and assignment targets");
|
||||
self.emit(Opcode::StoreFast, index)?;
|
||||
} else {
|
||||
self.emit(Opcode::StoreGlobal, self.name_index(name))?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn statement(&mut self, statement: &Stmt, symbols: &SymbolTable) -> Result<(), Diagnostic> {
|
||||
match &statement.kind {
|
||||
StmtKind::Binding(binding) => {
|
||||
self.expression(&binding.value)?;
|
||||
if self.scope.kind == ScopeKind::Function {
|
||||
let index = self
|
||||
.scope
|
||||
.layout
|
||||
.locals
|
||||
.iter()
|
||||
.position(|name| name == &binding.name.text)
|
||||
.expect("analysis allocates each local");
|
||||
self.emit(Opcode::StoreFast, index)?;
|
||||
} else {
|
||||
self.emit(Opcode::StoreGlobal, self.name_index(&binding.name.text))?;
|
||||
}
|
||||
StmtKind::Binding(binding) => self.store_binding(&binding.name.text, &binding.value)?,
|
||||
StmtKind::Assignment(assignment) => {
|
||||
self.store_binding(&assignment.name.text, &assignment.value)?
|
||||
}
|
||||
StmtKind::Return(statement) => {
|
||||
if let Some(value) = &statement.value {
|
||||
|
||||
Reference in New Issue
Block a user