Implement support for global variables in nac3standalone #546

Merged
sb10q merged 10 commits from enhance/global-vars into master 2024-10-04 14:00:10 +08:00
2 changed files with 97 additions and 2 deletions
Showing only changes of commit 1407553a2f - Show all commits

View File

@ -1,6 +1,6 @@
use std::rc::Rc; use std::rc::Rc;
use nac3parser::ast::fold::Fold; use nac3parser::ast::{fold::Fold, ExprKind};
use super::*; use super::*;
use crate::{ use crate::{
@ -382,8 +382,58 @@ impl TopLevelComposer {
)) ))
} }
ast::StmtKind::AnnAssign { target, annotation, .. } => {
let ExprKind::Name { id: name, .. } = target.node else {
return Err(format!(
"global variable declaration must be an identifier (at {})",
ast.location
));
};
if self.keyword_list.contains(&name) {
return Err(format!(
"cannot use keyword `{}` as a class name (at {})",
name,
ast.location
));
}
let global_var_name = if mod_path.is_empty() {
name.to_string()
} else {
format!("{mod_path}.{name}")
};
if !defined_names.insert(global_var_name.clone()) {
return Err(format!(
"global variable `{}` defined twice (at {})",
global_var_name,
ast.location
));
}
let ty_to_be_unified = self.unifier.get_dummy_var().ty;
self.definition_ast_list.push((
RwLock::new(Self::make_top_level_variable_def(
global_var_name,
name,
// dummy here, unify with correct type later,
ty_to_be_unified,
*(annotation.clone()),
resolver,
Some(ast.location),
)).into(),
None,
));
Ok((
name,
DefinitionId(self.definition_ast_list.len() - 1),
Some(ty_to_be_unified),
))
}
_ => Err(format!( _ => Err(format!(
"registrations of constructs other than top level classes/functions are not supported (at {})", "registrations of constructs other than top level classes/functions/variables are not supported (at {})",
ast.location ast.location
)), )),
} }

View File

@ -245,6 +245,34 @@ fn handle_assignment_pattern(
} }
} }
fn handle_global_var(
target: &Expr,
value: Option<&Expr>,
resolver: &(dyn SymbolResolver + Send + Sync),
internal_resolver: &ResolverInternal,
) -> Result<(), String> {
let ExprKind::Name { id, .. } = target.node else {
return Err(format!(
"global variable declaration must be an identifier (at {})",
target.location,
));
};
let Some(value) = value else {
return Err(format!("global variable `{id}` must be initialized in its definition"));
};
if let Ok(val) = parse_parameter_default_value(value, resolver) {
internal_resolver.add_module_global(id, val);
Ok(())
} else {
Err(format!(
"failed to evaluate this expression `{:?}` as a constant at {}",
target.node, target.location,
))
}
}
fn main() { fn main() {
let cli = CommandLineArgs::parse(); let cli = CommandLineArgs::parse();
let CommandLineArgs { file_name, threads, opt_level, emit_llvm, triple, mcpu, target_features } = let CommandLineArgs { file_name, threads, opt_level, emit_llvm, triple, mcpu, target_features } =
@ -342,6 +370,23 @@ fn main() {
panic!("{err}"); panic!("{err}");
} }
} }
StmtKind::AnnAssign { target, value, .. } => {
if let Err(err) = handle_global_var(
target,
value.as_ref().map(Box::as_ref),
resolver.as_ref(),
internal_resolver.as_ref(),
) {
panic!("{err}");
}
let (name, def_id, _) = composer
.register_top_level(stmt, Some(resolver.clone()), "__main__", true)
.unwrap();
internal_resolver.add_id_def(name, def_id);
}
// allow (and ignore) "from __future__ import annotations" // allow (and ignore) "from __future__ import annotations"
StmtKind::ImportFrom { module, names, .. } StmtKind::ImportFrom { module, names, .. }
if module == &Some("__future__".into()) if module == &Some("__future__".into())