[WIP] Cleanup irrelevant part

This commit is contained in:
abdul124 2025-01-09 17:40:13 +08:00
parent b03e81adef
commit 9c4283fea3
20 changed files with 2044 additions and 1685 deletions

View File

@ -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__":

View File

@ -202,7 +202,6 @@ class Core:
def run(self, method, *args, **kwargs):
global allow_registration
embedding = EmbeddingMap()
if allow_registration:

View File

@ -1 +0,0 @@
../../target/release/libnac3artiq.so

View File

@ -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

View File

@ -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:

View File

@ -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();

View File

@ -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;

View File

@ -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()

View File

@ -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,

View File

@ -82,6 +82,7 @@ pub trait CodeGenerator {
where
Self: Sized,
{
println!("[+] Calling gen function on {:?}", expr);
gen_expr(self, ctx, expr)
}

View File

@ -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())
})
}

View File

@ -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();

View File

@ -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}"),

View File

@ -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(())
}

View File

@ -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 {

View File

@ -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.

View File

@ -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,

View File

@ -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),
})

View File

@ -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