use std::collections::HashMap; use std::fmt::Debug; use std::{cell::RefCell, sync::Arc}; use crate::{ codegen::CodeGenContext, toplevel::{DefinitionId, TopLevelDef}, }; use crate::{ codegen::CodeGenerator, typecheck::{ type_inferencer::PrimitiveStore, typedef::{Type, Unifier}, }, }; use crate::typecheck::typedef::TypeEnum; use inkwell::values::{BasicValueEnum, FloatValue, IntValue, PointerValue}; use itertools::{chain, izip}; use nac3parser::ast::{Expr, StrRef}; use parking_lot::RwLock; #[derive(Clone, PartialEq, Debug)] pub enum SymbolValue { I32(i32), I64(i64), Str(String), Double(f64), Bool(bool), Tuple(Vec), } pub trait StaticValue { fn get_unique_identifier(&self) -> u64; fn get_const_obj<'ctx, 'a>( &self, ctx: &mut CodeGenContext<'ctx, 'a>, generator: &mut dyn CodeGenerator, ) -> BasicValueEnum<'ctx>; fn to_basic_value_enum<'ctx, 'a>( &self, ctx: &mut CodeGenContext<'ctx, 'a>, generator: &mut dyn CodeGenerator, ) -> BasicValueEnum<'ctx>; fn get_field<'ctx, 'a>( &self, name: StrRef, ctx: &mut CodeGenContext<'ctx, 'a>, ) -> Option>; } #[derive(Clone)] pub enum ValueEnum<'ctx> { Static(Arc), Dynamic(BasicValueEnum<'ctx>), } impl<'ctx> From> for ValueEnum<'ctx> { fn from(v: BasicValueEnum<'ctx>) -> Self { ValueEnum::Dynamic(v) } } impl<'ctx> From> for ValueEnum<'ctx> { fn from(v: PointerValue<'ctx>) -> Self { ValueEnum::Dynamic(v.into()) } } impl<'ctx> From> for ValueEnum<'ctx> { fn from(v: IntValue<'ctx>) -> Self { ValueEnum::Dynamic(v.into()) } } impl<'ctx> From> 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>, generator: &mut dyn CodeGenerator, ) -> BasicValueEnum<'ctx> { match self { ValueEnum::Static(v) => v.to_basic_value_enum(ctx, generator), ValueEnum::Dynamic(v) => v, } } } pub trait SymbolResolver { // get type of type variable identifier or top-level function type fn get_symbol_type( &self, unifier: &mut Unifier, top_level_defs: &[Arc>], primitives: &PrimitiveStore, str: StrRef, ) -> Result; // get the top-level definition of identifiers fn get_identifier_def(&self, str: StrRef) -> Option; fn get_symbol_value<'ctx, 'a>( &self, str: StrRef, ctx: &mut CodeGenContext<'ctx, 'a>, ) -> Option>; fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option; fn get_string_id(&self, s: &str) -> i32; // handle function call etc. } thread_local! { static IDENTIFIER_ID: [StrRef; 10] = [ "int32".into(), "int64".into(), "float".into(), "bool".into(), "None".into(), "virtual".into(), "list".into(), "tuple".into(), "str".into(), "Exception".into(), ]; } // convert type annotation into type pub fn parse_type_annotation( resolver: &dyn SymbolResolver, top_level_defs: &[Arc>], unifier: &mut Unifier, primitives: &PrimitiveStore, expr: &Expr, ) -> Result { use nac3parser::ast::ExprKind::*; let ids = IDENTIFIER_ID.with(|ids| *ids); let int32_id = ids[0]; let int64_id = ids[1]; let float_id = ids[2]; let bool_id = ids[3]; let none_id = ids[4]; let virtual_id = ids[5]; let list_id = ids[6]; let tuple_id = ids[7]; let str_id = ids[8]; let exn_id = ids[9]; let name_handling = |id: &StrRef, unifier: &mut Unifier| { if *id == int32_id { Ok(primitives.int32) } else if *id == int64_id { Ok(primitives.int64) } else if *id == float_id { Ok(primitives.float) } else if *id == bool_id { Ok(primitives.bool) } else if *id == none_id { Ok(primitives.none) } else if *id == str_id { Ok(primitives.str) } else if *id == exn_id { Ok(primitives.exception) } else { let obj_id = resolver.get_identifier_def(*id); if let Some(obj_id) = obj_id { let def = top_level_defs[obj_id.0].read(); if let TopLevelDef::Class { fields, methods, type_vars, .. } = &*def { if !type_vars.is_empty() { return Err(format!( "Unexpected number of type parameters: expected {} but got 0", type_vars.len() )); } let fields = RefCell::new( chain( fields.iter().map(|(k, v, m)| (*k, (*v, *m))), methods.iter().map(|(k, v, _)| (*k, (*v, false))), ) .collect(), ); Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields, params: Default::default(), })) } else { Err("Cannot use function name as type".into()) } } else { // it could be a type variable let ty = resolver.get_symbol_type(unifier, top_level_defs, primitives, *id)?; if let TypeEnum::TVar { .. } = &*unifier.get_ty(ty) { Ok(ty) } else { Err(format!("Unknown type annotation {}", id)) } } } }; let subscript_name_handle = |id: &StrRef, slice: &Expr, unifier: &mut Unifier| { if *id == virtual_id { let ty = parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?; Ok(unifier.add_ty(TypeEnum::TVirtual { ty })) } else if *id == list_id { let ty = parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?; Ok(unifier.add_ty(TypeEnum::TList { ty })) } else if *id == tuple_id { if let Tuple { elts, .. } = &slice.node { let ty = elts .iter() .map(|elt| { parse_type_annotation(resolver, top_level_defs, unifier, primitives, elt) }) .collect::, _>>()?; Ok(unifier.add_ty(TypeEnum::TTuple { ty })) } else { Err("Expected multiple elements for tuple".into()) } } else { let types = if let Tuple { elts, .. } = &slice.node { elts.iter() .map(|v| { parse_type_annotation(resolver, top_level_defs, unifier, primitives, v) }) .collect::, _>>()? } else { vec![parse_type_annotation(resolver, top_level_defs, unifier, primitives, slice)?] }; let obj_id = resolver .get_identifier_def(*id) .ok_or_else(|| format!("Unknown type annotation {}", id))?; let def = top_level_defs[obj_id.0].read(); if let TopLevelDef::Class { fields, methods, type_vars, .. } = &*def { if types.len() != type_vars.len() { return Err(format!( "Unexpected number of type parameters: expected {} but got {}", type_vars.len(), types.len() )); } let mut subst = HashMap::new(); for (var, ty) in izip!(type_vars.iter(), types.iter()) { let id = if let TypeEnum::TVar { id, .. } = &*unifier.get_ty(*var) { *id } else { unreachable!() }; subst.insert(id, *ty); } let mut fields = fields .iter() .map(|(attr, ty, is_mutable)| { let ty = unifier.subst(*ty, &subst).unwrap_or(*ty); (*attr, (ty, *is_mutable)) }) .collect::>(); fields.extend(methods.iter().map(|(attr, ty, _)| { let ty = unifier.subst(*ty, &subst).unwrap_or(*ty); (*attr, (ty, false)) })); Ok(unifier.add_ty(TypeEnum::TObj { obj_id, fields: fields.into(), params: subst.into(), })) } else { Err("Cannot use function name as type".into()) } } }; match &expr.node { Name { id, .. } => name_handling(id, unifier), Subscript { value, slice, .. } => { if let Name { id, .. } = &value.node { subscript_name_handle(id, slice, unifier) } else { Err(format!("unsupported type expression at {}", expr.location)) } } _ => Err(format!("unsupported type expression at {}", expr.location)), } } impl dyn SymbolResolver + Send + Sync { pub fn parse_type_annotation( &self, top_level_defs: &[Arc>], unifier: &mut Unifier, primitives: &PrimitiveStore, expr: &Expr, ) -> Result { parse_type_annotation(self, top_level_defs, unifier, primitives, expr) } pub fn get_type_name( &self, top_level_defs: &[Arc>], unifier: &mut Unifier, ty: Type, ) -> String { unifier.stringify( ty, &mut |id| { if let TopLevelDef::Class { name, .. } = &*top_level_defs[id].read() { name.to_string() } else { unreachable!("expected class definition") } }, &mut |id| format!("var{}", id), ) } } impl Debug for dyn SymbolResolver + Send + Sync { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "") } }