Skip to content

Commit

Permalink
Add detection of main under more circumstances
Browse files Browse the repository at this point in the history
The cases that are intended to be added by this commit are:

- Code with no comments but ends in a semicolon before the declaration
  of `main`.

  No comments was required to prevent `//` being included to comment
  out the line. This was done by not allowing `/` as part of the code
  before the `;` While this is more restrictive than necessary, it
  didn't seem likely that the code before `main` would include `/`
  so didn't seem worthwhile to take the performance hit to make the
  check less restrictive. To prevent long regex scans going multiple
  lines I also disallowed newlines in the code by including `\n` and
  `\r` as disallowed characters. The whole point is code on the same
  line as `main` so this seemed fine and would help prevent
  unnecessarily matching all lines before main when it doesn't
  matter.

- Allow multiline comments within the arguments area of main that both
  start and end within the brackets.

  I'm not expecting a substantial performance cost from this one
  because this case is near the end of the matching.

I used the following test cases

```rust
fn main() { // Should work
    println!("Hello, world!");
}

//;fn main() { //Shouldn't work
    println!("Hello, world!");
}

use std; fn main(){ println!("Hello, world!"); } // Should work

const fn main() { // Should work
    println!("Hello, world!");
}

/* fn main() {} */ // Shouldn't work

fn main(/* comment */) { // Should work
   // snip
}
```

Co-authored-by: Jake Goulding <[email protected]>
  • Loading branch information
c-git and shepmaster committed Dec 2, 2023
1 parent 1b83eff commit 39186ac
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
8 changes: 8 additions & 0 deletions ui/frontend/selectors/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,12 @@ describe('checking for a main function', () => {
test('a function with the substring main does not count', () => {
expect(doMainFunctionSelector('fn mainly()')).toBe(false);
});

test('a main function after other items on the same line', () => {
expect(doMainFunctionSelector('use std; fn main(){ println!("Hello, world!"); }')).toBe(true);
});

test('a main function with a block comment in the argument list', () => {
expect(doMainFunctionSelector('fn main(/* comment */) {')).toBe(true);
});
});
10 changes: 9 additions & 1 deletion ui/frontend/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@ export const selectionSelector = (state: State) => state.selection;
const HAS_TESTS_RE = /^\s*#\s*\[\s*test\s*([^"]*)]/m;
export const hasTestsSelector = createSelector(codeSelector, code => !!code.match(HAS_TESTS_RE));

const HAS_MAIN_FUNCTION_RE = /^\s*(pub\s+)?\s*(const\s+)?\s*(async\s+)?\s*fn\s+main\s*\(\s*\)/m;
// https://stackoverflow.com/a/34755045/155423
const HAS_MAIN_FUNCTION_RE = new RegExp(
[
/^([^\n\r\/]*;)?/,
/\s*(pub\s+)?\s*(const\s+)?\s*(async\s+)?\s*/,
/fn\s+main\s*\(\s*(\/\*.*\*\/)?\s*\)/,
].map((r) => r.source).join(''),
'm'
);
export const hasMainFunctionSelector = createSelector(codeSelector, code => !!code.match(HAS_MAIN_FUNCTION_RE));

const CRATE_TYPE_RE = /^\s*#!\s*\[\s*crate_type\s*=\s*"([^"]*)"\s*]/m;
Expand Down

0 comments on commit 39186ac

Please sign in to comment.