Community discussions

MikroTik App
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

execute & parse

Sun Mar 24, 2024 7:56 pm

The topic has been discussed many times, but everything is forgotten when there is little practice...
Is it possible to access a variable whose name is not known in advance to the script function by passing it in a parameter? Something like this...
:return [[:parse ":global \$1; return [\$1 hello]"]]
or
:return [:execute ":global $1; :return [$1 hello]"]
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Mon Mar 25, 2024 9:49 am

:put [:return [[:parse ":global $1; return [$1 hello]"]]]
expected command name
In other words, Question: is how to call a function whose name is set by a parameter of another function? Or is this not possible because at the time of execution of :parse, the function declared in :global has not yet been defined? Is there any way around this problem?
 
User avatar
patrikg
Member Candidate
Member Candidate
Posts: 262
Joined: Thu Feb 07, 2013 6:38 pm
Location: Stockholm, Sweden

Re: execute & parse

Mon Mar 25, 2024 9:58 am

Like eval in another script languages ?
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Mon Mar 25, 2024 10:06 am

I can't judge other scripting languages, I'm not a programmer...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: execute & parse

Mon Mar 25, 2024 10:54 am

RouterOS is not a programming language.

There are certainly simpler ways of doing things.

Concrete and well-explained examples may have specific suggestions.
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Mon Mar 25, 2024 12:48 pm

Hello Rex. I don't know what can be explained well here. I am writing a global function that should receive data from other global functions, the names of which would be passed to the first one as parameter $1, a $2 to be the parameter passed to the second function. Having received data from other functions, the main one can do whatever it wants with it...

All my desire is expressed in the lines above, the meaning of which is absolutely clear to you, like a pro. Their syntax is of course not correct, I don’t know how to write it...

:global myFunc do={
     :local Ans [[:parse ":global $1; return [$1 $2]"]]
     :set Ans ($Ans+5)
     :return $Ans
}

[$myFunc Func1 Parametr1] 
Above is an example ...
 
User avatar
rextended
Forum Guru
Forum Guru
Posts: 12014
Joined: Tue Feb 25, 2014 12:49 pm
Location: Italy
Contact:

Re: execute & parse

Mon Mar 25, 2024 2:27 pm

Given that it seems like xxxxx to me, unnecessary complications,
it's done like this:

example code

:global addten do={
    :local input [:tonum $1]
    :return ($input + 10)
}

:global removeten do={
    :local input [:tonum $1]
    :return ($input - 10)
}

:global dosomething do={
     :local func  [:tostr $1]
     :local input [:tostr $2]
     :local output [[:parse ":global $func ; :return [\$$func $input]"]]
     :return $output
}

:put [$dosomething addten 6]

:put [$dosomething removeten 15]
Last edited by chechito on Mon Mar 25, 2024 7:23 pm, edited 1 time in total.
Reason: harsh language
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3506
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: execute & parse

Mon Mar 25, 2024 4:02 pm

Like eval in another script languages ?
Yes. And same generally approach: string interpolation to dynamically create a command.

Here the use more complex. @rextended and @Sertik are trying to get around the restriction that a function must declare any global variables to be able to use them. So the :parse (aka eval()) is used to create a new scope to run a global function provided by a string name (not variable)

@patrikg asked likely because it common wisdom that "eval() is bad". @rextended expresses that as "seems like bullshit to me". ;)

IMO using an RouterOS array to store functions is a better approach (akin to a C++ vtable) than use weird :parse tricks to dynamically call functions from other function. Especially since in V7 there are lot more restrictions of sharing global variables (e.g. netwatch etc script) and could be more in future.
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Mon Mar 25, 2024 4:06 pm

Thank you so much, Rex! This is not nonsense, but a very necessary thing for me! That's the line I was waiting for from you and you helped me a lot in this.:
 :return [[:parse ":global $1 ; :return [\$$1 $2]"]]
I found the solution myself, but I was wrong about one thing - I had to screen it here twice : \$$1

As always, you're on top! Thank you, Teacher!
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Mon Mar 25, 2024 4:10 pm

In this way, you can call functions whose names are not known in advance, that is, they will be determined during the script !

