handle global variables

This commit is contained in:
Sébastien Bourdeauducq 2024-10-04 14:48:49 +08:00
parent e64ee40d63
commit 8d6f8086f5
2 changed files with 116 additions and 35 deletions

View File

@ -1,6 +1,14 @@
use nac3core::nac3parser::ast::{self, StrRef}; use std::{
collections::{HashMap, HashSet},
sync::Arc,
};
use parking_lot::{Mutex, RwLock};
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::{CodeGenContext, CodeGenerator},
inkwell::{module::Linkage, values::BasicValue},
nac3parser::ast::{self, StrRef},
symbol_resolver::{SymbolResolver, SymbolValue, ValueEnum}, symbol_resolver::{SymbolResolver, SymbolValue, ValueEnum},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
@ -8,9 +16,6 @@ use nac3core::{
typedef::{Type, Unifier}, typedef::{Type, Unifier},
}, },
}; };
use parking_lot::{Mutex, RwLock};
use std::collections::HashSet;
use std::{collections::HashMap, sync::Arc};
pub struct ResolverInternal { pub struct ResolverInternal {
pub id_to_type: Mutex<HashMap<StrRef, Type>>, pub id_to_type: Mutex<HashMap<StrRef, Type>>,
@ -45,9 +50,9 @@ impl SymbolResolver for Resolver {
fn get_symbol_type( fn get_symbol_type(
&self, &self,
_: &mut Unifier, unifier: &mut Unifier,
_: &[Arc<RwLock<TopLevelDef>>], _: &[Arc<RwLock<TopLevelDef>>],
_: &PrimitiveStore, primitives: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Result<Type, String> { ) -> Result<Type, String> {
self.0 self.0
@ -55,15 +60,41 @@ impl SymbolResolver for Resolver {
.lock() .lock()
.get(&str) .get(&str)
.copied() .copied()
.or_else(|| {
self.0
.module_globals
.lock()
.get(&str)
.cloned()
.map(|v| v.get_type(primitives, unifier))
})
.ok_or(format!("cannot get type of {str}")) .ok_or(format!("cannot get type of {str}"))
} }
fn get_symbol_value<'ctx>( fn get_symbol_value<'ctx>(
&self, &self,
_: StrRef, str: StrRef,
_: &mut CodeGenContext<'ctx, '_>, ctx: &mut CodeGenContext<'ctx, '_>,
generator: &mut dyn CodeGenerator,
) -> Option<ValueEnum<'ctx>> { ) -> Option<ValueEnum<'ctx>> {
unimplemented!() self.0.module_globals.lock().get(&str).cloned().map(|v| {
ctx.module
.get_global(&str.to_string())
.unwrap_or_else(|| {
let ty = v.get_type(&ctx.primitives, &mut ctx.unifier);
let init_val = ctx.gen_symbol_val(generator, &v, ty);
let llvm_ty = init_val.get_type();
let global = ctx.module.add_global(llvm_ty, None, &str.to_string());
global.set_linkage(Linkage::LinkOnceAny);
global.set_initializer(&init_val);
global
})
.as_basic_value_enum()
.into()
})
} }
fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, HashSet<String>> { fn get_identifier_def(&self, id: StrRef) -> Result<DefinitionId, HashSet<String>> {

View File

@ -199,6 +199,36 @@ fn handle_assignment_pattern(
} }
} }
fn handle_global_var(
target: &nac3parser::ast::Expr,
value: Option<&nac3parser::ast::Expr>,
resolver: &(dyn nac3core::symbol_resolver::SymbolResolver + Send + Sync),
internal_resolver: &ResolverInternal,
) -> Result<(), String> {
let nac3parser::ast::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) = toplevel::helper::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 compile(code: &String, run_symbol: &String, output_filename: &Path) -> Result<(), String> { fn compile(code: &String, run_symbol: &String, output_filename: &Path) -> Result<(), String> {
let mut target_machine_options = codegen::CodeGenTargetMachineOptions::from_host(); let mut target_machine_options = codegen::CodeGenTargetMachineOptions::from_host();
target_machine_options.reloc_mode = inkwell::targets::RelocMode::PIC; target_machine_options.reloc_mode = inkwell::targets::RelocMode::PIC;
@ -241,34 +271,54 @@ fn compile(code: &String, run_symbol: &String, output_filename: &Path) -> Result
} }
}; };
for mut stmt in parser_result { for mut stmt in parser_result {
if let nac3parser::ast::StmtKind::Assign { targets, value, .. } = stmt.node { match stmt.node {
let def_list = composer.extract_def_list(); nac3parser::ast::StmtKind::Assign { targets, value, .. } => {
let unifier = &mut composer.unifier; let def_list = composer.extract_def_list();
let primitives = &composer.primitives_ty; let unifier = &mut composer.unifier;
handle_assignment_pattern( let primitives = &composer.primitives_ty;
&targets, handle_assignment_pattern(
&value, &targets,
resolver.as_ref(), &value,
internal_resolver.as_ref(), resolver.as_ref(),
&def_list, internal_resolver.as_ref(),
unifier, &def_list,
primitives, unifier,
)?; primitives,
} else { )?;
if let nac3parser::ast::StmtKind::FunctionDef { name, .. } = &mut stmt.node {
if name.to_string() == "run" {
*name = run_symbol.as_str().into();
}
} }
match composer.register_top_level(stmt, Some(resolver.clone()), "__main__", true) { nac3parser::ast::StmtKind::AnnAssign {
Ok((name, def_id, ty)) => { ref target,
internal_resolver.add_id_def(name, def_id); ref value,
if let Some(ty) = ty { ..
internal_resolver.add_id_type(name, ty); } => {
handle_global_var(
&target,
value.as_ref().map(Box::as_ref),
resolver.as_ref(),
internal_resolver.as_ref(),
)?;
let (name, def_id, _) = composer
.register_top_level(stmt, Some(resolver.clone()), "__main__", true)
.unwrap();
internal_resolver.add_id_def(name, def_id);
}
_ => {
if let nac3parser::ast::StmtKind::FunctionDef { name, .. } = &mut stmt.node {
if name.to_string() == "run" {
*name = run_symbol.as_str().into();
} }
} }
Err(err) => { match composer.register_top_level(stmt, Some(resolver.clone()), "__main__", true) {
return Err(format!("composer error: {}", err)); Ok((name, def_id, ty)) => {
internal_resolver.add_id_def(name, def_id);
if let Some(ty) = ty {
internal_resolver.add_id_type(name, ty);
}
}
Err(err) => {
return Err(format!("composer error: {}", err));
}
} }
} }
} }