From 048dd25bfbc85ec64653b9ffbb839c5d6af2a819 Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 28 Aug 2016 11:06:12 -0700 Subject: [PATCH 1/5] Add ExprBuilder::closure. --- src/expr.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test_expr.rs | 66 ++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index b6cfa54fd..026bc77bf 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -9,6 +9,7 @@ use syntax::ptr::P; use arm::ArmBuilder; use attr::AttrBuilder; use block::BlockBuilder; +use fn_decl::FnDeclBuilder; use ident::ToIdent; use invoke::{Invoke, Identity}; use lit::LitBuilder; @@ -801,6 +802,14 @@ impl ExprBuilder builder: self, }).span(span) } + + pub fn closure(self) -> ExprClosureBuilder { + ExprClosureBuilder { + span: self.span, + builder: self, + capture_by: ast::CaptureBy::Ref, + } + } } impl Invoke for ExprBuilder @@ -1850,3 +1859,84 @@ impl Invoke> for ExprTryBuilder .build() } } + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprClosureBuilder { + builder: ExprBuilder, + capture_by: ast::CaptureBy, + span: Span, +} + +impl ExprClosureBuilder { + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn by_value(mut self) -> Self { + self.capture_by = ast::CaptureBy::Value; + self + } + + pub fn by_ref(mut self) -> Self { + self.capture_by = ast::CaptureBy::Ref; + self + } + + pub fn fn_decl(self) -> FnDeclBuilder { + FnDeclBuilder::with_callback(self) + } + + pub fn build_fn_decl(self, fn_decl: P) -> ExprClosureBlockBuilder { + ExprClosureBlockBuilder { + builder: self.builder, + capture_by: self.capture_by, + fn_decl: fn_decl, + span: self.span, + } + } +} + +impl Invoke> for ExprClosureBuilder { + type Result = ExprClosureBlockBuilder; + + fn invoke(self, fn_decl: P) -> ExprClosureBlockBuilder { + self.build_fn_decl(fn_decl) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprClosureBlockBuilder { + builder: ExprBuilder, + capture_by: ast::CaptureBy, + fn_decl: P, + span: Span, +} + +impl ExprClosureBlockBuilder + where F: Invoke>, +{ + pub fn expr(self) -> ExprBuilder> { + self.block().expr() + } + + pub fn block(self) -> BlockBuilder { + BlockBuilder::with_callback(self) + } + + pub fn build_block(self, block: P) -> F::Result { + self.builder.build_expr_kind(ast::ExprKind::Closure(self.capture_by, self.fn_decl, block, self.span)) + } +} + +impl Invoke> for ExprClosureBlockBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, block: P) -> F::Result { + self.build_block(block) + } +} diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 60ade6538..9d9a0421b 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -494,3 +494,69 @@ fn test_repeat() { ) ); } + +#[test] +fn test_trivial_closure() { + let builder = AstBuilder::new(); + + let expr = builder.expr().closure() + .by_value() + .fn_decl().default_return() + .expr().usize(1); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::Closure( + ast::CaptureBy::Value, + builder.fn_decl().default_return(), + builder.block().expr().usize(1), + DUMMY_SP, + ) + ) + ); +} + +#[test] +fn test_closure_by_ref() { + let builder = AstBuilder::new(); + + let expr = builder.expr().closure() + .by_ref() + .fn_decl().default_return() + .expr().usize(2); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::Closure( + ast::CaptureBy::Ref, + builder.fn_decl().default_return(), + builder.block().expr().usize(2), + DUMMY_SP, + ) + ) + ); +} + +#[test] +fn test_closure_block() { + let builder = AstBuilder::new(); + + let expr = builder.expr().closure() + .by_ref() + .fn_decl().default_return() + .block().expr().usize(3); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::Closure( + ast::CaptureBy::Ref, + builder.fn_decl().default_return(), + builder.block().expr().usize(3), + DUMMY_SP, + ) + ) + ); +} From 17741a0f4cc3a30c22a3c328b628c0704cf100ce Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 28 Aug 2016 19:46:05 -0700 Subject: [PATCH 2/5] Add PathSegmentBuilder::{return_,no_return}. --- src/path.rs | 37 +++++++++++++++++++++++++++++++++ tests/test_path.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/src/path.rs b/src/path.rs index aebdafc67..c1ec86c63 100644 --- a/src/path.rs +++ b/src/path.rs @@ -276,6 +276,29 @@ impl PathSegmentBuilder }).span(span) } + pub fn no_return(self) -> F::Result { + self.build_return(None) + } + + pub fn return_(self) -> TyBuilder> { + TyBuilder::with_callback(PathSegmentReturnBuilder(self)) + } + + pub fn build_return(self, output: Option>) -> F::Result { + let data = ast::ParenthesizedParameterData { + span: self.span, + inputs: self.tys, + output: output, + }; + + let parameters = ast::PathParameters::Parenthesized(data); + + self.callback.invoke(ast::PathSegment { + identifier: self.id, + parameters: parameters, + }) + } + pub fn build(self) -> F::Result { let data = ast::AngleBracketedParameterData { lifetimes: self.lifetimes, @@ -326,3 +349,17 @@ impl Invoke> for TypeBindingBuilder }) } } + +////////////////////////////////////////////////////////////////////////////// + +pub struct PathSegmentReturnBuilder(PathSegmentBuilder); + +impl Invoke> for PathSegmentReturnBuilder + where F: Invoke +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> Self::Result { + self.0.build_return(Some(ty)) + } +} diff --git a/tests/test_path.rs b/tests/test_path.rs index 9d4c51d16..e0afe2426 100644 --- a/tests/test_path.rs +++ b/tests/test_path.rs @@ -147,3 +147,55 @@ fn test_lifetimes() { } ); } + +#[test] +fn test_parenthesized_no_return() { + let builder = AstBuilder::new(); + let path = builder.path().segment("Fn").ty().u8().no_return().build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ + ast::PathSegment { + identifier: builder.id("Fn"), + parameters: ast::PathParameters::Parenthesized( + ast::ParenthesizedParameterData { + span: DUMMY_SP, + inputs: vec![builder.ty().u8()], + output: None, + } + ), + }, + ] + } + ); +} + +#[test] +fn test_parenthesized_with_return() { + let builder = AstBuilder::new(); + let path = builder.path().segment("FnMut").ty().u16().return_().u32().build(); + + assert_eq!( + path, + ast::Path { + span: DUMMY_SP, + global: false, + segments: vec![ + ast::PathSegment { + identifier: builder.id("FnMut"), + parameters: ast::PathParameters::Parenthesized( + ast::ParenthesizedParameterData { + span: DUMMY_SP, + inputs: vec![builder.ty().u16()], + output: Some(builder.ty().u32()), + } + ), + }, + ] + } + ); +} From fa5a25cbb961313d5903f020c876e701d9bd65cb Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 28 Aug 2016 23:42:11 -0700 Subject: [PATCH 3/5] Add PatBuilder::{ref_,ref_mut}. --- src/pat.rs | 31 +++++++++++++++++++++++++++++++ tests/test.rs | 1 + tests/test_pat.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 tests/test_pat.rs diff --git a/src/pat.rs b/src/pat.rs index 5453b23a7..397d168b2 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -135,6 +135,20 @@ impl PatBuilder wild: None, } } + + pub fn ref_(self) -> PatBuilder> { + PatBuilder::with_callback(PatRefBuilder { + builder: self, + mutability: ast::Mutability::Immutable, + }) + } + + pub fn ref_mut(self) -> PatBuilder> { + PatBuilder::with_callback(PatRefBuilder { + builder: self, + mutability: ast::Mutability::Mutable, + }) + } } impl Invoke for PatBuilder @@ -447,3 +461,20 @@ impl Invoke> for PatTupleBuilder self.with_pat(pat) } } + +////////////////////////////////////////////////////////////////////////////// + +pub struct PatRefBuilder { + builder: PatBuilder, + mutability: ast::Mutability, +} + +impl Invoke> for PatRefBuilder + where F: Invoke> +{ + type Result = F::Result; + + fn invoke(self, pat: P) -> F::Result { + self.builder.build_pat_kind(ast::PatKind::Ref(pat, self.mutability)) + } +} diff --git a/tests/test.rs b/tests/test.rs index c102ed4d2..8c2598a82 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -18,6 +18,7 @@ mod test_fn_decl; mod test_generics; mod test_item; mod test_lit; +mod test_pat; mod test_path; mod test_stmt; mod test_struct_field; diff --git a/tests/test_pat.rs b/tests/test_pat.rs new file mode 100644 index 000000000..3a16de0de --- /dev/null +++ b/tests/test_pat.rs @@ -0,0 +1,45 @@ +use syntax::ast; +use syntax::codemap::DUMMY_SP; +use syntax::ptr::P; + +use aster::AstBuilder; + +const DUMMY_PAT: ast::Pat = ast::Pat { + id: ast::DUMMY_NODE_ID, + node: ast::PatKind::Wild, + span: DUMMY_SP, +}; + +#[test] +fn test_pat_ref() { + let builder = AstBuilder::new(); + + let pat = builder.pat().ref_().expr().unit(); + + assert_eq!( + pat, + P(ast::Pat { node: ast::PatKind::Ref( + P(ast::Pat { node: ast::PatKind::Lit( + builder.expr().unit(), + ), ..DUMMY_PAT }), + ast::Mutability::Immutable, + ), ..DUMMY_PAT }) + ); +} + +#[test] +fn test_pat_ref_mut() { + let builder = AstBuilder::new(); + + let pat = builder.pat().ref_mut().expr().unit(); + + assert_eq!( + pat, + P(ast::Pat { node: ast::PatKind::Ref( + P(ast::Pat { node: ast::PatKind::Lit( + builder.expr().unit(), + ), ..DUMMY_PAT }), + ast::Mutability::Mutable, + ), ..DUMMY_PAT }) + ); +} From 34de636fa212b3f2ad7c7fa52cfda48d8b371dda Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 28 Aug 2016 23:49:58 -0700 Subject: [PATCH 4/5] Add ExprBuilder::while_. --- src/expr.rs | 96 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test_expr.rs | 74 +++++++++++++++++++++++++++++++++++ 2 files changed, 170 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index 026bc77bf..3fadb56b6 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -810,6 +810,12 @@ impl ExprBuilder capture_by: ast::CaptureBy::Ref, } } + + pub fn while_(self) -> ExprBuilder> { + ExprBuilder::with_callback(ExprWhileBuilder { + builder: self, + }) + } } impl Invoke for ExprBuilder @@ -1940,3 +1946,93 @@ impl Invoke> for ExprClosureBlockBuilder self.build_block(block) } } + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprWhileBuilder { + builder: ExprBuilder, +} + +impl Invoke> for ExprWhileBuilder + where F: Invoke>, +{ + type Result = ExprWhileBlockBuilder; + + fn invoke(self, condition: P) -> ExprWhileBlockBuilder { + ExprWhileBlockBuilder { + span: self.builder.span, + builder: self.builder, + condition: condition, + pat: None, + label: None, + } + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprWhileBlockBuilder { + builder: ExprBuilder, + condition: P, + pat: Option>, + span: Span, + label: Option, +} + +impl ExprWhileBlockBuilder { + pub fn pat(self) -> PatBuilder { + PatBuilder::with_callback(self) + } + + pub fn span(mut self, span: Span) -> Self { + self.span = span; + self + } + + pub fn label(mut self, id: I) -> Self + where I: ToIdent, + { + self.label = Some(respan(self.span, id.to_ident())); + self + } + + pub fn build_pat(mut self, pat: P) -> Self { + self.pat = Some(pat); + self + } +} + +impl ExprWhileBlockBuilder + where F: Invoke>, +{ + pub fn block(self) -> BlockBuilder { + BlockBuilder::with_callback(self) + } + + pub fn build_block(self, block: P) -> F::Result { + match self.pat { + Some(p) => self.builder.build_expr_kind(ast::ExprKind::WhileLet( + p, self.condition, block, self.label)), + None => self.builder.build_expr_kind(ast::ExprKind::While( + self.condition, block, self.label)), + } + } +} + +impl Invoke> for ExprWhileBlockBuilder { + type Result = Self; + + fn invoke(self, pat: P) -> Self { + self.build_pat(pat) + } +} + +impl Invoke> for ExprWhileBlockBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, block: P) -> F::Result { + self.build_block(block) + } +} diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 9d9a0421b..ce5feb820 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -560,3 +560,77 @@ fn test_closure_block() { ) ); } + +#[test] +fn test_while_loop() { + let builder = AstBuilder::new(); + + let expr = builder.expr().while_().true_().block().expr().unit(); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::While( + builder.expr().true_(), + builder.block().expr().unit(), + None, + ) + ) + ); +} + +#[test] +fn test_while_loop_label() { + let builder = AstBuilder::new(); + + let expr = builder.expr().while_().true_().label("'lab").block().expr().unit(); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::While( + builder.expr().true_(), + builder.block().expr().unit(), + Some(respan(DUMMY_SP, builder.id("'lab"))), + ) + ) + ); +} + +#[test] +fn test_while_let_loop() { + let builder = AstBuilder::new(); + + let expr = builder.expr().while_().unit().pat().expr().unit().block().expr().unit(); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::WhileLet( + builder.pat().expr().unit(), + builder.expr().unit(), + builder.block().expr().unit(), + None, + ) + ) + ); +} + +#[test] +fn test_while_let_loop_label() { + let builder = AstBuilder::new(); + + let expr = builder.expr().while_().unit().label("'lab").pat().expr().unit().block().expr().unit(); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::WhileLet( + builder.pat().expr().unit(), + builder.expr().unit(), + builder.block().expr().unit(), + Some(respan(DUMMY_SP, builder.id("'lab"))), + ) + ) + ); +} From 9397bffcf83fe325787de1a4d031d7c7aa82cbce Mon Sep 17 00:00:00 2001 From: Aaron Gallagher <_@habnab.it> Date: Sun, 28 Aug 2016 23:53:30 -0700 Subject: [PATCH 5/5] Add ExprBuilder::type_. It's type ascription, which is still unstable and poorly documented in the ast module. --- src/expr.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ tests/test_expr.rs | 17 +++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index 3fadb56b6..52ea88f27 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -816,6 +816,12 @@ impl ExprBuilder builder: self, }) } + + pub fn type_(self) -> ExprBuilder> { + ExprBuilder::with_callback(ExprTypeBuilder { + builder: self, + }) + } } impl Invoke for ExprBuilder @@ -2036,3 +2042,39 @@ impl Invoke> for ExprWhileBlockBuilder self.build_block(block) } } + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprTypeBuilder { + builder: ExprBuilder, +} + +impl Invoke> for ExprTypeBuilder + where F: Invoke>, +{ + type Result = TyBuilder>; + + fn invoke(self, expr: P) -> TyBuilder> { + TyBuilder::with_callback(ExprTypeTyBuilder { + builder: self.builder, + expr: expr, + }) + } +} + +////////////////////////////////////////////////////////////////////////////// + +pub struct ExprTypeTyBuilder { + builder: ExprBuilder, + expr: P, +} + +impl Invoke> for ExprTypeTyBuilder + where F: Invoke>, +{ + type Result = F::Result; + + fn invoke(self, ty: P) -> F::Result { + self.builder.build_expr_kind(ast::ExprKind::Type(self.expr, ty)) + } +} diff --git a/tests/test_expr.rs b/tests/test_expr.rs index ce5feb820..bf083c170 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -634,3 +634,20 @@ fn test_while_let_loop_label() { ) ); } + +#[test] +fn test_type_ascription() { + let builder = AstBuilder::new(); + + let expr = builder.expr().type_().u8(1).u8(); + + assert_eq!( + expr, + builder.expr().build_expr_kind( + ast::ExprKind::Type( + builder.expr().u8(1), + builder.ty().u8(), + ) + ) + ); +}