default paramter support simple global modules

This commit is contained in:
ychenfo 2021-11-21 21:31:10 +08:00
parent e75ec35687
commit 6397e42e74
10 changed files with 188 additions and 55 deletions

View File

@ -2,7 +2,7 @@ use inkwell::{types::BasicType, values::BasicValueEnum, AddressSpace};
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::SymbolResolver, symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
@ -14,7 +14,7 @@ use pyo3::{
types::{PyList, PyModule, PyTuple}, types::{PyList, PyModule, PyTuple},
PyAny, PyObject, PyResult, Python, PyAny, PyObject, PyResult, Python,
}; };
use nac3parser::ast::StrRef; use nac3parser::ast::{self, StrRef};
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, HashSet}, collections::{HashMap, HashSet},
@ -399,9 +399,86 @@ impl Resolver {
} }
} }
} }
fn get_default_param_obj_value(&self, obj: &PyAny, helper: &PythonHelper) -> PyResult<Result<SymbolValue, String>> {
let ty_id: u64 = helper
.id_fn
.call1((helper.type_fn.call1((obj,))?,))?
.extract()?;
Ok(
if ty_id == self.primitive_ids.int || ty_id == self.primitive_ids.int32 {
let val: i32 = obj.extract()?;
Ok(SymbolValue::I32(val))
} else if ty_id == self.primitive_ids.int64 {
let val: i64 = obj.extract()?;
Ok(SymbolValue::I64(val))
} else if ty_id == self.primitive_ids.bool {
let val: bool = obj.extract()?;
Ok(SymbolValue::Bool(val))
} else if ty_id == self.primitive_ids.float {
let val: f64 = obj.extract()?;
Ok(SymbolValue::Double(val))
} else if ty_id == self.primitive_ids.tuple {
let elements: &PyTuple = obj.cast_as()?;
let elements: Result<Result<Vec<_>, String>, _> = elements
.iter()
.map(|elem| {
self.get_default_param_obj_value(
elem,
helper
)
})
.collect();
let elements = match elements? {
Ok(el) => el,
Err(err) => return Ok(Err(err))
};
Ok(SymbolValue::Tuple(elements))
} else {
Err("only primitives values and tuple can be default parameter value".into())
}
)
}
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_default_param_value(
&self,
expr: &ast::Expr
) -> Option<SymbolValue> {
match &expr.node {
ast::ExprKind::Name { id, .. } => {
Python::with_gil(
|py| -> PyResult<Option<SymbolValue>> {
let obj: &PyAny = self.module.extract(py)?;
let members: &PyList = PyModule::import(py, "inspect")?
.getattr("getmembers")?
.call1((obj,))?
.cast_as()?;
let mut sym_value = None;
for member in members.iter() {
let key: &str = member.get_item(0)?.extract()?;
let val = member.get_item(1)?;
if key == id.to_string() {
let builtins = PyModule::import(py, "builtins")?;
let helper = PythonHelper {
id_fn: builtins.getattr("id").unwrap(),
len_fn: builtins.getattr("len").unwrap(),
type_fn: builtins.getattr("type").unwrap(),
};
sym_value = Some(self.get_default_param_obj_value(val, &helper).unwrap().unwrap());
break;
}
}
Ok(sym_value)
}
)
.unwrap()
}
_ => unimplemented!("other type of expr not supported at {}", expr.location)
}
}
fn get_symbol_type( fn get_symbol_type(
&self, &self,
unifier: &mut Unifier, unifier: &mut Unifier,

View File

@ -37,6 +37,10 @@ impl Resolver {
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
unimplemented!()
}
fn get_symbol_type( fn get_symbol_type(
&self, &self,
_: &mut Unifier, _: &mut Unifier,

View File

@ -44,6 +44,7 @@ pub trait SymbolResolver {
ctx: &mut CodeGenContext<'ctx, 'a>, ctx: &mut CodeGenContext<'ctx, 'a>,
) -> Option<BasicValueEnum<'ctx>>; ) -> Option<BasicValueEnum<'ctx>>;
fn get_symbol_location(&self, str: StrRef) -> Option<Location>; fn get_symbol_location(&self, str: StrRef) -> Option<Location>;
fn get_default_param_value(&self, expr: &nac3parser::ast::Expr) -> Option<SymbolValue>;
// handle function call etc. // handle function call etc.
} }

View File

@ -1136,7 +1136,7 @@ impl TopLevelComposer {
default_value: match default { default_value: match default {
None => None, None => None,
Some(default) => Some(default) =>
Some(Self::parse_parameter_default_value(default)?) Some(Self::parse_parameter_default_value(default, resolver)?)
} }
}) })
}) })
@ -1353,7 +1353,7 @@ impl TopLevelComposer {
if name == "self".into() { if name == "self".into() {
return Err(format!("`self` parameter cannot take default value at {}", x.location)); return Err(format!("`self` parameter cannot take default value at {}", x.location));
} }
Some(Self::parse_parameter_default_value(default)?) Some(Self::parse_parameter_default_value(default, class_resolver)?)
} }
} }
}; };

