Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiline comment issue #7

Open
weswigham opened this issue Nov 28, 2013 · 17 comments
Open

Multiline comment issue #7

weswigham opened this issue Nov 28, 2013 · 17 comments
Labels

Comments

@weswigham
Copy link
Contributor

I really like the way multiline comment look right now,

#=
    Yay, a comment!
#=

Here's the problem, though:

#=
    Block A
#=
    Block B
#=
    Block C
#=

What in that is actually commented? In other languages, it would depend on the direction of the multiline comment sigil, eg.

/*
    Block A
*/
    Block B
/*
    Block C
*/

The remedy is trivial, change the multiline comment syntax to having an 'opening' and 'closing' sigil.

Perhaps

#<
    Block A
>#
    Block B
#<
    Block C
>#

Which, for style, means you could

#<================================
    Block A
================================>#

If you were into that kinda thing.

@weswigham
Copy link
Contributor Author

Additionally, as it stands right now, it looks kinda bad to have an inline-multiline comment (if that's even valid)

let! x = ["Alpha", #= "Beta", "Gamma", #= "Omega"]

@toroidal-code
Copy link
Member

Brick's multiline comments are actually known as documentation comments, as they don't only comment out code, but augment the code further. When I was designing the comment syntax I wanted something easy to deal with, and people seem generally happy with Python and Ruby's single-line comments. So I augmented the single-line comment syntax to create sane documentation without directional indicators, because you should never be nesting documentation.

After realizing the ambiguity in cases like the one in this issue, the 'standard' doc strings were made a bit more verbose.

This is the proper style for a doc comment.

#=
# Hi! I'm a docstring. We can have really cool stuff here,
# like type information that is checked at compile time!
@param [Int, Int] Two numbers to add together
@return [Int] The sum
@type Int -> Int -> Int
#=

This is still valid, but not good style:

#=
   Hello!
#=

It should be

#=
#  Hello!
#=

There are no inline-multiline comments. I mean, in theory, yes you can do that. But no. Don't do that.

@weswigham
Copy link
Contributor Author

...So no OCaml style comments within comments?

@weswigham
Copy link
Contributor Author

Also, there arises the problem of if I have a class such as

module Foo

    #=
    # This is the Bar class
    #=
    class Bar
        members
            name : String
            id : Int

        #=
        # This is the Foo method
        #=
        method Foo
            self.name + ": " + self.id

I have no way to comment out the entire Bar class without putting #'s on every line, and if I try

module Foo
#=    
    #=
    # This is the Bar class
    #=
    class Bar
        members
            name : String
            id : Int

        #=
        # This is the Foo method
        #=
        method Foo
            self.name + ": " + self.id
#=

I'm not even sure if what will happen will be what I wanted.

@weswigham
Copy link
Contributor Author

This is actually a big problem if i want to put commented code into a comment.

@toroidal-code
Copy link
Member

No, there are no nesting comments. And there's nothing wrong with this, most languages don't have it. OCaml is the exception.
Most text editors have a "comment this area out". In Emacs, it's M-;. In Sublime, it's C-/ When doing this in Ruby, or Brick, the single line comment is used.
Unless you are documenting code, do not use the block comment. The lexer literally treats the contents of a doc comment differently than single line comment: the parser gets info from a doc comment, while nothing from a single line comment is passed beyond the lexer.

You should be doing this:

module Foo

    # #=
    # # This is the Bar class
    # #=
    # class Bar
    #     members
    #         name : String
    #         id : Int

    #     #=
    #     # This is the Foo method
    #     #=
    #     method Foo
    #         self.name + ": " + self.id

@weswigham
Copy link
Contributor Author

So, the following nice, big, descriptive comment block is invalid:

#=
Pavlov
======
A behavior-driven-development testing framework for Brick

An example test story (shamelessly stolen from wikipedia):
```brick
import Pavlov
import Pavlov::Dogs
import Calculator

#=
# Division Test Suite
# Inherits from _Dogs_, the Pavlov test base
#=
class Division : Dogs
    members
        calc : Calculator
        result : Number

    #=
    describe
    @returns a description of who and what the story is about
    #=
    fn describe
        | "In order to avoid silly mistakes" # I'm pretending this is a multiline string syntax for now
        | "Cashiers must be able to calculate a fraction"
    #=
    # A scenario is a single user story
    # All it needs to do is spell out the scenario
    #=
    method scenario("Regular Numbers") # I shouldn't have to specify the :String, should I?
        Given our.self("has entered 3 into the calculator")
        And our.self("has entered 2 into the calculator")
        When our.self("has pressed divide")
        Then our.self("sees 1.5 on the screen")

    #=
    # A before hook on scenario serves as a setup
    # function for all of our scenarios
    #=
    method scenario:before
        our.self.calc = Calculator()

    #=
    # An after hook serves as our teardown
    #=
    method scenario:after
        return

    #=
    # given/when/then
    #
    # In a scenario, a phrase is either 'Given', 'When', or 'Then' ('And' is a convenience that duplicates the previously called one)
    # This is how the test runner knows how to interpret a statement
    # The function with the pattern matching the description is run.
    #=
    method given(our_self(/has entered (\d+) into the calculator/)) -> |n| # Again, I shouldn't have to specify :String, should I?
        our.self.calc.push(n)


    method when(our_self(/has pressed (\w+)/)) -> |op| 
        our.self.result = our.self.calc[op]

    #=
    # Of note, 'then' should return a boolean, as its output is the sole
    # determination of test pass/failure, assuming there is no error
    #=
    method then(our_self(/sees (.*) on the screen/)) -> |result| 
        our.self.result.should == result

# Then run the tests
ring_bell.each -> |k, v|
    puts("# Feature: "+k)
    k().describe.each_line -> |line|
        puts("#          "+line)
    TAP(v)
``
#=
module Pavlov
    fn Object::should
        return our.self

    fn our_self(pattern:Pattern)
        return pattern

    let! prev

    fn Given(obj:Dogs, str:String)
        try
            prev = Given
            obj.given(str)
        catch NoSignatureMatch
            error("Object '"+obj+"' does not know how to interpret Given '"+srr+"'.")

    fn When(obj:Dogs, str:String)
        try
            prev = When
            obj.when(str)
        catch NoSignatureMatch
            error("Object '"+obj+"' does not know how to interpret When '"+srr+"'.")

    fn Then(obj:Dogs, str:String)
        try
            prev = Then
            obj.then(str)
        catch NoSignatureMatch
            error("Object '"+obj+"' does not know how to interpret Then '"+srr+"'.")

    fn And(obj:Dogs, str:String)
        prev(obj, str)

    class Dogs impl Callable
        method __self(pattern:Pattern)
            return pattern

        method __self(str:String)
            return self, str

        method given(s:String)
            throw NoSignatureMatch

        method when(s:String)
            throw NoSignatureMatch

        method then(s:String)
            throw NoSignatureMatch

        fn describe
            ":woof: Test has no description :woof:"

        method scenario
            return

    fn ring_bell # find all descendants of Dogs and run them
        { t.class: ring_bell_for<t> for t in Dogs.descendants }

    fn ring_bell_for<type:Dogs>
        let! t = type()
        { s: type().scenario(s) for s in t.scenario.signature.filter( |sig| -> type(sig)=="String" ) }

    # Test Anything Protocol output
    fn TAP(out:HashMap<String, Boolean>)
        let! c = 0 
                -> c +! 1 
        puts("1.."+out.count)
        out.each -> |k, v|
            puts((v and "ok " or "not ok ")+c+" "+k)

But I would really like to be able to have a nice big comment block like that.

@weswigham
Copy link
Contributor Author

Oh lordy, I can't put github flavored markdown tags in my github flavored markdown. This is an issue.

Edit: corrected by introducing an error in the closing tag for the markdown block inside the code block

@weswigham
Copy link
Contributor Author

In short, neither github flavored markdown nor brick's current multiline comment syntax allow me to validly have 'code in my code,' yo.

@toroidal-code
Copy link
Member

We're actually going to offload markdown lexing and parsing to a separate module. So that should be valid. The standard brick lexer never touches the inside of markdown code blocks exactly for that reason.

@toroidal-code
Copy link
Member

It's actually going to be something similar to YARD or Doxygen, but for Brick, probably as a pallet.

@nickmccurdy
Copy link

This is the proper style for a doc comment.

#=
# Hi! I'm a docstring. We can have really cool stuff here,
# like type information that is checked at compile time!
@param [Int, Int] Two numbers to add together
@return [Int] The sum
@type Int -> Int -> Int
#=

@toroidal-code Did you intentionally leave out the #s before the @ tags? I feel like this looks confusing, as you would always need to comment out an @ tag in Ruby/YARD, and I think it would make more sense if the entire block comment had this line beginning style instead of just using it for the description. (I understand that you don't need the #s in front because this is a block comment, I just think it looks funny.)

@toroidal-code
Copy link
Member

@thenickperson it does look a little funny, and I'm open to suggestions.

The reason it's like that right now, is because it makes it easier for the compiler to handle, since the lexer can ignore everything after a '#' but still see the tagged info.

Unlike YARD which is an extension to Ruby, the document builder and parser will be built in to kiln.

The parser would only see this:

#=
@param [Int, Int] Two numbers to add together
@return [Int] The sum
@type Int -> Int -> Int
#=

@weswigham
Copy link
Contributor Author

@weswigham still wants to be able to have multi-line comments inside his multi-line comments.

#=
@param [String] Parses function metadata if in the form 
    ```
    #=
    @param [Type] Description...
    #=
    ```
@return [HashMap<Symbol, String>] Metadata captured from comments
@type String -> HashMap<Symbol, String>
#=

@toroidal-code
Copy link
Member

@weswigham as mentioned in comment 29488529, since the lexer skips things between Markdown code block fences, that is totally valid.

@weswigham
Copy link
Contributor Author

But can it handle markdown code fences inside markdown code fences? Because it needs to do that, too.

@toroidal-code
Copy link
Member

That'll be part of the markdown parser, which will be a separate lexer and parser inside of kiln for documenation rendering. (We'll probably end up using parts of redcarpet or markup). We can address that when we build those components.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants