ownwership and none type

This commit is contained in:
pca006132 2020-12-29 14:47:41 +08:00
parent 1cc4c3f8d4
commit a439ce61f7
2 changed files with 39 additions and 19 deletions

View File

@ -1,13 +1,13 @@
use crate::inference::resolve_call; use crate::inference::resolve_call;
use crate::operators::*;
use crate::primitives::*; use crate::primitives::*;
use crate::typedef::{GlobalContext, Type, Type::*}; use crate::typedef::{GlobalContext, Type, Type::*};
use rustpython_parser::ast::{Expression, ExpressionType}; use rustpython_parser::ast::{Comparison, Expression, ExpressionType, Operator, UnaryOperator};
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
type SymTable<'a> = HashMap<&'a str, Rc<Type>>; type SymTable<'a> = HashMap<&'a str, Rc<Type>>;
type ParserResult = Result<Rc<Type>, String>; type ParserResult = Result<Option<Rc<Type>>, String>;
pub fn parse_expr(ctx: &GlobalContext, sym_table: &SymTable, expr: &Expression) -> ParserResult { pub fn parse_expr(ctx: &GlobalContext, sym_table: &SymTable, expr: &Expression) -> ParserResult {
Err("not supported".into()) Err("not supported".into())
@ -22,7 +22,7 @@ fn parse_constant(
match value { match value {
Number::Integer { .. } => { Number::Integer { .. } => {
// not check the range now // not check the range now
Ok(PrimitiveType(INT32_TYPE).into()) Ok(Some(PrimitiveType(INT32_TYPE).into()))
// if i32::try_from(&value).is_ok() { // if i32::try_from(&value).is_ok() {
// Ok(PrimitiveType(INT32_TYPE).into()) // Ok(PrimitiveType(INT32_TYPE).into())
// } else if i64::try_from(&value).is_ok() { // } else if i64::try_from(&value).is_ok() {
@ -31,40 +31,47 @@ fn parse_constant(
// Err("integer out of range".into()) // Err("integer out of range".into())
// } // }
} }
Number::Float { .. } => Ok(PrimitiveType(FLOAT_TYPE).into()), Number::Float { .. } => Ok(Some(PrimitiveType(FLOAT_TYPE).into())),
_ => Err("not supported".into()), _ => Err("not supported".into()),
} }
} }
fn parse_identifier(_: &GlobalContext, sym_table: &SymTable, name: &str) -> ParserResult { fn parse_identifier(_: &GlobalContext, sym_table: &SymTable, name: &str) -> ParserResult {
match sym_table.get(name) { match sym_table.get(name) {
Some(v) => Ok(v.clone()), Some(v) => Ok(Some(v.clone())),
None => Err("unbounded variable".into()), None => Err("unbounded variable".into()),
} }
} }
fn parse_list(ctx: &GlobalContext, sym_table: &SymTable, elements: &[Expression]) -> ParserResult { fn parse_list(ctx: &GlobalContext, sym_table: &SymTable, elements: &[Expression]) -> ParserResult {
if elements.len() == 0 { if elements.len() == 0 {
return Ok(ParametricType(LIST_TYPE, vec![BotType.into()]).into()); return Ok(Some(ParametricType(LIST_TYPE, vec![BotType.into()]).into()));
} }
let mut types = elements.iter().map(|v| parse_expr(&ctx, sym_table, v)); let mut types = elements.iter().map(|v| parse_expr(&ctx, sym_table, v));
let head = types.next().unwrap()?; let head = types.next().unwrap()?;
if head.is_none() {
return Err("list elements must have some type".into());
}
for v in types { for v in types {
if v? != head { if v? != head {
return Err("inhomogeneous list is not allowed".into()); return Err("inhomogeneous list is not allowed".into());
} }
} }
Ok(ParametricType(LIST_TYPE, vec![head]).into()) Ok(Some(ParametricType(LIST_TYPE, vec![head.unwrap()]).into()))
} }
fn parse_tuple(ctx: &GlobalContext, sym_table: &SymTable, elements: &[Expression]) -> ParserResult { fn parse_tuple(ctx: &GlobalContext, sym_table: &SymTable, elements: &[Expression]) -> ParserResult {
let types: Result<Vec<_>, String> = elements let types: Result<Option<Vec<_>>, String> = elements
.iter() .iter()
.map(|v| parse_expr(&ctx, sym_table, v)) .map(|v| parse_expr(&ctx, sym_table, v))
.collect(); .collect();
Ok(ParametricType(TUPLE_TYPE, types?).into()) if let Some(t) = types? {
Ok(Some(ParametricType(TUPLE_TYPE, t).into()))
} else {
Err("tuple elements must have some type".into())
}
} }
fn parse_attribute( fn parse_attribute(
@ -73,7 +80,7 @@ fn parse_attribute(
value: &Expression, value: &Expression,
name: String, name: String,
) -> ParserResult { ) -> ParserResult {
let value = parse_expr(ctx, sym_table, value)?; let value = parse_expr(ctx, sym_table, value)?.ok_or("no value".to_string())?;
if let TypeVariable(id) = value.as_ref() { if let TypeVariable(id) = value.as_ref() {
let v = ctx.get_variable(*id); let v = ctx.get_variable(*id);
if v.bound.len() == 0 { if v.bound.len() == 0 {
@ -91,12 +98,12 @@ fn parse_attribute(
return Err("unknown field (type mismatch between variants)".into()); return Err("unknown field (type mismatch between variants)".into());
} }
} }
return Ok(ty.unwrap().clone()); return Ok(Some(ty.unwrap().clone()));
} }
match value.get_base(ctx) { match value.get_base(ctx) {
Some(b) => match b.fields.get(name.as_str()) { Some(b) => match b.fields.get(name.as_str()) {
Some(t) => Ok(t.clone()), Some(t) => Ok(Some(t.clone())),
None => Err("no such field".into()), None => Err("no such field".into()),
}, },
None => Err("this object has no fields".into()), None => Err("this object has no fields".into()),
@ -109,15 +116,28 @@ fn parse_bool_ops(
values: &[Expression], values: &[Expression],
) -> ParserResult { ) -> ParserResult {
assert_eq!(values.len(), 2); assert_eq!(values.len(), 2);
let left = parse_expr(ctx, sym_table, &values[0])?; let left = parse_expr(ctx, sym_table, &values[0])?.ok_or("no value".to_string())?;
let right = parse_expr(ctx, sym_table, &values[1])?; let right = parse_expr(ctx, sym_table, &values[1])?.ok_or("no value".to_string())?;
let b = PrimitiveType(BOOL_TYPE); let b = PrimitiveType(BOOL_TYPE);
if left.as_ref() == &b && right.as_ref() == &b { if left.as_ref() == &b && right.as_ref() == &b {
Ok(b.into()) Ok(Some(b.into()))
} else { } else {
Err("bool operands must be bool".into()) Err("bool operands must be bool".into())
} }
} }
fn parse_bin_ops(
ctx: &GlobalContext,
sym_table: &SymTable,
op: &Operator,
left: &Expression,
right: &Expression,
) -> ParserResult {
let left = parse_expr(ctx, sym_table, left)?.ok_or("no value".to_string())?;
let right = parse_expr(ctx, sym_table, right)?.ok_or("no value".to_string())?;
let fun = binop_name(op);
let mut assumptions = HashMap::new();
resolve_call(ctx, Some(left), fun, &[right], &mut assumptions)
}

View File

@ -1,6 +1,6 @@
use rustpython_parser::ast::{Comparison, Operator, UnaryOperator}; use rustpython_parser::ast::{Comparison, Operator, UnaryOperator};
pub fn binop_name(op: Operator) -> &'static str { pub fn binop_name(op: &Operator) -> &'static str {
match op { match op {
Operator::Add => "add", Operator::Add => "add",
Operator::Sub => "sub", Operator::Sub => "sub",
@ -18,7 +18,7 @@ pub fn binop_name(op: Operator) -> &'static str {
} }
} }
pub fn unaryop_name(op: UnaryOperator) -> &'static str { pub fn unaryop_name(op: &UnaryOperator) -> &'static str {
match op { match op {
UnaryOperator::Pos => "pos", UnaryOperator::Pos => "pos",
UnaryOperator::Neg => "neg", UnaryOperator::Neg => "neg",
@ -27,7 +27,7 @@ pub fn unaryop_name(op: UnaryOperator) -> &'static str {
} }
} }
pub fn comparison_name(op: Comparison) -> Option<&'static str> { pub fn comparison_name(op: &Comparison) -> Option<&'static str> {
match op { match op {
Comparison::Less => Some("lt"), Comparison::Less => Some("lt"),
Comparison::LessOrEqual => Some("le"), Comparison::LessOrEqual => Some("le"),