nac3core: option type front end

This commit is contained in:
ychenfo 2022-03-14 05:12:43 +08:00
parent 55db05fdbb
commit 62d13e297c
6 changed files with 161 additions and 2 deletions

View File

@ -385,6 +385,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
range: unifier.get_representative(primitives.range),
str: unifier.get_representative(primitives.str),
exception: unifier.get_representative(primitives.exception),
option: unifier.get_representative(primitives.option),
};
let mut type_cache: HashMap<_, _> = [
@ -417,6 +418,7 @@ pub fn gen_func<'ctx, G: CodeGenerator>(
exception.set_body(&fields, false);
exception.ptr_type(AddressSpace::Generic).into()
});
// TODO: insert option type cache
let (args, ret) = if let ConcreteTypeEnum::TFunc { args, ret, .. } =
task.store.get(task.signature)

View File

@ -105,6 +105,20 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
("__param2__".into(), int64, true),
];
// for Option, is_some and is_none share the same type: () -> bool,
// and they are methods under the same class `Option`
let (is_some_ty, unwrap_ty, (option_ty_var, option_ty_var_id)) =
if let TypeEnum::TObj { fields, params, .. } =
primitives.1.get_ty(primitives.0.option).as_ref()
{
(
*fields.get(&"is_some".into()).unwrap(),
*fields.get(&"unwrap".into()).unwrap(),
(*params.iter().next().unwrap().1, *params.iter().next().unwrap().0),
)
} else {
unreachable!()
};
let top_level_def_list = vec![
Arc::new(RwLock::new(TopLevelComposer::make_top_level_class_def(
0,
@ -180,6 +194,58 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
None,
None,
))),
Arc::new(RwLock::new({
TopLevelDef::Class {
name: "Option".into(),
object_id: DefinitionId(10),
type_vars: vec![option_ty_var],
fields: vec![],
methods: vec![
("is_some".into(), is_some_ty.0, DefinitionId(11)),
("is_none".into(), is_some_ty.0, DefinitionId(12)),
("unwrap".into(), unwrap_ty.0, DefinitionId(13)),
],
ancestors: vec![TypeAnnotation::CustomClass {
id: DefinitionId(10),
params: Default::default(),
}],
constructor: None,
resolver: None,
loc: None,
}
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "Option.is_some".into(),
simple_name: "is_some".into(),
signature: is_some_ty.0,
var_id: vec![option_ty_var_id],
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| {
// TODO:
unimplemented!()
},
)))),
loc: None,
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "Option.unwrap".into(),
simple_name: "unwrap".into(),
signature: unwrap_ty.0,
var_id: vec![option_ty_var_id],
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| {
// TODO:
unimplemented!()
},
)))),
loc: None,
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "int32".into(),
simple_name: "int32".into(),
@ -1098,6 +1164,25 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
)))),
loc: None,
})),
Arc::new(RwLock::new(TopLevelDef::Function {
name: "Some".into(),
simple_name: "Some".into(),
signature: primitives.1.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![FuncArg { name: "n".into(), ty: option_ty_var, default_value: None }],
ret: primitives.0.option,
vars: HashMap::from([(option_ty_var_id, option_ty_var)]),
})),
var_id: vec![option_ty_var_id],
instance_to_symbol: Default::default(),
instance_to_stmt: Default::default(),
resolver: None,
codegen_callback: Some(Arc::new(GenCall::new(Box::new(
|ctx, _, fun, args, generator| {
unimplemented!()
},
)))),
loc: None,
})),
];
let ast_list: Vec<Option<ast::Stmt<()>>> =
@ -1123,6 +1208,7 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
"min",
"max",
"abs",
"Some",
],
)
}

View File

@ -74,6 +74,8 @@ impl TopLevelComposer {
"self".into(),
"Kernel".into(),
"KernelInvariant".into(),
"Some".into(),
"Option".into(),
]);
let defined_names: HashSet<String> = Default::default();
let method_class: HashMap<DefinitionId, DefinitionId> = Default::default();
@ -92,7 +94,6 @@ impl TopLevelComposer {
} else if let TopLevelDef::Class { name, constructor, object_id, type_vars, .. } = &*def
{
assert!(id == object_id.0);
assert!(type_vars.is_empty());
if let Some(constructor) = constructor {
builtin_ty.insert(*name, *constructor);
}

View File

@ -107,7 +107,42 @@ impl TopLevelComposer {
fields: HashMap::new(),
params: HashMap::new(),
});
let primitives = PrimitiveStore { int32, int64, float, bool, none, range, str, exception, uint32, uint64 };
let option_type_var = unifier.get_fresh_var(Some("option_type_var".into()), None);
let is_some_type_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: bool,
vars: HashMap::from([(option_type_var.1, option_type_var.0)]),
}));
let unwrap_fun_ty = unifier.add_ty(TypeEnum::TFunc(FunSignature {
args: vec![],
ret: option_type_var.0,
vars: HashMap::from([(option_type_var.1, option_type_var.0)]),
}));
let option = unifier.add_ty(TypeEnum::TObj {
obj_id: DefinitionId(10),
fields: vec![
("is_some".into(), (is_some_type_fun_ty, true)),
("unwrap".into(), (unwrap_fun_ty, true)),
]
.into_iter()
.collect::<HashMap<_, _>>(),
params: HashMap::from([(option_type_var.1, option_type_var.0)]),
});
let primitives = PrimitiveStore {
int32,
int64,
float,
bool,
none,
range,
str,
exception,
uint32,
uint64,
option,
};
crate::typecheck::magic_methods::set_primitives_magic_methods(&primitives, &mut unifier);
(primitives, unifier)
}

View File

@ -223,6 +223,29 @@ pub fn parse_ast_to_type_annotation_kinds<T>(
Ok(TypeAnnotation::List(def_ann.into()))
}
// option
ast::ExprKind::Subscript { value, slice, .. }
if {
matches!(&value.node, ast::ExprKind::Name { id, .. } if id == &"Option".into())
} =>
{
let def_ann = parse_ast_to_type_annotation_kinds(
resolver,
top_level_defs,
unifier,
primitives,
slice.as_ref(),
locked,
)?;
let id =
if let TypeEnum::TObj { obj_id, .. } = unifier.get_ty(primitives.option).as_ref() {
*obj_id
} else {
unreachable!()
};
Ok(TypeAnnotation::CustomClass { id, params: vec![def_ann] })
}
// tuple
ast::ExprKind::Subscript { value, slice, .. }
if {

View File

@ -40,6 +40,7 @@ pub struct PrimitiveStore {
pub range: Type,
pub str: Type,
pub exception: Type,
pub option: Type,
}
pub struct FunctionData {
@ -932,6 +933,17 @@ impl<'a> Inferencer<'a> {
Ok(self.unifier.add_ty(TypeEnum::TTuple { ty: ty? }))
}
ast::Constant::Str(_) => Ok(self.primitives.str),
ast::Constant::None => {
let option_ty = self.primitives.option;
let new_mapping = if let TypeEnum::TObj { params, .. } = &*self.unifier.get_ty_immutable(option_ty) {
let (id, _) = params.iter().next().unwrap();
// None can be Option[Any]
vec![(*id, self.unifier.get_fresh_var(None, None).0)].into_iter().collect()
} else {
unreachable!("option must be tobj")
};
Ok(self.unifier.subst(option_ty, &new_mapping).unwrap())
}
_ => report_error("not supported", *loc),
}
}