about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJakub Wieczorek <jakub@jakub.cc>2014-07-18 00:56:56 +0200
committerJakub Wieczorek <jakub@jakub.cc>2014-07-20 12:40:08 +0200
commit4b9bc2e8f268dfe2a2462c4e378e5a0eeefa2cf4 (patch)
treeada16b620d93f1ae709185df0986c58a62614e8d
parent50481f55030f02543e1b3b6ae008d77b1cef3e98 (diff)
downloadrust-4b9bc2e8f268dfe2a2462c4e378e5a0eeefa2cf4.tar.gz
rust-4b9bc2e8f268dfe2a2462c4e378e5a0eeefa2cf4.zip
Implement new mod import sugar
Implements RFC #168.
-rw-r--r--src/librustc/middle/privacy.rs36
-rw-r--r--src/librustc/middle/resolve.rs80
-rw-r--r--src/librustc/middle/save/mod.rs25
-rw-r--r--src/librustdoc/clean/mod.rs18
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/libsyntax/ast.rs18
-rw-r--r--src/libsyntax/ast_util.rs2
-rw-r--r--src/libsyntax/ext/build.rs2
-rw-r--r--src/libsyntax/fold.rs18
-rw-r--r--src/libsyntax/lib.rs2
-rw-r--r--src/libsyntax/parse/parser.rs16
-rw-r--r--src/libsyntax/print/pprust.rs9
-rw-r--r--src/libsyntax/visit.rs7
-rw-r--r--src/test/compile-fail/use-mod-2.rs19
-rw-r--r--src/test/compile-fail/use-mod-3.rs24
-rw-r--r--src/test/compile-fail/use-mod.rs32
-rw-r--r--src/test/run-pass/use-mod.rs38
17 files changed, 268 insertions, 80 deletions
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index cdb3f9dbb1d..bad6a288294 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -901,21 +901,29 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
             ast::ViewItemUse(ref vpath) => {
                 match vpath.node {
                     ast::ViewPathSimple(..) | ast::ViewPathGlob(..) => {}
-                    ast::ViewPathList(_, ref list, _) => {
+                    ast::ViewPathList(ref prefix, ref list, _) => {
                         for pid in list.iter() {
-                            debug!("privacy - list {}", pid.node.id);
-                            let seg = ast::PathSegment {
-                                identifier: pid.node.name,
-                                lifetimes: Vec::new(),
-                                types: OwnedSlice::empty(),
-                            };
-                            let segs = vec!(seg);
-                            let path = ast::Path {
-                                global: false,
-                                span: pid.span,
-                                segments: segs,
-                            };
-                            self.check_path(pid.span, pid.node.id, &path);
+                            match pid.node {
+                                ast::PathListIdent { id, name } => {
+                                    debug!("privacy - ident item {}", id);
+                                    let seg = ast::PathSegment {
+                                        identifier: name,
+                                        lifetimes: Vec::new(),
+                                        types: OwnedSlice::empty(),
+                                    };
+                                    let segs = vec![seg];
+                                    let path = ast::Path {
+                                        global: false,
+                                        span: pid.span,
+                                        segments: segs,
+                                    };
+                                    self.check_path(pid.span, id, &path);
+                                }
+                                ast::PathListMod { id } => {
+                                    debug!("privacy - mod item {}", id);
+                                    self.check_path(pid.span, id, prefix);
+                                }
+                            }
                         }
                     }
                 }
diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs
index a0adbf6e920..0fb377838fe 100644
--- a/src/librustc/middle/resolve.rs
+++ b/src/librustc/middle/resolve.rs
@@ -1455,29 +1455,20 @@ impl<'a> Resolver<'a> {
                 // Extract and intern the module part of the path. For
                 // globs and lists, the path is found directly in the AST;
                 // for simple paths we have to munge the path a little.
-
-                let mut module_path = Vec::new();
-                match view_path.node {
+                let module_path = match view_path.node {
                     ViewPathSimple(_, ref full_path, _) => {
-                        let path_len = full_path.segments.len();
-                        assert!(path_len != 0);
-
-                        for (i, segment) in full_path.segments
-                                                     .iter()
-                                                     .enumerate() {
-                            if i != path_len - 1 {
-                                module_path.push(segment.identifier)
-                            }
-                        }
+                        full_path.segments
+                            .as_slice().init()
+                            .iter().map(|ident| ident.identifier)
+                            .collect()
                     }
 
                     ViewPathGlob(ref module_ident_path, _) |
                     ViewPathList(ref module_ident_path, _, _) => {
-                        for segment in module_ident_path.segments.iter() {
-                            module_path.push(segment.identifier)
-                        }
+                        module_ident_path.segments
+                            .iter().map(|ident| ident.identifier).collect()
                     }
-                }
+                };
 
                 // Build up the import directives.
                 let module_ = parent.module();
@@ -1486,6 +1477,11 @@ impl<'a> Resolver<'a> {
                     ViewPathSimple(binding, ref full_path, id) => {
                         let source_ident =
                             full_path.segments.last().unwrap().identifier;
+                        if token::get_ident(source_ident).get() == "mod" {
+                            self.resolve_error(view_path.span,
+                                "`mod` imports are only allowed within a { } list");
+                        }
+
                         let subclass = SingleImport(binding,
                                                     source_ident);
                         self.build_import_directive(&*module_,
@@ -1495,16 +1491,50 @@ impl<'a> Resolver<'a> {
                                                     id,
                                                     is_public);
                     }
-                    ViewPathList(_, ref source_idents, _) => {
-                        for source_ident in source_idents.iter() {
-                            let name = source_ident.node.name;
+                    ViewPathList(_, ref source_items, _) => {
+                        // Make sure there's at most one `mod` import in the list.
+                        let mod_spans = source_items.iter().filter_map(|item| match item.node {
+                            PathListMod { .. } => Some(item.span),
+                            _ => None
+                        }).collect::<Vec<Span>>();
+                        match mod_spans.as_slice() {
+                            [first, second, ..other] => {
+                                self.resolve_error(first,
+                                    "`mod` import can only appear once in the list");
+                                self.session.span_note(second,
+                                        "another `mod` import appears here");
+                                for &other_span in other.iter() {
+                                    self.session.span_note(other_span,
+                                        "another `mod` import appears here");
+                                }
+                            },
+                            [_] | [] => ()
+                        }
+
+                        for source_item in source_items.iter() {
+                            let (module_path, name) = match source_item.node {
+                                PathListIdent { name, .. } =>
+                                    (module_path.clone(), name),
+                                PathListMod { .. } => {
+                                    let name = match module_path.last() {
+                                        Some(ident) => ident.clone(),
+                                        None => {
+                                            self.resolve_error(source_item.span,
+                                                "`mod` import can only appear in an import list \
+                                                 with a non-empty prefix");
+                                            continue;
+                                        }
+                                    };
+                                    let module_path = module_path.as_slice().init();
+                                    (Vec::from_slice(module_path), name)
+                                }
+                            };
                             self.build_import_directive(
                                 &*module_,
-                                module_path.clone(),
+                                module_path,
                                 SingleImport(name, name),
-                                source_ident.span,
-                                source_ident.node.id,
-                                is_public);
+                                source_item.span,
+                                source_item.node.id(), is_public);
                         }
                     }
                     ViewPathGlob(_, id) => {
@@ -5492,7 +5522,7 @@ impl<'a> Resolver<'a> {
                     ViewPathSimple(_, _, id) => self.finalize_import(id, p.span),
                     ViewPathList(_, ref list, _) => {
                         for i in list.iter() {
-                            self.finalize_import(i.node.id, i.span);
+                            self.finalize_import(i.node.id(), i.span);
                         }
                     },
                     ViewPathGlob(_, id) => {
diff --git a/src/librustc/middle/save/mod.rs b/src/librustc/middle/save/mod.rs
index 9f1f4057be6..c4373a023cc 100644
--- a/src/librustc/middle/save/mod.rs
+++ b/src/librustc/middle/save/mod.rs
@@ -1120,16 +1120,23 @@ impl<'l> Visitor<DxrVisitorEnv> for DxrVisitor<'l> {
                     }
                     ast::ViewPathList(ref path, ref list, _) => {
                         for plid in list.iter() {
-                            match self.lookup_type_ref(plid.node.id) {
-                                Some(id) => match self.lookup_def_kind(plid.node.id, plid.span) {
-                                    Some(kind) => self.fmt.ref_str(kind,
-                                                                   plid.span,
-                                                                   Some(plid.span),
-                                                                   id,
-                                                                   e.cur_scope),
-                                    None => (),
+                            match plid.node {
+                                ast::PathListIdent { id, .. } => {
+                                    match self.lookup_type_ref(id) {
+                                        Some(def_id) =>
+                                            match self.lookup_def_kind(id, plid.span) {
+                                                Some(kind) => {
+                                                    self.fmt.ref_str(
+                                                        kind, plid.span,
+                                                        Some(plid.span),
+                                                        def_id, e.cur_scope);
+                                                }
+                                                None => ()
+                                            },
+                                        None => ()
+                                    }
                                 },
-                                None => ()
+                                ast::PathListMod { .. } => ()
                             }
                         }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9f5df205aa4..3cb2e9c6ec9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1779,13 +1779,13 @@ impl Clean<Vec<Item>> for ast::ViewItem {
                         // to keep any non-inlineable reexports so they can be
                         // listed in the documentation.
                         let remaining = list.iter().filter(|path| {
-                            match inline::try_inline(path.node.id) {
+                            match inline::try_inline(path.node.id()) {
                                 Some(items) => {
                                     ret.extend(items.move_iter()); false
                                 }
                                 None => true,
                             }
-                        }).map(|a| a.clone()).collect::<Vec<ast::PathListIdent>>();
+                        }).map(|a| a.clone()).collect::<Vec<ast::PathListItem>>();
                         if remaining.len() > 0 {
                             let path = ast::ViewPathList(a.clone(),
                                                          remaining,
@@ -1868,11 +1868,17 @@ pub struct ViewListIdent {
     pub source: Option<ast::DefId>,
 }
 
-impl Clean<ViewListIdent> for ast::PathListIdent {
+impl Clean<ViewListIdent> for ast::PathListItem {
     fn clean(&self) -> ViewListIdent {
-        ViewListIdent {
-            name: self.node.name.clean(),
-            source: resolve_def(self.node.id),
+        match self.node {
+            ast::PathListIdent { id, name } => ViewListIdent {
+                name: name.clean(),
+                source: resolve_def(id)
+            },
+            ast::PathListMod { id } => ViewListIdent {
+                name: "mod".to_string(),
+                source: resolve_def(id)
+            }
         }
     }
 }
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index b7ef0956a7c..c8f9ed64a77 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -187,7 +187,7 @@ impl<'a> RustdocVisitor<'a> {
             ast::ViewPathList(ref p, ref paths, ref b) => {
                 let mut mine = Vec::new();
                 for path in paths.iter() {
-                    if !self.resolve_id(path.node.id, false, om, please_inline) {
+                    if !self.resolve_id(path.node.id(), false, om, please_inline) {
                         mine.push(path.clone());
                     }
                 }
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 394d4a82516..7ad9a18a15e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -1033,12 +1033,20 @@ pub struct Variant_ {
 pub type Variant = Spanned<Variant_>;
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
-pub struct PathListIdent_ {
-    pub name: Ident,
-    pub id: NodeId,
+pub enum PathListItem_ {
+    PathListIdent { pub name: Ident, pub id: NodeId },
+    PathListMod { pub id: NodeId }
+}
+
+impl PathListItem_ {
+    pub fn id(&self) -> NodeId {
+        match *self {
+            PathListIdent { id, .. } | PathListMod { id } => id
+        }
+    }
 }
 
-pub type PathListIdent = Spanned<PathListIdent_>;
+pub type PathListItem = Spanned<PathListItem_>;
 
 pub type ViewPath = Spanned<ViewPath_>;
 
@@ -1056,7 +1064,7 @@ pub enum ViewPath_ {
     ViewPathGlob(Path, NodeId),
 
     /// `foo::bar::{a,b,c}`
-    ViewPathList(Path, Vec<PathListIdent> , NodeId)
+    ViewPathList(Path, Vec<PathListItem> , NodeId)
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index 3b4f6a6e0f8..99726da69c9 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -405,7 +405,7 @@ impl<'a, O: IdVisitingOperation> Visitor<()> for IdVisitor<'a, O> {
                     ViewPathList(_, ref paths, node_id) => {
                         self.operation.visit_id(node_id);
                         for path in paths.iter() {
-                            self.operation.visit_id(path.node.id)
+                            self.operation.visit_id(path.node.id())
                         }
                     }
                 }
diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs
index 4d3913da365..7d683382589 100644
--- a/src/libsyntax/ext/build.rs
+++ b/src/libsyntax/ext/build.rs
@@ -1045,7 +1045,7 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
     fn view_use_list(&self, sp: Span, vis: ast::Visibility,
                      path: Vec<ast::Ident> , imports: &[ast::Ident]) -> ast::ViewItem {
         let imports = imports.iter().map(|id| {
-            respan(sp, ast::PathListIdent_ { name: *id, id: ast::DUMMY_NODE_ID })
+            respan(sp, ast::PathListIdent { name: *id, id: ast::DUMMY_NODE_ID })
         }).collect();
 
         self.view_use(sp, vis,
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 5417991c9df..e31ec048653 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -55,17 +55,17 @@ pub trait Folder {
                 let id = self.new_id(node_id);
                 ViewPathList(self.fold_path(path),
                              path_list_idents.iter().map(|path_list_ident| {
-                                let id = self.new_id(path_list_ident.node
-                                                                    .id);
                                 Spanned {
-                                    node: PathListIdent_ {
-                                        name: path_list_ident.node
-                                                             .name
-                                                             .clone(),
-                                        id: id,
+                                    node: match path_list_ident.node {
+                                        PathListIdent { id, name } =>
+                                            PathListIdent {
+                                                id: self.new_id(id),
+                                                name: name.clone()
+                                            },
+                                        PathListMod { id } =>
+                                            PathListMod { id: self.new_id(id) }
                                     },
-                                    span: self.new_span(
-                                        path_list_ident.span)
+                                    span: self.new_span(path_list_ident.span)
                                 }
                              }).collect(),
                              id)
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 8b9cb086949..13d2a632f36 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -24,7 +24,7 @@
        html_root_url = "http://doc.rust-lang.org/master/")]
 
 #![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
-#![feature(quote, unsafe_destructor)]
+#![feature(quote, struct_variant, unsafe_destructor)]
 #![allow(deprecated)]
 
 extern crate fmt_macros;
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 394288bd9f2..73de47e7b12 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -537,12 +537,16 @@ impl<'a> Parser<'a> {
         }
     }
 
-    pub fn parse_path_list_ident(&mut self) -> ast::PathListIdent {
+    pub fn parse_path_list_item(&mut self) -> ast::PathListItem {
         let lo = self.span.lo;
-        let ident = self.parse_ident();
+        let node = if self.eat_keyword(keywords::Mod) {
+            ast::PathListMod { id: ast::DUMMY_NODE_ID }
+        } else {
+            let ident = self.parse_ident();
+            ast::PathListIdent { name: ident, id: ast::DUMMY_NODE_ID }
+        };
         let hi = self.last_span.hi;
-        spanned(lo, hi, ast::PathListIdent_ { name: ident,
-                                              id: ast::DUMMY_NODE_ID })
+        spanned(lo, hi, node)
     }
 
     /// Consume token 'tok' if it exists. Returns true if the given
@@ -5176,7 +5180,7 @@ impl<'a> Parser<'a> {
             let idents = self.parse_unspanned_seq(
                 &token::LBRACE, &token::RBRACE,
                 seq_sep_trailing_allowed(token::COMMA),
-                |p| p.parse_path_list_ident());
+                |p| p.parse_path_list_item());
             let path = ast::Path {
                 span: mk_sp(lo, self.span.hi),
                 global: false,
@@ -5232,7 +5236,7 @@ impl<'a> Parser<'a> {
                         &token::LBRACE,
                         &token::RBRACE,
                         seq_sep_trailing_allowed(token::COMMA),
-                        |p| p.parse_path_list_ident()
+                        |p| p.parse_path_list_item()
                     );
                     let path = ast::Path {
                         span: mk_sp(lo, self.span.hi),
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index dd96118ea49..305e67a916e 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -2182,7 +2182,14 @@ impl<'a> State<'a> {
                     try!(word(&mut self.s, "::{"));
                 }
                 try!(self.commasep(Inconsistent, idents.as_slice(), |s, w| {
-                    s.print_ident(w.node.name)
+                    match w.node {
+                        ast::PathListIdent { name, .. } => {
+                            s.print_ident(name)
+                        },
+                        ast::PathListMod { .. } => {
+                            word(&mut s.s, "mod")
+                        }
+                    }
                 }));
                 word(&mut self.s, "}")
             }
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index d5fb75a4d69..3c6f06ddfc3 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -186,7 +186,12 @@ pub fn walk_view_item<E: Clone, V: Visitor<E>>(visitor: &mut V, vi: &ViewItem, e
                 }
                 ViewPathList(ref path, ref list, _) => {
                     for id in list.iter() {
-                        visitor.visit_ident(id.span, id.node.name, env.clone())
+                        match id.node {
+                            PathListIdent { name, .. } => {
+                                visitor.visit_ident(id.span, name, env.clone());
+                            }
+                            PathListMod { .. } => ()
+                        }
                     }
                     walk_path(visitor, path, env.clone());
                 }
diff --git a/src/test/compile-fail/use-mod-2.rs b/src/test/compile-fail/use-mod-2.rs
new file mode 100644
index 00000000000..12d4531078d
--- /dev/null
+++ b/src/test/compile-fail/use-mod-2.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+mod foo {
+    use self::{mod};
+    //~^ ERROR unresolved import `self`. There is no `self` in `???`
+
+    use super::{mod};
+    //~^ ERROR unresolved import `super`. There is no `super` in `???`
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/use-mod-3.rs b/src/test/compile-fail/use-mod-3.rs
new file mode 100644
index 00000000000..0263dc392f1
--- /dev/null
+++ b/src/test/compile-fail/use-mod-3.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use foo::bar::{
+    mod //~ ERROR module `bar` is private
+};
+use foo::bar::{
+    Bar, //~ ERROR type `Bar` is inaccessible
+    //~^ NOTE module `bar` is private
+    mod //~ ERROR module `bar` is private
+};
+
+mod foo {
+    mod bar { pub type Bar = int; }
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/use-mod.rs b/src/test/compile-fail/use-mod.rs
new file mode 100644
index 00000000000..b2b0eb21ace
--- /dev/null
+++ b/src/test/compile-fail/use-mod.rs
@@ -0,0 +1,32 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use foo::bar::{
+    mod,
+//~^ ERROR `mod` import can only appear once in the list
+    Bar,
+    mod
+//~^ NOTE another `mod` import appears here
+};
+
+use {mod};
+//~^ ERROR `mod` import can only appear in an import list with a non-empty prefix
+
+use foo::mod;
+//~^ ERROR `mod` imports are only allowed within a { } list
+
+mod foo {
+    pub mod bar {
+        pub struct Bar;
+        pub struct Baz;
+    }
+}
+
+fn main() {}
diff --git a/src/test/run-pass/use-mod.rs b/src/test/run-pass/use-mod.rs
new file mode 100644
index 00000000000..34c9f581f07
--- /dev/null
+++ b/src/test/run-pass/use-mod.rs
@@ -0,0 +1,38 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use foo::bar::{mod, First};
+use self::bar::Second;
+
+mod foo {
+    pub use self::bar::baz::{mod};
+
+    pub mod bar {
+        pub mod baz {
+            pub struct Fourth;
+        }
+        pub struct First;
+        pub struct Second;
+    }
+
+    pub struct Third;
+}
+
+mod baz {
+    use super::foo::{bar, mod};
+    pub use foo::Third;
+}
+
+fn main() {
+    let _ = First;
+    let _ = Second;
+    let _ = baz::Third;
+    let _ = foo::baz::Fourth;
+}