View File

@ -347,51 +347,64 @@ impl TopLevelComposer {
Ok(result) Ok(result)
} }
pub fn parse_parameter_default_value(default: &ast::Expr) -> Result<SymbolValue, String> { pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result<SymbolValue, String> {
fn handle_constant(val: &Constant, loc: &Location) -> Result<SymbolValue, String> { parse_parameter_default_value(default, resolver)
match val { }
Constant::Int(v) => { }
if let Ok(v) = v.try_into() {
Ok(SymbolValue::I32(v)) pub fn parse_parameter_default_value(default: &ast::Expr, resolver: &(dyn SymbolResolver + Send + Sync)) -> Result<SymbolValue, String> {
} else { fn handle_constant(val: &Constant, loc: &Location) -> Result<SymbolValue, String> {
Err(format!( match val {
"int64 default parameter should be specified explicitly by `int64()` at {}", Constant::Int(v) => {
loc if let Ok(v) = v.try_into() {
)) Ok(SymbolValue::I32(v))
} } else {
} Err(format!(
Constant::Float(v) => Ok(SymbolValue::Double(*v)), "int64 default parameter should be specified explicitly by `int64()` at {}",
Constant::Bool(v) => Ok(SymbolValue::Bool(*v)), loc
Constant::Tuple(tuple) => Ok(SymbolValue::Tuple( ))
tuple.iter().map(|x| handle_constant(x, loc)).collect::<Result<Vec<_>, _>>()? }
)), }
_ => unimplemented!("this constant is not supported at {}", loc), Constant::Float(v) => Ok(SymbolValue::Double(*v)),
} Constant::Bool(v) => Ok(SymbolValue::Bool(*v)),
} Constant::Tuple(tuple) => Ok(SymbolValue::Tuple(
match &default.node { tuple.iter().map(|x| handle_constant(x, loc)).collect::<Result<Vec<_>, _>>()?
ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location), )),
ast::ExprKind::Call { func, args, .. } if { _ => unimplemented!("this constant is not supported at {}", loc),
match &func.node { }
ast::ExprKind::Name { id, .. } => *id == "int64".into(), }
_ => false, match &default.node {
} ast::ExprKind::Constant { value, .. } => handle_constant(value, &default.location),
} => { ast::ExprKind::Call { func, args, .. } if {
if args.len() == 1 { match &func.node {
match &args[0].node { ast::ExprKind::Name { id, .. } => *id == "int64".into(),
ast::ExprKind::Constant { value: Constant::Int(v), .. } => _ => false,
Ok(SymbolValue::I64(v.try_into().unwrap())), }
_ => Err(format!("only allow constant integer here at {}", default.location)) } => {
} if args.len() == 1 {
} else { match &args[0].node {
Err(format!("only allow constant integer here at {}", default.location)) ast::ExprKind::Constant { value: Constant::Int(v), .. } =>
} Ok(SymbolValue::I64(v.try_into().unwrap())),
} _ => Err(format!("only allow constant integer here at {}", default.location))
ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts }
.iter() } else {
.map(|x| Self::parse_parameter_default_value(x)) Err(format!("only allow constant integer here at {}", default.location))
.collect::<Result<Vec<_>, _>>()? }
)), }
_ => unimplemented!("only constant default is supported now at {}", default.location), ast::ExprKind::Tuple { elts, .. } => Ok(SymbolValue::Tuple(elts
} .iter()
.map(|x| parse_parameter_default_value(x, resolver))
.collect::<Result<Vec<_>, _>>()?
)),
ast::ExprKind::Name { id, .. } => {
resolver.get_default_param_value(default).ok_or_else(
|| format!(
"this module global `{}` cannot be used as a default parameter at {} (should be primitive type or tuple)",
id,
default.location
)
)
}
_ => unimplemented!("only constant default is supported now at {}", default.location),
} }
} }

View File

@ -23,7 +23,7 @@ use inkwell::values::BasicValueEnum;
pub struct DefinitionId(pub usize); pub struct DefinitionId(pub usize);
pub mod composer; pub mod composer;
mod helper; pub mod helper;
mod type_annotation; mod type_annotation;
use composer::*; use composer::*;
use type_annotation::*; use type_annotation::*;

View File