Let me try to explain: imagine that you have a certain process (function) that, in order to solve its tasks, must and can, depending on the initial conditions, use several different functions-solutions to this problem. That's the way out. The main function will, based on the conditions, call different handler functions, passing them the same parameters.

I used the Rex hint and now everything works for me the way I wanted it to! I'm happy ! :D
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1068
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: execute & parse

Mon Mar 25, 2024 6:48 pm

 :return [[:parse ":global $1 ; :return [\$$1 $2]"]]

Yeah, that's a good one-liner. Here's another neat trick if you want to call system scripts with arguments. This also works with "[/file get /dirname/scriptname contents]" if you prefer to store your scripts in a different location. Use "" as shown above if you need to evaluate at runtime.
[[:parse [/system script get scriptname source]] $arg1 $arg2 varname=$varname ]
 
User avatar
Amm0
Forum Guru
Forum Guru
Posts: 3506
Joined: Sun May 01, 2016 7:12 pm
Location: California

Re: execute & parse

Mon Mar 25, 2024 7:25 pm

It just be nice if you could have some "stored functions" since they could just be saved in config like a script. e.g. "/system/scripts/function add addVLAN source={}" so NO :global be need. Without resorting the @Larsa's nifty but ugly approach.

As a "config language", functions be more generally useful if folks didn't need to result to weird tricks to effectively use them (e.g. scoping, :globals & :parse). Rather if functions were part of the config, it be easy to "share" function that do config things.

I actually like the nifty tricks folks use. And get why @Sertik is trying here. Just my problem is these nifty tricks get tricky if this a production router... Anyway Functions are useful, but annoying they are hidden beyond all the cruft to use them effectively.
 
User avatar
Larsa
Forum Guru
Forum Guru
Posts: 1068
Joined: Sat Aug 29, 2015 7:40 pm
Location: The North Pole, Santa's Workshop

Re: execute & parse

Mon Mar 25, 2024 7:35 pm

Couldn't agree more. There is clearly something flawed when all sorts of workarounds pop up in the flow..
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Tue Mar 26, 2024 12:41 pm

# example Magical :parse

# declaring a variable with substituting a value from Layer7 for it
[[:parse ":global $vname [:to$vtype $[/ip firewall layer7 get [find where name=$vname] regexp]]"]]

# Hack with array sorting (by Rextended)
:set hackSort ($hackSort, [[:parse "[:toarray {\"$ymd\"=\"$filename\"}]"]]);

# passing parameters to the script and running it
[[:parse "[:parse [/system script get $msgTxt source]] $Parametr1 $Parametr2"]]

# or the same thing, but with multithreading with parameter passing
:set result "[[:parse [system script get $calledFunctionName source]] ID=$queryID ChatID=$queryChatID]"
:execute script=$result

# or from the file
:execute script="[[:parse [/file get $FileName content]] ID=$queryID ChatID=$queryChatID]"
and there are many similar examples from forum scripts ...

Many authors have invested time and labor in creating such designs. There is a very good article in Russian by our esteemed Chupakabra (the author of the famous JSON parser for the Router OS), here is a link for those who are interested. The article examines the work in detail :parse, I highly recommend it to everyone:

https://habr.com/ru/articles/650795/

Yours truly also had a little hand in learning the functions in Microtik scripts:

https://habr.com/ru/articles/646663/

But we are far from real programmers like Amm0 and our great Rex!
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Tue Mar 26, 2024 12:52 pm

As for the difficulties, I agree with Larsa and Amm0... I don't know how from the point of view of implementation, but the scripting language of the OS Router does not allow you to directly write :global $Name or :local $Name, so that $Name itself is a variable, this generates many difficulties, of which we dodged in particular here...
 
User avatar
Sertik
Member
Member
Topic Author
Posts: 435
Joined: Fri Sep 25, 2020 3:30 pm
Location: Russia, Moscow

Re: execute & parse

Tue Mar 26, 2024 1:19 pm

Regarding the introduction of something new in functions, the type proposed by Amm0:
/system/scripts/function
developers should be careful. By introducing a new one, you should not violate the old features, as this will lead to the need to rewrite thousands of working scripts...

Who is online

Users browsing this forum: No registered users and 1 guest