From c864338820579acbcaacdb4b76531dc43f229b3f Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 19 Jul 2018 22:54:11 -0300 Subject: [PATCH] Parser: fix parsing of named tuple inside generic type --- spec/compiler/parser/parser_spec.cr | 1 + src/compiler/crystal/syntax/parser.cr | 25 ++++++++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/spec/compiler/parser/parser_spec.cr b/spec/compiler/parser/parser_spec.cr index ecdf0db3cc60..a1ff723a35e7 100644 --- a/spec/compiler/parser/parser_spec.cr +++ b/spec/compiler/parser/parser_spec.cr @@ -522,6 +522,7 @@ module Crystal it_parses "Foo({x: X})", Generic.new("Foo".path, [Generic.new(Path.global("NamedTuple"), [] of ASTNode, named_args: [NamedArgument.new("x", "X".path)])] of ASTNode) it_parses "Foo({x: X, y: Y})", Generic.new("Foo".path, [Generic.new(Path.global("NamedTuple"), [] of ASTNode, named_args: [NamedArgument.new("x", "X".path), NamedArgument.new("y", "Y".path)])] of ASTNode) + it_parses "Foo(T, {x: X})", Generic.new("Foo".path, ["T".path, Generic.new(Path.global("NamedTuple"), [] of ASTNode, named_args: [NamedArgument.new("x", "X".path)])] of ASTNode) assert_syntax_error "Foo({x: X, x: Y})", "duplicated key: x" it_parses %(Foo({"foo bar": X})), Generic.new("Foo".path, [Generic.new(Path.global("NamedTuple"), [] of ASTNode, named_args: [NamedArgument.new("foo bar", "X".path)])] of ASTNode) diff --git a/src/compiler/crystal/syntax/parser.cr b/src/compiler/crystal/syntax/parser.cr index 6d2d509f27f0..ad4bfa12440f 100644 --- a/src/compiler/crystal/syntax/parser.cr +++ b/src/compiler/crystal/syntax/parser.cr @@ -4557,7 +4557,7 @@ module Crystal end def parse_types(allow_primitives = false, allow_splat = false) - type = parse_type(allow_primitives: allow_primitives, allow_splat: allow_splat) + type = parse_type(allow_primitives: allow_primitives, allow_splat: allow_splat, inside_paren: true) case type when Array type @@ -4581,7 +4581,7 @@ module Crystal end end - def parse_type(allow_primitives, allow_commas = true, allow_splat = false) + def parse_type(allow_primitives, allow_commas = true, allow_splat = false, inside_paren = false) location = @token.location if @token.type == :"->" @@ -4589,7 +4589,11 @@ module Crystal else input_types = parse_type_union(allow_primitives, allow_splat) input_types = [input_types] unless input_types.is_a?(Array) - while allow_commas && @token.type == :"," && ((allow_primitives && next_comes_type_or_int) || (!allow_primitives && next_comes_type)) + while allow_commas && @token.type == :"," && ( + (allow_primitives && next_comes_type_or_int) || + (!allow_primitives && next_comes_type) || + (inside_paren && next_comes_curly) + ) next_token_skip_space_or_newline if @token.type == :"->" next_types = parse_type(false) @@ -4856,6 +4860,21 @@ module Crystal end end + def next_comes_curly + old_pos, old_line, old_column = current_pos, @line_number, @column_number + + @temp_token.copy_from(@token) + + next_token_skip_space_or_newline + + curly = @token.type == :"{" + + @token.copy_from(@temp_token) + self.current_pos, @line_number, @column_number = old_pos, old_line, old_column + + curly + end + def make_pointer_type(node) Generic.new(Path.global("Pointer").at(node), [node] of ASTNode).at(node) end