feat: execute source control flow and exact real arithmetic

This commit is contained in:
2026-11-12 10:48:27 +08:00
parent f3e1670c58
commit 5ff1c68f5f
28 changed files with 1045 additions and 117 deletions
+121 -44
View File
@@ -167,6 +167,16 @@ pub fn analyze(root: &AstRoot, options: &CompileOptions) -> Result<SymbolTable,
StmtKind::Expression(expression) => {
root_scope.expression(expression, &globals)?
}
StmtKind::If(_) | StmtKind::While(_) => {
let statements = std::slice::from_ref(statement);
collect_locals(
statements,
&mut declared,
&mut root_scope.scope.layout.names,
)?;
globals.extend(root_scope.scope.layout.names.iter().cloned());
root_scope.statements(statements, &globals)?;
}
StmtKind::Return(_) => {
return Err(error(statement.span, "return outside a function"));
}
@@ -207,21 +217,38 @@ fn function_scope(function: &Function, globals: &BTreeSet<String>) -> Result<Sco
.push(parameter.name.text.clone());
builder.initialized.insert(parameter.name.text.clone());
}
for statement in &function.body.statements {
collect_locals(
&function.body.statements,
&mut locals,
&mut builder.scope.layout.locals,
)?;
builder.statements(&function.body.statements, globals)?;
Ok(builder.scope)
}
fn collect_locals(
statements: &[frontend::ast::Stmt],
locals: &mut BTreeSet<String>,
layout: &mut Vec<String>,
) -> Result<(), Diagnostic> {
for statement in statements {
match &statement.kind {
StmtKind::Binding(binding) => {
declare(&mut locals, &binding.name.text, binding.name.span)?;
builder.scope.layout.locals.push(binding.name.text.clone());
StmtKind::Binding(b) => {
declare(locals, &b.name.text, b.name.span)?;
layout.push(b.name.text.clone());
}
StmtKind::Assignment(assignment) => {
if locals.insert(assignment.name.text.clone()) {
builder
.scope
.layout
.locals
.push(assignment.name.text.clone());
StmtKind::Assignment(a) => {
if locals.insert(a.name.text.clone()) {
layout.push(a.name.text.clone());
}
}
StmtKind::If(b) => {
collect_locals(&b.body.statements, locals, layout)?;
if let Some(other) = &b.otherwise {
collect_locals(&other.statements, locals, layout)?;
}
}
StmtKind::While(b) => collect_locals(&b.body.statements, locals, layout)?,
StmtKind::Declaration(_) => {
return Err(error(
statement.span,
@@ -231,39 +258,7 @@ fn function_scope(function: &Function, globals: &BTreeSet<String>) -> Result<Sco
_ => {}
}
}
let mut returned = false;
for statement in &function.body.statements {
if returned {
return Err(error(
statement.span,
"statement after return is unreachable",
));
}
match &statement.kind {
StmtKind::Binding(binding) => {
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)?;
}
returned = true;
}
StmtKind::MemberAssignment(assignment) => {
builder.expression(&assignment.object, globals)?;
builder.expression(&assignment.value, globals)?;
builder.intern(&assignment.name.text);
}
StmtKind::Expression(expression) => builder.expression(expression, globals)?,
StmtKind::Declaration(_) => unreachable!("nested declaration rejected above"),
}
}
Ok(builder.scope)
Ok(())
}
struct Builder {
@@ -300,6 +295,88 @@ impl Builder {
}
}
/// Function-scoped locals; branches merge definite initialization. A loop
/// may execute zero times, so its writes do not initialize later reads.
fn statements(
&mut self,
statements: &[frontend::ast::Stmt],
globals: &BTreeSet<String>,
) -> Result<bool, Diagnostic> {
let mut returned = false;
for statement in statements {
if returned {
return Err(error(
statement.span,
"statement after return is unreachable",
));
}
match &statement.kind {
StmtKind::Binding(b) => {
self.expression(&b.value, globals)?;
self.initialized.insert(b.name.text.clone());
if self.scope.kind != ScopeKind::Function {
self.intern(&b.name.text);
}
}
StmtKind::Assignment(a) => {
self.expression(&a.value, globals)?;
self.initialized.insert(a.name.text.clone());
if self.scope.kind != ScopeKind::Function {
self.intern(&a.name.text);
}
}
StmtKind::MemberAssignment(a) => {
self.expression(&a.object, globals)?;
self.expression(&a.value, globals)?;
self.intern(&a.name.text);
}
StmtKind::Expression(e) => self.expression(e, globals)?,
StmtKind::Return(r) => {
if self.scope.kind != ScopeKind::Function {
return Err(error(statement.span, "return outside a function"));
}
if let Some(e) = &r.value {
self.expression(e, globals)?;
}
returned = true;
}
StmtKind::If(b) => {
self.expression(&b.condition, globals)?;
let before = self.initialized.clone();
let yes_return = self.statements(&b.body.statements, globals)?;
let yes = self.initialized.clone();
self.initialized = before;
let no_return = if let Some(other) = &b.otherwise {
self.statements(&other.statements, globals)?
} else {
false
};
self.initialized = if yes_return {
self.initialized.clone()
} else if no_return {
yes
} else {
yes.intersection(&self.initialized).cloned().collect()
};
returned = yes_return && no_return;
}
StmtKind::While(b) => {
self.expression(&b.condition, globals)?;
let before = self.initialized.clone();
self.statements(&b.body.statements, globals)?;
self.initialized = before;
}
StmtKind::Declaration(_) => {
return Err(error(
statement.span,
"nested declarations are not compiled yet",
));
}
}
}
Ok(returned)
}
fn expression(
&mut self,
expression: &Expr,