@ -35,6 +35,10 @@ impl ResolverInternal {
struct Resolver(Arc<ResolverInternal>); struct Resolver(Arc<ResolverInternal>);
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
unimplemented!()
}
fn get_symbol_type( fn get_symbol_type(
&self, &self,
_: &mut Unifier, _: &mut Unifier,

View File

@ -19,6 +19,10 @@ struct Resolver {
} }
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_default_param_value(&self, _: &nac3parser::ast::Expr) -> Option<crate::symbol_resolver::SymbolValue> {
unimplemented!()
}
fn get_symbol_type( fn get_symbol_type(
&self, &self,
_: &mut Unifier, _: &mut Unifier,

View File

@ -2,21 +2,22 @@ use inkwell::values::BasicValueEnum;
use nac3core::{ use nac3core::{
codegen::CodeGenContext, codegen::CodeGenContext,
location::Location, location::Location,
symbol_resolver::SymbolResolver, symbol_resolver::{SymbolResolver, SymbolValue},
toplevel::{DefinitionId, TopLevelDef}, toplevel::{DefinitionId, TopLevelDef, helper::parse_parameter_default_value},
typecheck::{ typecheck::{
type_inferencer::PrimitiveStore, type_inferencer::PrimitiveStore,
typedef::{Type, Unifier}, typedef::{Type, Unifier},
}, },
}; };
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use nac3parser::ast::StrRef; use nac3parser::ast::{self, StrRef};
use std::{collections::HashMap, sync::Arc}; use std::{collections::HashMap, sync::Arc};
pub struct ResolverInternal { pub struct ResolverInternal {
pub id_to_type: Mutex<HashMap<StrRef, Type>>, pub id_to_type: Mutex<HashMap<StrRef, Type>>,
pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>, pub id_to_def: Mutex<HashMap<StrRef, DefinitionId>>,
pub class_names: Mutex<HashMap<StrRef, Type>>, pub class_names: Mutex<HashMap<StrRef, Type>>,
pub module_globals: Mutex<HashMap<StrRef, ast::Expr>>,
} }
impl ResolverInternal { impl ResolverInternal {
@ -27,11 +28,27 @@ impl ResolverInternal {
pub fn add_id_type(&self, id: StrRef, ty: Type) { pub fn add_id_type(&self, id: StrRef, ty: Type) {
self.id_to_type.lock().insert(id, ty); self.id_to_type.lock().insert(id, ty);
} }
pub fn add_module_global(&self, id: StrRef, expr: &ast::Expr) {
self.module_globals.lock().insert(id, expr.clone());
}
} }
pub struct Resolver(pub Arc<ResolverInternal>); pub struct Resolver(pub Arc<ResolverInternal>);
impl SymbolResolver for Resolver { impl SymbolResolver for Resolver {
fn get_default_param_value(&self, expr: &ast::Expr) -> Option<SymbolValue> {
match &expr.node {
ast::ExprKind::Name { id, .. } => {
let expr = self.0.module_globals.lock().get(id).cloned();
expr.map(|x| {
parse_parameter_default_value(&x, self).unwrap()
})
}
_ => unimplemented!("other type of expr not supported at {}", expr.location)
}
}
fn get_symbol_type( fn get_symbol_type(
&self, &self,
_: &mut Unifier, _: &mut Unifier,

View File

@ -4,7 +4,7 @@ use inkwell::{
OptimizationLevel, OptimizationLevel,
}; };
use nac3core::typecheck::type_inferencer::PrimitiveStore; use nac3core::typecheck::type_inferencer::PrimitiveStore;
use nac3parser::parser; use nac3parser::{ast::{ExprKind, StmtKind}, parser};
use std::env; use std::env;
use std::fs; use std::fs;
use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime}; use std::{collections::HashMap, path::Path, sync::Arc, time::SystemTime};
@ -48,6 +48,7 @@ fn main() {
id_to_type: builtins_ty.into(), id_to_type: builtins_ty.into(),
id_to_def: builtins_def.into(), id_to_def: builtins_def.into(),
class_names: Default::default(), class_names: Default::default(),
module_globals: Default::default(),
} }
.into(); .into();
let resolver = let resolver =
@ -66,6 +67,18 @@ fn main() {
); );
for stmt in parser_result.into_iter() { for stmt in parser_result.into_iter() {
// handle module globals
if let StmtKind::Assign { targets, value, .. } = &stmt.node {
if targets.len() == 1 {
if let ExprKind::Name { id, .. } = &targets[0].node {
internal_resolver.add_module_global(*id, value);
}
} else {
unimplemented!("only single assign supported now")
}
continue;
}
let (name, def_id, ty) = composer let (name, def_id, ty) = composer
.register_top_level(stmt, Some(resolver.clone()), "__main__".into()) .register_top_level(stmt, Some(resolver.clone()), "__main__".into())
.unwrap(); .unwrap();