diff --git a/crates/analyzer/src/traversal/declarations.rs b/crates/analyzer/src/traversal/declarations.rs index 32d1495be4..76e8f82569 100644 --- a/crates/analyzer/src/traversal/declarations.rs +++ b/crates/analyzer/src/traversal/declarations.rs @@ -31,6 +31,22 @@ pub fn var_decl(scope: &mut BlockScope, stmt: &Node) -> Result<(), &value_attributes.typ, ); } + } else { + if matches!(declared_type, Type::Array(_)) { + scope.error( + "uninitialized variable", + target.span, + "uninitialized variable", + ); + } + + if matches!(declared_type, Type::Struct(_)) { + scope.error( + "uninitialized variable", + target.span, + "uninitialized variable", + ); + } } add_var(scope, target, declared_type)?; diff --git a/crates/parser/src/ast.rs b/crates/parser/src/ast.rs index d91784a14e..42f2e07989 100644 --- a/crates/parser/src/ast.rs +++ b/crates/parser/src/ast.rs @@ -303,6 +303,10 @@ pub enum Expr { List { elts: Vec>, }, + Repeat { + elt: Box>, + len: Box> + }, Tuple { elts: Vec>, }, @@ -901,6 +905,7 @@ impl fmt::Display for Expr { write!(f, "({})", node_comma_joined(&args.kind)) } Expr::List { elts } => write!(f, "[{}]", node_comma_joined(elts)), + Expr::Repeat { elt, len } => write!(f, "[{}; {}]", elt.kind, len.kind), Expr::Tuple { elts } => { if elts.len() == 1 { write!(f, "({},)", elts[0].kind) @@ -1118,6 +1123,7 @@ fn expr_left_binding_power(expr: &Expr) -> u8 { Expr::Subscript { .. } => max_power, Expr::Call { .. } => max_power, Expr::List { .. } => max_power, + Expr::Repeat { .. } => max_power, Expr::Tuple { .. } => max_power, Expr::Bool(_) => max_power, Expr::Name(_) => max_power, @@ -1141,6 +1147,7 @@ fn expr_right_binding_power(expr: &Expr) -> u8 { Expr::Subscript { .. } => max_power, Expr::Call { .. } => max_power, Expr::List { .. } => max_power, + Expr::Repeat { .. } => max_power, Expr::Tuple { .. } => max_power, Expr::Bool(_) => max_power, Expr::Name(_) => max_power, diff --git a/crates/parser/src/grammar/expressions.rs b/crates/parser/src/grammar/expressions.rs index 8ced7ebb61..807e1ec78f 100644 --- a/crates/parser/src/grammar/expressions.rs +++ b/crates/parser/src/grammar/expressions.rs @@ -230,7 +230,7 @@ fn parse_expr_head(par: &mut Parser) -> ParseResult> { unary_op(par, &op, operand) } ParenOpen => parse_group_or_tuple(par), - BracketOpen => parse_list(par), + BracketOpen => parse_list_or_repeat(par), _ => { let tok = par.next()?; par.unexpected_token_error( @@ -298,12 +298,29 @@ fn postfix_binding_power(op: TokenKind) -> Option { } /// Parse a square-bracket list expression, eg. `[1, 2, x]` -fn parse_list(par: &mut Parser) -> ParseResult> { +fn parse_list_or_repeat(par: &mut Parser) -> ParseResult> { let lbracket = par.assert(TokenKind::BracketOpen); - let elts = parse_expr_list(par, TokenKind::BracketClose, None)?; - let rbracket = par.assert(TokenKind::BracketClose); - let span = lbracket.span + rbracket.span; - Ok(Node::new(Expr::List { elts }, span)) + let elts = parse_expr_list(par, &[TokenKind::BracketClose, TokenKind::Semi], None)?; + + if elts.len() == 1 { + if par.peek() == Some(TokenKind::BracketClose) { + let rbracket = par.assert(TokenKind::BracketClose); + let span = lbracket.span + rbracket.span; + Ok(Node::new(Expr::List { elts }, span)) + } else if par.peek() == Some(TokenKind::Semi) { + par.assert(TokenKind::Semi); + let len = parse_expr(par)?; + let rbracket = par.assert(TokenKind::BracketClose); + let span = lbracket.span + rbracket.span; + Ok(Node::new(Expr::Repeat {elt: Box::new(elts[0].clone()), len: Box::new(len) }, span)) + } else { + panic!("shit") + } + } else { + let rbracket = par.assert(TokenKind::BracketClose); + let span = lbracket.span + rbracket.span; + Ok(Node::new(Expr::List { elts }, span)) + } } /// Parse a paren-wrapped expression, which might turn out to be a tuple @@ -328,7 +345,7 @@ fn parse_group_or_tuple(par: &mut Parser) -> ParseResult> { Comma => { // tuple par.next()?; - let elts = parse_expr_list(par, ParenClose, Some(elem))?; + let elts = parse_expr_list(par, &[ParenClose], Some(elem))?; let rparen = par.expect(ParenClose, "failed to parse tuple expression")?; let span = lparen.span + rparen.span; Ok(Node::new(Expr::Tuple { elts }, span)) @@ -349,7 +366,7 @@ fn parse_group_or_tuple(par: &mut Parser) -> ParseResult> { /// `peek()`ed. fn parse_expr_list( par: &mut Parser, - end_marker: TokenKind, + end_markers: &[TokenKind], head: Option>, ) -> ParseResult>> { let mut elts = vec![]; @@ -358,7 +375,7 @@ fn parse_expr_list( } loop { let next = par.peek_or_err()?; - if next == end_marker { + if end_markers.contains(&next) { break; } elts.push(parse_expr(par)?); @@ -366,7 +383,7 @@ fn parse_expr_list( TokenKind::Comma => { par.next()?; } - tk if tk == end_marker => break, + tk if end_markers.contains(&tk) => break, _ => { let tok = par.next()?; par.unexpected_token_error( diff --git a/crates/parser/tests/cases/parse_ast.rs b/crates/parser/tests/cases/parse_ast.rs index 70d8c59c9a..94f744667c 100644 --- a/crates/parser/tests/cases/parse_ast.rs +++ b/crates/parser/tests/cases/parse_ast.rs @@ -81,6 +81,8 @@ test_parse! { expr_path_call, expressions::parse_expr, "foo::bar::abc1()" } test_parse! { expr_string, expressions::parse_expr, r#""hi \tmom\n""# } test_parse! { expr_list, expressions::parse_expr, "[]" } test_parse! { expr_list2, expressions::parse_expr, "[x, y, z,]" } +test_parse! { expr_repeat, expressions::parse_expr, "[true; 42]" } +test_parse! { expr_repeat2, expressions::parse_expr, "[5 + 4; 26]" } test_parse! { expr_ternary, expressions::parse_expr, "x + 1 if y + 2 else z + 3" } test_parse! { expr_group, expressions::parse_expr, "(1 + 2) * 3" } test_parse! { expr_tuple1, expressions::parse_expr, "(1,)" } diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat.snap new file mode 100644 index 0000000000..245a7f4313 --- /dev/null +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat.snap @@ -0,0 +1,27 @@ +--- +source: crates/parser/tests/cases/parse_ast.rs +expression: "ast_string(stringify!(expr_repeat), expressions::parse_expr, \"[true; 42]\")" + +--- +Node( + kind: Repeat( + elt: Node( + kind: Bool(true), + span: Span( + start: 1, + end: 5, + ), + ), + len: Node( + kind: Num("42"), + span: Span( + start: 7, + end: 9, + ), + ), + ), + span: Span( + start: 0, + end: 10, + ), +) diff --git a/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat2.snap b/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat2.snap new file mode 100644 index 0000000000..a3c9f6d14f --- /dev/null +++ b/crates/parser/tests/cases/snapshots/cases__parse_ast__expr_repeat2.snap @@ -0,0 +1,49 @@ +--- +source: crates/parser/tests/cases/parse_ast.rs +expression: "ast_string(stringify!(expr_repeat2), expressions::parse_expr, \"[5 + 4; 26]\")" + +--- +Node( + kind: Repeat( + elt: Node( + kind: BinOperation( + left: Node( + kind: Num("5"), + span: Span( + start: 1, + end: 2, + ), + ), + op: Node( + kind: Add, + span: Span( + start: 3, + end: 4, + ), + ), + right: Node( + kind: Num("4"), + span: Span( + start: 5, + end: 6, + ), + ), + ), + span: Span( + start: 1, + end: 6, + ), + ), + len: Node( + kind: Num("26"), + span: Span( + start: 8, + end: 10, + ), + ), + ), + span: Span( + start: 0, + end: 11, + ), +) diff --git a/crates/test-files/fixtures/features/return_array.fe b/crates/test-files/fixtures/features/return_array.fe index 03bbd33b54..3d40a923f6 100644 --- a/crates/test-files/fixtures/features/return_array.fe +++ b/crates/test-files/fixtures/features/return_array.fe @@ -1,6 +1,6 @@ contract Foo { pub fn bar(x: u256) -> Array { - let my_array: Array + let my_array: Array = [8; 5] my_array[3] = x return my_array }