forked from M-Labs/nac3
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
be218fc0d4 |
@ -160,50 +160,50 @@ fn resolve_function<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_expr_unknowns<'a>(
|
fn get_expression_unknowns<'a>(
|
||||||
defined: &mut Vec<&'a str>,
|
defined: &[&'a str],
|
||||||
unknowns: &mut Vec<&'a str>,
|
unknowns: &mut Vec<&'a str>,
|
||||||
expr: &'a ExpressionType,
|
expr: &'a ExpressionType,
|
||||||
) {
|
) {
|
||||||
match expr {
|
match expr {
|
||||||
ExpressionType::BoolOp { values, .. } => {
|
ExpressionType::BoolOp { values, .. } => {
|
||||||
for v in values.iter() {
|
for v in values.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node)
|
get_expression_unknowns(defined, unknowns, &v.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Binop { a, b, .. } => {
|
ExpressionType::Binop { a, b, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &a.node);
|
get_expression_unknowns(defined, unknowns, &a.node);
|
||||||
get_expr_unknowns(defined, unknowns, &b.node);
|
get_expression_unknowns(defined, unknowns, &b.node);
|
||||||
}
|
}
|
||||||
ExpressionType::Subscript { a, b } => {
|
ExpressionType::Subscript { a, b } => {
|
||||||
get_expr_unknowns(defined, unknowns, &a.node);
|
get_expression_unknowns(defined, unknowns, &a.node);
|
||||||
get_expr_unknowns(defined, unknowns, &b.node);
|
get_expression_unknowns(defined, unknowns, &b.node);
|
||||||
}
|
}
|
||||||
ExpressionType::Unop { a, .. } => {
|
ExpressionType::Unop { a, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &a.node);
|
get_expression_unknowns(defined, unknowns, &a.node);
|
||||||
}
|
}
|
||||||
ExpressionType::Compare { vals, .. } => {
|
ExpressionType::Compare { vals, .. } => {
|
||||||
for v in vals.iter() {
|
for v in vals.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node)
|
get_expression_unknowns(defined, unknowns, &v.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Attribute { value, .. } => {
|
ExpressionType::Attribute { value, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &value.node);
|
get_expression_unknowns(defined, unknowns, &value.node);
|
||||||
}
|
}
|
||||||
ExpressionType::Call { function, args, .. } => {
|
ExpressionType::Call { function, args, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &function.node);
|
get_expression_unknowns(defined, unknowns, &function.node);
|
||||||
for v in args.iter() {
|
for v in args.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node)
|
get_expression_unknowns(defined, unknowns, &v.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::List { elements } => {
|
ExpressionType::List { elements } => {
|
||||||
for v in elements.iter() {
|
for v in elements.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node)
|
get_expression_unknowns(defined, unknowns, &v.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Tuple { elements } => {
|
ExpressionType::Tuple { elements } => {
|
||||||
for v in elements.iter() {
|
for v in elements.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node)
|
get_expression_unknowns(defined, unknowns, &v.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Comprehension { kind, generators } => {
|
ExpressionType::Comprehension { kind, generators } => {
|
||||||
@ -211,22 +211,22 @@ fn get_expr_unknowns<'a>(
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
let g = &generators[0];
|
let g = &generators[0];
|
||||||
get_expr_unknowns(defined, unknowns, &g.iter.node);
|
get_expression_unknowns(defined, unknowns, &g.iter.node);
|
||||||
let mut scoped = defined.clone();
|
let mut scoped = defined.to_owned();
|
||||||
get_expr_unknowns(defined, &mut scoped, &g.target.node);
|
get_expression_unknowns(defined, &mut scoped, &g.target.node);
|
||||||
for if_expr in g.ifs.iter() {
|
for if_expr in g.ifs.iter() {
|
||||||
get_expr_unknowns(&mut scoped, unknowns, &if_expr.node);
|
get_expression_unknowns(&scoped, unknowns, &if_expr.node);
|
||||||
}
|
}
|
||||||
match kind.as_ref() {
|
match kind.as_ref() {
|
||||||
ComprehensionKind::List { element } => {
|
ComprehensionKind::List { element } => {
|
||||||
get_expr_unknowns(&mut scoped, unknowns, &element.node);
|
get_expression_unknowns(&scoped, unknowns, &element.node);
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Slice { elements } => {
|
ExpressionType::Slice { elements } => {
|
||||||
for v in elements.iter() {
|
for v in elements.iter() {
|
||||||
get_expr_unknowns(defined, unknowns, &v.node);
|
get_expression_unknowns(defined, unknowns, &v.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::Identifier { name } => {
|
ExpressionType::Identifier { name } => {
|
||||||
@ -235,81 +235,35 @@ fn get_expr_unknowns<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExpressionType::IfExpression { test, body, orelse } => {
|
ExpressionType::IfExpression { test, body, orelse } => {
|
||||||
get_expr_unknowns(defined, unknowns, &test.node);
|
get_expression_unknowns(defined, unknowns, &test.node);
|
||||||
get_expr_unknowns(defined, unknowns, &body.node);
|
get_expression_unknowns(defined, unknowns, &body.node);
|
||||||
get_expr_unknowns(defined, unknowns, &orelse.node);
|
get_expression_unknowns(defined, unknowns, &orelse.node);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExprPattern<'a>(&'a ExpressionType, Vec<usize>, bool);
|
pub fn get_pattern_match_unknowns<'a>(
|
||||||
|
defined: &mut Vec<&'a str>,
|
||||||
impl<'a> ExprPattern<'a> {
|
unknowns: &mut Vec<&'a str>,
|
||||||
fn new(expr: &'a ExpressionType) -> ExprPattern {
|
expr: &'a ExpressionType,
|
||||||
let mut pattern = ExprPattern(expr, Vec::new(), true);
|
) {
|
||||||
pattern.find_leaf();
|
match expr {
|
||||||
pattern
|
ExpressionType::Identifier { name } => {
|
||||||
|
defined.push(&name.as_str());
|
||||||
}
|
}
|
||||||
|
ExpressionType::Tuple { elements } => {
|
||||||
fn pointed(&mut self) -> &'a ExpressionType {
|
for v in elements.iter() {
|
||||||
let mut current = self.0;
|
get_pattern_match_unknowns(defined, unknowns, &v.node);
|
||||||
for v in self.1.iter() {
|
|
||||||
if let ExpressionType::Tuple { elements } = current {
|
|
||||||
current = &elements[*v].node
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
current
|
_ => {
|
||||||
}
|
get_expression_unknowns(defined, unknowns, expr);
|
||||||
|
|
||||||
fn find_leaf(&mut self) {
|
|
||||||
let mut current = self.pointed();
|
|
||||||
while let ExpressionType::Tuple { elements } = current {
|
|
||||||
if elements.is_empty() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
current = &elements[0].node;
|
|
||||||
self.1.push(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inc(&mut self) -> bool {
|
|
||||||
loop {
|
|
||||||
if self.1.is_empty() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
let ind = self.1.pop().unwrap() + 1;
|
|
||||||
let parent = self.pointed();
|
|
||||||
if let ExpressionType::Tuple { elements } = parent {
|
|
||||||
if ind < elements.len() {
|
|
||||||
self.1.push(ind);
|
|
||||||
self.find_leaf();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for ExprPattern<'a> {
|
|
||||||
type Item = &'a ExpressionType;
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
if self.2 {
|
|
||||||
self.2 = false;
|
|
||||||
Some(self.pointed())
|
|
||||||
} else if self.inc() {
|
|
||||||
Some(self.pointed())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_stmt_unknowns<'a>(
|
pub fn get_statement_unknowns<'a>(
|
||||||
defined: &mut Vec<&'a str>,
|
defined: &mut Vec<&'a str>,
|
||||||
unknowns: &mut Vec<&'a str>,
|
unknowns: &mut Vec<&'a str>,
|
||||||
stmts: &'a [Statement],
|
stmts: &'a [Statement],
|
||||||
@ -317,78 +271,59 @@ fn get_stmt_unknowns<'a>(
|
|||||||
for stmt in stmts.iter() {
|
for stmt in stmts.iter() {
|
||||||
match &stmt.node {
|
match &stmt.node {
|
||||||
StatementType::Return { value } => {
|
StatementType::Return { value } => {
|
||||||
if let Some(value) = value {
|
if let Some(v) = value {
|
||||||
get_expr_unknowns(defined, unknowns, &value.node);
|
get_expression_unknowns(defined, unknowns, &v.node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementType::Assign { targets, value } => {
|
StatementType::Assign { targets, value } => {
|
||||||
get_expr_unknowns(defined, unknowns, &value.node);
|
get_expression_unknowns(defined, unknowns, &value.node);
|
||||||
for target in targets.iter() {
|
for t in targets.iter() {
|
||||||
for node in ExprPattern::new(&target.node).into_iter() {
|
get_pattern_match_unknowns(defined, unknowns, &t.node);
|
||||||
if let ExpressionType::Identifier { name } = node {
|
|
||||||
let name = name.as_str();
|
|
||||||
if !defined.contains(&name) {
|
|
||||||
defined.push(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
get_expr_unknowns(defined, unknowns, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementType::AugAssign { target, value, .. } => {
|
StatementType::AugAssign { target, value, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &target.node);
|
get_expression_unknowns(defined, unknowns, &target.node);
|
||||||
get_expr_unknowns(defined, unknowns, &value.node);
|
get_expression_unknowns(defined, unknowns, &value.node);
|
||||||
}
|
}
|
||||||
StatementType::AnnAssign { target, value, .. } => {
|
StatementType::AnnAssign { target, value, .. } => {
|
||||||
get_expr_unknowns(defined, unknowns, &target.node);
|
if let Some(v) = value {
|
||||||
if let Some(value) = value {
|
get_expression_unknowns(defined, unknowns, &v.node);
|
||||||
get_expr_unknowns(defined, unknowns, &value.node);
|
|
||||||
}
|
}
|
||||||
|
get_pattern_match_unknowns(defined, unknowns, &target.node);
|
||||||
}
|
}
|
||||||
StatementType::Expression { expression } => {
|
StatementType::Expression { expression } => {
|
||||||
get_expr_unknowns(defined, unknowns, &expression.node);
|
get_expression_unknowns(defined, unknowns, &expression.node);
|
||||||
}
|
|
||||||
StatementType::Global { names } => {
|
|
||||||
for name in names.iter() {
|
|
||||||
let name = name.as_str();
|
|
||||||
if !unknowns.contains(&name) {
|
|
||||||
unknowns.push(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
StatementType::If { test, body, orelse }
|
StatementType::If { test, body, orelse }
|
||||||
| StatementType::While { test, body, orelse } => {
|
| StatementType::While { test, body, orelse } => {
|
||||||
get_expr_unknowns(defined, unknowns, &test.node);
|
get_expression_unknowns(defined, unknowns, &test.node);
|
||||||
// we are not very strict at this point...
|
get_statement_unknowns(defined, unknowns, body.as_slice());
|
||||||
// some identifiers not treated as unknowns may not be resolved
|
|
||||||
// but should be checked during type inference
|
|
||||||
get_stmt_unknowns(defined, unknowns, body.as_slice());
|
|
||||||
if let Some(orelse) = orelse {
|
if let Some(orelse) = orelse {
|
||||||
get_stmt_unknowns(defined, unknowns, orelse.as_slice());
|
get_statement_unknowns(defined, unknowns, orelse.as_slice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatementType::For { is_async, target, iter, body, orelse } => {
|
StatementType::For { is_async, target, body, orelse, iter } => {
|
||||||
if *is_async {
|
if *is_async {
|
||||||
unimplemented!()
|
unimplemented!();
|
||||||
}
|
}
|
||||||
get_expr_unknowns(defined, unknowns, &iter.node);
|
let mut scoped = defined.to_owned();
|
||||||
for node in ExprPattern::new(&target.node).into_iter() {
|
get_expression_unknowns(defined, unknowns, &iter.node);
|
||||||
if let ExpressionType::Identifier { name } = node {
|
get_expression_unknowns(defined, &mut scoped, &target.node);
|
||||||
let name = name.as_str();
|
get_statement_unknowns(&mut scoped, unknowns, body.as_slice());
|
||||||
if !defined.contains(&name) {
|
|
||||||
defined.push(name);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
get_expr_unknowns(defined, unknowns, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get_stmt_unknowns(defined, unknowns, body.as_slice());
|
|
||||||
if let Some(orelse) = orelse {
|
if let Some(orelse) = orelse {
|
||||||
get_stmt_unknowns(defined, unknowns, orelse.as_slice());
|
get_statement_unknowns(&mut scoped, unknowns, orelse.as_slice());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
StatementType::With { is_async, items, body } => {
|
||||||
|
if *is_async {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
let mut scoped = defined.to_owned();
|
||||||
|
for item in items.iter() {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,7 +390,7 @@ pub fn resolve_signatures<'a>(ctx: &mut TopLevelContext<'a>, stmts: &'a [Stateme
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use indoc::indoc;
|
use indoc::indoc;
|
||||||
use rustpython_parser::parser::{parse_program, parse_statement};
|
use rustpython_parser::parser::parse_program;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_classes() {
|
fn test_get_classes() {
|
||||||
@ -465,14 +400,14 @@ mod tests {
|
|||||||
b: Test
|
b: Test
|
||||||
|
|
||||||
def test(self, a: int32) -> Test2:
|
def test(self, a: int32) -> Test2:
|
||||||
return self.b
|
return b
|
||||||
|
|
||||||
class Bar(Foo, 'FooBar'):
|
class Bar(Foo, 'FooBar'):
|
||||||
def test2(self, a: list[Foo]) -> Test2:
|
def test2(self, a: list[Foo]) -> Test2:
|
||||||
return self.b
|
return b
|
||||||
|
|
||||||
def test3(self, a: list[FooBar2]) -> Test2:
|
def test3(self, a: list[FooBar2]) -> Test2:
|
||||||
return self.b
|
return b
|
||||||
" })
|
" })
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (mut classes, mut unknowns) = get_typenames(&ast.statements);
|
let (mut classes, mut unknowns) = get_typenames(&ast.statements);
|
||||||
@ -485,19 +420,4 @@ mod tests {
|
|||||||
assert_eq!(&classes, &["Bar", "Foo"]);
|
assert_eq!(&classes, &["Bar", "Foo"]);
|
||||||
assert_eq!(&unknowns, &["FooBar", "FooBar2", "Test", "Test2"]);
|
assert_eq!(&unknowns, &["FooBar", "FooBar2", "Test", "Test2"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_assignment() {
|
|
||||||
let ast = parse_statement(indoc! {"
|
|
||||||
((a, b), c[i]) = core.foo(x, get_y())
|
|
||||||
" })
|
|
||||||
.unwrap();
|
|
||||||
let mut defined = Vec::new();
|
|
||||||
let mut unknowns = Vec::new();
|
|
||||||
get_stmt_unknowns(&mut defined, &mut unknowns, ast.as_slice());
|
|
||||||
defined.sort();
|
|
||||||
unknowns.sort();
|
|
||||||
assert_eq!(defined.as_slice(), &["a", "b"]);
|
|
||||||
assert_eq!(unknowns.as_slice(), &["c", "core", "get_y", "i", "x"]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
19
todo.txt
19
todo.txt
@ -12,23 +12,12 @@ Errors:
|
|||||||
- Incorrect number of parameters
|
- Incorrect number of parameters
|
||||||
|
|
||||||
Symbol Resolution:
|
Symbol Resolution:
|
||||||
- Add all files with annotated class/functions.
|
|
||||||
- Find class references, load them all in TopLevelContext.
|
- Find class references, load them all in TopLevelContext.
|
||||||
- Find unbounded identifiers in the functions.
|
- Find unbounded identifiers/functions in functions.
|
||||||
- If it is a function/class name, record its object ID.
|
- `inspect.getmodule(x)` every unknown `x` if not primitive/list of primitives,
|
||||||
- Otherwise, load its value. (check to see if specified with `global`)
|
check their files recursively by getting their file path, cache with
|
||||||
(Function implemented in python, with rust binding to add value to global
|
(normalized) path as key.
|
||||||
variable dictionary)
|
|
||||||
|
|
||||||
Global variable dictionary:
|
|
||||||
- Primitives, including integers, floats, bools, etc.
|
|
||||||
- Primitive lists.
|
|
||||||
- Numpy multi-dimensional array, with value + dimension vectors.
|
|
||||||
- Reference array, with integer index referring to other things.
|
|
||||||
- Symbol table: python id -> reference id.
|
|
||||||
|
|
||||||
TopLevelContext/InferenceContext:
|
TopLevelContext/InferenceContext:
|
||||||
- Restrict visibility by user defined function.
|
- Restrict visibility by user defined function.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user