I'm writing a .sublime-syntax for the Specman language and need help with multiple line method declaration.
A method is declared using the keyword is which comes after most of the other parts of the method declaration.
E.g.
fwd_init() #driver.clock is {
or
add(x : uint, y : uint) is also {
or
private do_stuff(field : my_type) is only {
etc...
My problem is that parts of the declaration can be quite long in case a lot of parameters are passed to the method, so I tend to split the line to multiple lines.
I'm having trouble matching the syntax for the method, as I need multiple line matches.
The following is what I have currently, but it's not working:
methods:
- match: (?=^\s*(?:private|static|final)?\s+[a-zA-Z](?:[a-zA-Z0-9_]+)?\s*\()
set:
- match: (?=\bis\b)
push: method-declaration
Basically I want to return to lookahead, possibly match for the function, in case it's not a function pop it.
As I was writing the question I realized, all I needed to do is push the method-declaration onto the stack and first of all do a negative lookahead for is.
As follows:
methods:
- match: (?=^\s*(?:private|static|final)?\s+[a-zA-Z](?:[a-zA-Z0-9_]+)?\s*\()
push: method-declaration
method-declaration:
- match: (?!is(?:\s+)(only|first|also)?)
pop: true
- ... parsing of the method declaration
Hope this helps anybody else looking for info on the subject.
Related
I'm configuring SwiftLint for a project, and one of our standards that I would like to enforce is this: when a function is declared or called, and its parameters or arguments are broken over multiple lines, then the first parameter should always be on the line after the function name.
In other words, it should always look like this:
func foo(
bar: Int,
baz: Int
...
foo(
bar: 0,
baz: 1
and never like this:
func foo(bar: Int
baz: Int
...
foo(bar: 0,
baz: 1
...
I've looked for a rule like this in among the predefined rules, but I couldn't find one. I'm really hoping I just missed it, because this seems like a rule that could be auto-applied with --fix quite easily.
If no such rule exists, I suppose it wouldn't be too hard to create a custom rule, but then (to my understanding) setting it up to be auto-applied is out of the question. Or am I wrong?
To answer my own question:
No, this rule doesn't seem to be supported out of the box. The closest that seems to exist is multiline_parameters, which is perfectly happy with the snippet that I would want to consider a violation
No, SwiftLint doesn't support autocorrecting custom rules
My custom rule still needs a lot of love, but here is what I've got so far, which at least doesn't seem to trigger false positives:
# Triggered when a multi-line parameter or argument list starts on the same line as the opening bracket
# func foo(x: Int,
# y: Int...
# ---OR---
# foo(x: 1,
# y: 2...
multi_line_args_start_on_same_line:
name: "Multi-line args format"
message: "Multi-line arguments or parameters should start on a new line"
included: ".*\\.swift"
# Line-by-line:
# - start of function with opening bracket; e.g. `foo(`
# - A parameter name, then a colon, and then whitespace; e.g. `x: `
# - A parameter value or type, followed by a comma and newline,
# e.g. `Int,\n` or `10,\n`
# - Anything, to account for subsequent parameters or args
# - A closing bracket at the end
regex: "\
[\\w\\d]+\\(\
[\\w\\d]+:\\s*\
[\\w\\d]+,\\n\
.*\
\\)$"
severity: error
I've got a Node module file containing about 100 exported methods, which looks something like this:
exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};
Goal: What I'd like to do is figure out how to grab the name of any method which contains a call to fooMethod, and return the correct method names: methodTwo and methodThree. I wrote a regex which gets kinda close:
exports\.(\w+).*(\n.*?){1,}fooMethod
Problem: using my example code from above, though, it would effectively match methodOne and methodThree because it finds the first instance of export and then the first instance of fooMethod and goes on from there. Here's a regex101 example.
I suspect I could make use of lookaheads or lookbehinds, but I have little experience with those parts of regex, so any guidance would be much appreciated!
Edit: Turns out regex is poorly-suited for this type of task. #ctcherry advised using a parser, and using that as a springboard, I was able to learn about Abstract Syntax Trees (ASTs) and the recast tool which lets you traverse the tree after using various tools (acorn and others) to parse your code into tree form.
With these tools in hand, I successfully built a script to parse and traverse my node app's files, and was able to find all methods containing fooMethod as intended.
Regex isn't the best tool to tackle all the parts of this problem, ideally we could rely on something higher level, a parser.
One way to do this is to let the javascript parse itself during load and execution. If your node module doesn't include anything that would execute on its own (or at least anything that would conflict with the below), you can put this at the bottom of your module, and then run the module with node mod.js.
console.log(Object.keys(exports).filter(fn => exports[fn].toString().includes("fooMethod(")));
(In the comments below it is revealed that the above isn't possible.)
Another option would be to use a library like https://github.com/acornjs/acorn (there are other options) to write some other javascript that parses your original target javascript, then you would have a tree structure you could use to perform your matching and eventually return the function names you are after. I'm not an expert in that library so unfortunately I don't have sample code for you.
This regex matches (only) the method names that contain a call to fooMethod();
(?<=exports\.)\w+(?=[^{]+\{[^}]+fooMethod\(\)[^}]+};)
See live demo.
Assuming that all methods have their body enclosed within { and }, I would make an approach to get to the final regex like this:
First, find a regex to get the individual methods. This can be done using this regex:
exports\.(\w+)(\s|.)*?\{(\s|.)*?\}
Next, we are interested in those methods that have fooMethod in them before they close. So, look for } or fooMethod.*}, in that order. So, let us name the group searching for fooMethod as FOO and the name of the method calling it as METH. When we iterate the matches, if group FOO is present in a match, we will use the corresponding METH group, else we will reject it.
exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})
Explanation:
exports\.(?<METH>\w+): Till the method name (you have already covered this)
(\s|.)*?\{(\s|.)*?: Some code before { and after, non-greedy so that the subsequent group is given preference
(\}|(?<FOO>fooMethod)(\s|.)*?\}): This has 2 parts:
\}: Match the method close delimiter, OR
(?<FOO>fooMethod)(\s|.)*?\}): The call to fooMethod followed by optional code and method close delimiter.
Here's a JavaScript code that demostrates this:
let p = /exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})/g
let input = `exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};';`
let match = p.exec( input );
while( match !== null) {
if( match.groups.FOO !== undefined ) console.log( match.groups.METH );
match = p.exec( input )
}
I am a new dev in SIEVE and I am trying to create a filter in Thunderbird with two conditions. sorry if the question is dumb
first: Subject must match a specific string ([SUPPORT])
second : if some terms are present flagged the email in question.
I have tried first with nested if but it do not work. After several tries I have this script :
require ["body","imap4flags", "regex"];
# rule:[RT QA]
if not header :contains "subject" "[SUPPORT]"
{
keep ;
}
elsif body :regex ["pay.*impossible|impossible.*pay","/b+u+g+/","login.*impossible|impossible.*login"]
{
addflag "$label1";
}
but do not seem to work either . Any idea / lead welcomed
I need a custom validator to ban a specific list of banned words from a textarea field.
I need exactly this type of implementation, I know that it's not logically correct to let the user type part of a query but it's exactly what I need.
I tried with a regExp but it has a strange behaviour.
My RegExp
/(drop|update|truncate|delete|;|alter|insert)+./gi
my Validator
export function forbiddenWordsValidator(sqlRe: RegExp): ValidatorFn {
return (control: AbstractControl): { [key: string]: any } | null => {
const forbidden = sqlRe.test(control.value);
return forbidden ? { forbiddenSql: { value: control.value } } : null;
};
}
my formControl:
whereCondition: new FormControl("", [
Validators.required,
forbiddenWordsValidator(this.BAN_SQL_KEYWORDS)...
It works only in certain cases and I don't understand why does the same string works one time and doesn't work if i delete a char and rewrite it or sometimes if i type a whitespace the validator returns ok.
There are several issues here:
The global g modifier leads to unexpected alternated results when used in RegExp#test and similar methods that move the regex index after a valid match, it must be removed
. at the end requires any 1 char other than line break char, hence it must be removed.
Use
/drop|update|truncate|delete|;|alter|insert/i
Or, to match the words as whole words use
/\b(?:drop|update|truncate|delete|alter|insert)\b|;/i
This way, insert in insertion and drop in dropout won't get "caught" (=matched).
See the regex demo.
it's not a great idea to give such power to the user
I am looking for the regex which will let me use search replace to add 2 lines of code to all java methods in file using Notepad++
Before:
public void startProcessing() {
..............
..............
}
After:
public void startProcessing() {
logger.info( "Entering into startProcessing" );
..............
..............
logger.info( "Exiting startProcessing" );
}
Is this possible, if yes can anyone help me with the code... or guide me on any other possible way to do this.
To start with the "bad news", you won't be able to insert the "Exiting" line unless you have a much-better fingerprint to match against. With your current code-sample, the best you can match against is } and, as a wild guess, there are probably a lot of closing-curly-brackets throughout your code.
To insert the "Starting" line is do-able, but the robustness depends on your input.
If you will always want to replace the same line as in your sample code (or the same format but different function name), you could do the following in the Find+Replace menu:
Find:
public void startProcessing() {
Replace:
public void startProcessing() {\n\tlogger.info("Entering into startProcessing");
Search Mode: Extended
If you want to dynamically do the replacement with a non-hardcoded function name, you could try the following:
Find:
(public void )([a-zA-Z0-9_$]+)(.*)
Replace:
\1\2\3\n\tlogger.info\("Entering into \2"\);
Search Mode: Regular Expression
This "dynamic" method will require whatever methods you're searching for the be declared in the same format though, public void functionName.... I've used [a-zA-Z0-9_$] as the character-set for the function names, but you can adjust this to suit your needs.
UPDATE (ignore get/set methods)
To ignore get/set methods, such as getFieldValueUnits() or setFieldValueUnits(int val), you can use the following Find value (the Replace is the same-as-above):
(public void )(?!get|set)([a-zA-Z0-9_$]+)(.*)
This will match all functions that do not start with get or set (and are declared as public void, as above).