forked from M-Labs/nac3
nac3artiq: kernel invariant support
This commit is contained in:
parent
ba08deada6
commit
f5ec103c82
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in New Issue