TypeVar and virtual support in Symbol Resolver #99
|
@ -2,6 +2,7 @@ use nac3core::{
|
||||||
codegen::{expr::gen_call, stmt::gen_with, CodeGenContext, CodeGenerator},
|
codegen::{expr::gen_call, stmt::gen_with, CodeGenContext, CodeGenerator},
|
||||||
toplevel::DefinitionId,
|
toplevel::DefinitionId,
|
||||||
typecheck::typedef::{FunSignature, Type},
|
typecheck::typedef::{FunSignature, Type},
|
||||||
|
symbol_resolver::ValueEnum,
|
||||||
};
|
};
|
||||||
|
|
||||||
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
use nac3parser::ast::{Expr, ExprKind, Located, Stmt, StmtKind, StrRef};
|
||||||
|
@ -38,13 +39,13 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
fn gen_call<'ctx, 'a>(
|
fn gen_call<'ctx, 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, DefinitionId),
|
fun: (&FunSignature, DefinitionId),
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
let result = gen_call(self, ctx, obj, fun, params);
|
let result = gen_call(self, ctx, obj, fun, params);
|
||||||
if let Some(end) = self.end.clone() {
|
if let Some(end) = self.end.clone() {
|
||||||
let old_end = self.gen_expr(ctx, &end).unwrap();
|
let old_end = self.gen_expr(ctx, &end).unwrap().to_basic_value_enum(ctx);
|
||||||
let now = self.timeline.emit_now_mu(ctx);
|
let now = self.timeline.emit_now_mu(ctx);
|
||||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
let i64 = ctx.ctx.i64_type();
|
let i64 = ctx.ctx.i64_type();
|
||||||
|
@ -64,7 +65,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
ctx.builder.build_store(end_store, max);
|
ctx.builder.build_store(end_store, max);
|
||||||
}
|
}
|
||||||
if let Some(start) = self.start.clone() {
|
if let Some(start) = self.start.clone() {
|
||||||
let start_val = self.gen_expr(ctx, &start).unwrap();
|
let start_val = self.gen_expr(ctx, &start).unwrap().to_basic_value_enum(ctx);
|
||||||
self.timeline.emit_at_mu(ctx, start_val);
|
self.timeline.emit_at_mu(ctx, start_val);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
@ -96,7 +97,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
let old_start = self.start.take();
|
let old_start = self.start.take();
|
||||||
let old_end = self.end.take();
|
let old_end = self.end.take();
|
||||||
let now = if let Some(old_start) = &old_start {
|
let now = if let Some(old_start) = &old_start {
|
||||||
self.gen_expr(ctx, old_start).unwrap()
|
self.gen_expr(ctx, old_start).unwrap().to_basic_value_enum(ctx)
|
||||||
} else {
|
} else {
|
||||||
self.timeline.emit_now_mu(ctx)
|
self.timeline.emit_now_mu(ctx)
|
||||||
};
|
};
|
||||||
|
@ -145,7 +146,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
}
|
}
|
||||||
// set duration
|
// set duration
|
||||||
let end_expr = self.end.take().unwrap();
|
let end_expr = self.end.take().unwrap();
|
||||||
let end_val = self.gen_expr(ctx, &end_expr).unwrap();
|
let end_val = self.gen_expr(ctx, &end_expr).unwrap().to_basic_value_enum(ctx);
|
||||||
|
|
||||||
// inside an sequential block
|
// inside an sequential block
|
||||||
if old_start.is_none() {
|
if old_start.is_none() {
|
||||||
|
@ -153,7 +154,7 @@ impl<'b> CodeGenerator for ArtiqCodeGenerator<'b> {
|
||||||
}
|
}
|
||||||
// inside a parallel block, should update the outer max now_mu
|
// inside a parallel block, should update the outer max now_mu
|
||||||
if let Some(old_end) = &old_end {
|
if let Some(old_end) = &old_end {
|
||||||
let outer_end_val = self.gen_expr(ctx, old_end).unwrap();
|
let outer_end_val = self.gen_expr(ctx, old_end).unwrap().to_basic_value_enum(ctx);
|
||||||
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
let smax = ctx.module.get_function("llvm.smax.i64").unwrap_or_else(|| {
|
||||||
let i64 = ctx.ctx.i64_type();
|
let i64 = ctx.ctx.i64_type();
|
||||||
ctx.module.add_function(
|
ctx.module.add_function(
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -77,9 +80,14 @@ 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) =
|
||||||
|
Python::with_gil(|py| -> PyResult<(String, String, PythonHelper)> {
|
||||||
let module: &PyAny = module.extract(py)?;
|
let module: &PyAny = module.extract(py)?;
|
||||||
let builtins = PyModule::import(py, "builtins")?;
|
let builtins = PyModule::import(py, "builtins")?;
|
||||||
let id_fn = builtins.getattr("id")?;
|
let id_fn = builtins.getattr("id")?;
|
||||||
|
@ -92,9 +100,15 @@ impl Nac3 {
|
||||||
let val = id_fn.call1((member.get_item(1)?,))?.extract()?;
|
let val = id_fn.call1((member.get_item(1)?,))?.extract()?;
|
||||||
name_to_pyid.insert(key.into(), val);
|
name_to_pyid.insert(key.into(), val);
|
||||||
}
|
}
|
||||||
|
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),
|
||||||
|
};
|
||||||
Ok((
|
Ok((
|
||||||
module.getattr("__name__")?.extract()?,
|
module.getattr("__name__")?.extract()?,
|
||||||
module.getattr("__file__")?.extract()?,
|
module.getattr("__file__")?.extract()?,
|
||||||
|
helper,
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
@ -103,7 +117,8 @@ impl Nac3 {
|
||||||
})?;
|
})?;
|
||||||
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(),
|
||||||
|
@ -113,7 +128,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();
|
||||||
|
|
||||||
|
@ -144,10 +160,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)
|
|
||||||
}
|
}
|
||||||
}).unwrap()
|
_ => Ok(true),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
});
|
});
|
||||||
body.retain(|stmt| {
|
body.retain(|stmt| {
|
||||||
if let ast::StmtKind::FunctionDef {
|
if let ast::StmtKind::FunctionDef {
|
||||||
|
@ -345,7 +362,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,
|
||||||
|
@ -359,12 +380,13 @@ 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) =
|
||||||
|
Python::with_gil(|py| -> PyResult<(HashMap<u64, PyObject>, HashSet<u64>)> {
|
||||||
let mut modules: HashMap<u64, PyObject> = HashMap::new();
|
let mut modules: HashMap<u64, PyObject> = HashMap::new();
|
||||||
let mut class_ids: HashSet<u64> = HashSet::new();
|
let mut class_ids: HashSet<u64> = HashSet::new();
|
||||||
|
|
||||||
|
@ -419,7 +441,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(),
|
||||||
|
@ -429,7 +457,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(
|
||||||
|
@ -482,6 +511,7 @@ impl Nac3 {
|
||||||
store,
|
store,
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
calls: instance.calls,
|
calls: instance.calls,
|
||||||
|
id: 0,
|
||||||
};
|
};
|
||||||
let isa = self.isa;
|
let isa = self.isa;
|
||||||
let working_directory = self.working_directory.path().to_owned();
|
let working_directory = self.working_directory.path().to_owned();
|
||||||
|
@ -493,9 +523,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(),
|
||||||
|
@ -541,11 +580,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, SymbolValue},
|
symbol_resolver::{StaticValue, SymbolResolver, SymbolValue, 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::{self, 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::{self, 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,34 +31,94 @@ 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,
|
||||||
origin_ty_fn: &'a PyAny,
|
pub len_fn: PyObject,
|
||||||
args_ty_fn: &'a PyAny,
|
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 {
|
||||||
|
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>> {
|
||||||
sb10q
commented
same same
|
|||||||
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,44 +133,47 @@ impl Resolver {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle python objects that represent types themselves
|
fn get_obj_type(
|
||||||
// primitives and class types should be themselves, use `ty_id` to check,
|
|
||||||
// TypeVars and GenericAlias(`A[int, bool]`) should use `ty_ty_id` to check
|
|
||||||
// the `bool` value returned indicates whether they are instantiated or not
|
|
||||||
fn get_pyty_obj_type(
|
|
||||||
&self,
|
&self,
|
||||||
pyty: &PyAny,
|
py: Python,
|
||||||
helper: &PythonHelper,
|
obj: &PyAny,
|
||||||
unifier: &mut Unifier,
|
unifier: &mut Unifier,
|
||||||
defs: &[Arc<RwLock<TopLevelDef>>],
|
defs: &[Arc<RwLock<TopLevelDef>>],
|
||||||
primitives: &PrimitiveStore,
|
primitives: &PrimitiveStore,
|
||||||
) -> PyResult<Result<(Type, bool), String>> {
|
) -> PyResult<Option<Type>> {
|
||||||
let ty_id: u64 = helper
|
let ty_id: u64 = self
|
||||||
|
.helper
|
||||||
.id_fn
|
.id_fn
|
||||||
.call1((pyty,))?
|
.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?
|
||||||
.extract()?;
|
.extract(py)?;
|
||||||
let ty_ty_id: u64 = helper
|
|
||||||
.id_fn
|
|
||||||
.call1((helper.type_fn.call1((pyty,))?,))?
|
|
||||||
.extract()?;
|
|
||||||
|
|
||||||
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(Ok((primitives.int32, true)))
|
Ok(Some(primitives.int32))
|
||||||
} else if ty_id == self.primitive_ids.int64 {
|
} else if ty_id == self.primitive_ids.int64 {
|
||||||
Ok(Ok((primitives.int64, true)))
|
Ok(Some(primitives.int64))
|
||||||
} else if ty_id == self.primitive_ids.bool {
|
} else if ty_id == self.primitive_ids.bool {
|
||||||
Ok(Ok((primitives.bool, true)))
|
Ok(Some(primitives.bool))
|
||||||
} else if ty_id == self.primitive_ids.float {
|
} else if ty_id == self.primitive_ids.float {
|
||||||
Ok(Ok((primitives.float, true)))
|
Ok(Some(primitives.float))
|
||||||
} else if ty_id == self.primitive_ids.list {
|
} else if ty_id == self.primitive_ids.list {
|
||||||
// do not handle type var param and concrete check here
|
let len: usize = self.helper.len_fn.call1(py, (obj,))?.extract(py)?;
|
||||||
|
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(Ok((list, false)))
|
Ok(Some(list))
|
||||||
|
} else {
|
||||||
|
let ty = self.get_list_elem_type(py, obj, len, unifier, defs, primitives)?;
|
||||||
|
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 {
|
||||||
// do not handle type var param and concrete check here
|
let elements: &PyTuple = obj.cast_as()?;
|
||||||
Ok(Ok((unifier.add_ty(TypeEnum::TTuple { ty: vec![] }), false)))
|
let types: Result<Option<Vec<_>>, _> = elements
|
||||||
} else if let Some(def_id) = self.pyid_to_def.read().get(&ty_id).cloned() {
|
.iter()
|
||||||
|
.map(|elem| self.get_obj_type(py, elem, unifier, defs, primitives))
|
||||||
|
.collect();
|
||||||
|
let types = types?;
|
||||||
|
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
|
||||||
|
} else if let Some(def_id) = self.pyid_to_def.read().get(&ty_id) {
|
||||||
let def = defs[def_id.0].read();
|
let def = defs[def_id.0].read();
|
||||||
if let TopLevelDef::Class {
|
if let TopLevelDef::Class {
|
||||||
object_id,
|
object_id,
|
||||||
|
@ -120,283 +183,67 @@ impl Resolver {
|
||||||
..
|
..
|
||||||
} = &*def
|
} = &*def
|
||||||
{
|
{
|
||||||
// do not handle type var param and concrete check here, and no subst
|
let var_map: HashMap<_, _> = type_vars
|
||||||
Ok(Ok({
|
|
||||||
let ty = TypeEnum::TObj {
|
|
||||||
obj_id: *object_id,
|
|
||||||
params: RefCell::new({
|
|
||||||
type_vars
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| {
|
.map(|var| {
|
||||||
if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*x) {
|
(
|
||||||
(*id, *x)
|
if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*var) {
|
||||||
} else { unreachable!() }
|
*id
|
||||||
}).collect()
|
|
||||||
}),
|
|
||||||
fields: RefCell::new({
|
|
||||||
let mut res = methods
|
|
||||||
.iter()
|
|
||||||
.map(|(iden, ty, _)| (*iden, (*ty, false)))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
res.extend(fields.clone().into_iter().map(|x| (x.0, (x.1, x.2))));
|
|
||||||
res
|
|
||||||
})
|
|
||||||
};
|
|
||||||
// here also false, later insta use python object to check compatible
|
|
||||||
(unifier.add_ty(ty), false)
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
// only object is supported, functions are not supported
|
|
||||||
unreachable!("function type is not supported, should not be queried")
|
|
||||||
}
|
|
||||||
} else if ty_ty_id == self.primitive_ids.typevar {
|
|
||||||
let constraint_types = {
|
|
||||||
let constraints = pyty.getattr("__constraints__").unwrap();
|
|
||||||
let mut result: Vec<Type> = vec![];
|
|
||||||
for i in 0.. {
|
|
||||||
if let Ok(constr) = constraints.get_item(i) {
|
|
||||||
result.push({
|
|
||||||
match self.get_pyty_obj_type(constr, helper, unifier, defs, primitives)? {
|
|
||||||
Ok((ty, _)) => {
|
|
||||||
if unifier.is_concrete(ty, &[]) {
|
|
||||||
ty
|
|
||||||
} else {
|
|
||||||
return Ok(Err(format!(
|
|
||||||
"the {}th constraint of TypeVar `{}` is not concrete",
|
|
||||||
i + 1,
|
|
||||||
pyty.getattr("__name__")?.extract::<String>()?
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(err) => return Ok(Err(err))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result
|
|
||||||
};
|
|
||||||
let res = unifier.get_fresh_var_with_range(&constraint_types).0;
|
|
||||||
Ok(Ok((res, true)))
|
|
||||||
} else if ty_ty_id == self.primitive_ids.generic_alias.0 || ty_ty_id == self.primitive_ids.generic_alias.1 {
|
|
||||||
let origin = helper.origin_ty_fn.call1((pyty,))?;
|
|
||||||
let args: &PyTuple = helper.args_ty_fn.call1((pyty,))?.cast_as()?;
|
|
||||||
let origin_ty = match self.get_pyty_obj_type(origin, helper, unifier, defs, primitives)? {
|
|
||||||
Ok((ty, false)) => ty,
|
|
||||||
Ok((_, true)) => return Ok(Err("instantiated type does not take type parameters".into())),
|
|
||||||
Err(err) => return Ok(Err(err))
|
|
||||||
};
|
|
||||||
|
|
||||||
match &*unifier.get_ty(origin_ty) {
|
|
||||||
TypeEnum::TList { .. } => {
|
|
||||||
if args.len() == 1 {
|
|
||||||
let ty = match self.get_pyty_obj_type(args.get_item(0), helper, unifier, defs, primitives)? {
|
|
||||||
Ok(ty) => ty,
|
|
||||||
Err(err) => return Ok(Err(err))
|
|
||||||
};
|
|
||||||
if !unifier.is_concrete(ty.0, &[]) && !ty.1 {
|
|
||||||
panic!("type list should take concrete parameters in type var ranges")
|
|
||||||
}
|
|
||||||
Ok(Ok((unifier.add_ty(TypeEnum::TList { ty: ty.0 }), true)))
|
|
||||||
} else {
|
|
||||||
return Ok(Err(format!("type list needs exactly 1 type parameters, found {}", args.len())))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
TypeEnum::TTuple { .. } => {
|
|
||||||
let args = match args
|
|
||||||
.iter()
|
|
||||||
.map(|x| self.get_pyty_obj_type(x, helper, unifier, defs, primitives))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<_>, _>>() {
|
|
||||||
Ok(args) if !args.is_empty() => args
|
|
||||||
.into_iter()
|
|
||||||
.map(|(x, check)| if !unifier.is_concrete(x, &[]) && !check {
|
|
||||||
panic!("type tuple should take concrete parameters in type var ranges")
|
|
||||||
} else {
|
|
||||||
x
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
Err(err) => return Ok(Err(err)),
|
|
||||||
_ => return Ok(Err("tuple type needs at least 1 type parameters".to_string()))
|
|
||||||
};
|
|
||||||
Ok(Ok((unifier.add_ty(TypeEnum::TTuple { ty: args }), true)))
|
|
||||||
},
|
|
||||||
TypeEnum::TObj { params, obj_id, .. } => {
|
|
||||||
let subst = {
|
|
||||||
let params = &*params.borrow();
|
|
||||||
if params.len() != args.len() {
|
|
||||||
return Ok(Err(format!(
|
|
||||||
"for class #{}, expect {} type parameters, got {}.",
|
|
||||||
obj_id.0,
|
|
||||||
params.len(),
|
|
||||||
args.len(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
let args = match args
|
|
||||||
.iter()
|
|
||||||
.map(|x| self.get_pyty_obj_type(x, helper, unifier, defs, primitives))
|
|
||||||
.collect::<Result<Vec<_>, _>>()?
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Result<Vec<_>, _>>() {
|
|
||||||
Ok(args) => args
|
|
||||||
.into_iter()
|
|
||||||
.map(|(x, check)| if !unifier.is_concrete(x, &[]) && !check {
|
|
||||||
panic!("type class should take concrete parameters in type var ranges")
|
|
||||||
} else {
|
|
||||||
x
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
Err(err) => return Ok(Err(err)),
|
|
||||||
};
|
|
||||||
params
|
|
||||||
.iter()
|
|
||||||
.zip(args.iter())
|
|
||||||
.map(|((id, _), ty)| (*id, *ty))
|
|
||||||
.collect::<HashMap<_, _>>()
|
|
||||||
};
|
|
||||||
Ok(Ok((unifier.subst(origin_ty, &subst).unwrap_or(origin_ty), true)))
|
|
||||||
},
|
|
||||||
TypeEnum::TVirtual { .. } => {
|
|
||||||
if args.len() == 1 {
|
|
||||||
let ty = match self.get_pyty_obj_type(args.get_item(0), helper, unifier, defs, primitives)? {
|
|
||||||
Ok(ty) => ty,
|
|
||||||
Err(err) => return Ok(Err(err))
|
|
||||||
};
|
|
||||||
if !unifier.is_concrete(ty.0, &[]) && !ty.1 {
|
|
||||||
panic!("virtual class should take concrete parameters in type var ranges")
|
|
||||||
}
|
|
||||||
Ok(Ok((unifier.add_ty(TypeEnum::TVirtual { ty: ty.0 }), true)))
|
|
||||||
} else {
|
|
||||||
return Ok(Err(format!("virtual class needs exactly 1 type parameters, found {}", args.len())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unimplemented!()
|
|
||||||
}
|
|
||||||
} else if ty_id == self.primitive_ids.virtual_id {
|
|
||||||
Ok(Ok(({
|
|
||||||
let ty = TypeEnum::TVirtual { ty: unifier.get_fresh_var().0 };
|
|
||||||
unifier.add_ty(ty)
|
|
||||||
}, false)))
|
|
||||||
} else {
|
|
||||||
Ok(Err("unknown type".into()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_obj_type(
|
|
||||||
&self,
|
|
||||||
obj: &PyAny,
|
|
||||||
helper: &PythonHelper,
|
|
||||||
unifier: &mut Unifier,
|
|
||||||
defs: &[Arc<RwLock<TopLevelDef>>],
|
|
||||||
primitives: &PrimitiveStore,
|
|
||||||
) -> PyResult<Option<Type>> {
|
|
||||||
let (extracted_ty, inst_check) = match self.get_pyty_obj_type(
|
|
||||||
{
|
|
||||||
let ty = helper.type_fn.call1((obj,)).unwrap();
|
|
||||||
if [self.primitive_ids.typevar,
|
|
||||||
self.primitive_ids.generic_alias.0,
|
|
||||||
self.primitive_ids.generic_alias.1
|
|
||||||
].contains(&helper.id_fn.call1((ty,))?.extract::<u64>()?) {
|
|
||||||
obj
|
|
||||||
} else {
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
},
|
|
||||||
helper,
|
|
||||||
unifier,
|
|
||||||
defs,
|
|
||||||
primitives
|
|
||||||
)? {
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(_) => return Ok(None)
|
|
||||||
};
|
|
||||||
return match (&*unifier.get_ty(extracted_ty), inst_check) {
|
|
||||||
// do the instantiation for these three types
|
|
||||||
(TypeEnum::TList { ty }, false) => {
|
|
||||||
let len: usize = helper.len_fn.call1((obj,))?.extract()?;
|
|
||||||
if len == 0 {
|
|
||||||
assert!(matches!(
|
|
||||||
&*unifier.get_ty(extracted_ty),
|
|
||||||
TypeEnum::TVar { meta: nac3core::typecheck::typedef::TypeVarMeta::Generic, range, .. }
|
|
||||||
if range.borrow().is_empty()
|
|
||||||
));
|
|
||||||
Ok(Some(extracted_ty))
|
|
||||||
} else {
|
|
||||||
let actual_ty = self
|
|
||||||
.get_list_elem_type(obj, len, helper, unifier, defs, primitives)?;
|
|
||||||
if let Some(actual_ty) = actual_ty {
|
|
||||||
unifier.unify(*ty, actual_ty).unwrap();
|
|
||||||
Ok(Some(extracted_ty))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(TypeEnum::TTuple { .. }, false) => {
|
|
||||||
let elements: &PyTuple = obj.cast_as()?;
|
|
||||||
let types: Result<Option<Vec<_>>, _> = elements
|
|
||||||
.iter()
|
|
||||||
.map(|elem| self.get_obj_type(elem, helper, unifier, defs, primitives))
|
|
||||||
.collect();
|
|
||||||
let types = types?;
|
|
||||||
Ok(types.map(|types| unifier.add_ty(TypeEnum::TTuple { ty: types })))
|
|
||||||
}
|
|
||||||
(TypeEnum::TObj { params, fields, .. }, false) => {
|
|
||||||
let var_map = params
|
|
||||||
.borrow()
|
|
||||||
.iter()
|
|
||||||
.map(|(id_var, ty)| {
|
|
||||||
if let TypeEnum::TVar { id, range, .. } = &*unifier.get_ty(*ty) {
|
|
||||||
assert_eq!(*id, *id_var);
|
|
||||||
(*id, unifier.get_fresh_var_with_range(&range.borrow()).0)
|
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
},
|
||||||
|
unifier.get_fresh_var().0,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
.collect::<HashMap<_, _>>();
|
.collect();
|
||||||
// loop through non-function fields of the class to get the instantiated value
|
let mut fields_ty = HashMap::new();
|
||||||
for field in fields.borrow().iter() {
|
for method in methods.iter() {
|
||||||
let name: String = (*field.0).into();
|
fields_ty.insert(method.0, (method.1, false));
|
||||||
if let TypeEnum::TFunc( .. ) = &*unifier.get_ty(field.1.0) {
|
}
|
||||||
continue;
|
for field in fields.iter() {
|
||||||
} else {
|
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.0, &var_map).unwrap_or(field.1.0);
|
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() {
|
||||||
// field type mismatch
|
// field type mismatch
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
}
|
fields_ty.insert(field.0, (ty, field.2));
|
||||||
}
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(Some(unifier.subst(extracted_ty, &var_map).unwrap_or(extracted_ty)));
|
Ok(Some(unifier.add_ty(TypeEnum::TObj {
|
||||||
|
obj_id: *object_id,
|
||||||
|
fields: RefCell::new(fields_ty),
|
||||||
|
params: RefCell::new(var_map),
|
||||||
|
})))
|
||||||
|
} else {
|
||||||
|
// only object is supported, functions are not supported
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
_ => Ok(Some(extracted_ty))
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()))
|
||||||
|
@ -412,16 +259,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,
|
||||||
|
@ -453,7 +300,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();
|
||||||
|
@ -514,15 +361,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,
|
||||||
|
@ -548,7 +395,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);
|
||||||
|
@ -558,17 +405,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)
|
||||||
|
@ -597,7 +438,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?;
|
||||||
|
@ -617,11 +458,16 @@ impl Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_default_param_obj_value(&self, obj: &PyAny, helper: &PythonHelper) -> PyResult<Result<SymbolValue, String>> {
|
fn get_default_param_obj_value(
|
||||||
let ty_id: u64 = helper
|
&self,
|
||||||
|
py: Python,
|
||||||
|
obj: &PyAny,
|
||||||
|
) -> PyResult<Result<SymbolValue, String>> {
|
||||||
|
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)?;
|
||||||
Ok(
|
Ok(
|
||||||
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()?;
|
||||||
|
@ -639,35 +485,26 @@ impl Resolver {
|
||||||
let elements: &PyTuple = obj.cast_as()?;
|
let elements: &PyTuple = obj.cast_as()?;
|
||||||
let elements: Result<Result<Vec<_>, String>, _> = elements
|
let elements: Result<Result<Vec<_>, String>, _> = elements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|elem| {
|
.map(|elem| self.get_default_param_obj_value(py, elem))
|
||||||
self.get_default_param_obj_value(
|
|
||||||
elem,
|
|
||||||
helper
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
let elements = match elements? {
|
let elements = match elements? {
|
||||||
Ok(el) => el,
|
Ok(el) => el,
|
||||||
Err(err) => return Ok(Err(err))
|
Err(err) => return Ok(Err(err)),
|
||||||
};
|
};
|
||||||
Ok(SymbolValue::Tuple(elements))
|
Ok(SymbolValue::Tuple(elements))
|
||||||
} else {
|
} else {
|
||||||
Err("only primitives values and tuple can be default parameter value".into())
|
Err("only primitives values and tuple can be default parameter value".into())
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SymbolResolver for Resolver {
|
impl SymbolResolver for Resolver {
|
||||||
fn get_default_param_value(
|
fn get_default_param_value(&self, expr: &ast::Expr) -> Option<SymbolValue> {
|
||||||
&self,
|
|
||||||
expr: &ast::Expr
|
|
||||||
) -> Option<SymbolValue> {
|
|
||||||
match &expr.node {
|
match &expr.node {
|
||||||
ast::ExprKind::Name { id, .. } => {
|
ast::ExprKind::Name { id, .. } => {
|
||||||
Python::with_gil(
|
Python::with_gil(|py| -> PyResult<Option<SymbolValue>> {
|
||||||
|py| -> PyResult<Option<SymbolValue>> {
|
let obj: &PyAny = self.0.module.extract(py)?;
|
||||||
let obj: &PyAny = self.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,))?
|
||||||
|
@ -677,25 +514,20 @@ 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")?;
|
sym_value = Some(
|
||||||
let typings = PyModule::import(py, "typing")?;
|
self.0
|
||||||
let helper = PythonHelper {
|
.get_default_param_obj_value(py, val)
|
||||||
id_fn: builtins.getattr("id").unwrap(),
|
.unwrap()
|
||||||
len_fn: builtins.getattr("len").unwrap(),
|
.unwrap(),
|
||||||
type_fn: builtins.getattr("type").unwrap(),
|
);
|
||||||
origin_ty_fn: typings.getattr("get_origin").unwrap(),
|
|
||||||
args_ty_fn: typings.getattr("get_args").unwrap(),
|
|
||||||
};
|
|
||||||
sym_value = Some(self.get_default_param_obj_value(val, &helper).unwrap().unwrap());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(sym_value)
|
Ok(sym_value)
|
||||||
}
|
})
|
||||||
)
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
_ => unimplemented!("other type of expr not supported at {}", expr.location)
|
_ => unimplemented!("other type of expr not supported at {}", expr.location),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -706,13 +538,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,))?
|
||||||
|
@ -721,18 +553,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 typings = PyModule::import(py, "typing")?;
|
py,
|
||||||
let helper = PythonHelper {
|
|
||||||
id_fn: builtins.getattr("id").unwrap(),
|
|
||||||
len_fn: builtins.getattr("len").unwrap(),
|
|
||||||
type_fn: builtins.getattr("type").unwrap(),
|
|
||||||
origin_ty_fn: typings.getattr("get_origin").unwrap(),
|
|
||||||
args_ty_fn: typings.getattr("get_args").unwrap(),
|
|
||||||
};
|
|
||||||
sym_ty = self.get_obj_type(
|
|
||||||
member.get_item(1)?,
|
member.get_item(1)?,
|
||||||
&helper,
|
|
||||||
unifier,
|
unifier,
|
||||||
defs,
|
defs,
|
||||||
primitives,
|
primitives,
|
||||||
|
@ -755,10 +578,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<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
Python::with_gil(|py| -> PyResult<Option<BasicValueEnum<'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,))?
|
||||||
|
@ -768,20 +591,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 typings = PyModule::import(py, "typing")?;
|
sym_value = Some(PythonValue {
|
||||||
let helper = PythonHelper {
|
id,
|
||||||
id_fn: builtins.getattr("id").unwrap(),
|
value: val.extract()?,
|
||||||
len_fn: builtins.getattr("len").unwrap(),
|
resolver: self.0.clone(),
|
||||||
type_fn: builtins.getattr("type").unwrap(),
|
});
|
||||||
origin_ty_fn: typings.getattr("get_origin").unwrap(),
|
|
||||||
args_ty_fn: typings.getattr("get_args").unwrap(),
|
|
||||||
};
|
|
||||||
sym_value = self.get_obj_value(val, &helper, ctx)?;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(sym_value)
|
Ok(sym_value.map(|v| ValueEnum::Static(Arc::new(v))))
|
||||||
})
|
})
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -791,10 +610,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use crate::{
|
||||||
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
concrete_type::{ConcreteFuncArg, ConcreteTypeEnum, ConcreteTypeStore},
|
||||||
get_llvm_type, CodeGenContext, CodeGenTask,
|
get_llvm_type, CodeGenContext, CodeGenTask,
|
||||||
},
|
},
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::{SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
typecheck::typedef::{FunSignature, FuncArg, Type, TypeEnum, Unifier},
|
||||||
};
|
};
|
||||||
|
@ -15,9 +15,7 @@ use inkwell::{
|
||||||
AddressSpace,
|
AddressSpace,
|
||||||
};
|
};
|
||||||
use itertools::{chain, izip, zip, Itertools};
|
use itertools::{chain, izip, zip, Itertools};
|
||||||
use nac3parser::ast::{
|
use nac3parser::ast::{self, Boolop, Comprehension, Constant, Expr, ExprKind, Operator, StrRef};
|
||||||
self, Boolop, Comprehension, Constant, Expr, ExprKind, Operator, StrRef,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::CodeGenerator;
|
use super::CodeGenerator;
|
||||||
|
|
||||||
|
@ -231,7 +229,7 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
signature: &FunSignature,
|
signature: &FunSignature,
|
||||||
def: &TopLevelDef,
|
def: &TopLevelDef,
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
match def {
|
match def {
|
||||||
TopLevelDef::Class { methods, .. } => {
|
TopLevelDef::Class { methods, .. } => {
|
||||||
|
@ -244,12 +242,17 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
let ty = ctx.get_llvm_type(signature.ret).into_pointer_type();
|
let ty = ctx.get_llvm_type(signature.ret).into_pointer_type();
|
||||||
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
let zelf_ty: BasicTypeEnum = ty.get_element_type().try_into().unwrap();
|
||||||
let zelf = ctx.builder.build_alloca(zelf_ty, "alloca").into();
|
let zelf: BasicValueEnum<'ctx> = ctx.builder.build_alloca(zelf_ty, "alloca").into();
|
||||||
// call `__init__` if there is one
|
// call `__init__` if there is one
|
||||||
if let Some(fun_id) = fun_id {
|
if let Some(fun_id) = fun_id {
|
||||||
let mut sign = signature.clone();
|
let mut sign = signature.clone();
|
||||||
sign.ret = ctx.primitives.none;
|
sign.ret = ctx.primitives.none;
|
||||||
generator.gen_call(ctx, Some((signature.ret, zelf)), (&sign, fun_id), params);
|
generator.gen_call(
|
||||||
|
ctx,
|
||||||
|
Some((signature.ret, zelf.into())),
|
||||||
|
(&sign, fun_id),
|
||||||
|
params,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
zelf
|
zelf
|
||||||
}
|
}
|
||||||
|
@ -259,8 +262,9 @@ pub fn gen_constructor<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
|
|
||||||
pub fn gen_func_instance<'ctx, 'a>(
|
pub fn gen_func_instance<'ctx, 'a>(
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, &mut TopLevelDef, String),
|
fun: (&FunSignature, &mut TopLevelDef, String),
|
||||||
|
id: usize,
|
||||||
) -> String {
|
) -> String {
|
||||||
if let (
|
if let (
|
||||||
sign,
|
sign,
|
||||||
|
@ -272,8 +276,8 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
{
|
{
|
||||||
instance_to_symbol.get(&key).cloned().unwrap_or_else(|| {
|
instance_to_symbol.get(&key).cloned().unwrap_or_else(|| {
|
||||||
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
let symbol = format!("{}.{}", name, instance_to_symbol.len());
|
||||||
instance_to_symbol.insert(key, symbol.clone());
|
instance_to_symbol.insert(key.clone(), symbol.clone());
|
||||||
let key = ctx.get_subst_key(obj.map(|a| a.0), sign, Some(var_id));
|
let key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), sign, Some(var_id));
|
||||||
let instance = instance_to_stmt.get(&key).unwrap();
|
let instance = instance_to_stmt.get(&key).unwrap();
|
||||||
|
|
||||||
let mut store = ConcreteTypeStore::new();
|
let mut store = ConcreteTypeStore::new();
|
||||||
|
@ -316,6 +320,7 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
signature,
|
signature,
|
||||||
store,
|
store,
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
|
id,
|
||||||
});
|
});
|
||||||
symbol
|
symbol
|
||||||
})
|
})
|
||||||
|
@ -327,20 +332,86 @@ pub fn gen_func_instance<'ctx, 'a>(
|
||||||
pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, DefinitionId),
|
fun: (&FunSignature, DefinitionId),
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
let definition = ctx.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
let definition = ctx.top_level.definitions.read().get(fun.1 .0).cloned().unwrap();
|
||||||
let key = ctx.get_subst_key(obj.map(|a| a.0), fun.0, None);
|
|
||||||
|
let id;
|
||||||
|
let key;
|
||||||
|
let param_vals;
|
||||||
let symbol = {
|
let symbol = {
|
||||||
// make sure this lock guard is dropped at the end of this scope...
|
// make sure this lock guard is dropped at the end of this scope...
|
||||||
let def = definition.read();
|
let def = definition.read();
|
||||||
match &*def {
|
match &*def {
|
||||||
TopLevelDef::Function { instance_to_symbol, codegen_callback, .. } => {
|
TopLevelDef::Function {
|
||||||
|
instance_to_symbol,
|
||||||
|
instance_to_stmt,
|
||||||
|
codegen_callback,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
if let Some(callback) = codegen_callback {
|
if let Some(callback) = codegen_callback {
|
||||||
|
// TODO: Change signature
|
||||||
|
let obj = obj.map(|(t, v)| (t, v.to_basic_value_enum(ctx)));
|
||||||
|
let params = params
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, val)| (name, val.to_basic_value_enum(ctx)))
|
||||||
|
.collect();
|
||||||
return callback.run(ctx, obj, fun, params);
|
return callback.run(ctx, obj, fun, params);
|
||||||
}
|
}
|
||||||
|
let old_key = ctx.get_subst_key(obj.as_ref().map(|a| a.0), fun.0, None);
|
||||||
|
let mut keys = fun.0.args.clone();
|
||||||
|
let mut mapping = HashMap::new();
|
||||||
|
for (key, value) in params.into_iter() {
|
||||||
|
mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value);
|
||||||
|
}
|
||||||
|
// default value handling
|
||||||
|
for k in keys.into_iter() {
|
||||||
|
mapping.insert(k.name, ctx.gen_symbol_val(&k.default_value.unwrap()).into());
|
||||||
|
}
|
||||||
|
// reorder the parameters
|
||||||
|
let mut real_params =
|
||||||
|
fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
|
||||||
|
if let Some(obj) = &obj {
|
||||||
|
real_params.insert(0, obj.1.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let static_params = real_params
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(i, v)| {
|
||||||
|
if let ValueEnum::Static(s) = v {
|
||||||
|
Some((i, s.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
id = {
|
||||||
|
let ids = static_params
|
||||||
|
.iter()
|
||||||
|
.map(|(i, v)| (*i, v.get_unique_identifier()))
|
||||||
|
.collect_vec();
|
||||||
|
let mut store = ctx.static_value_store.lock();
|
||||||
|
match store.lookup.get(&ids) {
|
||||||
|
Some(index) => *index,
|
||||||
|
None => {
|
||||||
|
let length = store.store.len();
|
||||||
|
store.lookup.insert(ids, length);
|
||||||
|
store.store.push(static_params.into_iter().collect());
|
||||||
|
length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// special case: extern functions
|
||||||
|
key = if instance_to_stmt.is_empty() {
|
||||||
|
"".to_string()
|
||||||
|
} else {
|
||||||
|
format!("{}:{}", id, old_key)
|
||||||
|
};
|
||||||
|
param_vals =
|
||||||
|
real_params.into_iter().map(|p| p.to_basic_value_enum(ctx)).collect_vec();
|
||||||
instance_to_symbol.get(&key).cloned()
|
instance_to_symbol.get(&key).cloned()
|
||||||
}
|
}
|
||||||
TopLevelDef::Class { .. } => {
|
TopLevelDef::Class { .. } => {
|
||||||
|
@ -349,7 +420,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
generator.gen_func_instance(ctx, obj, (fun.0, &mut *definition.write(), key))
|
generator.gen_func_instance(ctx, obj.clone(), (fun.0, &mut *definition.write(), key), id)
|
||||||
});
|
});
|
||||||
let fun_val = ctx.module.get_function(&symbol).unwrap_or_else(|| {
|
let fun_val = ctx.module.get_function(&symbol).unwrap_or_else(|| {
|
||||||
let mut args = fun.0.args.clone();
|
let mut args = fun.0.args.clone();
|
||||||
|
@ -364,21 +435,7 @@ pub fn gen_call<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
};
|
};
|
||||||
ctx.module.add_function(&symbol, fun_ty, None)
|
ctx.module.add_function(&symbol, fun_ty, None)
|
||||||
});
|
});
|
||||||
let mut keys = fun.0.args.clone();
|
ctx.builder.build_call(fun_val, ¶m_vals, "call").try_as_basic_value().left()
|
||||||
let mut mapping = HashMap::new();
|
|
||||||
for (key, value) in params.into_iter() {
|
|
||||||
mapping.insert(key.unwrap_or_else(|| keys.remove(0).name), value);
|
|
||||||
}
|
|
||||||
// default value handling
|
|
||||||
for k in keys.into_iter() {
|
|
||||||
mapping.insert(k.name, ctx.gen_symbol_val(&k.default_value.unwrap()));
|
|
||||||
}
|
|
||||||
// reorder the parameters
|
|
||||||
let mut params = fun.0.args.iter().map(|arg| mapping.remove(&arg.name).unwrap()).collect_vec();
|
|
||||||
if let Some(obj) = obj {
|
|
||||||
params.insert(0, obj.1);
|
|
||||||
}
|
|
||||||
ctx.builder.build_call(fun_val, ¶ms, "call").try_as_basic_value().left()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destructure_range<'ctx, 'a>(
|
pub fn destructure_range<'ctx, 'a>(
|
||||||
|
@ -435,7 +492,7 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
|
|
||||||
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
let Comprehension { target, iter, ifs, .. } = &generators[0];
|
||||||
let iter_val = generator.gen_expr(ctx, iter).unwrap();
|
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx);
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
|
|
||||||
|
@ -534,10 +591,11 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
)
|
)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
||||||
generator.gen_assign(ctx, target, val);
|
generator.gen_assign(ctx, target, val.into());
|
||||||
}
|
}
|
||||||
for cond in ifs.iter() {
|
for cond in ifs.iter() {
|
||||||
let result = generator.gen_expr(ctx, cond).unwrap().into_int_value();
|
let result =
|
||||||
|
generator.gen_expr(ctx, cond).unwrap().to_basic_value_enum(ctx).into_int_value();
|
||||||
let succ = ctx.ctx.append_basic_block(current, "then");
|
let succ = ctx.ctx.append_basic_block(current, "then");
|
||||||
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
ctx.builder.build_conditional_branch(result, succ, test_bb);
|
||||||
ctx.builder.position_at_end(succ);
|
ctx.builder.position_at_end(succ);
|
||||||
|
@ -545,7 +603,8 @@ pub fn gen_comprehension<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let elem = generator.gen_expr(ctx, elt).unwrap();
|
let elem = generator.gen_expr(ctx, elt).unwrap();
|
||||||
let i = ctx.builder.build_load(index, "i").into_int_value();
|
let i = ctx.builder.build_load(index, "i").into_int_value();
|
||||||
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
let elem_ptr = unsafe { ctx.builder.build_gep(list_content, &[i], "elem_ptr") };
|
||||||
ctx.builder.build_store(elem_ptr, elem);
|
let val = elem.to_basic_value_enum(ctx);
|
||||||
|
ctx.builder.build_store(elem_ptr, val);
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_store(index, ctx.builder.build_int_add(i, int32.const_int(1, false), "inc"));
|
.build_store(index, ctx.builder.build_int_add(i, int32.const_int(1, false), "inc"));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
|
@ -562,27 +621,29 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_int(0, false);
|
let zero = int32.const_int(0, false);
|
||||||
Some(match &expr.node {
|
Some(match &expr.node {
|
||||||
ExprKind::Constant { value, .. } => {
|
ExprKind::Constant { value, .. } => {
|
||||||
let ty = expr.custom.unwrap();
|
let ty = expr.custom.unwrap();
|
||||||
ctx.gen_const(value, ty)
|
ctx.gen_const(value, ty).into()
|
||||||
}
|
}
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
||||||
let ptr = ctx.var_assignment.get(id);
|
Some((ptr, None, _)) => ctx.builder.build_load(*ptr, "load").into(),
|
||||||
if let Some(ptr) = ptr {
|
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
||||||
ctx.builder.build_load(*ptr, "load")
|
None => {
|
||||||
} else {
|
|
||||||
let resolver = ctx.resolver.clone();
|
let resolver = ctx.resolver.clone();
|
||||||
resolver.get_symbol_value(*id, ctx).unwrap()
|
resolver.get_symbol_value(*id, ctx).unwrap()
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ExprKind::List { elts, .. } => {
|
ExprKind::List { elts, .. } => {
|
||||||
// this shall be optimized later for constant primitive lists...
|
// this shall be optimized later for constant primitive lists...
|
||||||
// we should use memcpy for that instead of generating thousands of stores
|
// we should use memcpy for that instead of generating thousands of stores
|
||||||
let elements = elts.iter().map(|x| generator.gen_expr(ctx, x).unwrap()).collect_vec();
|
let elements = elts
|
||||||
|
.iter()
|
||||||
|
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx))
|
||||||
|
.collect_vec();
|
||||||
let ty = if elements.is_empty() { int32.into() } else { elements[0].get_type() };
|
let ty = if elements.is_empty() { int32.into() } else { elements[0].get_type() };
|
||||||
let length = int32.const_int(elements.len() as u64, false);
|
let length = int32.const_int(elements.len() as u64, false);
|
||||||
let arr_str_ptr = allocate_list(ctx, ty, length);
|
let arr_str_ptr = allocate_list(ctx, ty, length);
|
||||||
|
@ -602,8 +663,10 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
arr_str_ptr.into()
|
arr_str_ptr.into()
|
||||||
}
|
}
|
||||||
ExprKind::Tuple { elts, .. } => {
|
ExprKind::Tuple { elts, .. } => {
|
||||||
let element_val =
|
let element_val = elts
|
||||||
elts.iter().map(|x| generator.gen_expr(ctx, x).unwrap()).collect_vec();
|
.iter()
|
||||||
|
.map(|x| generator.gen_expr(ctx, x).unwrap().to_basic_value_enum(ctx))
|
||||||
|
.collect_vec();
|
||||||
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
let element_ty = element_val.iter().map(BasicValueEnum::get_type).collect_vec();
|
||||||
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
let tuple_ty = ctx.ctx.struct_type(&element_ty, false);
|
||||||
let tuple_ptr = ctx.builder.build_alloca(tuple_ty, "tuple");
|
let tuple_ptr = ctx.builder.build_alloca(tuple_ty, "tuple");
|
||||||
|
@ -621,13 +684,31 @@ 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() {
|
||||||
|
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);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let ptr = generator.gen_expr(ctx, value).unwrap().into_pointer_value();
|
ValueEnum::Dynamic(ctx.build_gep_and_load(
|
||||||
ctx.build_gep_and_load(ptr, &[zero, int32.const_int(index as u64, false)])
|
v.into_pointer_value(),
|
||||||
|
&[zero, int32.const_int(index as u64, false)],
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
ValueEnum::Dynamic(v) => {
|
||||||
|
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)],
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ExprKind::BoolOp { op, values } => {
|
ExprKind::BoolOp { op, values } => {
|
||||||
// requires conditional branches for short-circuiting...
|
// requires conditional branches for short-circuiting...
|
||||||
let left = generator.gen_expr(ctx, &values[0]).unwrap().into_int_value();
|
let left = generator
|
||||||
|
.gen_expr(ctx, &values[0])
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_int_value();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
let a_bb = ctx.ctx.append_basic_block(current, "a");
|
||||||
let b_bb = ctx.ctx.append_basic_block(current, "b");
|
let b_bb = ctx.ctx.append_basic_block(current, "b");
|
||||||
|
@ -639,13 +720,21 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let a = ctx.ctx.bool_type().const_int(1, false);
|
let a = ctx.ctx.bool_type().const_int(1, false);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = generator.gen_expr(ctx, &values[1]).unwrap().into_int_value();
|
let b = generator
|
||||||
|
.gen_expr(ctx, &values[1])
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
(a, b)
|
(a, b)
|
||||||
}
|
}
|
||||||
Boolop::And => {
|
Boolop::And => {
|
||||||
ctx.builder.position_at_end(a_bb);
|
ctx.builder.position_at_end(a_bb);
|
||||||
let a = generator.gen_expr(ctx, &values[1]).unwrap().into_int_value();
|
let a = generator
|
||||||
|
.gen_expr(ctx, &values[1])
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_int_value();
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(b_bb);
|
ctx.builder.position_at_end(b_bb);
|
||||||
let b = ctx.ctx.bool_type().const_int(0, false);
|
let b = ctx.ctx.bool_type().const_int(0, false);
|
||||||
|
@ -656,13 +745,13 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(ctx.ctx.bool_type(), "phi");
|
let phi = ctx.builder.build_phi(ctx.ctx.bool_type(), "phi");
|
||||||
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
phi.add_incoming(&[(&a, a_bb), (&b, b_bb)]);
|
||||||
phi.as_basic_value()
|
phi.as_basic_value().into()
|
||||||
}
|
}
|
||||||
ExprKind::BinOp { op, left, right } => {
|
ExprKind::BinOp { op, left, right } => {
|
||||||
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(left.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(right.custom.unwrap());
|
||||||
let left = generator.gen_expr(ctx, left).unwrap();
|
let left = generator.gen_expr(ctx, left).unwrap().to_basic_value_enum(ctx);
|
||||||
let right = generator.gen_expr(ctx, right).unwrap();
|
let right = generator.gen_expr(ctx, right).unwrap().to_basic_value_enum(ctx);
|
||||||
|
|
||||||
// we can directly compare the types, because we've got their representatives
|
// we can directly compare the types, because we've got their representatives
|
||||||
// which would be unchanged until further unification, which we would never do
|
// which would be unchanged until further unification, which we would never do
|
||||||
|
@ -674,10 +763,11 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
} else {
|
} else {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
ExprKind::UnaryOp { op, operand } => {
|
ExprKind::UnaryOp { op, operand } => {
|
||||||
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
let ty = ctx.unifier.get_representative(operand.custom.unwrap());
|
||||||
let val = generator.gen_expr(ctx, operand).unwrap();
|
let val = generator.gen_expr(ctx, operand).unwrap().to_basic_value_enum(ctx);
|
||||||
if ty == ctx.primitives.bool {
|
if ty == ctx.primitives.bool {
|
||||||
let val = val.into_int_value();
|
let val = val.into_int_value();
|
||||||
match op {
|
match op {
|
||||||
|
@ -734,8 +824,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
BasicValueEnum::IntValue(lhs),
|
BasicValueEnum::IntValue(lhs),
|
||||||
BasicValueEnum::IntValue(rhs),
|
BasicValueEnum::IntValue(rhs),
|
||||||
) = (
|
) = (
|
||||||
generator.gen_expr(ctx, lhs).unwrap(),
|
generator.gen_expr(ctx, lhs).unwrap().to_basic_value_enum(ctx),
|
||||||
generator.gen_expr(ctx, rhs).unwrap(),
|
generator.gen_expr(ctx, rhs).unwrap().to_basic_value_enum(ctx),
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -756,8 +846,8 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
BasicValueEnum::FloatValue(lhs),
|
BasicValueEnum::FloatValue(lhs),
|
||||||
BasicValueEnum::FloatValue(rhs),
|
BasicValueEnum::FloatValue(rhs),
|
||||||
) = (
|
) = (
|
||||||
generator.gen_expr(ctx, lhs).unwrap(),
|
generator.gen_expr(ctx, lhs).unwrap().to_basic_value_enum(ctx),
|
||||||
generator.gen_expr(ctx, rhs).unwrap(),
|
generator.gen_expr(ctx, rhs).unwrap().to_basic_value_enum(ctx),
|
||||||
) {
|
) {
|
||||||
(lhs, rhs)
|
(lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
|
@ -782,22 +872,23 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
.into() // as there should be at least 1 element, it should never be none
|
.into() // as there should be at least 1 element, it should never be none
|
||||||
}
|
}
|
||||||
ExprKind::IfExp { test, body, orelse } => {
|
ExprKind::IfExp { test, body, orelse } => {
|
||||||
let test = generator.gen_expr(ctx, test).unwrap().into_int_value();
|
let test =
|
||||||
|
generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx).into_int_value();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
let then_bb = ctx.ctx.append_basic_block(current, "then");
|
||||||
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
let else_bb = ctx.ctx.append_basic_block(current, "else");
|
||||||
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
let cont_bb = ctx.ctx.append_basic_block(current, "cont");
|
||||||
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
ctx.builder.build_conditional_branch(test, then_bb, else_bb);
|
||||||
ctx.builder.position_at_end(then_bb);
|
ctx.builder.position_at_end(then_bb);
|
||||||
let a = generator.gen_expr(ctx, body).unwrap();
|
let a = generator.gen_expr(ctx, body).unwrap().to_basic_value_enum(ctx);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(else_bb);
|
ctx.builder.position_at_end(else_bb);
|
||||||
let b = generator.gen_expr(ctx, orelse).unwrap();
|
let b = generator.gen_expr(ctx, orelse).unwrap().to_basic_value_enum(ctx);
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
let phi = ctx.builder.build_phi(a.get_type(), "ifexpr");
|
||||||
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
|
phi.add_incoming(&[(&a, then_bb), (&b, else_bb)]);
|
||||||
phi.as_basic_value()
|
phi.as_basic_value().into()
|
||||||
}
|
}
|
||||||
ExprKind::Call { func, args, keywords } => {
|
ExprKind::Call { func, args, keywords } => {
|
||||||
let mut params =
|
let mut params =
|
||||||
|
@ -825,7 +916,9 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
ExprKind::Name { id, .. } => {
|
ExprKind::Name { id, .. } => {
|
||||||
// TODO: handle primitive casts and function pointers
|
// TODO: handle primitive casts and function pointers
|
||||||
let fun = ctx.resolver.get_identifier_def(*id).expect("Unknown identifier");
|
let fun = ctx.resolver.get_identifier_def(*id).expect("Unknown identifier");
|
||||||
return generator.gen_call(ctx, None, (&signature, fun), params);
|
return generator
|
||||||
|
.gen_call(ctx, None, (&signature, fun), params)
|
||||||
|
.map(|v| v.into());
|
||||||
}
|
}
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let val = generator.gen_expr(ctx, value).unwrap();
|
let val = generator.gen_expr(ctx, value).unwrap();
|
||||||
|
@ -851,12 +944,14 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return generator.gen_call(
|
return generator
|
||||||
|
.gen_call(
|
||||||
ctx,
|
ctx,
|
||||||
Some((value.custom.unwrap(), val)),
|
Some((value.custom.unwrap(), val)),
|
||||||
(&signature, fun_id),
|
(&signature, fun_id),
|
||||||
params,
|
params,
|
||||||
);
|
)
|
||||||
|
.map(|v| v.into());
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
|
@ -867,19 +962,36 @@ pub fn gen_expr<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
} else {
|
} else {
|
||||||
// TODO: bound check
|
// TODO: bound check
|
||||||
let v = generator.gen_expr(ctx, value).unwrap().into_pointer_value();
|
let v = generator
|
||||||
let index = generator.gen_expr(ctx, slice).unwrap().into_int_value();
|
.gen_expr(ctx, value)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_pointer_value();
|
||||||
|
let index = generator
|
||||||
|
.gen_expr(ctx, slice)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_int_value();
|
||||||
let arr_ptr =
|
let arr_ptr =
|
||||||
ctx.build_gep_and_load(v, &[int32.const_zero(), int32.const_int(1, false)]);
|
ctx.build_gep_and_load(v, &[int32.const_zero(), int32.const_int(1, false)]);
|
||||||
ctx.build_gep_and_load(arr_ptr.into_pointer_value(), &[index])
|
ctx.build_gep_and_load(arr_ptr.into_pointer_value(), &[index])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let v = generator.gen_expr(ctx, value).unwrap().into_pointer_value();
|
let v = generator
|
||||||
let index = generator.gen_expr(ctx, slice).unwrap().into_int_value();
|
.gen_expr(ctx, value)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_pointer_value();
|
||||||
|
let index = generator
|
||||||
|
.gen_expr(ctx, slice)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_int_value();
|
||||||
ctx.build_gep_and_load(v, &[int32.const_zero(), index])
|
ctx.build_gep_and_load(v, &[int32.const_zero(), index])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr),
|
.into(),
|
||||||
|
ExprKind::ListComp { .. } => gen_comprehension(generator, ctx, expr).into(),
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::{expr::*, stmt::*, CodeGenContext},
|
codegen::{expr::*, stmt::*, CodeGenContext},
|
||||||
|
symbol_resolver::ValueEnum,
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::typedef::{FunSignature, Type},
|
typecheck::typedef::{FunSignature, Type},
|
||||||
};
|
};
|
||||||
|
@ -18,9 +19,9 @@ pub trait CodeGenerator {
|
||||||
fn gen_call<'ctx, 'a>(
|
fn gen_call<'ctx, 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, DefinitionId),
|
fun: (&FunSignature, DefinitionId),
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<BasicValueEnum<'ctx>> {
|
||||||
gen_call(self, ctx, obj, fun, params)
|
gen_call(self, ctx, obj, fun, params)
|
||||||
}
|
}
|
||||||
|
@ -34,7 +35,7 @@ pub trait CodeGenerator {
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
signature: &FunSignature,
|
signature: &FunSignature,
|
||||||
def: &TopLevelDef,
|
def: &TopLevelDef,
|
||||||
params: Vec<(Option<StrRef>, BasicValueEnum<'ctx>)>,
|
params: Vec<(Option<StrRef>, ValueEnum<'ctx>)>,
|
||||||
) -> BasicValueEnum<'ctx> {
|
) -> BasicValueEnum<'ctx> {
|
||||||
gen_constructor(self, ctx, signature, def, params)
|
gen_constructor(self, ctx, signature, def, params)
|
||||||
}
|
}
|
||||||
|
@ -49,10 +50,11 @@ pub trait CodeGenerator {
|
||||||
fn gen_func_instance<'ctx, 'a>(
|
fn gen_func_instance<'ctx, 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
obj: Option<(Type, BasicValueEnum<'ctx>)>,
|
obj: Option<(Type, ValueEnum<'ctx>)>,
|
||||||
fun: (&FunSignature, &mut TopLevelDef, String),
|
fun: (&FunSignature, &mut TopLevelDef, String),
|
||||||
|
id: usize,
|
||||||
) -> String {
|
) -> String {
|
||||||
gen_func_instance(ctx, obj, fun)
|
gen_func_instance(ctx, obj, fun, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate the code for an expression.
|
/// Generate the code for an expression.
|
||||||
|
@ -60,7 +62,7 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
expr: &Expr<Option<Type>>,
|
expr: &Expr<Option<Type>>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
gen_expr(self, ctx, expr)
|
gen_expr(self, ctx, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +90,7 @@ pub trait CodeGenerator {
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
target: &Expr<Option<Type>>,
|
target: &Expr<Option<Type>>,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: ValueEnum<'ctx>,
|
||||||
) {
|
) {
|
||||||
gen_assign(self, ctx, target, value)
|
gen_assign(self, ctx, target, value)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::{StaticValue, SymbolResolver},
|
||||||
toplevel::{TopLevelContext, TopLevelDef},
|
toplevel::{TopLevelContext, TopLevelDef},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::{CodeLocation, PrimitiveStore},
|
type_inferencer::{CodeLocation, PrimitiveStore},
|
||||||
|
@ -18,8 +18,8 @@ use inkwell::{
|
||||||
AddressSpace, OptimizationLevel,
|
AddressSpace, OptimizationLevel,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use parking_lot::{Condvar, Mutex};
|
|
||||||
use nac3parser::ast::{Stmt, StrRef};
|
use nac3parser::ast::{Stmt, StrRef};
|
||||||
|
use parking_lot::{Condvar, Mutex};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{
|
use std::sync::{
|
||||||
atomic::{AtomicBool, Ordering},
|
atomic::{AtomicBool, Ordering},
|
||||||
|
@ -29,8 +29,8 @@ use std::thread;
|
||||||
|
|
||||||
pub mod concrete_type;
|
pub mod concrete_type;
|
||||||
pub mod expr;
|
pub mod expr;
|
||||||
pub mod stmt;
|
|
||||||
mod generator;
|
mod generator;
|
||||||
|
pub mod stmt;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
@ -38,6 +38,14 @@ mod test;
|
||||||
use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore};
|
use concrete_type::{ConcreteType, ConcreteTypeEnum, ConcreteTypeStore};
|
||||||
pub use generator::{CodeGenerator, DefaultCodeGenerator};
|
pub use generator::{CodeGenerator, DefaultCodeGenerator};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct StaticValueStore {
|
||||||
|
pub lookup: HashMap<Vec<(usize, u64)>, usize>,
|
||||||
|
pub store: Vec<HashMap<usize, Arc<dyn StaticValue + Send + Sync>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type VarValue<'ctx> = (PointerValue<'ctx>, Option<Arc<dyn StaticValue + Send + Sync>>, i64);
|
||||||
|
|
||||||
pub struct CodeGenContext<'ctx, 'a> {
|
pub struct CodeGenContext<'ctx, 'a> {
|
||||||
pub ctx: &'ctx Context,
|
pub ctx: &'ctx Context,
|
||||||
pub builder: Builder<'ctx>,
|
pub builder: Builder<'ctx>,
|
||||||
|
@ -45,7 +53,8 @@ pub struct CodeGenContext<'ctx, 'a> {
|
||||||
pub top_level: &'a TopLevelContext,
|
pub top_level: &'a TopLevelContext,
|
||||||
pub unifier: Unifier,
|
pub unifier: Unifier,
|
||||||
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||||
pub var_assignment: HashMap<StrRef, PointerValue<'ctx>>,
|
pub static_value_store: Arc<Mutex<StaticValueStore>>,
|
||||||
|
pub var_assignment: HashMap<StrRef, VarValue<'ctx>>,
|
||||||
pub type_cache: HashMap<Type, BasicTypeEnum<'ctx>>,
|
pub type_cache: HashMap<Type, BasicTypeEnum<'ctx>>,
|
||||||
pub primitives: PrimitiveStore,
|
pub primitives: PrimitiveStore,
|
||||||
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
||||||
|
@ -80,6 +89,8 @@ pub struct WorkerRegistry {
|
||||||
task_count: Mutex<usize>,
|
task_count: Mutex<usize>,
|
||||||
thread_count: usize,
|
thread_count: usize,
|
||||||
wait_condvar: Condvar,
|
wait_condvar: Condvar,
|
||||||
|
top_level_ctx: Arc<TopLevelContext>,
|
||||||
|
static_value_store: Arc<Mutex<StaticValueStore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkerRegistry {
|
impl WorkerRegistry {
|
||||||
|
@ -92,23 +103,29 @@ impl WorkerRegistry {
|
||||||
let task_count = Mutex::new(0);
|
let task_count = Mutex::new(0);
|
||||||
let wait_condvar = Condvar::new();
|
let wait_condvar = Condvar::new();
|
||||||
|
|
||||||
|
// init: 0 to be empty
|
||||||
|
let mut static_value_store: StaticValueStore = Default::default();
|
||||||
|
static_value_store.lookup.insert(Default::default(), 0);
|
||||||
|
static_value_store.store.push(Default::default());
|
||||||
|
|
||||||
let registry = Arc::new(WorkerRegistry {
|
let registry = Arc::new(WorkerRegistry {
|
||||||
sender: Arc::new(sender),
|
sender: Arc::new(sender),
|
||||||
receiver: Arc::new(receiver),
|
receiver: Arc::new(receiver),
|
||||||
thread_count: generators.len(),
|
thread_count: generators.len(),
|
||||||
panicked: AtomicBool::new(false),
|
panicked: AtomicBool::new(false),
|
||||||
|
static_value_store: Arc::new(Mutex::new(static_value_store)),
|
||||||
task_count,
|
task_count,
|
||||||
wait_condvar,
|
wait_condvar,
|
||||||
|
top_level_ctx,
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut handles = Vec::new();
|
let mut handles = Vec::new();
|
||||||
for mut generator in generators.into_iter() {
|
for mut generator in generators.into_iter() {
|
||||||
let top_level_ctx = top_level_ctx.clone();
|
|
||||||
let registry = registry.clone();
|
let registry = registry.clone();
|
||||||
let registry2 = registry.clone();
|
let registry2 = registry.clone();
|
||||||
let f = f.clone();
|
let f = f.clone();
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
registry.worker_thread(generator.as_mut(), top_level_ctx, f);
|
registry.worker_thread(generator.as_mut(), f);
|
||||||
});
|
});
|
||||||
let handle = thread::spawn(move || {
|
let handle = thread::spawn(move || {
|
||||||
if let Err(e) = handle.join() {
|
if let Err(e) = handle.join() {
|
||||||
|
@ -161,12 +178,7 @@ impl WorkerRegistry {
|
||||||
self.sender.send(Some(task)).unwrap();
|
self.sender.send(Some(task)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn worker_thread<G: CodeGenerator>(
|
fn worker_thread<G: CodeGenerator>(&self, generator: &mut G, f: Arc<WithCall>) {
|
||||||
&self,
|
|
||||||
generator: &mut G,
|
|
||||||
top_level_ctx: Arc<TopLevelContext>,
|
|
||||||
f: Arc<WithCall>,
|
|
||||||
) {
|
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let mut builder = context.create_builder();
|
let mut builder = context.create_builder();
|
||||||
let mut module = context.create_module(generator.get_name());
|
let mut module = context.create_module(generator.get_name());
|
||||||
|
@ -177,8 +189,7 @@ impl WorkerRegistry {
|
||||||
pass_builder.populate_function_pass_manager(&passes);
|
pass_builder.populate_function_pass_manager(&passes);
|
||||||
|
|
||||||
while let Some(task) = self.receiver.recv().unwrap() {
|
while let Some(task) = self.receiver.recv().unwrap() {
|
||||||
let result =
|
let result = gen_func(&context, generator, self, builder, module, task);
|
||||||
gen_func(&context, generator, self, builder, module, task, top_level_ctx.clone());
|
|
||||||
builder = result.0;
|
builder = result.0;
|
||||||
module = result.1;
|
module = result.1;
|
||||||
passes.run_on(&result.2);
|
passes.run_on(&result.2);
|
||||||
|
@ -208,6 +219,7 @@ pub struct CodeGenTask {
|
||||||
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
pub calls: Arc<HashMap<CodeLocation, CallId>>,
|
||||||
pub unifier_index: usize,
|
pub unifier_index: usize,
|
||||||
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
pub resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||||
|
pub id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_llvm_type<'ctx>(
|
fn get_llvm_type<'ctx>(
|
||||||
|
@ -268,8 +280,9 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
builder: Builder<'ctx>,
|
builder: Builder<'ctx>,
|
||||||
module: Module<'ctx>,
|
module: Module<'ctx>,
|
||||||
task: CodeGenTask,
|
task: CodeGenTask,
|
||||||
top_level_ctx: Arc<TopLevelContext>,
|
|
||||||
) -> (Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>) {
|
) -> (Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>) {
|
||||||
|
let top_level_ctx = registry.top_level_ctx.clone();
|
||||||
|
let static_value_store = registry.static_value_store.clone();
|
||||||
let (mut unifier, primitives) = {
|
let (mut unifier, primitives) = {
|
||||||
let (unifier, primitives) = &top_level_ctx.unifiers.read()[task.unifier_index];
|
let (unifier, primitives) = &top_level_ctx.unifiers.read()[task.unifier_index];
|
||||||
(Unifier::from_shared_unifier(unifier), *primitives)
|
(Unifier::from_shared_unifier(unifier), *primitives)
|
||||||
|
@ -306,7 +319,10 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
(unifier.get_representative(primitives.int64), context.i64_type().into()),
|
(unifier.get_representative(primitives.int64), context.i64_type().into()),
|
||||||
(unifier.get_representative(primitives.float), context.f64_type().into()),
|
(unifier.get_representative(primitives.float), context.f64_type().into()),
|
||||||
(unifier.get_representative(primitives.bool), context.bool_type().into()),
|
(unifier.get_representative(primitives.bool), context.bool_type().into()),
|
||||||
(unifier.get_representative(primitives.str), context.i8_type().ptr_type(AddressSpace::Generic).into()),
|
(
|
||||||
|
unifier.get_representative(primitives.str),
|
||||||
|
context.i8_type().ptr_type(AddressSpace::Generic).into(),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
|
@ -366,8 +382,17 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
&arg.name.to_string(),
|
&arg.name.to_string(),
|
||||||
);
|
);
|
||||||
builder.build_store(alloca, param);
|
builder.build_store(alloca, param);
|
||||||
var_assignment.insert(arg.name, alloca);
|
var_assignment.insert(arg.name, (alloca, None, 0));
|
||||||
}
|
}
|
||||||
|
let static_values = {
|
||||||
|
let store = registry.static_value_store.lock();
|
||||||
|
store.store[task.id].clone()
|
||||||
|
};
|
||||||
|
for (k, v) in static_values.into_iter() {
|
||||||
|
let (_, static_val, _) = var_assignment.get_mut(&args[k].name).unwrap();
|
||||||
|
*static_val = Some(v);
|
||||||
|
}
|
||||||
|
|
||||||
builder.build_unconditional_branch(body_bb);
|
builder.build_unconditional_branch(body_bb);
|
||||||
builder.position_at_end(body_bb);
|
builder.position_at_end(body_bb);
|
||||||
|
|
||||||
|
@ -385,6 +410,7 @@ pub fn gen_func<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
builder,
|
builder,
|
||||||
module,
|
module,
|
||||||
unifier,
|
unifier,
|
||||||
|
static_value_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut returned = false;
|
let mut returned = false;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{expr::destructure_range, CodeGenContext, CodeGenerator};
|
use super::{expr::destructure_range, CodeGenContext, CodeGenerator, super::symbol_resolver::ValueEnum};
|
||||||
use crate::typecheck::typedef::Type;
|
use crate::typecheck::typedef::Type;
|
||||||
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
use inkwell::values::{BasicValue, BasicValueEnum, PointerValue};
|
||||||
use nac3parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
use nac3parser::ast::{Expr, ExprKind, Stmt, StmtKind};
|
||||||
|
@ -22,14 +22,14 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// very similar to gen_expr, but we don't do an extra load at the end
|
// very similar to gen_expr, but we don't do an extra load at the end
|
||||||
// and we flatten nested tuples
|
// and we flatten nested tuples
|
||||||
match &pattern.node {
|
match &pattern.node {
|
||||||
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).cloned().unwrap_or_else(|| {
|
ExprKind::Name { id, .. } => ctx.var_assignment.get(id).map(|v| v.0).unwrap_or_else(|| {
|
||||||
let ptr = generator.gen_var_alloc(ctx, pattern.custom.unwrap());
|
let ptr = generator.gen_var_alloc(ctx, pattern.custom.unwrap());
|
||||||
ctx.var_assignment.insert(*id, ptr);
|
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
||||||
ptr
|
ptr
|
||||||
}),
|
}),
|
||||||
ExprKind::Attribute { value, attr, .. } => {
|
ExprKind::Attribute { value, attr, .. } => {
|
||||||
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
let index = ctx.get_attr_index(value.custom.unwrap(), *attr);
|
||||||
let val = generator.gen_expr(ctx, value).unwrap();
|
let val = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx);
|
||||||
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
let ptr = if let BasicValueEnum::PointerValue(v) = val {
|
||||||
v
|
v
|
||||||
} else {
|
} else {
|
||||||
|
@ -48,8 +48,13 @@ pub fn gen_store_target<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
ExprKind::Subscript { value, slice, .. } => {
|
ExprKind::Subscript { value, slice, .. } => {
|
||||||
let i32_type = ctx.ctx.i32_type();
|
let i32_type = ctx.ctx.i32_type();
|
||||||
let v = generator.gen_expr(ctx, value).unwrap().into_pointer_value();
|
let v = generator
|
||||||
let index = generator.gen_expr(ctx, slice).unwrap().into_int_value();
|
.gen_expr(ctx, value)
|
||||||
|
.unwrap()
|
||||||
|
.to_basic_value_enum(ctx)
|
||||||
|
.into_pointer_value();
|
||||||
|
let index =
|
||||||
|
generator.gen_expr(ctx, slice).unwrap().to_basic_value_enum(ctx).into_int_value();
|
||||||
unsafe {
|
unsafe {
|
||||||
let arr_ptr = ctx
|
let arr_ptr = ctx
|
||||||
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_int(1, false)])
|
.build_gep_and_load(v, &[i32_type.const_zero(), i32_type.const_int(1, false)])
|
||||||
|
@ -65,24 +70,32 @@ pub fn gen_assign<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
target: &Expr<Option<Type>>,
|
target: &Expr<Option<Type>>,
|
||||||
value: BasicValueEnum<'ctx>,
|
value: ValueEnum<'ctx>,
|
||||||
) {
|
) {
|
||||||
let i32_type = ctx.ctx.i32_type();
|
|
||||||
if let ExprKind::Tuple { elts, .. } = &target.node {
|
if let ExprKind::Tuple { elts, .. } = &target.node {
|
||||||
if let BasicValueEnum::PointerValue(ptr) = value {
|
if let BasicValueEnum::PointerValue(ptr) = value.to_basic_value_enum(ctx) {
|
||||||
|
let i32_type = ctx.ctx.i32_type();
|
||||||
for (i, elt) in elts.iter().enumerate() {
|
for (i, elt) in elts.iter().enumerate() {
|
||||||
let v = ctx.build_gep_and_load(
|
let v = ctx.build_gep_and_load(
|
||||||
ptr,
|
ptr,
|
||||||
&[i32_type.const_zero(), i32_type.const_int(i as u64, false)],
|
&[i32_type.const_zero(), i32_type.const_int(i as u64, false)],
|
||||||
);
|
);
|
||||||
generator.gen_assign(ctx, elt, v);
|
generator.gen_assign(ctx, elt, v.into());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let ptr = generator.gen_store_target(ctx, target);
|
let ptr = generator.gen_store_target(ctx, target);
|
||||||
ctx.builder.build_store(ptr, value);
|
if let ExprKind::Name { id, .. } = &target.node {
|
||||||
|
let (_, static_value, counter) = ctx.var_assignment.get_mut(id).unwrap();
|
||||||
|
*counter += 1;
|
||||||
|
if let ValueEnum::Static(s) = &value {
|
||||||
|
*static_value = Some(s.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let val = value.to_basic_value_enum(ctx);
|
||||||
|
ctx.builder.build_store(ptr, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +105,10 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) {
|
) {
|
||||||
if let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node {
|
if let StmtKind::For { iter, target, body, orelse, .. } = &stmt.node {
|
||||||
|
// var_assignment static values may be changed in another branch
|
||||||
|
// if so, remove the static value as it may not be correct in this branch
|
||||||
|
let var_assignment = ctx.var_assignment.clone();
|
||||||
|
|
||||||
let int32 = ctx.ctx.i32_type();
|
let int32 = ctx.ctx.i32_type();
|
||||||
let zero = int32.const_zero();
|
let zero = int32.const_zero();
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
|
@ -104,7 +121,7 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
// store loop bb information and restore it later
|
// store loop bb information and restore it later
|
||||||
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
||||||
|
|
||||||
let iter_val = generator.gen_expr(ctx, iter).unwrap();
|
let iter_val = generator.gen_expr(ctx, iter).unwrap().to_basic_value_enum(ctx);
|
||||||
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
if ctx.unifier.unioned(iter.custom.unwrap(), ctx.primitives.range) {
|
||||||
// setup
|
// setup
|
||||||
let iter_val = iter_val.into_pointer_value();
|
let iter_val = iter_val.into_pointer_value();
|
||||||
|
@ -160,12 +177,18 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
)
|
)
|
||||||
.into_pointer_value();
|
.into_pointer_value();
|
||||||
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
let val = ctx.build_gep_and_load(arr_ptr, &[tmp]);
|
||||||
generator.gen_assign(ctx, target, val);
|
generator.gen_assign(ctx, target, val.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
for stmt in body.iter() {
|
for stmt in body.iter() {
|
||||||
generator.gen_stmt(ctx, stmt);
|
generator.gen_stmt(ctx, stmt);
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
if !orelse.is_empty() {
|
if !orelse.is_empty() {
|
||||||
ctx.builder.position_at_end(orelse_bb);
|
ctx.builder.position_at_end(orelse_bb);
|
||||||
|
@ -174,6 +197,12 @@ pub fn gen_for<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
ctx.loop_bb = loop_bb;
|
ctx.loop_bb = loop_bb;
|
||||||
} else {
|
} else {
|
||||||
|
@ -187,6 +216,10 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) {
|
) {
|
||||||
if let StmtKind::While { test, body, orelse, .. } = &stmt.node {
|
if let StmtKind::While { test, body, orelse, .. } = &stmt.node {
|
||||||
|
// var_assignment static values may be changed in another branch
|
||||||
|
// if so, remove the static value as it may not be correct in this branch
|
||||||
|
let var_assignment = ctx.var_assignment.clone();
|
||||||
|
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
||||||
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
||||||
|
@ -198,7 +231,7 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
let loop_bb = ctx.loop_bb.replace((test_bb, cont_bb));
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test).unwrap();
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx);
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,6 +241,12 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
for stmt in body.iter() {
|
for stmt in body.iter() {
|
||||||
generator.gen_stmt(ctx, stmt);
|
generator.gen_stmt(ctx, stmt);
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
if !orelse.is_empty() {
|
if !orelse.is_empty() {
|
||||||
ctx.builder.position_at_end(orelse_bb);
|
ctx.builder.position_at_end(orelse_bb);
|
||||||
|
@ -216,6 +255,12 @@ pub fn gen_while<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
}
|
}
|
||||||
ctx.builder.build_unconditional_branch(cont_bb);
|
ctx.builder.build_unconditional_branch(cont_bb);
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
ctx.loop_bb = loop_bb;
|
ctx.loop_bb = loop_bb;
|
||||||
} else {
|
} else {
|
||||||
|
@ -229,6 +274,10 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
stmt: &Stmt<Option<Type>>,
|
stmt: &Stmt<Option<Type>>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if let StmtKind::If { test, body, orelse, .. } = &stmt.node {
|
if let StmtKind::If { test, body, orelse, .. } = &stmt.node {
|
||||||
|
// var_assignment static values may be changed in another branch
|
||||||
|
// if so, remove the static value as it may not be correct in this branch
|
||||||
|
let var_assignment = ctx.var_assignment.clone();
|
||||||
|
|
||||||
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
let current = ctx.builder.get_insert_block().unwrap().get_parent().unwrap();
|
||||||
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
let test_bb = ctx.ctx.append_basic_block(current, "test");
|
||||||
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
let body_bb = ctx.ctx.append_basic_block(current, "body");
|
||||||
|
@ -242,7 +291,7 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
};
|
};
|
||||||
ctx.builder.build_unconditional_branch(test_bb);
|
ctx.builder.build_unconditional_branch(test_bb);
|
||||||
ctx.builder.position_at_end(test_bb);
|
ctx.builder.position_at_end(test_bb);
|
||||||
let test = generator.gen_expr(ctx, test).unwrap();
|
let test = generator.gen_expr(ctx, test).unwrap().to_basic_value_enum(ctx);
|
||||||
if let BasicValueEnum::IntValue(test) = test {
|
if let BasicValueEnum::IntValue(test) = test {
|
||||||
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
ctx.builder.build_conditional_branch(test, body_bb, orelse_bb);
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,6 +305,13 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !exited {
|
if !exited {
|
||||||
if cont_bb.is_none() {
|
if cont_bb.is_none() {
|
||||||
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
cont_bb = Some(ctx.ctx.append_basic_block(current, "cont"));
|
||||||
|
@ -285,6 +341,12 @@ pub fn gen_if<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
if let Some(cont_bb) = cont_bb {
|
if let Some(cont_bb) = cont_bb {
|
||||||
ctx.builder.position_at_end(cont_bb);
|
ctx.builder.position_at_end(cont_bb);
|
||||||
}
|
}
|
||||||
|
for (k, (_, _, counter)) in var_assignment.iter() {
|
||||||
|
let (_, static_val, counter2) = ctx.var_assignment.get_mut(k).unwrap();
|
||||||
|
if counter != counter2 {
|
||||||
|
*static_val = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
then_exited && else_exited
|
then_exited && else_exited
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -311,7 +373,9 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
generator.gen_expr(ctx, value);
|
generator.gen_expr(ctx, value);
|
||||||
}
|
}
|
||||||
StmtKind::Return { value, .. } => {
|
StmtKind::Return { value, .. } => {
|
||||||
let value = value.as_ref().map(|v| generator.gen_expr(ctx, v).unwrap());
|
let value = value
|
||||||
|
.as_ref()
|
||||||
|
.map(|v| generator.gen_expr(ctx, v).unwrap().to_basic_value_enum(ctx));
|
||||||
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
let value = value.as_ref().map(|v| v as &dyn BasicValue);
|
||||||
ctx.builder.build_return(value);
|
ctx.builder.build_return(value);
|
||||||
return true;
|
return true;
|
||||||
|
@ -325,14 +389,14 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
StmtKind::Assign { targets, value, .. } => {
|
StmtKind::Assign { targets, value, .. } => {
|
||||||
let value = generator.gen_expr(ctx, value).unwrap();
|
let value = generator.gen_expr(ctx, value).unwrap();
|
||||||
for target in targets.iter() {
|
for target in targets.iter() {
|
||||||
generator.gen_assign(ctx, target, value);
|
generator.gen_assign(ctx, target, value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StmtKind::Continue { .. } => {
|
StmtKind::Continue { .. } => {
|
||||||
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().0);
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
StmtKind::Break { .. }=> {
|
StmtKind::Break { .. } => {
|
||||||
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().1);
|
ctx.builder.build_unconditional_branch(ctx.loop_bb.unwrap().1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -344,8 +408,8 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
let value = {
|
let value = {
|
||||||
let ty1 = ctx.unifier.get_representative(target.custom.unwrap());
|
let ty1 = ctx.unifier.get_representative(target.custom.unwrap());
|
||||||
let ty2 = ctx.unifier.get_representative(value.custom.unwrap());
|
let ty2 = ctx.unifier.get_representative(value.custom.unwrap());
|
||||||
let left = generator.gen_expr(ctx, target).unwrap();
|
let left = generator.gen_expr(ctx, target).unwrap().to_basic_value_enum(ctx);
|
||||||
let right = generator.gen_expr(ctx, value).unwrap();
|
let right = generator.gen_expr(ctx, value).unwrap().to_basic_value_enum(ctx);
|
||||||
|
|
||||||
// we can directly compare the types, because we've got their representatives
|
// we can directly compare the types, because we've got their representatives
|
||||||
// which would be unchanged until further unification, which we would never do
|
// which would be unchanged until further unification, which we would never do
|
||||||
|
@ -358,7 +422,7 @@ pub fn gen_stmt<'ctx, 'a, G: CodeGenerator + ?Sized>(
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
generator.gen_assign(ctx, target, value);
|
generator.gen_assign(ctx, target, value.into());
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
||||||
WithCall, WorkerRegistry,
|
WithCall, WorkerRegistry,
|
||||||
},
|
},
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::{SymbolResolver, ValueEnum},
|
||||||
toplevel::{
|
toplevel::{
|
||||||
composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
|
composer::TopLevelComposer, DefinitionId, FunInstance, TopLevelContext, TopLevelDef,
|
||||||
},
|
},
|
||||||
|
@ -14,12 +14,11 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use inkwell::values::BasicValueEnum;
|
|
||||||
use parking_lot::RwLock;
|
|
||||||
use nac3parser::{
|
use nac3parser::{
|
||||||
ast::{fold::Fold, StrRef},
|
ast::{fold::Fold, StrRef},
|
||||||
parser::parse_program,
|
parser::parse_program,
|
||||||
};
|
};
|
||||||
|
use parking_lot::RwLock;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -55,7 +54,7 @@ impl SymbolResolver for Resolver {
|
||||||
&self,
|
&self,
|
||||||
_: StrRef,
|
_: StrRef,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +146,7 @@ fn test_primitives() {
|
||||||
resolver,
|
resolver,
|
||||||
store,
|
store,
|
||||||
signature,
|
signature,
|
||||||
|
id: 0,
|
||||||
};
|
};
|
||||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||||
// the following IR is equivalent to
|
// the following IR is equivalent to
|
||||||
|
@ -314,6 +314,7 @@ fn test_simple_call() {
|
||||||
resolver,
|
resolver,
|
||||||
signature,
|
signature,
|
||||||
store,
|
store,
|
||||||
|
id: 0,
|
||||||
};
|
};
|
||||||
let f = Arc::new(WithCall::new(Box::new(|module| {
|
let f = Arc::new(WithCall::new(Box::new(|module| {
|
||||||
let expected = indoc! {"
|
let expected = indoc! {"
|
||||||
|
|
|
@ -11,7 +11,7 @@ use crate::{
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
};
|
};
|
||||||
use crate::{location::Location, typecheck::typedef::TypeEnum};
|
use crate::{location::Location, typecheck::typedef::TypeEnum};
|
||||||
use inkwell::values::BasicValueEnum;
|
use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue};
|
||||||
use itertools::{chain, izip};
|
use itertools::{chain, izip};
|
||||||
use nac3parser::ast::{Expr, StrRef};
|
use nac3parser::ast::{Expr, StrRef};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
@ -23,8 +23,63 @@ pub enum SymbolValue {
|
||||||
Double(f64),
|
Double(f64),
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
Tuple(Vec<SymbolValue>),
|
Tuple(Vec<SymbolValue>),
|
||||||
// we should think about how to implement bytes later...
|
}
|
||||||
// Bytes(&'a [u8]),
|
|
||||||
|
pub trait StaticValue {
|
||||||
|
fn get_unique_identifier(&self) -> u64;
|
||||||
|
|
||||||
|
fn to_basic_value_enum<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
) -> BasicValueEnum<'ctx>;
|
||||||
|
|
||||||
|
fn get_field<'ctx, 'a>(
|
||||||
|
&self,
|
||||||
|
name: StrRef,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
) -> Option<ValueEnum<'ctx>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum ValueEnum<'ctx> {
|
||||||
|
Static(Arc<dyn StaticValue + Send + Sync>),
|
||||||
|
Dynamic(BasicValueEnum<'ctx>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<BasicValueEnum<'ctx>> for ValueEnum<'ctx> {
|
||||||
|
fn from(v: BasicValueEnum<'ctx>) -> Self {
|
||||||
|
ValueEnum::Dynamic(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<PointerValue<'ctx>> for ValueEnum<'ctx> {
|
||||||
|
fn from(v: PointerValue<'ctx>) -> Self {
|
||||||
|
ValueEnum::Dynamic(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<IntValue<'ctx>> for ValueEnum<'ctx> {
|
||||||
|
fn from(v: IntValue<'ctx>) -> Self {
|
||||||
|
ValueEnum::Dynamic(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> From<FloatValue<'ctx>> for ValueEnum<'ctx> {
|
||||||
|
fn from(v: FloatValue<'ctx>) -> Self {
|
||||||
|
ValueEnum::Dynamic(v.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx> ValueEnum<'ctx> {
|
||||||
|
pub fn to_basic_value_enum<'a>(
|
||||||
|
self,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
|
) -> BasicValueEnum<'ctx> {
|
||||||
|
match self {
|
||||||
|
ValueEnum::Static(v) => v.to_basic_value_enum(ctx),
|
||||||
|
ValueEnum::Dynamic(v) => v,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait SymbolResolver {
|
pub trait SymbolResolver {
|
||||||
|
@ -36,13 +91,16 @@ pub trait SymbolResolver {
|
||||||
primitives: &PrimitiveStore,
|
primitives: &PrimitiveStore,
|
||||||
str: StrRef,
|
str: StrRef,
|
||||||
) -> Option<Type>;
|
) -> Option<Type>;
|
||||||
|
|
||||||
// get the top-level definition of identifiers
|
// get the top-level definition of identifiers
|
||||||
fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>;
|
fn get_identifier_def(&self, str: StrRef) -> Option<DefinitionId>;
|
||||||
|
|
||||||
fn get_symbol_value<'ctx, 'a>(
|
fn get_symbol_value<'ctx, 'a>(
|
||||||
&self,
|
&self,
|
||||||
str: StrRef,
|
str: StrRef,
|
||||||
ctx: &mut CodeGenContext<'ctx, 'a>,
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<BasicValueEnum<'ctx>>;
|
) -> Option<ValueEnum<'ctx>>;
|
||||||
|
|
||||||
fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
|
fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
|
||||||
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
|
||||||
// handle function call etc.
|
// handle function call etc.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use nac3parser::ast::fold::Fold;
|
use nac3parser::ast::fold::Fold;
|
||||||
use inkwell::FloatPredicate;
|
use inkwell::{FloatPredicate, IntPredicate};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
symbol_resolver::SymbolValue,
|
symbol_resolver::SymbolValue,
|
||||||
|
@ -195,7 +195,7 @@ impl TopLevelComposer {
|
||||||
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||||
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
||||||
ret: float,
|
ret: float,
|
||||||
vars: var_map,
|
vars: var_map.clone(),
|
||||||
}))),
|
}))),
|
||||||
var_id: Default::default(),
|
var_id: Default::default(),
|
||||||
instance_to_symbol: Default::default(),
|
instance_to_symbol: Default::default(),
|
||||||
|
@ -398,7 +398,7 @@ impl TopLevelComposer {
|
||||||
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
signature: primitives.1.add_ty(TypeEnum::TFunc(RefCell::new(FunSignature {
|
||||||
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
args: vec![FuncArg { name: "_".into(), ty: num_ty.0, default_value: None }],
|
||||||
ret: primitives.0.bool,
|
ret: primitives.0.bool,
|
||||||
vars: Default::default(),
|
vars: var_map,
|
||||||
}))),
|
}))),
|
||||||
var_id: Default::default(),
|
var_id: Default::default(),
|
||||||
instance_to_symbol: Default::default(),
|
instance_to_symbol: Default::default(),
|
||||||
|
@ -415,15 +415,12 @@ impl TopLevelComposer {
|
||||||
if ctx.unifier.unioned(arg_ty, boolean) {
|
if ctx.unifier.unioned(arg_ty, boolean) {
|
||||||
Some(arg)
|
Some(arg)
|
||||||
} else if ctx.unifier.unioned(arg_ty, int32) || ctx.unifier.unioned(arg_ty, int64) {
|
} else if ctx.unifier.unioned(arg_ty, int32) || ctx.unifier.unioned(arg_ty, int64) {
|
||||||
Some(
|
Some(ctx.builder.build_int_compare(
|
||||||
ctx.builder
|
IntPredicate::NE,
|
||||||
.build_int_truncate(
|
ctx.ctx.i64_type().const_zero(),
|
||||||
arg.into_int_value(),
|
arg.into_int_value(),
|
||||||
ctx.ctx.bool_type(),
|
"bool",
|
||||||
"trunc",
|
).into())
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
)
|
|
||||||
} else if ctx.unifier.unioned(arg_ty, float) {
|
} else if ctx.unifier.unioned(arg_ty, float) {
|
||||||
let val = ctx.builder.
|
let val = ctx.builder.
|
||||||
build_float_compare(
|
build_float_compare(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::SymbolResolver,
|
symbol_resolver::{SymbolResolver, ValueEnum},
|
||||||
toplevel::DefinitionId,
|
toplevel::DefinitionId,
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
|
@ -54,7 +54,7 @@ impl SymbolResolver for Resolver {
|
||||||
&self,
|
&self,
|
||||||
_: StrRef,
|
_: StrRef,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,10 @@ use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
location::Location,
|
location::Location,
|
||||||
|
symbol_resolver::ValueEnum,
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
};
|
};
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use inkwell::values::BasicValueEnum;
|
|
||||||
use itertools::zip;
|
use itertools::zip;
|
||||||
use nac3parser::parser::parse_program;
|
use nac3parser::parser::parse_program;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
@ -37,7 +37,7 @@ impl SymbolResolver for Resolver {
|
||||||
&self,
|
&self,
|
||||||
_: StrRef,
|
_: StrRef,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
use inkwell::values::BasicValueEnum;
|
|
||||||
use nac3core::{
|
use nac3core::{
|
||||||
codegen::CodeGenContext,
|
codegen::CodeGenContext,
|
||||||
location::Location,
|
location::Location,
|
||||||
symbol_resolver::{SymbolResolver, SymbolValue},
|
symbol_resolver::{SymbolResolver, SymbolValue, ValueEnum},
|
||||||
toplevel::{DefinitionId, TopLevelDef},
|
toplevel::{DefinitionId, TopLevelDef},
|
||||||
typecheck::{
|
typecheck::{
|
||||||
type_inferencer::PrimitiveStore,
|
type_inferencer::PrimitiveStore,
|
||||||
typedef::{Type, Unifier},
|
typedef::{Type, Unifier},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use parking_lot::{Mutex, RwLock};
|
|
||||||
use nac3parser::ast::{self, StrRef};
|
use nac3parser::ast::{self, StrRef};
|
||||||
|
use parking_lot::{Mutex, RwLock};
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
pub struct ResolverInternal {
|
pub struct ResolverInternal {
|
||||||
|
@ -64,7 +63,7 @@ impl SymbolResolver for Resolver {
|
||||||
&self,
|
&self,
|
||||||
_: StrRef,
|
_: StrRef,
|
||||||
_: &mut CodeGenContext<'ctx, 'a>,
|
_: &mut CodeGenContext<'ctx, 'a>,
|
||||||
) -> Option<BasicValueEnum<'ctx>> {
|
) -> Option<ValueEnum<'ctx>> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -262,6 +262,7 @@ fn main() {
|
||||||
store,
|
store,
|
||||||
unifier_index: instance.unifier_id,
|
unifier_index: instance.unifier_id,
|
||||||
calls: instance.calls,
|
calls: instance.calls,
|
||||||
|
id: 0,
|
||||||
};
|
};
|
||||||
let f = Arc::new(WithCall::new(Box::new(move |module| {
|
let f = Arc::new(WithCall::new(Box::new(move |module| {
|
||||||
let builder = PassManagerBuilder::create();
|
let builder = PassManagerBuilder::create();
|
||||||
|
|
Loading…
Reference in New Issue
remove println