handle global variables
This commit is contained in:
parent
e64ee40d63
commit
8d6f8086f5
|
@ -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>> {
|
||||||
|
|
100
src/main.rs
100
src/main.rs
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue