changeset 82:2d906d1cb940

Add ast.Subscript.
author Bastien Orivel <eijebong@bananium.fr>
date Mon, 13 Jun 2016 21:32:43 +0200
parents dc82a0d8f144
children e59cd5754268
files src/ast_convert.rs src/ast_dump.rs src/python_ast.rs tests/test_parse_files/test_subscript.py
diffstat 4 files changed, 89 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/ast_convert.rs
+++ b/src/ast_convert.rs
@@ -1,4 +1,4 @@
-use python_ast::{Module, stmt, expr, expr_context, cmpop, boolop, operator, unaryop, arguments, arg, alias, comprehension, keyword, withitem, excepthandler};
+use python_ast::{Module, stmt, expr, expr_context, cmpop, boolop, operator, unaryop, arguments, arg, alias, comprehension, keyword, withitem, excepthandler, slice};
 
 use cpython::{Python, PyObject};
 use cpython::ObjectProtocol; //for call method
@@ -267,6 +267,46 @@ fn parse_excepthandler(py: Python, ast: 
     excepthandler{type_: type_, name: name, body: body}
 }
 
+fn parse_slice(py: Python, ast: PyObject) -> slice {
+    let builtins_module = py.import("builtins").unwrap();
+    let isinstance = builtins_module.get(py, "isinstance").unwrap();
+
+    let is_instance = |object: &PyObject, type_: &PyObject| {
+        return isinstance.call(py, (object, type_), None).unwrap().is_true(py).unwrap();
+    };
+
+    let ast_module = py.import("ast").unwrap();
+    let ast_type = ast_module.get(py, "AST").unwrap();
+    let index_type = ast_module.get(py, "Index").unwrap();
+    let slice_type = ast_module.get(py, "Slice").unwrap();
+    let ext_slice_type = ast_module.get(py, "ExtSlice").unwrap();
+
+    assert!(is_instance(&ast, &ast_type));
+
+    if is_instance(&ast, &index_type) {
+        let value = ast.getattr(py, "value").unwrap();
+        let value = parse_expr(py, value);
+
+        slice::Index(value)
+    } else if is_instance(&ast, &slice_type) {
+        let lower = ast.getattr(py, "lower").unwrap();
+        let upper = ast.getattr(py, "upper").unwrap();
+        let step = ast.getattr(py, "step").unwrap();
+
+        let lower = parse_optional_expr(py, lower);
+        let upper = parse_optional_expr(py, upper);
+        let step = parse_optional_expr(py, step);
+        slice::Slice(lower, upper, step)
+    } else if is_instance(&ast, &ext_slice_type) {
+        let dims = ast.getattr(py, "dims").unwrap();
+        let dims = parse_list(py, dims, parse_slice);
+
+        slice::ExtSlice(dims)
+    } else {
+        unreachable!()
+    }
+}
+
 fn parse_optional_expr(py: Python, ast: PyObject) -> Option<expr> {
     if ast == py.None() {
         None
@@ -310,6 +350,7 @@ fn parse_expr(py: Python, ast: PyObject)
     let lambda_type = ast_module.get(py, "Lambda").unwrap();
     let ifexp_type = ast_module.get(py, "IfExp").unwrap();
     let dict_type = ast_module.get(py, "Dict").unwrap();
+    let subscript_type = ast_module.get(py, "Subscript").unwrap();
 
     assert!(is_instance(&ast, &ast_type));
 
@@ -473,6 +514,15 @@ fn parse_expr(py: Python, ast: PyObject)
         let values = parse_list(py, values, parse_expr);
 
         expr::Dict(keys, values)
+    } else if is_instance(&ast, &subscript_type) {
+        let value = ast.getattr(py, "value").unwrap();
+        let slice = ast.getattr(py, "slice").unwrap();
+        let ctx = get_ctx(py, ast);
+
+        let value = parse_expr(py, value);
+        let slice = parse_slice(py, slice);
+
+        expr::Subscript(Box::new(value), Box::new(slice), ctx)
     } else {
         println!("expr {}", ast);
         unreachable!()
--- a/src/ast_dump.rs
+++ b/src/ast_dump.rs
@@ -1,4 +1,4 @@
-use python_ast::{Module, stmt, expr, boolop, operator, unaryop, cmpop, arguments, arg, keyword, comprehension, withitem, excepthandler};
+use python_ast::{Module, stmt, expr, boolop, operator, unaryop, cmpop, arguments, arg, keyword, comprehension, withitem, excepthandler, slice};
 
 use std::iter;
 
@@ -117,6 +117,37 @@ impl to_string_able for comprehension {
     }
 }
 
+impl to_string_able for slice {
+    fn to_string(&self) -> String {
+        match *self {
+            slice::Index(ref value) => value.to_string(),
+            slice::Slice(ref lower, ref upper, ref step) => {
+                format!("{}{}{}",
+                    match *lower {
+                        None => String::new(),
+                        Some(ref lower) => lower.to_string()
+                    },
+                    match *upper {
+                        None => String::new(),
+                        Some(ref upper) => format!(":{}", upper.to_string())
+                    },
+                    match *step {
+                        None => String::new(),
+                        Some(ref step) => format!(":{}", step.to_string())
+                    },
+                )
+            },
+            slice::ExtSlice(ref dims) => {
+                let mut dims_ = vec!();
+                for dim in dims {
+                    dims_.push(dim.to_string());
+                }
+                dims_.join(", ")
+            }
+        }
+    }
+}
+
 impl excepthandler {
     fn to_string(self, indent: usize) -> String {
         let current_indent = make_indent(indent);
@@ -214,6 +245,7 @@ impl to_string_able for expr {
                     }
                 )
             },
+            expr::Subscript(value, slice, _) => format!("{}[{}]", value.to_string(), slice.to_string()),
         }
     }
 }
--- a/src/python_ast.rs
+++ b/src/python_ast.rs
@@ -108,7 +108,7 @@ pub enum expr {
 
     // the following expression can appear in assignment context
     Attribute(Box<expr>, String, expr_context),
-    //Subscript(Box<expr>, slice, expr_context),
+    Subscript(Box<expr>, Box<slice>, expr_context),
     //Starred(Box<expr>, expr_context),
     Name(String, expr_context),
     List(Vec<expr>, expr_context),
new file mode 100644
--- /dev/null
+++ b/tests/test_parse_files/test_subscript.py
@@ -0,0 +1,4 @@
+a[5] = b
+a[1:2] = c
+a[1:2:4] = d
+a[1:2, 3] = e