Skip to content

Conversation

watermarkhu
Copy link
Contributor

@watermarkhu watermarkhu commented Dec 4, 2023

This PR fixes #72, when function definitions are declared on multiple lines.

I will add comments in every change of the tmLanguage describing why is is required.

The PR adds scope checks and additional cases to the existing test test/t41FunctionDefinitions.m

Limitation

Due to the nature of the per-line matching behavior of the textmate language grammar, and the almost unrestricted usage of MATLAB's line continuation operator ..., it is impossible to differentiate between:

  1. Function with no output argument and input argument declaration including parenthesis on new line:
function funcNoOutputParensOnNewLine ... (inputArg) disp(inputArg); end
  1. Function with a single output argument without brackets and equals sign on new line:
function outputArg ...  = funcSingleOutputEqualSignOnNewLine (inputArg) outputArg = inputArg; end

Here, a choice needs to be made to favor one over the other. The current PR favors option 2, for no other reason than that it looks less weird to me than option 1. If option 2 is chosen, the input argument of the example of option 1 will be tokenized as:

(inputArg) %< punctuation.section.parens.begin.matlab %^^^^^^^^ meta.parens.matlab variable.other.readwrite.matlab % ^ punctuation.section.parens.end.matlab

The added testcase covers option 2.
https://github.com/watermarkhu/MATLAB-Language-grammar/blob/f69e90b0d935ad1f39caf6728b6561544af0efa9/test/t41FunctionDefinitions.m#L87-L91

<string>\G</string>
<key>end</key>
<string>(?&lt;=[\)\n])</string>
<string>(?&lt;=\))|(?&gt;(?&lt;!\.{3}.*)\n)</string>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ending the function declaration on ) or \n will not allow for line continuations in the declaration.

<string>meta.assignment.variable.output.matlab</string>
<key>begin</key>
<string>\G(?=.*?=)</string>
<string>\G(?=[^\(]*?(?:=|\[|\.{3}))</string>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous regex expected = on the same line, which does not allow for line continuations between the output arguments and =.

In order to differentiate between a function name and a single output argument, the negative lookforward on [^\(]* expects a parathesis open ( on the same line as the function name. This determines the behavior of option 2 in the PR description.

<dict>
<key>match</key>
<string>(\])\s*\z</string>
<string>(\])\s*</string>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

\z expected ] at the end of an line, always 🤔

<string>entity.name.function.matlab</string>
<key>match</key>
<string>[a-zA-Z][a-zA-Z0-9_.]*(?=[^a-zA-Z0-9_.])</string>
<string>[a-zA-Z][a-zA-Z0-9_]*(?&gt;\.[a-zA-Z0-9_]+)*</string>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous regex will result in functionName... to be fully tokenized as the function name.
The fix correctly parses line continuations, but still allows for correct tokenization of setter and getter calls e.g. get.propertyName.

<string>meta.parameters.matlab</string>
<key>begin</key>
<string>(?&lt;=[a-zA-Z0-9_])\s*\(</string>
<string>\s*\(</string>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previous regex expected = and function name to start on the same line as (. This is not the case anymore by adding line continuations to the meta.parameters.matlab scope below.

@watermarkhu
Copy link
Contributor Author

watermarkhu commented Dec 4, 2023

It is quite ironic that line continuations, intended to make the code more readable, makes it so problematic to be read by textmate.

@watermarkhu
Copy link
Contributor Author

@dklilley This has been open for a while now

@dklilley
Copy link
Member

dklilley commented Feb 6, 2024

My apologies, I must have missed the notification that this was no longer a draft! I will plan to take a look at this next week.

@dklilley
Copy link
Member

Thanks for working on this!

These changes look good to me.

I don't know why the tests aren't running automatically in this pull request, but I ran them locally. I am seeing a failure in the lineContinuations.m snap test. Can you check this? You should be able to run it with npm run testGrammarSnap.

@watermarkhu
Copy link
Contributor Author

watermarkhu commented Feb 17, 2024

Perhaps I started the PR as draft?

Anyway, all tests are passing on my side, on both node 16 and 18. Perhaps you can trigger the action manually to check whether it passes in CI?

@dklilley
Copy link
Member

I believe I had an old version of that test locally. Everything looks good to me. Thanks for making this improvement!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants