diff --git a/spec/examples/array_literal b/spec/examples/array_literal index a22bdd787..a656b7cac 100644 --- a/spec/examples/array_literal +++ b/spec/examples/array_literal @@ -53,3 +53,14 @@ component Main {
} } +------------------------------------------------------------------------------- +module Test { + fun test : Array(String) { + [ + // Start Comment + "Item 1", + // End comment + "Item 2" + ] of String + } +} diff --git a/spec/examples/operation b/spec/examples/operation index 9f0129630..c9ac6b1ce 100644 --- a/spec/examples/operation +++ b/spec/examples/operation @@ -151,3 +151,10 @@ component Main { "Hello" + "There" } } +------------------------------------------------------------------------------- +component Main { + fun render : String { + "Hello" // Some comment + + "There" + } +} diff --git a/spec/examples/pipe b/spec/examples/pipe index ab0726818..266fcd9dd 100644 --- a/spec/examples/pipe +++ b/spec/examples/pipe @@ -76,3 +76,17 @@ component Main { } } +------------------------------------------------------------------------------- +component Main { + fun test (value : String) { + value + } + + fun render : Html { + "test" + // Some comment + |> test + + + } +} diff --git a/spec/formatters/array_with_comments b/spec/formatters/array_with_comments new file mode 100644 index 000000000..16167928d --- /dev/null +++ b/spec/formatters/array_with_comments @@ -0,0 +1,23 @@ +module Test { + fun test : Array(String) { + [ + // Item 1 Comment + "Item 1", + // Item 2 comment + "Item 2" + // End comment + ] of String + } +} +-------------------------------------------------------------------------------- +module Test { + fun test : Array(String) { + [ + // Item 1 Comment + "Item 1", + // Item 2 comment + "Item 2" + // End comment + ] of String + } +} diff --git a/spec/formatters/operation_with_comment b/spec/formatters/operation_with_comment new file mode 100644 index 000000000..0eacace0a --- /dev/null +++ b/spec/formatters/operation_with_comment @@ -0,0 +1,13 @@ +component Main { + fun render : String { + "Hello" // Some comment + + "There" + } +} +-------------------------------------------------------------------------------- +component Main { + fun render : String { + "Hello" // Some comment + + "There" + } +} diff --git a/spec/formatters/pipe_with_comment b/spec/formatters/pipe_with_comment new file mode 100644 index 000000000..92dd985ec --- /dev/null +++ b/spec/formatters/pipe_with_comment @@ -0,0 +1,27 @@ +component Main { + fun test (value : String) { + value + } + + fun render : Html { + "test" + // Some comment + |> test + + + } +} +-------------------------------------------------------------------------------- +component Main { + fun test (value : String) { + value + } + + fun render : Html { + "test" + // Some comment + |> test + + + } +} diff --git a/spec/formatters/record_update_with_comments b/spec/formatters/record_update_with_comments new file mode 100644 index 000000000..44717c4a6 --- /dev/null +++ b/spec/formatters/record_update_with_comments @@ -0,0 +1,33 @@ +type A { + a : String +} + +module Test { + fun test : A { + let x = + { a : "Blah" } + + { x| + // Comment + a:"Hello" + // End Comment + } + } +} +-------------------------------------------------------------------------------- +type A { + a : String +} + +module Test { + fun test : A { + let x = + { a: "Blah" } + + { x | + // Comment + a: "Hello" + // End Comment + } + } +} diff --git a/spec/formatters/record_with_comments b/spec/formatters/record_with_comments new file mode 100644 index 000000000..8d2574034 --- /dev/null +++ b/spec/formatters/record_with_comments @@ -0,0 +1,27 @@ +type A { + a : String +} + +module Test { + fun test : A { + { + // Comment + a:"Hello" + // End Comment + } + } +} +-------------------------------------------------------------------------------- +type A { + a : String +} + +module Test { + fun test : A { + { + // Comment + a: "Hello" + // End Comment + } + } +} diff --git a/spec/formatters/tuple_with_comments b/spec/formatters/tuple_with_comments new file mode 100644 index 000000000..e7438f744 --- /dev/null +++ b/spec/formatters/tuple_with_comments @@ -0,0 +1,23 @@ +module Test { + fun test : Tuple(String, String) { + { + // Comment for "Blah" + "Blah", + // Comment for "Joe" + "Joe" + // End comment + } + } +} +-------------------------------------------------------------------------------- +module Test { + fun test : Tuple(String, String) { + { + // Comment for "Blah" + "Blah", + // Comment for "Joe" + "Joe" + // End comment + } + } +} diff --git a/spec/formatters/type_definition_with_comments b/spec/formatters/type_definition_with_comments index bd7775ea6..15d1aa7ea 100644 --- a/spec/formatters/type_definition_with_comments +++ b/spec/formatters/type_definition_with_comments @@ -1,4 +1,6 @@ -/*A*/typeTest{/*B*/a:String,/*C*/b:Blah} +/*A*/typeTest{ + /*B*/a:String,/*C*/b:Blah// End comment +} -------------------------------------------------------------------------------- /* A */ type Test { @@ -7,4 +9,6 @@ type Test { /* C */ b : Blah + + // End comment } diff --git a/src/ast/array_literal.cr b/src/ast/array_literal.cr index f066c1aff..abf5f15ac 100644 --- a/src/ast/array_literal.cr +++ b/src/ast/array_literal.cr @@ -1,12 +1,13 @@ module Mint class Ast class ArrayLiteral < Node - getter items, type + getter comment, items, type - def initialize(@from : Parser::Location, + def initialize(@items : Array(CommentedExpression), + @from : Parser::Location, @to : Parser::Location, @file : Parser::File, - @items : Array(Node), + @comment : Comment?, @type : Node?) end end diff --git a/src/ast/commented_expression.cr b/src/ast/commented_expression.cr new file mode 100644 index 000000000..e342a4bd7 --- /dev/null +++ b/src/ast/commented_expression.cr @@ -0,0 +1,14 @@ +module Mint + class Ast + class CommentedExpression < Node + getter expression, comment + + def initialize(@from : Parser::Location, + @to : Parser::Location, + @file : Parser::File, + @comment : Comment?, + @expression : Node) + end + end + end +end diff --git a/src/ast/operation.cr b/src/ast/operation.cr index 8ef59e03a..6ceb07558 100644 --- a/src/ast/operation.cr +++ b/src/ast/operation.cr @@ -1,11 +1,12 @@ module Mint class Ast class Operation < Node - getter operator, right, left + getter operator, comment, right, left def initialize(@from : Parser::Location, @to : Parser::Location, @file : Parser::File, + @comment : Comment?, @operator : String, @right : Node, @left : Node) diff --git a/src/ast/pipe.cr b/src/ast/pipe.cr index cb01b8050..7d9bb26a1 100644 --- a/src/ast/pipe.cr +++ b/src/ast/pipe.cr @@ -1,11 +1,12 @@ module Mint class Ast class Pipe < Node - getter expression, argument + getter expression, argument, comment def initialize(@from : Parser::Location, @to : Parser::Location, @file : Parser::File, + @comment : Comment?, @expression : Node, @argument : Node) end diff --git a/src/ast/record.cr b/src/ast/record.cr index cce9b6c3f..f4fec012f 100644 --- a/src/ast/record.cr +++ b/src/ast/record.cr @@ -1,12 +1,13 @@ module Mint class Ast class Record < Node - getter fields + getter fields, comment def initialize(@from : Parser::Location, @to : Parser::Location, @fields : Array(Field), - @file : Parser::File) + @file : Parser::File, + @comment : Comment?) end end end diff --git a/src/ast/record_update.cr b/src/ast/record_update.cr index 22712279e..8ee9be54f 100644 --- a/src/ast/record_update.cr +++ b/src/ast/record_update.cr @@ -1,13 +1,14 @@ module Mint class Ast class RecordUpdate < Node - getter expression, fields + getter expression, fields, comment def initialize(@from : Parser::Location, @expression : Ast::Node, @to : Parser::Location, @fields : Array(Field), - @file : Parser::File) + @file : Parser::File, + @comment : Comment?) end end end diff --git a/src/ast/tuple_literal.cr b/src/ast/tuple_literal.cr index 2775cc84f..0df24f063 100644 --- a/src/ast/tuple_literal.cr +++ b/src/ast/tuple_literal.cr @@ -1,12 +1,13 @@ module Mint class Ast class TupleLiteral < Node - getter items + getter comment, items - def initialize(@from : Parser::Location, + def initialize(@items : Array(CommentedExpression), + @from : Parser::Location, @to : Parser::Location, @file : Parser::File, - @items : Array(Node)) + @comment : Comment?) end end end diff --git a/src/ast/type_definition.cr b/src/ast/type_definition.cr index 72a58b24d..ffea0e920 100644 --- a/src/ast/type_definition.cr +++ b/src/ast/type_definition.cr @@ -1,11 +1,12 @@ module Mint class Ast class TypeDefinition < Node - getter parameters, comment, fields, name + getter parameters, end_comment, comment, fields, name def initialize(@fields : Array(TypeDefinitionField) | Array(TypeVariant), @parameters : Array(TypeVariable), @from : Parser::Location, + @end_comment : Comment?, @to : Parser::Location, @file : Parser::File, @comment : Comment?, diff --git a/src/compilers/commented_expression.cr b/src/compilers/commented_expression.cr new file mode 100644 index 000000000..7aeb573ca --- /dev/null +++ b/src/compilers/commented_expression.cr @@ -0,0 +1,9 @@ +module Mint + class Compiler + def compile(node : Ast::CommentedExpression) : Compiled + compile node do + compile(node.expression) + end + end + end +end diff --git a/src/formatter.cr b/src/formatter.cr index 1f3fd4954..45b5c9dcc 100644 --- a/src/formatter.cr +++ b/src/formatter.cr @@ -47,7 +47,8 @@ module Mint # record List, items : Array(Tuple(Ast::Node, Nodes)), - separator : String? = nil + separator : String? = nil, + comment : Nodes? = nil # Describes a group of nodes, with start and end characters and a separator # character (or characters). The layout of the nodes are determined during @@ -83,7 +84,8 @@ module Mint items : Array(Nodes), behavior : Behavior, separator : String, - pad : Bool + pad : Bool, + comment : Nodes = [] of Node # The possibilities on how to format groups. enum Behavior @@ -133,10 +135,6 @@ module Mint [Group.new(**params)] of Node end - def list(**params) - [List.new(**params)] of Node - end - # Actuall formatting things as strings... def format!(*args, **named) : String diff --git a/src/formatter/processor.cr b/src/formatter/processor.cr index b99e42d3c..d4a974687 100644 --- a/src/formatter/processor.cr +++ b/src/formatter/processor.cr @@ -158,7 +158,14 @@ module Mint last = item end - result + if comment = node.comment + line_count = + new_line?(last_formatted) ? 2 : 1 + + result + process([Line.new(line_count)] + comment) + else + result + end in Entity arguments = if node.arguments.empty? @@ -212,14 +219,22 @@ module Mint padding = node.pad ? " " : "" - case node.behavior + comment, behavior = + if node.comment.size > 0 + {node.comment.unshift(Line.new(1)), Behavior::Block} + else + {node.comment, node.behavior} + end + + case behavior in Behavior::Block process( [ node.ends[0], Nest.new( [Line.new(1)] + - node.items.intersperse([node.separator, Line.new(1)]).flatten + node.items.intersperse([node.separator, Line.new(1)]).flatten + + comment ), Line.new(1), node.ends[1], @@ -374,6 +389,7 @@ module Mint node.pad ? 2 : 0 node.items.sum(&->size(Array(Node))) + + size(node.comment) + node.ends[0].size + node.ends[1].size + separators + diff --git a/src/formatters/array_literal.cr b/src/formatters/array_literal.cr index e86409436..95c3eae1a 100644 --- a/src/formatters/array_literal.cr +++ b/src/formatters/array_literal.cr @@ -12,6 +12,7 @@ module Mint else group( items: node.items.map(&->format(Ast::Node)), + comment: format(node.comment), behavior: Behavior::BreakAll, ends: {"[", "]"}, separator: ",", diff --git a/src/formatters/commented_expression.cr b/src/formatters/commented_expression.cr new file mode 100644 index 000000000..034494678 --- /dev/null +++ b/src/formatters/commented_expression.cr @@ -0,0 +1,13 @@ +module Mint + class Formatter + def format(node : Ast::CommentedExpression) : Nodes + comment = + format_documentation_comment node.comment + + expression = + format node.expression + + comment + expression + end + end +end diff --git a/src/formatters/list.cr b/src/formatters/list.cr index c5c07e311..62438c6c4 100644 --- a/src/formatters/list.cr +++ b/src/formatters/list.cr @@ -1,9 +1,16 @@ module Mint class Formatter - def list(nodes : Array(Ast::Node), delimeter : String? = nil) : Nodes - list( - items: nodes.map(&.as(Ast::Node)).zip(nodes.map(&->format(Ast::Node))), - separator: delimeter) + def list( + nodes : Array(Ast::Node), + separator : String? = nil, + comment : Nodes? = nil + ) : Nodes + [ + List.new( + items: nodes.map(&.as(Ast::Node)).zip(nodes.map(&->format(Ast::Node))), + separator: separator, + comment: comment), + ] of Node end end end diff --git a/src/formatters/operation.cr b/src/formatters/operation.cr index edef1a17f..79d7d4dcf 100644 --- a/src/formatters/operation.cr +++ b/src/formatters/operation.cr @@ -1,17 +1,18 @@ module Mint class Formatter def format(node : Ast::Operation) : Nodes + comment = + format_documentation_comment(node.comment).tap do |item| + item.unshift(" ") if item.size > 0 + end + left = format node.left right = format node.right - if node.right.is_a?(Ast::Operation) - left + [" #{node.operator} "] + right - else - left + [" #{node.operator} "] + right - end + left + comment + [" #{node.operator} "] + right end end end diff --git a/src/formatters/pipe.cr b/src/formatters/pipe.cr index 29829704f..545212508 100644 --- a/src/formatters/pipe.cr +++ b/src/formatters/pipe.cr @@ -1,13 +1,16 @@ module Mint class Formatter def format(node : Ast::Pipe) : Nodes + comment = + format_documentation_comment node.comment + argument = format node.argument expression = format node.expression - argument + [Line.new(1), "|> "] of Node + expression + argument + ([Line.new(1)] of Node) + comment + (["|> "] of Node) + expression end end end diff --git a/src/formatters/record.cr b/src/formatters/record.cr index 348c5dbe2..d48212eba 100644 --- a/src/formatters/record.cr +++ b/src/formatters/record.cr @@ -6,6 +6,7 @@ module Mint else group( items: node.fields.map(&->format(Ast::Node)), + comment: format(node.comment), behavior: Behavior::BreakAll, ends: {"{", "}"}, separator: ",", diff --git a/src/formatters/record_update.cr b/src/formatters/record_update.cr index 1954c10c0..7ec0061bd 100644 --- a/src/formatters/record_update.cr +++ b/src/formatters/record_update.cr @@ -7,6 +7,7 @@ module Mint ["{ "] + expression + [" |"] + group( items: node.fields.map(&->format(Ast::Node)), + comment: format(node.comment), behavior: Behavior::BreakAll, ends: {"", "}"}, separator: ",", diff --git a/src/formatters/tuple_literal.cr b/src/formatters/tuple_literal.cr index 873d34f54..f9cf56fcf 100644 --- a/src/formatters/tuple_literal.cr +++ b/src/formatters/tuple_literal.cr @@ -3,6 +3,7 @@ module Mint def format(node : Ast::TupleLiteral) : Nodes group( items: node.items.map(&->format(Ast::Node)), + comment: format(node.comment), behavior: Behavior::BreakAll, ends: {"{", "}"}, separator: ",", diff --git a/src/formatters/type_definition.cr b/src/formatters/type_definition.cr index 11a2c8e36..6f06335b6 100644 --- a/src/formatters/type_definition.cr +++ b/src/formatters/type_definition.cr @@ -10,17 +10,20 @@ module Mint name = format node.name + end_comment = + node.end_comment.try(&->format(Ast::Comment)) + comment + ["type "] + name + parameters + [" "] + if node.fields.is_a?(Array(Ast::TypeVariant)) group( + items: [list(nodes: node.fields, comment: end_comment)], behavior: Behavior::Block, - items: [list(node.fields)], ends: {"{", "}"}, separator: "", pad: false) else group( - items: [list(node.fields, ",")], + items: [list(nodes: node.fields, separator: ",", comment: end_comment)], behavior: Behavior::Block, ends: {"{", "}"}, separator: ",", diff --git a/src/parsers/array_literal.cr b/src/parsers/array_literal.cr index 97acf0c56..e9e14f8c8 100644 --- a/src/parsers/array_literal.cr +++ b/src/parsers/array_literal.cr @@ -8,7 +8,10 @@ module Mint items = list( terminator: ']', separator: ',' - ) { expression } + ) { commented_expression } + whitespace + + comment = self.comment whitespace next error :array_expected_closing_bracket do @@ -41,6 +44,7 @@ module Mint Ast::ArrayLiteral.new( from: start_position, + comment: comment, items: items, to: position, type: type, diff --git a/src/parsers/commented_expression.cr b/src/parsers/commented_expression.cr new file mode 100644 index 000000000..4204c8271 --- /dev/null +++ b/src/parsers/commented_expression.cr @@ -0,0 +1,19 @@ +module Mint + class Parser + def commented_expression : Ast::CommentedExpression? + parse do |start_position| + comment = self.comment + whitespace + + return unless expression = self.expression + + Ast::CommentedExpression.new( + expression: expression, + from: start_position, + comment: comment, + to: position, + file: file) + end + end + end +end diff --git a/src/parsers/expression.cr b/src/parsers/expression.cr index f15dadd49..fb2380271 100644 --- a/src/parsers/expression.cr +++ b/src/parsers/expression.cr @@ -3,8 +3,11 @@ module Mint def expression : Ast::Node? return unless expression = base_expression - if operator = self.operator - pipe operation(expression, operator) + if item = self.operator + operator, comment = + item + + pipe operation(expression, operator, comment) else expression end diff --git a/src/parsers/operation.cr b/src/parsers/operation.cr index e101087a8..98fdd67c9 100644 --- a/src/parsers/operation.cr +++ b/src/parsers/operation.cr @@ -5,26 +5,35 @@ module Mint # found in the operator parser file. # # Operations can be chained recursively with this method as seen below. - def operation(left : Ast::Node, operator : String) : Ast::Operation? + def operation( + left : Ast::Node, + operator : String, + comment : Ast::Comment? + ) : Ast::Operation? parse do next error :operation_expected_expression do expected "the right side expression of an operation", word snippet self end unless right = base_expression - if next_operator = self.operator + if item = self.operator + next_operator, next_comment = + item + if OPERATORS[next_operator] > OPERATORS[operator] - right = operation(right, next_operator) + right = operation(right, next_operator, next_comment) else return operation( Ast::Operation.new( operator: operator, + comment: comment, from: left.from, to: right.to, right: right, file: file, left: left), - next_operator) + next_operator, + next_comment) end end @@ -32,6 +41,7 @@ module Mint Ast::Operation.new( operator: operator, + comment: comment, from: left.from, to: right.to, right: right, diff --git a/src/parsers/operator.cr b/src/parsers/operator.cr index 2e399137a..2c425e3b9 100644 --- a/src/parsers/operator.cr +++ b/src/parsers/operator.cr @@ -26,10 +26,13 @@ module Mint "!" => 16, } - def operator : String? + def operator : Tuple(String, Ast::Comment?)? parse do |start_position| whitespace + comment = self.comment + whitespace + saved_position = position @@ -90,7 +93,7 @@ module Mint end whitespace - operator + {operator, comment} end end end diff --git a/src/parsers/pipe.cr b/src/parsers/pipe.cr index d6b15a17d..64e605b0a 100644 --- a/src/parsers/pipe.cr +++ b/src/parsers/pipe.cr @@ -17,6 +17,7 @@ module Mint end Ast::Pipe.new( + comment: operation.comment, expression: expression, from: argument.from, argument: argument, diff --git a/src/parsers/record.cr b/src/parsers/record.cr index 46f428c02..c6a119221 100644 --- a/src/parsers/record.cr +++ b/src/parsers/record.cr @@ -8,9 +8,13 @@ module Mint unless char! '}' whitespace + fields = list(terminator: '}', separator: ',') { field } whitespace + comment = self.comment + whitespace + next unless char! '}' end @@ -18,6 +22,7 @@ module Mint Ast::Record.new( from: start_position, + comment: comment, fields: fields, to: position, file: file) diff --git a/src/parsers/record_update.cr b/src/parsers/record_update.cr index bff466fea..2e7ba79ac 100644 --- a/src/parsers/record_update.cr +++ b/src/parsers/record_update.cr @@ -30,6 +30,8 @@ module Mint snippet self end if fields.empty? + whitespace + comment = self.comment whitespace next error :record_update_expected_closing_bracket do @@ -40,6 +42,7 @@ module Mint Ast::RecordUpdate.new( expression: expression, from: start_position, + comment: comment, fields: fields, to: position, file: file) diff --git a/src/parsers/tuple_literal.cr b/src/parsers/tuple_literal.cr index 9e59f8177..f2f178103 100644 --- a/src/parsers/tuple_literal.cr +++ b/src/parsers/tuple_literal.cr @@ -5,21 +5,25 @@ module Mint next unless char! '{' whitespace - next unless head = expression + next unless head = commented_expression whitespace next unless char! ',' items = - list(terminator: '}', separator: ',') { expression } + list(terminator: '}', separator: ',') { commented_expression } whitespace + comment = self.comment + whitespace + next unless char! '}' items.unshift(head) Ast::TupleLiteral.new( from: start_position, + comment: comment, to: position, items: items, file: file) diff --git a/src/parsers/type_definition.cr b/src/parsers/type_definition.cr index 10d096f9d..78b7fca9c 100644 --- a/src/parsers/type_definition.cr +++ b/src/parsers/type_definition.cr @@ -30,7 +30,7 @@ module Mint whitespace - fields = begin + fields, end_comment = begin if char! '{' variants = list(separator: ',', terminator: '}') { type_definition_field } @@ -43,16 +43,20 @@ module Mint end whitespace + fields_comment = self.comment + whitespace + next error :type_definition_expected_closing_bracket do expected "the closing bracket of a type definition", word snippet self end unless char! '}' - items - end || [] of Ast::TypeDefinitionField + {items, fields_comment} + end || {[] of Ast::TypeDefinitionField, nil} end Ast::TypeDefinition.new( + end_comment: end_comment, parameters: parameters, from: start_position, comment: comment, diff --git a/src/scope.cr b/src/scope.cr index 2f4f6e3c0..b7d45f2c2 100644 --- a/src/scope.cr +++ b/src/scope.cr @@ -229,6 +229,7 @@ module Mint Ast::Js build(node.value.select(Ast::Interpolation), node) when Ast::ParenthesizedExpression, + Ast::CommentedExpression, Ast::NegatedExpression, Ast::Interpolation, Ast::UnaryMinus, diff --git a/src/type_checkers/commented_expression.cr b/src/type_checkers/commented_expression.cr new file mode 100644 index 000000000..be48cb703 --- /dev/null +++ b/src/type_checkers/commented_expression.cr @@ -0,0 +1,7 @@ +module Mint + class TypeChecker + def check(node : Ast::CommentedExpression) : Checkable + resolve node.expression + end + end +end