forked from M-Labs/nac3
1
0
Fork 0

nac3artiq: kernel invariant support

This commit is contained in:
pca006132 2021-11-20 21:15:15 +08:00
parent ba08deada6
commit f5ec103c82
3 changed files with 229 additions and 118 deletions

View File

@ -8,12 +8,12 @@ use inkwell::{
targets::*, targets::*,
OptimizationLevel, OptimizationLevel,
}; };
use pyo3::prelude::*;
use pyo3::{exceptions, types::PyList, types::PySet, types::PyBytes};
use nac3parser::{ use nac3parser::{
ast::{self, StrRef}, ast::{self, StrRef},
parser::{self, parse_program}, parser::{self, parse_program},
}; };
use pyo3::prelude::*;
use pyo3::{exceptions, types::PyBytes, types::PyList, types::PySet};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
@ -27,7 +27,10 @@ use nac3core::{
use tempfile::{self, TempDir}; use tempfile::{self, TempDir};
use crate::{codegen::ArtiqCodeGenerator, symbol_resolver::Resolver}; use crate::{
codegen::ArtiqCodeGenerator,
symbol_resolver::{InnerResolver, PythonHelper, Resolver},
};
mod codegen; mod codegen;
mod symbol_resolver; mod symbol_resolver;
@ -73,33 +76,45 @@ struct Nac3 {
} }
impl Nac3 { impl Nac3 {
fn register_module(&mut self, module: PyObject, registered_class_ids: &HashSet<u64>) -> PyResult<()> { fn register_module(
&mut self,
module: PyObject,
registered_class_ids: &HashSet<u64>,
) -> PyResult<()> {
let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new(); let mut name_to_pyid: HashMap<StrRef, u64> = HashMap::new();
let (module_name, source_file) = Python::with_gil(|py| -> PyResult<(String, String)> { let (module_name, source_file, helper) =
let module: &PyAny = module.extract(py)?; Python::with_gil(|py| -> PyResult<(String, String, PythonHelper)> {
let builtins = PyModule::import(py, "builtins")?; let module: &PyAny = module.extract(py)?;
let id_fn = builtins.getattr("id")?; let builtins = PyModule::import(py, "builtins")?;
let members: &PyList = PyModule::import(py, "inspect")? let id_fn = builtins.getattr("id")?;
.getattr("getmembers")? let members: &PyList = PyModule::import(py, "inspect")?
.call1((module,))? .getattr("getmembers")?
.cast_as()?; .call1((module,))?
for member in members.iter() { .cast_as()?;
let key: &str = member.get_item(0)?.extract()?; for member in members.iter() {
let val = id_fn.call1((member.get_item(1)?,))?.extract()?; let key: &str = member.get_item(0)?.extract()?;
name_to_pyid.insert(key.into(), val); let val = id_fn.call1((member.get_item(1)?,))?.extract()?;
} name_to_pyid.insert(key.into(), val);
Ok(( }
module.getattr("__name__")?.extract()?, let helper = PythonHelper {
module.getattr("__file__")?.extract()?, id_fn: builtins.getattr("id").unwrap().to_object(py),
)) len_fn: builtins.getattr("len").unwrap().to_object(py),
})?; type_fn: builtins.getattr("type").unwrap().to_object(py),
};
Ok((
module.getattr("__name__")?.extract()?,
module.getattr("__file__")?.extract()?,
helper,
))
})?;
let source = fs::read_to_string(source_file).map_err(|e| { let source = fs::read_to_string(source_file).map_err(|e| {
exceptions::PyIOError::new_err(format!("failed to read input file: {}", e)) exceptions::PyIOError::new_err(format!("failed to read input file: {}", e))
})?; })?;
let parser_result = parser::parse_program(&source) let parser_result = parser::parse_program(&source)
.map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {}", e)))?; .map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {}", e)))?;
let resolver = Arc::new(Resolver {
let resolver = Arc::new(Resolver(Arc::new(InnerResolver {
id_to_type: self.builtins_ty.clone().into(), id_to_type: self.builtins_ty.clone().into(),
id_to_def: self.builtins_def.clone().into(), id_to_def: self.builtins_def.clone().into(),
pyid_to_def: self.pyid_to_def.clone(), pyid_to_def: self.pyid_to_def.clone(),
@ -109,7 +124,8 @@ impl Nac3 {
class_names: Default::default(), class_names: Default::default(),
name_to_pyid: name_to_pyid.clone(), name_to_pyid: name_to_pyid.clone(),
module: module.clone(), module: module.clone(),
}) as Arc<dyn SymbolResolver + Send + Sync>; helper,
}))) as Arc<dyn SymbolResolver + Send + Sync>;
let mut name_to_def = HashMap::new(); let mut name_to_def = HashMap::new();
let mut name_to_type = HashMap::new(); let mut name_to_type = HashMap::new();
@ -140,10 +156,11 @@ impl Nac3 {
let base_obj = module.getattr(py, id.to_string())?; let base_obj = module.getattr(py, id.to_string())?;
let base_id = id_fn.call1((base_obj,))?.extract()?; let base_id = id_fn.call1((base_obj,))?.extract()?;
Ok(registered_class_ids.contains(&base_id)) Ok(registered_class_ids.contains(&base_id))
}, }
_ => Ok(true) _ => Ok(true),
} }
}).unwrap() })
.unwrap()
}); });
body.retain(|stmt| { body.retain(|stmt| {
if let ast::StmtKind::FunctionDef { if let ast::StmtKind::FunctionDef {
@ -306,7 +323,11 @@ impl Nac3 {
}; };
let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap(); let working_directory = tempfile::Builder::new().prefix("nac3-").tempdir().unwrap();
fs::write(working_directory.path().join("kernel.ld"), include_bytes!("kernel.ld")).unwrap(); fs::write(
working_directory.path().join("kernel.ld"),
include_bytes!("kernel.ld"),
)
.unwrap();
Ok(Nac3 { Ok(Nac3 {
isa, isa,
@ -320,29 +341,30 @@ impl Nac3 {
pyid_to_def: Default::default(), pyid_to_def: Default::default(),
pyid_to_type: Default::default(), pyid_to_type: Default::default(),
global_value_ids: Default::default(), global_value_ids: Default::default(),
working_directory working_directory,
}) })
} }
fn analyze(&mut self, functions: &PySet, classes: &PySet) -> PyResult<()> { fn analyze(&mut self, functions: &PySet, classes: &PySet) -> PyResult<()> {
let (modules, class_ids) = Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> { let (modules, class_ids) =
let mut modules: HashMap<u64, PyObject> = HashMap::new(); Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> {
let mut class_ids: HashSet<u64> = HashSet::new(); let mut modules: HashMap<u64, PyObject> = HashMap::new();
let mut class_ids: HashSet<u64> = HashSet::new();
let id_fn = PyModule::import(py, "builtins")?.getattr("id")?; let id_fn = PyModule::import(py, "builtins")?.getattr("id")?;
let getmodule_fn = PyModule::import(py, "inspect")?.getattr("getmodule")?; let getmodule_fn = PyModule::import(py, "inspect")?.getattr("getmodule")?;
for function in functions.iter() { for function in functions.iter() {
let module = getmodule_fn.call1((function,))?.extract()?; let module = getmodule_fn.call1((function,))?.extract()?;
modules.insert(id_fn.call1((&module,))?.extract()?, module); modules.insert(id_fn.call1((&module,))?.extract()?, module);
} }
for class in classes.iter() { for class in classes.iter() {
let module = getmodule_fn.call1((class,))?.extract()?; let module = getmodule_fn.call1((class,))?.extract()?;
modules.insert(id_fn.call1((&module,))?.extract()?, module); modules.insert(id_fn.call1((&module,))?.extract()?, module);
class_ids.insert(id_fn.call1((class,))?.extract()?); class_ids.insert(id_fn.call1((class,))?.extract()?);
} }
Ok((modules, class_ids)) Ok((modules, class_ids))
})?; })?;
for module in modules.into_values() { for module in modules.into_values() {
self.register_module(module, &class_ids)?; self.register_module(module, &class_ids)?;
@ -380,7 +402,13 @@ impl Nac3 {
) )
}; };
let mut synthesized = parse_program(&synthesized).unwrap(); let mut synthesized = parse_program(&synthesized).unwrap();
let resolver = Arc::new(Resolver { let builtins = PyModule::import(py, "builtins")?;
let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap().to_object(py),
len_fn: builtins.getattr("len").unwrap().to_object(py),
type_fn: builtins.getattr("type").unwrap().to_object(py),
};
let resolver = Arc::new(Resolver(Arc::new(InnerResolver {
id_to_type: self.builtins_ty.clone().into(), id_to_type: self.builtins_ty.clone().into(),
id_to_def: self.builtins_def.clone().into(), id_to_def: self.builtins_def.clone().into(),
pyid_to_def: self.pyid_to_def.clone(), pyid_to_def: self.pyid_to_def.clone(),
@ -390,7 +418,8 @@ impl Nac3 {
class_names: Default::default(), class_names: Default::default(),
name_to_pyid, name_to_pyid,
module: module.to_object(py), module: module.to_object(py),
}) as Arc<dyn SymbolResolver + Send + Sync>; helper,
}))) as Arc<dyn SymbolResolver + Send + Sync>;
let (_, def_id, _) = self let (_, def_id, _) = self
.composer .composer
.register_top_level( .register_top_level(
@ -455,9 +484,18 @@ impl Nac3 {
passes.run_on(module); passes.run_on(module);
let (triple, features) = match isa { let (triple, features) = match isa {
Isa::Host => (TargetMachine::get_default_triple(), TargetMachine::get_host_cpu_features().to_string()), Isa::Host => (
Isa::RiscV32G => (TargetTriple::create("riscv32-unknown-linux"), "+a,+m,+f,+d".to_string()), TargetMachine::get_default_triple(),
Isa::RiscV32IMA => (TargetTriple::create("riscv32-unknown-linux"), "+a,+m".to_string()), TargetMachine::get_host_cpu_features().to_string(),
),
Isa::RiscV32G => (
TargetTriple::create("riscv32-unknown-linux"),
"+a,+m,+f,+d".to_string(),
),
Isa::RiscV32IMA => (
TargetTriple::create("riscv32-unknown-linux"),
"+a,+m".to_string(),
),
Isa::CortexA9 => ( Isa::CortexA9 => (
TargetTriple::create("armv7-unknown-linux-gnueabihf"), TargetTriple::create("armv7-unknown-linux-gnueabihf"),
"+dsp,+fp16,+neon,+vfp3".to_string(), "+dsp,+fp16,+neon,+vfp3".to_string(),
@ -482,6 +520,7 @@ impl Nac3 {
&working_directory.join(&format!("{}.o", module.get_name().to_str().unwrap())), &working_directory.join(&format!("{}.o", module.get_name().to_str().unwrap())),
) )
.expect("couldn't write module to file"); .expect("couldn't write module to file");
println!("{}", module.print_to_string().to_str().unwrap());
}))); })));
let thread_names: Vec<String> = (0..4).map(|i| format!("module{}", i)).collect(); let thread_names: Vec<String> = (0..4).map(|i| format!("module{}", i)).collect();
let threads: Vec<_> = thread_names let threads: Vec<_> = thread_names
@ -503,11 +542,24 @@ impl Nac3 {
filename.to_string(), filename.to_string(),
]; ];
if isa != Isa::Host { if isa != Isa::Host {
linker_args.push("-T".to_string() + self.working_directory.path().join("kernel.ld").to_str().unwrap()); linker_args.push(
"-T".to_string()
+ self
.working_directory
.path()
.join("kernel.ld")
.to_str()
.unwrap(),
);
} }
linker_args.extend(thread_names.iter().map(|name| { linker_args.extend(thread_names.iter().map(|name| {
let name_o = name.to_owned() + ".o"; let name_o = name.to_owned() + ".o";
self.working_directory.path().join(name_o.as_str()).to_str().unwrap().to_string() self.working_directory
.path()
.join(name_o.as_str())
.to_str()
.unwrap()
.to_string()
})); }));
if let Ok(linker_status) = Command::new("ld.lld").args(linker_args).status() { if let Ok(linker_status) = Command::new("ld.lld").args(linker_args).status() {
if !linker_status.success() { if !linker_status.success() {

View File

@ -2,19 +2,19 @@ use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::{SymbolResolver, ValueEnum}, symbol_resolver::{StaticValue, SymbolResolver, ValueEnum},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
typedef::{Type, TypeEnum, Unifier}, typedef::{Type, TypeEnum, Unifier},
}, },
}; };
use nac3parser::ast::StrRef;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use pyo3::{ use pyo3::{
types::{PyList, PyModule, PyTuple}, types::{PyList, PyModule, PyTuple},
PyAny, PyObject, PyResult, Python, PyAny, PyObject, PyResult, Python,
}; };
use nac3parser::ast::StrRef;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -23,7 +23,7 @@ use std::{
use crate::PrimitivePythonId; use crate::PrimitivePythonId;
pub struct Resolver { pub struct InnerResolver {
pub id_to_type: Mutex<HashMap<StrRef, Type>>, pub id_to_type: Mutex<HashMap<StrRef, Type>>,
pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>, pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
pub global_value_ids: Arc<Mutex<HashSet<u64>>>, pub global_value_ids: Arc<Mutex<HashSet<u64>>>,
@ -31,32 +31,95 @@ pub struct Resolver {
pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>, pub pyid_to_def: Arc<RwLock<HashMap<u64, DefinitionId>>>,
pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>, pub pyid_to_type: Arc<RwLock<HashMap<u64, Type>>>,
pub primitive_ids: PrimitivePythonId, pub primitive_ids: PrimitivePythonId,
pub helper: PythonHelper,
// module specific // module specific
pub name_to_pyid: HashMap<StrRef, u64>, pub name_to_pyid: HashMap<StrRef, u64>,
pub module: PyObject, pub module: PyObject,
} }
struct PythonHelper<'a> { pub struct Resolver(pub Arc<InnerResolver>);
type_fn: &'a PyAny,
len_fn: &'a PyAny, pub struct PythonHelper {
id_fn: &'a PyAny, pub type_fn: PyObject,
pub len_fn: PyObject,
pub id_fn: PyObject,
} }
impl Resolver { struct PythonValue {
id: u64,
value: PyObject,
resolver: Arc<InnerResolver>,
}
impl StaticValue for PythonValue {
fn get_unique_identifier(&self) -> u64 {
self.id
}
fn to_basic_value_enum<'ctx, 'a>(
&self,
ctx: &mut CodeGenContext<'ctx, 'a>,
) -> BasicValueEnum<'ctx> {
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
self.resolver
.get_obj_value(py, self.value.as_ref(py), ctx)
.map(Option::unwrap)
})
.unwrap()
}
fn get_field<'ctx, 'a>(
&self,
name: StrRef,
ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<ValueEnum<'ctx>> {
Python::with_gil(|py| -> PyResult<Option<ValueEnum<'ctx>>> {
let helper = &self.resolver.helper;
let ty = helper.type_fn.call1(py, (&self.value,))?;
let ty_id: u64 = helper.id_fn.call1(py, (ty,))?.extract(py)?;
let def_id = { *self.resolver.pyid_to_def.read().get(&ty_id).unwrap() };
let mut mutable = true;
let defs = ctx.top_level.definitions.read();
if let TopLevelDef::Class { fields, .. } = &*defs[def_id.0].read() {
for (field_name, _, is_mutable) in fields.iter() {
if field_name == &name {
mutable = *is_mutable;
break;
}
}
}
Ok(if mutable {
None
} else {
println!("getting attribute {}", name);
let obj = self.value.getattr(py, &name.to_string())?;
let id = self.resolver.helper.id_fn.call1(py, (&obj,))?.extract(py)?;
Some(ValueEnum::Static(Arc::new(PythonValue {
id,
value: obj,
resolver: self.resolver.clone(),
})))
})
})
.unwrap()
}
}
impl InnerResolver {
fn get_list_elem_type( fn get_list_elem_type(
&self, &self,
py: Python,
list: &PyAny, list: &PyAny,
len: usize, len: usize,
helper: &PythonHelper,
unifier: &mut Unifier, unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> { ) -> PyResult<Option<Type>> {
let first = self.get_obj_type(list.get_item(0)?, helper, unifier, defs, primitives)?; let first = self.get_obj_type(py, list.get_item(0)?, unifier, defs, primitives)?;
Ok((1..len).fold(first, |a, i| { Ok((1..len).fold(first, |a, i| {
let b = list let b = list
.get_item(i) .get_item(i)
.map(|elem| self.get_obj_type(elem, helper, unifier, defs, primitives)); .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives));
a.and_then(|a| { a.and_then(|a| {
if let Ok(Ok(Some(ty))) = b { if let Ok(Ok(Some(ty))) = b {
if unifier.unify(a, ty).is_ok() { if unifier.unify(a, ty).is_ok() {
@ -73,16 +136,17 @@ impl Resolver {
fn get_obj_type( fn get_obj_type(
&self, &self,
py: Python,
obj: &PyAny, obj: &PyAny,
helper: &PythonHelper,
unifier: &mut Unifier, unifier: &mut Unifier,
defs: &[Arc<RwLock<TopLevelDef>>], defs: &[Arc<RwLock<TopLevelDef>>],
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
) -> PyResult<Option<Type>> { ) -> PyResult<Option<Type>> {
let ty_id: u64 = helper let ty_id: u64 = self
.helper
.id_fn .id_fn
.call1((helper.type_fn.call1((obj,))?,))? .call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?
.extract()?; .extract(py)?;
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 { if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
Ok(Some(primitives.int32)) Ok(Some(primitives.int32))
@ -93,20 +157,20 @@ impl Resolver {
} else if ty_id == self.primitive_ids.float { } else if ty_id == self.primitive_ids.float {
Ok(Some(primitives.float)) Ok(Some(primitives.float))
} else if ty_id == self.primitive_ids.list { } else if ty_id == self.primitive_ids.list {
let len: usize = helper.len_fn.call1((obj,))?.extract()?; let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
if len == 0 { if len == 0 {
let var = unifier.get_fresh_var().0; let var = unifier.get_fresh_var().0;
let list = unifier.add_ty(TypeEnum::TList { ty: var }); let list = unifier.add_ty(TypeEnum::TList { ty: var });
Ok(Some(list)) Ok(Some(list))
} else { } else {
let ty = self.get_list_elem_type(obj, len, helper, unifier, defs, primitives)?; let ty = self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?;
Ok(ty.map(|ty| unifier.add_ty(TypeEnum::TList { ty }))) Ok(ty.map(|ty| unifier.add_ty(TypeEnum::TList { ty })))
} }
} else if ty_id == self.primitive_ids.tuple { } else if ty_id == self.primitive_ids.tuple {
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements let types: Result<Option<Vec<_>>, _> = elements
.iter() .iter()
.map(|elem| self.get_obj_type(elem, helper, unifier, defs, primitives)) .map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))
.collect(); .collect();
let types = types?; let types = types?;
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types }))) Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
@ -141,7 +205,7 @@ impl Resolver {
let name: String = field.0.into(); let name: String = field.0.into();
let field_data = obj.getattr(&name)?; let field_data = obj.getattr(&name)?;
let ty = self let ty = self
.get_obj_type(field_data, helper, unifier, defs, primitives)? .get_obj_type(py, field_data, unifier, defs, primitives)?
.unwrap_or(primitives.none); .unwrap_or(primitives.none);
let field_ty = unifier.subst(field.1, &var_map).unwrap_or(field.1); let field_ty = unifier.subst(field.1, &var_map).unwrap_or(field.1);
if unifier.unify(ty, field_ty).is_err() { if unifier.unify(ty, field_ty).is_err() {
@ -153,7 +217,7 @@ impl Resolver {
for (_, ty) in var_map.iter() { for (_, ty) in var_map.iter() {
// must be concrete type // must be concrete type
if !unifier.is_concrete(*ty, &[]) { if !unifier.is_concrete(*ty, &[]) {
return Ok(None) return Ok(None);
} }
} }
Ok(Some(unifier.add_ty(TypeEnum::TObj { Ok(Some(unifier.add_ty(TypeEnum::TObj {
@ -172,14 +236,15 @@ impl Resolver {
fn get_obj_value<'ctx, 'a>( fn get_obj_value<'ctx, 'a>(
&self, &self,
py: Python,
obj: &PyAny, obj: &PyAny,
helper: &PythonHelper,
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
) -> PyResult<Option<BasicValueEnum<'ctx>>> { ) -> PyResult<Option<BasicValueEnum<'ctx>>> {
let ty_id: u64 = helper let ty_id: u64 = self
.helper
.id_fn .id_fn
.call1((helper.type_fn.call1((obj,))?,))? .call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?
.extract()?; .extract(py)?;
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 { if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
let val: i32 = obj.extract()?; let val: i32 = obj.extract()?;
Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into())) Ok(Some(ctx.ctx.i32_type().const_int(val as u64, false).into()))
@ -195,16 +260,16 @@ impl Resolver {
let val: f64 = obj.extract()?; let val: f64 = obj.extract()?;
Ok(Some(ctx.ctx.f64_type().const_float(val).into())) Ok(Some(ctx.ctx.f64_type().const_float(val).into()))
} else if ty_id == self.primitive_ids.list { } else if ty_id == self.primitive_ids.list {
let id: u64 = helper.id_fn.call1((obj,))?.extract()?; let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
let id_str = id.to_string(); let id_str = id.to_string();
let len: usize = helper.len_fn.call1((obj,))?.extract()?; let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
let ty = if len == 0 { let ty = if len == 0 {
ctx.primitives.int32 ctx.primitives.int32
} else { } else {
self.get_list_elem_type( self.get_list_elem_type(
py,
obj, obj,
len, len,
helper,
&mut ctx.unifier, &mut ctx.unifier,
&ctx.top_level.definitions.read(), &ctx.top_level.definitions.read(),
&ctx.primitives, &ctx.primitives,
@ -236,7 +301,7 @@ impl Resolver {
let arr: Result<Option<Vec<_>>, _> = (0..len) let arr: Result<Option<Vec<_>>, _> = (0..len)
.map(|i| { .map(|i| {
obj.get_item(i) obj.get_item(i)
.and_then(|elem| self.get_obj_value(elem, helper, ctx)) .and_then(|elem| self.get_obj_value(py, elem, ctx))
}) })
.collect(); .collect();
let arr = arr?.unwrap(); let arr = arr?.unwrap();
@ -297,15 +362,15 @@ impl Resolver {
Ok(Some(global.as_pointer_value().into())) Ok(Some(global.as_pointer_value().into()))
} else if ty_id == self.primitive_ids.tuple { } else if ty_id == self.primitive_ids.tuple {
let id: u64 = helper.id_fn.call1((obj,))?.extract()?; let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
let id_str = id.to_string(); let id_str = id.to_string();
let elements: &PyTuple = obj.cast_as()?; let elements: &PyTuple = obj.cast_as()?;
let types: Result<Option<Vec<_>>, _> = elements let types: Result<Option<Vec<_>>, _> = elements
.iter() .iter()
.map(|elem| { .map(|elem| {
self.get_obj_type( self.get_obj_type(
py,
elem, elem,
helper,
&mut ctx.unifier, &mut ctx.unifier,
&ctx.top_level.definitions.read(), &ctx.top_level.definitions.read(),
&ctx.primitives, &ctx.primitives,
@ -331,7 +396,7 @@ impl Resolver {
let val: Result<Option<Vec<_>>, _> = elements let val: Result<Option<Vec<_>>, _> = elements
.iter() .iter()
.map(|elem| self.get_obj_value(elem, helper, ctx)) .map(|elem| self.get_obj_value(py, elem, ctx))
.collect(); .collect();
let val = val?.unwrap(); let val = val?.unwrap();
let val = ctx.ctx.const_struct(&val, false); let val = ctx.ctx.const_struct(&val, false);
@ -341,17 +406,11 @@ impl Resolver {
global.set_initializer(&val); global.set_initializer(&val);
Ok(Some(global.as_pointer_value().into())) Ok(Some(global.as_pointer_value().into()))
} else { } else {
let id: u64 = helper.id_fn.call1((obj,))?.extract()?; let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
let id_str = id.to_string(); let id_str = id.to_string();
let top_level_defs = ctx.top_level.definitions.read(); let top_level_defs = ctx.top_level.definitions.read();
let ty = self let ty = self
.get_obj_type( .get_obj_type(py, obj, &mut ctx.unifier, &top_level_defs, &ctx.primitives)?
obj,
helper,
&mut ctx.unifier,
&top_level_defs,
&ctx.primitives,
)?
.unwrap(); .unwrap();
let ty = ctx let ty = ctx
.get_llvm_type(ty) .get_llvm_type(ty)
@ -380,7 +439,7 @@ impl Resolver {
let values: Result<Option<Vec<_>>, _> = fields let values: Result<Option<Vec<_>>, _> = fields
.iter() .iter()
.map(|(name, _, _)| { .map(|(name, _, _)| {
self.get_obj_value(obj.getattr(&name.to_string())?, helper, ctx) self.get_obj_value(py, obj.getattr(&name.to_string())?, ctx)
}) })
.collect(); .collect();
let values = values?; let values = values?;
@ -409,13 +468,13 @@ impl SymbolResolver for Resolver {
primitives: &PrimitiveStore, primitives: &PrimitiveStore,
str: StrRef, str: StrRef,
) -> Option<Type> { ) -> Option<Type> {
let mut id_to_type = self.id_to_type.lock(); let mut id_to_type = self.0.id_to_type.lock();
id_to_type.get(&str).cloned().or_else(|| { id_to_type.get(&str).cloned().or_else(|| {
let py_id = self.name_to_pyid.get(&str); let py_id = self.0.name_to_pyid.get(&str);
let result = py_id.and_then(|id| { let result = py_id.and_then(|id| {
self.pyid_to_type.read().get(id).copied().or_else(|| { self.0.pyid_to_type.read().get(id).copied().or_else(|| {
Python::with_gil(|py| -> PyResult<Option<Type>> { Python::with_gil(|py| -> PyResult<Option<Type>> {
let obj: &PyAny = self.module.extract(py)?; let obj: &PyAny = self.0.module.extract(py)?;
let members: &PyList = PyModule::import(py, "inspect")? let members: &PyList = PyModule::import(py, "inspect")?
.getattr("getmembers")? .getattr("getmembers")?
.call1((obj,))? .call1((obj,))?
@ -424,15 +483,9 @@ impl SymbolResolver for Resolver {
for member in members.iter() { for member in members.iter() {
let key: &str = member.get_item(0)?.extract()?; let key: &str = member.get_item(0)?.extract()?;
if key == str.to_string() { if key == str.to_string() {
let builtins = PyModule::import(py, "builtins")?; sym_ty = self.0.get_obj_type(
let helper = PythonHelper { py,
id_fn: builtins.getattr("id").unwrap(),
len_fn: builtins.getattr("len").unwrap(),
type_fn: builtins.getattr("type").unwrap(),
};
sym_ty = self.get_obj_type(
member.get_item(1)?, member.get_item(1)?,
&helper,
unifier, unifier,
defs, defs,
primitives, primitives,
@ -455,10 +508,10 @@ impl SymbolResolver for Resolver {
fn get_symbol_value<'ctx, 'a>( fn get_symbol_value<'ctx, 'a>(
&self, &self,
id: StrRef, id: StrRef,
ctx: &mut CodeGenContext<'ctx, 'a>, _: &mut CodeGenContext<'ctx, 'a>,
) -> Option<ValueEnum<'ctx>> { ) -> Option<ValueEnum<'ctx>> {
Python::with_gil(|py| -> PyResult<Option<ValueEnum<'ctx>>> { Python::with_gil(|py| -> PyResult<Option<ValueEnum<'ctx>>> {
let obj: &PyAny = self.module.extract(py)?; let obj: &PyAny = self.0.module.extract(py)?;
let members: &PyList = PyModule::import(py, "inspect")? let members: &PyList = PyModule::import(py, "inspect")?
.getattr("getmembers")? .getattr("getmembers")?
.call1((obj,))? .call1((obj,))?
@ -468,17 +521,16 @@ impl SymbolResolver for Resolver {
let key: &str = member.get_item(0)?.extract()?; let key: &str = member.get_item(0)?.extract()?;
let val = member.get_item(1)?; let val = member.get_item(1)?;
if key == id.to_string() { if key == id.to_string() {
let builtins = PyModule::import(py, "builtins")?; let id = self.0.helper.id_fn.call1(py, (val,))?.extract(py)?;
let helper = PythonHelper { sym_value = Some(PythonValue {
id_fn: builtins.getattr("id").unwrap(), id,
len_fn: builtins.getattr("len").unwrap(), value: val.extract()?,
type_fn: builtins.getattr("type").unwrap(), resolver: self.0.clone(),
}; });
sym_value = self.get_obj_value(val, &helper, ctx)?;
break; break;
} }
} }
Ok(sym_value.map(|v| v.into())) Ok(sym_value.map(|v| ValueEnum::Static(Arc::new(v))))
}) })
.unwrap() .unwrap()
} }
@ -488,10 +540,10 @@ impl SymbolResolver for Resolver {
} }
fn get_identifier_def(&self, id: StrRef) -> Option<DefinitionId> { fn get_identifier_def(&self, id: StrRef) -> Option<DefinitionId> {
let mut id_to_def = self.id_to_def.lock(); let mut id_to_def = self.0.id_to_def.lock();
id_to_def.get(&id).cloned().or_else(|| { id_to_def.get(&id).cloned().or_else(|| {
let py_id = self.name_to_pyid.get(&id); let py_id = self.0.name_to_pyid.get(&id);
let result = py_id.and_then(|id| self.pyid_to_def.read().get(id).copied()); let result = py_id.and_then(|id| self.0.pyid_to_def.read().get(id).copied());
if let Some(result) = &result { if let Some(result) = &result {
id_to_def.insert(id, *result); id_to_def.insert(id, *result);
} }

View File

@ -676,7 +676,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
ExprKind::Attribute { value, attr, .. } => { ExprKind::Attribute { value, attr, .. } => {
// note that we would handle class methods directly in calls // note that we would handle class methods directly in calls
match generator.gen_expr(ctx, value).unwrap() { match generator.gen_expr(ctx, value).unwrap() {
ValueEnum::Static(v) => v.get_field(*attr, ctx).unwrap(), ValueEnum::Static(v) => v.get_field(*attr, ctx).unwrap_or_else(|| {
let v = v.to_basic_value_enum(ctx);
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
ValueEnum::Dynamic(ctx.build_gep_and_load(
v.into_pointer_value(),
&[zero, int32.const_int(index as u64, false)],
))
}),
ValueEnum::Dynamic(v) => { ValueEnum::Dynamic(v) => {
let index = ctx.get_attr_index(value.custom.unwrap(), *attr); let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
ValueEnum::Dynamic(ctx.build_gep_and_load( ValueEnum::Dynamic(ctx.build_gep_and_load(