forked from M-Labs/nac3
[WIP] Cleanup irrelevant part
This commit is contained in:
parent
b03e81adef
commit
9c4283fea3
@ -1,5 +1,27 @@
|
||||
from min_artiq import *
|
||||
from numpy import int32
|
||||
import string_attribute_issue337
|
||||
import support_class_attr_issue102
|
||||
import support_class_attr_issue102 as issue102
|
||||
import string_attribute_issue337 as issue337
|
||||
|
||||
# gvar22: int32 = 22
|
||||
@nac3
|
||||
class Test:
|
||||
attr1: KernelInvariant[int32] = 2
|
||||
attr2: int32 = 4
|
||||
attr3: Kernel[int32]
|
||||
|
||||
@kernel
|
||||
def __init__(self):
|
||||
self.attr3 = 8
|
||||
|
||||
@kernel
|
||||
def run(self) -> int32:
|
||||
# global gvar22
|
||||
gvar22 = 10
|
||||
self.attr3 = 1
|
||||
return self.attr3
|
||||
|
||||
@nac3
|
||||
class Demo:
|
||||
@ -14,12 +36,27 @@ class Demo:
|
||||
|
||||
@kernel
|
||||
def run(self):
|
||||
self.core.reset()
|
||||
while True:
|
||||
with parallel:
|
||||
self.led0.pulse(100.*ms)
|
||||
self.led1.pulse(100.*ms)
|
||||
self.core.delay(100.*ms)
|
||||
# global gvar22
|
||||
# issue337.Demo().run()
|
||||
a = Test()
|
||||
|
||||
a.run()
|
||||
Test.attr1
|
||||
# g = gvar22
|
||||
e = issue337.myTest()
|
||||
f = e.run()
|
||||
f = f + 1
|
||||
# g = gvar22
|
||||
b = issue102.fun2smn()
|
||||
c = string_attribute_issue337.fn1_dosmn()
|
||||
d = issue337.fn1_dosmn()
|
||||
|
||||
# self.core.reset()
|
||||
# while True:
|
||||
# with parallel:
|
||||
# self.led0.pulse(100.*ms)
|
||||
# self.led1.pulse(100.*ms)
|
||||
# self.core.delay(100.*ms)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -202,7 +202,6 @@ class Core:
|
||||
|
||||
def run(self, method, *args, **kwargs):
|
||||
global allow_registration
|
||||
|
||||
embedding = EmbeddingMap()
|
||||
|
||||
if allow_registration:
|
||||
|
@ -1 +0,0 @@
|
||||
../../target/release/libnac3artiq.so
|
@ -1,6 +1,30 @@
|
||||
from min_artiq import *
|
||||
from numpy import int32
|
||||
|
||||
gvar = "init"
|
||||
gvar2: str = "init"
|
||||
|
||||
@kernel
|
||||
def fn1_dosmn() -> bool:
|
||||
gvar = "S"
|
||||
a = 1
|
||||
b = 1
|
||||
return a == b
|
||||
|
||||
@nac3
|
||||
class myTest:
|
||||
attr1: Kernel[str]
|
||||
attr2: Kernel[int32]
|
||||
|
||||
@kernel
|
||||
def __init__(self):
|
||||
self.attr2 = 32
|
||||
self.attr1 = "SAMPLE"
|
||||
|
||||
@kernel
|
||||
def run(self) -> int32:
|
||||
print_int32(self.attr2)
|
||||
return self.attr2
|
||||
|
||||
@nac3
|
||||
class Demo:
|
||||
@ -8,7 +32,6 @@ class Demo:
|
||||
attr1: KernelInvariant[str]
|
||||
attr2: KernelInvariant[int32]
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.core = Core()
|
||||
self.attr2 = 32
|
||||
|
@ -1,6 +1,13 @@
|
||||
from min_artiq import *
|
||||
from numpy import int32
|
||||
|
||||
g1: int32 = 2
|
||||
|
||||
@kernel
|
||||
def fun2smn() -> int32:
|
||||
# global g1
|
||||
g1 = g1 + 1
|
||||
return g1
|
||||
|
||||
@nac3
|
||||
class Demo:
|
||||
|
@ -231,6 +231,18 @@ impl Nac3 {
|
||||
}
|
||||
// Required to capture alias used within module
|
||||
StmtKind::Import { .. } => false,
|
||||
StmtKind::AnnAssign { .. } => false,
|
||||
StmtKind::Assign { ref targets, .. } => {
|
||||
if targets.len() == 1 {
|
||||
if let ExprKind::Name { .. } = targets.first().unwrap().node {
|
||||
false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@ -483,11 +495,21 @@ impl Nac3 {
|
||||
(name_to_pyid, resolver, module_name)
|
||||
});
|
||||
|
||||
let (name, def_id, ty) = composer
|
||||
.register_top_level(stmt.clone(), Some(resolver.clone()), path, false)
|
||||
.map_err(|e| {
|
||||
CompileError::new_err(format!("compilation failed\n----------\n{e}"))
|
||||
})?;
|
||||
let (name, def_id, ty) = (match &stmt.node {
|
||||
StmtKind::Assign { targets, .. } => {
|
||||
let ExprKind::Name {id, ..} = targets.first().unwrap().node else { unreachable!() };
|
||||
// let id: StrRef = if path == "min_artiq" {
|
||||
// format!("min_artiq.{id}").into()
|
||||
// } else {
|
||||
// id
|
||||
// };
|
||||
println!("Calling Assign for {id}, {path}");
|
||||
composer.register_top_level_var(id, None, Some(resolver.clone()), path, targets.first().unwrap().location)
|
||||
},
|
||||
_ => composer.register_top_level(stmt.clone(), Some(resolver.clone()), path, false)
|
||||
}).map_err(|e| {
|
||||
CompileError::new_err(format!("compilation failed\n----------\n{e}"))
|
||||
})?;
|
||||
if let Some(class_obj) = class_obj {
|
||||
self.exception_ids
|
||||
.write()
|
||||
@ -625,6 +647,7 @@ impl Nac3 {
|
||||
);
|
||||
let signature = store.add_cty(signature);
|
||||
|
||||
println!("[+] Start composer Analysis");
|
||||
if let Err(e) = composer.start_analysis(true) {
|
||||
// report error of __modinit__ separately
|
||||
return if e.iter().any(|err| err.contains("<nac3_synthesized_modinit>")) {
|
||||
@ -647,6 +670,8 @@ impl Nac3 {
|
||||
)))
|
||||
};
|
||||
}
|
||||
println!("[+] Stop composer Analysis");
|
||||
|
||||
let top_level = Arc::new(composer.make_top_level_context());
|
||||
|
||||
{
|
||||
@ -705,7 +730,13 @@ impl Nac3 {
|
||||
instance_to_symbol.insert(String::new(), "__modinit__".into());
|
||||
instance_to_stmt[""].clone()
|
||||
};
|
||||
|
||||
|
||||
|
||||
for def in top_level.definitions.read().iter() {
|
||||
if let TopLevelDef::Variable { name, .. } = &*def.read() {
|
||||
println!("[+] Variable definition for {name}");
|
||||
}
|
||||
}
|
||||
let task = CodeGenTask {
|
||||
subst: Vec::default(),
|
||||
symbol_name: "__modinit__".to_string(),
|
||||
@ -730,7 +761,7 @@ impl Nac3 {
|
||||
let size_t = context
|
||||
.ptr_sized_int_type(&self.get_llvm_target_machine().get_target_data(), None)
|
||||
.get_bit_width();
|
||||
let num_threads = if is_multithreaded() { 4 } else { 1 };
|
||||
let num_threads = if is_multithreaded() { 1 } else { 1 };
|
||||
let thread_names: Vec<String> = (0..num_threads).map(|_| "main".to_string()).collect();
|
||||
let threads: Vec<_> = thread_names
|
||||
.iter()
|
||||
@ -775,7 +806,7 @@ impl Nac3 {
|
||||
let ExprKind::Call { .. } = expr.node else {
|
||||
unreachable!("toplevel expression must be a function call")
|
||||
};
|
||||
|
||||
println!("Yes this was called");
|
||||
let return_obj =
|
||||
generator.gen_expr(ctx, expr)?.map(|value| (expr.custom.unwrap(), value));
|
||||
has_return = return_obj.is_some();
|
||||
|
@ -155,6 +155,7 @@ impl StaticValue for PythonValue {
|
||||
generator: &mut dyn CodeGenerator,
|
||||
expected_ty: Type,
|
||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||
println!("- [+] Calling the global functions");
|
||||
if let Some(val) = self.resolver.id_to_primitive.read().get(&self.id) {
|
||||
return Ok(match val {
|
||||
PrimitiveValue::I32(val) => ctx.ctx.i32_type().const_int(*val as u64, false).into(),
|
||||
@ -171,10 +172,12 @@ impl StaticValue for PythonValue {
|
||||
});
|
||||
}
|
||||
if let Some(global) = ctx.module.get_global(&self.id.to_string()) {
|
||||
println!("- [-] Escaping Analysis");
|
||||
return Ok(global.as_pointer_value().into());
|
||||
}
|
||||
|
||||
|
||||
Python::with_gil(|py| -> PyResult<BasicValueEnum<'ctx>> {
|
||||
println!("3 Calling for {:?}", self.value.as_ref(py).to_string());
|
||||
self.resolver
|
||||
.get_obj_value(py, self.value.as_ref(py), ctx, generator, expected_ty)
|
||||
.map(Option::unwrap)
|
||||
@ -674,6 +677,42 @@ impl InnerResolver {
|
||||
})
|
||||
});
|
||||
|
||||
// check if obj is module
|
||||
if self.helper.id_fn.call1(py, (ty.clone(),))?.extract::<u64>(py)? == self.primitive_ids.module {
|
||||
let def_id = self.pyid_to_def.read().get(&py_obj_id).copied().unwrap();
|
||||
let def = defs[def_id.0].read();
|
||||
let TopLevelDef::Module { name: module_name, module_id, methods, .. } = &* def else {
|
||||
unreachable!("must be a module here");
|
||||
};
|
||||
|
||||
println!("[+] Adding Module {module_name}");
|
||||
|
||||
// Construct the module return type
|
||||
let mut module_attributes = HashMap::new();
|
||||
for (name, (_, _)) in methods.iter() {
|
||||
let method_obj = obj.getattr(name.to_string().as_str())?;
|
||||
let method_ty = self.get_obj_type(py, method_obj, unifier, defs, primitives)?;
|
||||
if let Ok(method_ty) = method_ty {
|
||||
let is_method = match &*unifier.get_ty(method_ty) {
|
||||
TypeEnum::TFunc(..) | TypeEnum::TObj { .. } => true,
|
||||
_ => false
|
||||
};
|
||||
module_attributes.insert(*name, (method_ty, is_method));
|
||||
println!("[+] Inserted {name} => {:?} ismethod? {}", unifier.stringify(method_ty), is_method);
|
||||
} else {
|
||||
println!("[-] No entry for {name}")
|
||||
// return Ok(Err(format!("Could not resolve {} in module {}", name, module_name)));
|
||||
}
|
||||
}
|
||||
let module_ty = TypeEnum::TModule {
|
||||
module_id: *module_id,
|
||||
attributes: module_attributes
|
||||
};
|
||||
let ty = unifier.add_ty(module_ty);
|
||||
self.pyid_to_type.write().insert(py_obj_id, ty);
|
||||
return Ok(Ok(ty));
|
||||
}
|
||||
|
||||
if let Some(ty) = constructor_ty {
|
||||
self.pyid_to_type.write().insert(py_obj_id, ty);
|
||||
return Ok(Ok(ty));
|
||||
@ -958,6 +997,7 @@ impl InnerResolver {
|
||||
generator: &mut dyn CodeGenerator,
|
||||
expected_ty: Type,
|
||||
) -> PyResult<Option<BasicValueEnum<'ctx>>> {
|
||||
println!("[-] Object value extraction? {:?}", obj.to_string());
|
||||
let ty_id: u64 =
|
||||
self.helper.id_fn.call1(py, (self.helper.type_fn.call1(py, (obj,))?,))?.extract(py)?;
|
||||
let id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?;
|
||||
@ -1373,9 +1413,29 @@ impl InnerResolver {
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
} else if ty_id == self.primitive_ids.module {
|
||||
let _top_level_defs = ctx.top_level.definitions.read();
|
||||
// let ty = self
|
||||
// .get_obj_type(py, obj, &mut ctx.unifier, &top_level_defs, &ctx.primitives)?
|
||||
// .unwrap();
|
||||
let _module_id: u64 = self.helper.id_fn.call1(py, (obj,))?.extract(py)?; // For use with vars later
|
||||
// println!("{ty_id} is in def? {}, {module_id} is in def?, {}", self.pyid_to_def.read().get(&ty_id).is_some(), self.pyid_to_def.read().get(&module_id).is_some());
|
||||
// println!("Received Type: {:?}, Expected Type: {:?}", ty, expected_ty);
|
||||
let ty = ctx
|
||||
.get_llvm_type(generator, expected_ty)
|
||||
.into_pointer_type()
|
||||
.get_element_type()
|
||||
.into_struct_type();
|
||||
let id_str = ctx.unifier.stringify(expected_ty);
|
||||
let val = ty.const_named_struct(&Vec::new());
|
||||
let global = ctx.module.get_global(&id_str).unwrap_or_else(|| {
|
||||
ctx.module.add_global(ty, Some(AddressSpace::default()), &id_str)
|
||||
});
|
||||
global.set_initializer(&val);
|
||||
Ok(Some(global.as_pointer_value().into()))
|
||||
} else {
|
||||
let id_str = id.to_string();
|
||||
|
||||
println!("{id_str}");
|
||||
if let Some(global) = ctx.module.get_global(&id_str) {
|
||||
return Ok(Some(global.as_pointer_value().into()));
|
||||
}
|
||||
@ -1384,6 +1444,12 @@ impl InnerResolver {
|
||||
let ty = self
|
||||
.get_obj_type(py, obj, &mut ctx.unifier, &top_level_defs, &ctx.primitives)?
|
||||
.unwrap();
|
||||
println!("Type: {:?}", ctx.unifier.stringify(ty));
|
||||
|
||||
if ty_id == self.primitive_ids.module {
|
||||
println!("Was a module with expected return: {:?}", ctx.unifier.stringify(expected_ty));
|
||||
}
|
||||
|
||||
let ty = ctx
|
||||
.get_llvm_type(generator, ty)
|
||||
.into_pointer_type()
|
||||
@ -1398,6 +1464,7 @@ impl InnerResolver {
|
||||
}
|
||||
self.global_value_ids.write().insert(id, obj.into());
|
||||
}
|
||||
|
||||
// should be classes
|
||||
let definition =
|
||||
top_level_defs.get(self.pyid_to_def.read().get(&ty_id).unwrap().0).unwrap().read();
|
||||
@ -1528,12 +1595,15 @@ impl SymbolResolver for Resolver {
|
||||
} {
|
||||
Ok(t)
|
||||
} else {
|
||||
println!("Desperately searching for {str}");
|
||||
Python::with_gil(|py| -> PyResult<Result<Type, String>> {
|
||||
let obj: &PyAny = self.0.module.extract(py)?;
|
||||
println!("KEY: {:?}", obj.to_string());
|
||||
let mut sym_ty = Err(format!("cannot find symbol `{str}`"));
|
||||
let members: &PyDict = obj.getattr("__dict__").unwrap().downcast().unwrap();
|
||||
for (key, val) in members {
|
||||
let key: &str = key.extract()?;
|
||||
|
||||
if key == str.to_string() {
|
||||
sym_ty = self.0.get_obj_type(py, val, unifier, defs, primitives)?;
|
||||
break;
|
||||
|
@ -56,6 +56,10 @@ pub enum ConcreteTypeEnum {
|
||||
fields: HashMap<StrRef, (ConcreteType, bool)>,
|
||||
params: IndexMap<TypeVarId, ConcreteType>,
|
||||
},
|
||||
TModule {
|
||||
module_id: DefinitionId,
|
||||
methods: HashMap<StrRef, (ConcreteType, bool)>,
|
||||
},
|
||||
TVirtual {
|
||||
ty: ConcreteType,
|
||||
},
|
||||
@ -205,6 +209,32 @@ impl ConcreteTypeStore {
|
||||
})
|
||||
.collect(),
|
||||
},
|
||||
TypeEnum::TModule { module_id, attributes } => {
|
||||
println!("Creating the concrete type for this thing");
|
||||
ConcreteTypeEnum::TModule {
|
||||
module_id: *module_id,
|
||||
methods: attributes.iter().filter_map(|(name, ty)| {
|
||||
// Returns none for everything
|
||||
// Cannot have type vars which prohibits class and function definition
|
||||
if let TypeEnum::TFunc(..) = &*unifier.get_ty(ty.0) {
|
||||
println!("Skipping var {name} ({:?}), {:?}", unifier.get_ty(ty.0), unifier.stringify(ty.0));
|
||||
None
|
||||
} else if let TypeEnum::TObj{ .. } = &*unifier.get_ty(ty.0) {
|
||||
println!("Skipping var {name} ({:?}), {:?}", unifier.get_ty(ty.0), unifier.stringify(ty.0));
|
||||
None
|
||||
} else {
|
||||
println!("Adding var {name} ({:?}), {:?}", unifier.get_ty(ty.0), unifier.stringify(ty.0));
|
||||
Some((
|
||||
*name,
|
||||
(
|
||||
self.from_unifier_type(unifier, primitives, ty.0, cache),
|
||||
ty.1,
|
||||
),
|
||||
))
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
}
|
||||
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
||||
},
|
||||
@ -214,6 +244,7 @@ impl ConcreteTypeStore {
|
||||
TypeEnum::TLiteral { values, .. } => {
|
||||
ConcreteTypeEnum::TLiteral { values: values.clone() }
|
||||
}
|
||||
|
||||
_ => unreachable!("{:?}", ty_enum.get_type_name()),
|
||||
};
|
||||
let index = if let Some(ConcreteType(index)) = cache.get(&ty).unwrap() {
|
||||
@ -284,6 +315,12 @@ impl ConcreteTypeStore {
|
||||
TypeVar { id, ty }
|
||||
})),
|
||||
},
|
||||
ConcreteTypeEnum::TModule { module_id, methods } => TypeEnum::TModule {
|
||||
module_id: *module_id,
|
||||
attributes: methods.iter().map(|(name, cty)| {
|
||||
(*name, (self.to_unifier_type(unifier, primitives, cty.0, cache), cty.1))
|
||||
}).collect::<HashMap<_, _>>(),
|
||||
},
|
||||
ConcreteTypeEnum::TFunc { args, ret, vars } => TypeEnum::TFunc(FunSignature {
|
||||
args: args
|
||||
.iter()
|
||||
|
@ -5,6 +5,7 @@ use std::{
|
||||
iter::{once, repeat, repeat_with, zip},
|
||||
};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use inkwell::{
|
||||
attributes::{Attribute, AttributeLoc},
|
||||
types::{AnyType, BasicType, BasicTypeEnum},
|
||||
@ -61,8 +62,11 @@ pub fn get_subst_key(
|
||||
) -> String {
|
||||
let mut vars = obj
|
||||
.map(|ty| {
|
||||
let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) else { unreachable!() };
|
||||
params.clone()
|
||||
if let TypeEnum::TObj { params, .. } = &*unifier.get_ty(ty) {
|
||||
params.clone()
|
||||
} else if let TypeEnum::TModule { .. } = &*unifier.get_ty(ty) {
|
||||
IndexMap::new()
|
||||
} else { unreachable!() }
|
||||
})
|
||||
.unwrap_or_default();
|
||||
vars.extend(fun_vars);
|
||||
@ -318,8 +322,10 @@ impl<'ctx> CodeGenContext<'ctx, '_> {
|
||||
.build_global_string_ptr(v, "const")
|
||||
.map(|v| v.as_pointer_value().into())
|
||||
.unwrap();
|
||||
println!("point1");
|
||||
|
||||
let size = generator.get_size_type(self.ctx).const_int(v.len() as u64, false);
|
||||
let ty = self.get_llvm_type(generator, self.primitives.str);
|
||||
let ty: BasicTypeEnum<'_> = self.get_llvm_type(generator, self.primitives.str);
|
||||
let val =
|
||||
ty.into_struct_type().const_named_struct(&[str_ptr, size.into()]).into();
|
||||
self.const_strings.insert(v.to_string(), val);
|
||||
@ -831,7 +837,8 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
|
||||
// Ensure that the function object only contains up to 1 vararg parameter
|
||||
debug_assert!(fun.0.args.iter().filter(|arg| arg.is_vararg).count() <= 1);
|
||||
|
||||
// Remove obj if belongs to module
|
||||
|
||||
let symbol = {
|
||||
// make sure this lock guard is dropped at the end of this scope...
|
||||
let def = definition.read();
|
||||
@ -842,7 +849,9 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
codegen_callback,
|
||||
..
|
||||
} => {
|
||||
println!("[[+]] Calling the function for the module and hopefully class");
|
||||
if let Some(callback) = codegen_callback {
|
||||
println!("[+] Callback does exist {:?}", callback);
|
||||
return callback.run(ctx, obj, fun, params, generator);
|
||||
}
|
||||
is_extern = instance_to_stmt.is_empty();
|
||||
@ -851,6 +860,7 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
let mut keys = fun.0.args.clone();
|
||||
let mut mapping = HashMap::<_, Vec<ValueEnum>>::new();
|
||||
|
||||
println!("The params are: {:?}", params.iter().map(|f| f.0).collect_vec());
|
||||
for (key, value) in params {
|
||||
// Find the matching argument
|
||||
let matching_param = fun
|
||||
@ -919,8 +929,14 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
.iter()
|
||||
.map(|arg| (mapping.remove(&arg.name).unwrap(), arg.ty))
|
||||
.collect_vec();
|
||||
println!("Init Real parms: {:?}", real_params.iter().map(|f| ctx.unifier.stringify(f.1)).collect_vec());
|
||||
if let Some(obj) = &obj {
|
||||
real_params.insert(0, (vec![obj.1.clone()], obj.0));
|
||||
if let TypeEnum::TModule{ .. } = &*ctx.unifier.get_ty(obj.0) {
|
||||
println!("[+] Matches with module skipping the additional parameter");
|
||||
real_params.insert(0, (vec![obj.1.clone()], obj.0));
|
||||
} else {
|
||||
real_params.insert(0, (vec![obj.1.clone()], obj.0));
|
||||
}
|
||||
}
|
||||
if let Some(vararg) = vararg_arg {
|
||||
let vararg_arg_name = get_va_count_arg_name(vararg.name);
|
||||
@ -944,6 +960,7 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
}
|
||||
})
|
||||
.collect_vec();
|
||||
println!("Static params: {:?}", static_params.iter().map(|f| (f.0, f.1.get_unique_identifier())).collect_vec());
|
||||
id = {
|
||||
let ids = static_params
|
||||
.iter()
|
||||
@ -965,6 +982,8 @@ pub fn gen_call<'ctx, G: CodeGenerator>(
|
||||
} else {
|
||||
format!("{id}:{old_key}")
|
||||
};
|
||||
println!("2");
|
||||
println!("Real parms: {:?}", real_params.iter().map(|f| ctx.unifier.stringify(f.1)).collect_vec());
|
||||
param_vals = real_params
|
||||
.into_iter()
|
||||
.map(|(ps, t)| {
|
||||
@ -2409,14 +2428,22 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
_ => codegen_unreachable!(ctx, "must be option type"),
|
||||
}
|
||||
}
|
||||
ExprKind::Name { id, .. } => match ctx.var_assignment.get(id) {
|
||||
ExprKind::Name { id, .. } => {
|
||||
println!("ID inquiry for {id}");
|
||||
for entry in ctx.var_assignment.iter(){
|
||||
println!("{:?} => {:?}, {:?}, {:?}", entry.0, entry.1.0, entry.1.1.is_some(), entry.1.2);
|
||||
}
|
||||
|
||||
match ctx.var_assignment.get(id) {
|
||||
Some((ptr, None, _)) => {
|
||||
ctx.builder.build_load(*ptr, id.to_string().as_str()).map(Into::into).unwrap()
|
||||
}
|
||||
Some((_, Some(static_value), _)) => ValueEnum::Static(static_value.clone()),
|
||||
None => {
|
||||
let resolver = ctx.resolver.clone();
|
||||
println!("Ask resolver for value");
|
||||
let value = resolver.get_symbol_value(*id, ctx, generator).unwrap();
|
||||
println!("Resolver returns value");
|
||||
|
||||
let globals = ctx
|
||||
.top_level
|
||||
@ -2425,6 +2452,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
.iter()
|
||||
.filter_map(|def| {
|
||||
if let TopLevelDef::Variable { simple_name, ty, .. } = &*def.read() {
|
||||
println!("Found in Vars! {simple_name}");
|
||||
Some((*simple_name, *ty))
|
||||
} else {
|
||||
None
|
||||
@ -2433,16 +2461,18 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
.collect_vec();
|
||||
|
||||
if let Some((_, ty)) = globals.iter().find(|(name, _)| name == id) {
|
||||
println!("Generating from 2nd clause");
|
||||
let ptr = value
|
||||
.to_basic_value_enum(ctx, generator, *ty)
|
||||
.map(BasicValueEnum::into_pointer_value)?;
|
||||
|
||||
ctx.builder.build_load(ptr, id.to_string().as_str()).map(Into::into).unwrap()
|
||||
} else {
|
||||
println!("Leaving func");
|
||||
value
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
ExprKind::List { elts, .. } => {
|
||||
// this shall be optimized later for constant primitive lists...
|
||||
// we should use memcpy for that instead of generating thousands of stores
|
||||
@ -2814,9 +2844,40 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
.gen_call(ctx, None, (&signature, fun), params)?
|
||||
.map(Into::into));
|
||||
}
|
||||
/*
|
||||
TODO: Update the actual call to link back to function or class constructor
|
||||
Function panics here, class is treated as a uncallable object
|
||||
|
||||
Function identifier registered as a module attribute only and no entry in resolver
|
||||
Either update the resolver to store all function simple paths or handle class representation properly
|
||||
*/
|
||||
ExprKind::Attribute { value, attr, .. } => {
|
||||
println!("The value was: {:?}", value);
|
||||
// if let Some(ty) = value.custom {
|
||||
// if let TypeEnum::TModule { module_id, attributes } = &*ctx.unifier.get_ty(ty) {
|
||||
// if let Some(details) = attributes.get(attr) {
|
||||
// let mut call_expr = expr.clone();
|
||||
// call_expr.custom = Some(details.0);
|
||||
// let mut node = func.clone();
|
||||
// let func_name = "string_attribute_issue337.".to_string() + &attr.to_string();
|
||||
// node.node = ExprKind::Name { id: func_name.into(), ctx: ast::ExprContext::Load };
|
||||
// node.custom = Some(details.0);
|
||||
// call_expr.node = ExprKind::Call { func: Box::new(node), args: args.clone(), keywords: keywords.clone() };
|
||||
// println!("Changed Expr from: {:?} to\n{:?}", expr, call_expr);
|
||||
// return generator.gen_expr(ctx, &call_expr);
|
||||
// }
|
||||
// unreachable!("Module Entry: {:?} => {:?}", module_id, attributes);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Evaluating the value field.
|
||||
// For classes this generates ValueEnum::Dynamic
|
||||
// For modules it generates ValueEnum::Static
|
||||
// Since module type is also dynamic, have it stored as ValueEnum::Dynamic(BasicValueEnum::StructValue)
|
||||
//
|
||||
// Can use this model for the variable definition later
|
||||
let Some(val) = generator.gen_expr(ctx, value)? else { return Ok(None) };
|
||||
|
||||
|
||||
// Handle Class Method calls
|
||||
// The attribute will be `DefinitionId` of the method if the call is to one of the parent methods
|
||||
let func_id = attr.to_string().parse::<usize>();
|
||||
@ -2825,6 +2886,8 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
&*ctx.unifier.get_ty(value.custom.unwrap())
|
||||
{
|
||||
*obj_id
|
||||
} else if let TypeEnum::TModule {module_id, .. } = &*ctx.unifier.get_ty(value.custom.unwrap()) {
|
||||
*module_id
|
||||
} else {
|
||||
codegen_unreachable!(ctx)
|
||||
};
|
||||
@ -2835,11 +2898,13 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
} else {
|
||||
let defs = ctx.top_level.definitions.read();
|
||||
let obj_def = defs.get(id.0).unwrap().read();
|
||||
let TopLevelDef::Class { methods, .. } = &*obj_def else {
|
||||
if let TopLevelDef::Class { methods, .. } = &*obj_def {
|
||||
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
||||
} else if let TopLevelDef::Module { methods, .. } = &*obj_def {
|
||||
methods.iter().find(|method| method.0 == attr).unwrap().1.0
|
||||
} else {
|
||||
codegen_unreachable!(ctx)
|
||||
};
|
||||
|
||||
methods.iter().find(|method| method.0 == *attr).unwrap().2
|
||||
}
|
||||
};
|
||||
// directly generate code for option.unwrap
|
||||
// since it needs to return static value to optimize for kernel invariant
|
||||
@ -2916,7 +2981,7 @@ pub fn gen_expr<'ctx, G: CodeGenerator>(
|
||||
|
||||
// Reset current_loc back to the location of the call
|
||||
ctx.current_loc = expr.location;
|
||||
|
||||
println!("[+] Function Call generated returning to {:?}", expr.location);
|
||||
return Ok(generator
|
||||
.gen_call(
|
||||
ctx,
|
||||
|
@ -82,6 +82,7 @@ pub trait CodeGenerator {
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
println!("[+] Calling gen function on {:?}", expr);
|
||||
gen_expr(self, ctx, expr)
|
||||
}
|
||||
|
||||
|
@ -481,6 +481,48 @@ fn get_llvm_type<'ctx, G: CodeGenerator + ?Sized>(
|
||||
type_cache.get(&unifier.get_representative(ty)).copied().unwrap_or_else(|| {
|
||||
let ty_enum = unifier.get_ty(ty);
|
||||
let result = match &*ty_enum {
|
||||
TModule {module_id, attributes} => {
|
||||
let top_level_defs = top_level.definitions.read();
|
||||
let definition = top_level_defs.get(module_id.0).unwrap();
|
||||
let TopLevelDef::Module { name, methods, .. } = &*definition.read() else {
|
||||
unreachable!()
|
||||
};
|
||||
let ty: BasicTypeEnum<'_> = if let Some(t) = module.get_struct_type(&name.to_string()) {
|
||||
t.ptr_type(AddressSpace::default()).into()
|
||||
} else {
|
||||
let struct_type = ctx.opaque_struct_type(&name.to_string());
|
||||
type_cache.insert(
|
||||
unifier.get_representative(ty),
|
||||
struct_type.ptr_type(AddressSpace::default()).into(),
|
||||
);
|
||||
// Change this to only loop over variables and not methods
|
||||
// let module_attributes = methods
|
||||
// .iter()
|
||||
// .filter_map(|f| {
|
||||
// // TODO: Not all have types
|
||||
// // Remove builtins from here
|
||||
// if !attributes.contains_key(f.0) {
|
||||
// None
|
||||
// } else {
|
||||
// Some(get_llvm_type(
|
||||
// ctx,
|
||||
// module,
|
||||
// generator,
|
||||
// unifier,
|
||||
// top_level,
|
||||
// type_cache,
|
||||
// attributes[&f.0].0,
|
||||
// ))
|
||||
// }
|
||||
// })
|
||||
// .collect_vec();
|
||||
let module_attributes: Vec<BasicTypeEnum<'_>> = Vec::new();
|
||||
struct_type.set_body(&module_attributes, false);
|
||||
struct_type.ptr_type(AddressSpace::default()).into()
|
||||
};
|
||||
println!("[+] Generated type for module");
|
||||
return ty;
|
||||
}
|
||||
TObj { obj_id, fields, .. } => {
|
||||
// check to avoid treating non-class primitives as classes
|
||||
if PrimDef::contains_id(*obj_id) {
|
||||
@ -683,6 +725,7 @@ pub fn gen_func_impl<
|
||||
task: CodeGenTask,
|
||||
codegen_function: F,
|
||||
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
|
||||
println!("Entered gen_func_impl");
|
||||
let top_level_ctx = registry.top_level_ctx.clone();
|
||||
let static_value_store = registry.static_value_store.clone();
|
||||
let (mut unifier, primitives) = {
|
||||
@ -767,6 +810,7 @@ pub fn gen_func_impl<
|
||||
.iter()
|
||||
.copied()
|
||||
.collect();
|
||||
println!("Function corss 50%");
|
||||
// NOTE: special handling of option cannot use this type cache since it contains type var,
|
||||
// handled inside get_llvm_type instead
|
||||
|
||||
@ -799,6 +843,7 @@ pub fn gen_func_impl<
|
||||
ret,
|
||||
))
|
||||
};
|
||||
println!("Function corss 70%");
|
||||
|
||||
let has_sret = ret_type.map_or(false, |ty| need_sret(ty));
|
||||
let mut params = args
|
||||
@ -853,6 +898,7 @@ pub fn gen_func_impl<
|
||||
),
|
||||
);
|
||||
}
|
||||
println!("Function corss 90%");
|
||||
|
||||
let init_bb = context.append_basic_block(fn_val, "init");
|
||||
builder.position_at_end(init_bb);
|
||||
@ -962,6 +1008,7 @@ pub fn gen_func_impl<
|
||||
/* is_optimized */ registry.llvm_options.opt_level != OptimizationLevel::None,
|
||||
);
|
||||
fn_val.set_subprogram(func_scope);
|
||||
println!("Function corss 510%");
|
||||
|
||||
let mut code_gen_context = CodeGenContext {
|
||||
ctx: context,
|
||||
@ -998,18 +1045,25 @@ pub fn gen_func_impl<
|
||||
);
|
||||
code_gen_context.builder.set_current_debug_location(loc);
|
||||
|
||||
println!("Function corss 10%");
|
||||
|
||||
let result = codegen_function(generator, &mut code_gen_context);
|
||||
println!("Function corss 501%");
|
||||
|
||||
// after static analysis, only void functions can have no return at the end.
|
||||
if !code_gen_context.is_terminated() {
|
||||
code_gen_context.builder.build_return(None).unwrap();
|
||||
}
|
||||
println!("Function corss 520%");
|
||||
|
||||
code_gen_context.builder.unset_current_debug_location();
|
||||
code_gen_context.debug_info.0.finalize();
|
||||
println!("Function corss 540%");
|
||||
|
||||
code_gen_context.debug_info.0.finalize();
|
||||
let CodeGenContext { builder, module, .. } = code_gen_context;
|
||||
if let Err(e) = result {
|
||||
println!("Function corss 100%");
|
||||
|
||||
return Err((builder, e));
|
||||
}
|
||||
|
||||
@ -1034,7 +1088,9 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
|
||||
task: CodeGenTask,
|
||||
) -> Result<(Builder<'ctx>, Module<'ctx>, FunctionValue<'ctx>), (Builder<'ctx>, String)> {
|
||||
let body = task.body.clone();
|
||||
println!("\n\n\n{:?}\n\n\n", body);
|
||||
gen_func_impl(context, generator, registry, builder, module, task, |generator, ctx| {
|
||||
println!("It was from this part");
|
||||
generator.gen_block(ctx, body.iter())
|
||||
})
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ pub fn gen_store_target<'ctx, G: CodeGenerator>(
|
||||
None => {
|
||||
let ptr_ty = ctx.get_llvm_type(generator, pattern.custom.unwrap());
|
||||
let ptr = generator.gen_var_alloc(ctx, ptr_ty, name)?;
|
||||
println!("Storing {id}");
|
||||
ctx.var_assignment.insert(*id, (ptr, None, 0));
|
||||
ptr
|
||||
}
|
||||
@ -1385,6 +1386,7 @@ pub fn gen_try<'ctx, 'a, G: CodeGenerator>(
|
||||
let ty = ctx.ctx.i32_type().fn_type(&[], true);
|
||||
ctx.module.add_function(personality_symbol, ty, None)
|
||||
});
|
||||
("here");
|
||||
let exception_type = ctx.get_llvm_type(generator, ctx.primitives.exception);
|
||||
let ptr_type = ctx.ctx.i8_type().ptr_type(inkwell::AddressSpace::default());
|
||||
let current_block = ctx.builder.get_insert_block().unwrap();
|
||||
|
@ -345,9 +345,10 @@ impl<'ctx> ValueEnum<'ctx> {
|
||||
generator: &mut dyn CodeGenerator,
|
||||
expected_ty: Type,
|
||||
) -> Result<BasicValueEnum<'ctx>, String> {
|
||||
println!("Calling the to_basic_value_enum() from {}, {}", file!(), line!());
|
||||
match self {
|
||||
ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator, expected_ty),
|
||||
ValueEnum::Dynamic(v) => Ok(v),
|
||||
ValueEnum::Static(v) => {println!("It was static"); v.to_basic_value_enum(ctx, generator, expected_ty)},
|
||||
ValueEnum::Dynamic(v) => {println!("It was dynamic"); Ok(v)},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,10 +599,12 @@ impl dyn SymbolResolver + Send + Sync {
|
||||
unifier.internal_stringify(
|
||||
ty,
|
||||
&mut |id| {
|
||||
let TopLevelDef::Class { name, .. } = &*top_level_defs[id].read() else {
|
||||
unreachable!("expected class definition")
|
||||
let top_level_def = &*top_level_defs[id].read();
|
||||
let name = match top_level_def {
|
||||
TopLevelDef::Class { name, .. } => name,
|
||||
TopLevelDef::Module { name, .. } => name,
|
||||
_ => unreachable!("expected class definition")
|
||||
};
|
||||
|
||||
name.to_string()
|
||||
},
|
||||
&mut |id| format!("typevar{id}"),
|
||||
|
@ -101,8 +101,7 @@ impl TopLevelComposer {
|
||||
let builtin_name_list = definition_ast_list
|
||||
.iter()
|
||||
.map(|def_ast| match *def_ast.0.read() {
|
||||
TopLevelDef::Class { name, .. } => name.to_string(),
|
||||
TopLevelDef::Module { alias, .. } => alias.to_string(),
|
||||
TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. } => name.to_string(),
|
||||
TopLevelDef::Function { simple_name, .. }
|
||||
| TopLevelDef::Variable { simple_name, .. } => simple_name.to_string(),
|
||||
})
|
||||
@ -207,20 +206,22 @@ impl TopLevelComposer {
|
||||
&mut self,
|
||||
module_name: String,
|
||||
name_to_pyid: Rc<HashMap<StrRef, u64>>,
|
||||
resolver: Arc<dyn SymbolResolver + Send + Sync>,
|
||||
// module_fields: (StrRef, DefinitionId, Option<Type>),
|
||||
resolver: Arc<dyn SymbolResolver + Send + Sync>
|
||||
) -> Result<DefinitionId, String> {
|
||||
// Construct methods field
|
||||
let mut methods: HashMap<StrRef, DefinitionId> = HashMap::new();
|
||||
for (name, _) in name_to_pyid.iter() {
|
||||
if let Ok(def_id) = resolver.get_identifier_def(*name) {
|
||||
methods.insert(*name, def_id);
|
||||
let mut methods: HashMap<StrRef, (DefinitionId, u64)> = HashMap::new();
|
||||
for (name, pyid) in name_to_pyid.iter() {
|
||||
if let Ok(def_id) = resolver.get_identifier_def(*name) {
|
||||
if !self.keyword_list.contains(name) && name.to_string() != module_name {
|
||||
methods.insert(*name, (def_id, *pyid));
|
||||
}
|
||||
};
|
||||
}
|
||||
let module_def = TopLevelDef::Module {
|
||||
name: module_name.clone().into(),
|
||||
alias: module_name.into(),
|
||||
module_id: DefinitionId(self.definition_ast_list.len()),
|
||||
methods,
|
||||
name: module_name.into(),
|
||||
module_id: DefinitionId(self.definition_ast_list.len()),
|
||||
methods,
|
||||
resolver: Some(resolver),
|
||||
loc: None
|
||||
};
|
||||
@ -432,6 +433,7 @@ impl TopLevelComposer {
|
||||
target.location
|
||||
));
|
||||
};
|
||||
println!("Annotated assign call called for {name}");
|
||||
|
||||
self.register_top_level_var(
|
||||
name,
|
||||
@ -462,9 +464,11 @@ impl TopLevelComposer {
|
||||
mod_path: &str,
|
||||
location: Location,
|
||||
) -> Result<(StrRef, DefinitionId, Option<Type>), String> {
|
||||
if self.keyword_list.contains(&name) {
|
||||
return Err(format!("cannot use keyword `{name}` as a class name (at {location})"));
|
||||
}
|
||||
// TODO: Keywords are initialized in min_artiq as StmtKind::Variable
|
||||
// Move the keyword definitions to a dedicated module before this check
|
||||
// if self.keyword_list.contains(&name) {
|
||||
// return Err(format!("cannot use keyword `{name}` as a variable name (at {location})"));
|
||||
// }
|
||||
|
||||
let global_var_name =
|
||||
if mod_path.is_empty() { name.to_string() } else { format!("{mod_path}.{name}") };
|
||||
@ -498,10 +502,14 @@ impl TopLevelComposer {
|
||||
self.analyze_top_level_class_definition()?;
|
||||
self.analyze_top_level_class_fields_methods()?;
|
||||
self.analyze_top_level_function()?;
|
||||
println!("Fill Variables first");
|
||||
self.analyze_top_level_variables()?;
|
||||
println!("Parse functions here");
|
||||
if inference {
|
||||
self.analyze_function_instance()?;
|
||||
}
|
||||
self.analyze_top_level_variables()?;
|
||||
println!("[+] Parsing functions here2");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -375,11 +375,11 @@ pub fn make_exception_fields(int32: Type, int64: Type, str: Type) -> Vec<(StrRef
|
||||
impl TopLevelDef {
|
||||
pub fn to_string(&self, unifier: &mut Unifier) -> String {
|
||||
match self {
|
||||
TopLevelDef::Module { name, alias, methods, .. } => {
|
||||
TopLevelDef::Module { name, methods, .. } => {
|
||||
let method_str = methods.iter().map(|(n, _)| n.to_string()).collect_vec();
|
||||
format!(
|
||||
"Module {{\nname: {:?},\nalias{:?},\nattributes{:?}\n}}",
|
||||
name, alias, method_str
|
||||
"Module {{\nname: {:?},\nattributes{:?}\n}}",
|
||||
name, method_str
|
||||
)
|
||||
}
|
||||
TopLevelDef::Class {
|
||||
|
@ -95,12 +95,12 @@ pub enum TopLevelDef {
|
||||
Module {
|
||||
/// Name of the module
|
||||
name: StrRef,
|
||||
/// Alias used by the module
|
||||
alias: StrRef,
|
||||
/// Module ID used for [`TypeEnum`]
|
||||
module_id: DefinitionId,
|
||||
/// Methods
|
||||
methods: HashMap<StrRef, DefinitionId>,
|
||||
///
|
||||
/// Name and definition ID of the classes and functions inside module
|
||||
methods: HashMap<StrRef, (DefinitionId, u64)>,
|
||||
/// Symbol resolver of the module defined the class.
|
||||
resolver: Option<Arc<dyn SymbolResolver + Send + Sync>>,
|
||||
/// Definition location.
|
||||
|
@ -97,6 +97,7 @@ impl Inferencer<'_> {
|
||||
&& ty.obj_id(self.unifier).is_none_or(|id| id != PrimDef::List.id())
|
||||
&& !self.unifier.is_concrete(*ty, &self.function_data.bound_variables)
|
||||
{
|
||||
println!("B4 Error: {:?}", expr);
|
||||
return Err(HashSet::from([format!(
|
||||
"expected concrete type at {} but got {}",
|
||||
expr.location,
|
||||
|
@ -2008,72 +2008,96 @@ impl Inferencer<'_> {
|
||||
ctx: ExprContext,
|
||||
) -> InferenceResult {
|
||||
let ty = value.custom.unwrap();
|
||||
if let TypeEnum::TObj { obj_id, fields, .. } = &*self.unifier.get_ty(ty) {
|
||||
// just a fast path
|
||||
match (fields.get(&attr), ctx == ExprContext::Store) {
|
||||
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
||||
(Some((ty, false)), true) => report_type_error(
|
||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
),
|
||||
(None, mutable) => {
|
||||
// Check whether it is a class attribute
|
||||
let defs = self.top_level.definitions.read();
|
||||
let result = {
|
||||
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
||||
attributes.iter().find_map(|f| {
|
||||
if f.0 == attr {
|
||||
return Some(f.1);
|
||||
}
|
||||
None
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
match result {
|
||||
Some(res) if !mutable => Ok(res),
|
||||
Some(_) => report_error(
|
||||
&format!("Class Attribute `{attr}` is immutable"),
|
||||
value.location,
|
||||
),
|
||||
None => report_type_error(
|
||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(ty) {
|
||||
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
||||
let result = {
|
||||
self.top_level.definitions.read().iter().find_map(|def| {
|
||||
if let Some(rear_guard) = def.try_read() {
|
||||
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
||||
if name.to_string() == self.unifier.stringify(sign.ret) {
|
||||
return attributes.iter().find_map(|f| {
|
||||
println!("InferAttr {attr}, Value type: {:?} ({:?})", self.unifier.stringify(ty), self.unifier.get_ty(ty));
|
||||
match &*self.unifier.get_ty(ty) {
|
||||
TypeEnum::TObj { obj_id, fields, .. } => {
|
||||
// just a fast path
|
||||
match (fields.get(&attr), ctx == ExprContext::Store) {
|
||||
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
||||
(Some((ty, false)), true) => report_type_error(
|
||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
),
|
||||
(None, mutable) => {
|
||||
// Check whether it is a class attribute
|
||||
let defs = self.top_level.definitions.read();
|
||||
let result = {
|
||||
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
||||
attributes.iter().find_map(|f| {
|
||||
if f.0 == attr {
|
||||
return Some(f.clone().1);
|
||||
return Some(f.1);
|
||||
}
|
||||
None
|
||||
});
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
match result {
|
||||
Some(res) if !mutable => Ok(res),
|
||||
Some(_) => report_error(
|
||||
&format!("Class Attribute `{attr}` is immutable"),
|
||||
value.location,
|
||||
),
|
||||
None => report_type_error(
|
||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
),
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
};
|
||||
match result {
|
||||
Some(f) if ctx != ExprContext::Store => Ok(f),
|
||||
Some(_) => {
|
||||
report_error(&format!("Class Attribute `{attr}` is immutable"), value.location)
|
||||
}
|
||||
None => self.infer_general_attribute(value, attr, ctx),
|
||||
}
|
||||
} else {
|
||||
self.infer_general_attribute(value, attr, ctx)
|
||||
TypeEnum::TFunc(sign) => {
|
||||
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
||||
let result = {
|
||||
self.top_level.definitions.read().iter().find_map(|def| {
|
||||
if let Some(rear_guard) = def.try_read() {
|
||||
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
||||
if name.to_string() == self.unifier.stringify(sign.ret) {
|
||||
return attributes.iter().find_map(|f| {
|
||||
if f.0 == attr {
|
||||
return Some(f.clone().1);
|
||||
}
|
||||
None
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
};
|
||||
match result {
|
||||
Some(f) if ctx != ExprContext::Store => Ok(f),
|
||||
Some(_) => {
|
||||
report_error(&format!("Class Attribute `{attr}` is immutable"), value.location)
|
||||
}
|
||||
None => self.infer_general_attribute(value, attr, ctx),
|
||||
}
|
||||
}
|
||||
TypeEnum::TModule { attributes, .. } => {
|
||||
let res = self.infer_general_attribute(value, attr, ctx);
|
||||
if let Ok(r) = res {
|
||||
println!("[[[+]]] {:?} => {:?}", self.unifier.stringify(r), self.unifier.get_ty(r));
|
||||
} else {
|
||||
println!("[[[-]]] {:?}", res.err().unwrap());
|
||||
}
|
||||
match (attributes.get(&attr), ctx == ExprContext::Load) {
|
||||
(Some((ty, _)), true) | (Some((ty, true)), false) => Ok(*ty),
|
||||
(Some((ty, false)), false) => report_type_error(
|
||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
),
|
||||
(None, _) => report_type_error(
|
||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||
Some(value.location),
|
||||
self.unifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
_ => self.infer_general_attribute(value, attr, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2734,8 +2758,8 @@ impl Inferencer<'_> {
|
||||
.read()
|
||||
.iter()
|
||||
.map(|def| match *def.read() {
|
||||
TopLevelDef::Class { name, .. } => (name, false),
|
||||
TopLevelDef::Module { alias, .. } => (alias, false),
|
||||
TopLevelDef::Class { name, .. }
|
||||
| TopLevelDef::Module { name, .. } => (name, false),
|
||||
TopLevelDef::Function { simple_name, .. } => (simple_name, false),
|
||||
TopLevelDef::Variable { simple_name, .. } => (simple_name, true),
|
||||
})
|
||||
|
@ -1,11 +1,5 @@
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::{self, Display},
|
||||
iter::{repeat, repeat_n, zip},
|
||||
rc::Rc,
|
||||
sync::{Arc, Mutex},
|
||||
borrow::Cow, cell::RefCell, collections::{HashMap, HashSet}, fmt::{self, Display}, iter::{repeat, repeat_n, zip}, ops::Deref, rc::Rc, sync::{Arc, Mutex}
|
||||
};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@ -1330,10 +1324,12 @@ impl Unifier {
|
||||
|| format!("{id}"),
|
||||
|top_level| {
|
||||
let top_level_def = &top_level.definitions.read()[id];
|
||||
let TopLevelDef::Class { name, .. } = &*top_level_def.read() else {
|
||||
unreachable!("expected class definition")
|
||||
let top_level_def = top_level_def.read();
|
||||
let name = match top_level_def.deref() {
|
||||
TopLevelDef::Class { name, .. } => name,
|
||||
TopLevelDef::Module { name, .. } => name,
|
||||
_ => unreachable!("expected class definition")
|
||||
};
|
||||
|
||||
name.to_string()
|
||||
},
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user