forked from M-Labs/nac3
statement inference: assignment
This commit is contained in:
parent
4902f9f645
commit
e1efb47ad2
|
@ -7,6 +7,7 @@ extern crate rustpython_parser;
|
||||||
|
|
||||||
pub mod expression_inference;
|
pub mod expression_inference;
|
||||||
pub mod inference_core;
|
pub mod inference_core;
|
||||||
|
pub mod statement_inference;
|
||||||
mod magic_methods;
|
mod magic_methods;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod typedef;
|
pub mod typedef;
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
use crate::context::InferenceContext;
|
||||||
|
use crate::expression_inference::infer_expr;
|
||||||
|
use crate::inference_core::resolve_call;
|
||||||
|
use crate::magic_methods::*;
|
||||||
|
use crate::primitives::*;
|
||||||
|
use crate::typedef::{Type, TypeEnum::*};
|
||||||
|
use rustpython_parser::ast::*;
|
||||||
|
|
||||||
|
fn get_target_type<'b: 'a, 'a>(
|
||||||
|
ctx: &mut InferenceContext<'a>,
|
||||||
|
target: &'b Expression,
|
||||||
|
) -> Result<Type, String> {
|
||||||
|
match &target.node {
|
||||||
|
ExpressionType::Subscript { a, b } => {
|
||||||
|
let int32 = ctx.get_primitive(INT32_TYPE);
|
||||||
|
if infer_expr(ctx, &a)? == Some(int32) {
|
||||||
|
let b = get_target_type(ctx, &b)?;
|
||||||
|
if let ParametricType(LIST_TYPE, t) = b.as_ref() {
|
||||||
|
Ok(t[0].clone())
|
||||||
|
} else {
|
||||||
|
Err("subscript is only supported for list".to_string())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err("subscript must be int32".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExpressionType::Attribute { value, name } => {
|
||||||
|
let t = get_target_type(ctx, &value)?;
|
||||||
|
let base = t.get_base(ctx).ok_or_else(|| "no attributes".to_string())?;
|
||||||
|
Ok(base
|
||||||
|
.fields
|
||||||
|
.get(name.as_str())
|
||||||
|
.ok_or_else(|| "no such attribute")?
|
||||||
|
.clone())
|
||||||
|
}
|
||||||
|
ExpressionType::Identifier { name } => Ok(ctx.resolve(name.as_str())?),
|
||||||
|
_ => Err("not supported".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_stmt_binding<'b: 'a, 'a>(
|
||||||
|
ctx: &mut InferenceContext<'a>,
|
||||||
|
target: &'b Expression,
|
||||||
|
ty: Type,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
match &target.node {
|
||||||
|
ExpressionType::Identifier { name } => {
|
||||||
|
if name.as_str() == "_" {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
match ctx.resolve(name.as_str()) {
|
||||||
|
Ok(t) if t == ty => Ok(()),
|
||||||
|
Err(_) => {
|
||||||
|
ctx.assign(name.as_str(), ty).unwrap();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
_ => Err("conflicting type".into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExpressionType::Tuple { elements } => {
|
||||||
|
if let ParametricType(TUPLE_TYPE, ls) = ty.as_ref() {
|
||||||
|
if ls.len() != elements.len() {
|
||||||
|
return Err("incorrect pattern length".into());
|
||||||
|
}
|
||||||
|
for (x, y) in elements.iter().zip(ls.iter()) {
|
||||||
|
check_stmt_binding(ctx, x, y.clone())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("pattern matching supports tuple only".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let t = get_target_type(ctx, target)?;
|
||||||
|
if ty == t {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("type mismatch".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_assign<'b: 'a, 'a>(
|
||||||
|
ctx: &mut InferenceContext<'a>,
|
||||||
|
targets: &'b [Expression],
|
||||||
|
value: &'b Expression,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let ty = infer_expr(ctx, value)?.ok_or_else(|| "no value".to_string())?;
|
||||||
|
for t in targets.iter() {
|
||||||
|
check_stmt_binding(ctx, t, ty.clone())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue