mIRC Home    About    Download    Register    News    Help

Print Thread
Joined: Oct 2003
Posts: 64
E
Exlax Offline OP
Babel fish
OP Offline
Babel fish
E
Joined: Oct 2003
Posts: 64
I have a script that does something like this...
(1) A variable %reply_message exists, which defines the format of a message to send a user. Specifically, [username] will be replaced by the actual username when the message is sent.
(2) Upon a certain event, a message is sent to the user. Specifically, %reply_message is the message that is sent where [username] is replaced by some other value. Also, other identifiers should be allowed in this variable definition (e.g. $iif(..), $duration(..), etc.)

Variable definition:
Code:
%reply_message You are $iif([username] == $null, not logged in, logged in as [username]) $+ .


The following code is trigged by some event:
Code:
msg $nick $eval($replacex(%reply_message, [username], %username), 2)


Let's break this down into the steps the computer will follow when evaluating this code...

Case 1: %username has been set to "test_username"
(1) Replace all occurrances of [username] with test_username
Code:
You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
becomes
Code:
You are $iif(test_username == $null, not logged in, logged in as test_username) $+ .

(2) Because of the $eval(.., 2) all identifiers are then evaluated. The $iif(..) is false, and so it becomes
Code:
You are logged in as test_username.

(3) Then this message is sent to the user.
THIS WORKS!

Case 2: %username has not been set
(1) Replace all occurrances of [username] with (nothing)
Code:
You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
becomes
Code:
You are $iif( == $null, not logged in, logged in as ) $+ .

(2) Because of the $eval(.., 2), all identifiers should then be evaluated. Uh oh! mIRC gives an error when it sees $iif( == $null, .......)
This doesn't work frown

Conclusion:
Instead of giving an error, mIRC should realize this expression evaluates to TRUE.

Joined: Dec 2002
Posts: 2,962
S
Hoopy frood
Offline
Hoopy frood
S
Joined: Dec 2002
Posts: 2,962
Well I think you may have figured out what's happening yourself, but I'll break it down anyway just in case:

The problem is that your $replacex() call is replacing "[username]" with the contents of %username - not the text "%username" - so when the whole contents of the %reply_message is evaluated mIRC sees the line $iif( == $null, ... which is of course invalid syntax.

I think you got that far, in which case we just need to explain why this isn't a bug but rather the desired behaviour. Simple really: If I type the code if ( == $null) ... into a script file directly, what do you think I meant there? There's really any number of ways to interpret that and none of them are obviously the right choice, what you mean in your case is probably the least likely to be the correct choice because in any typical situation (ie. where that script was hardcoded) you obviously wouldn't type if ( == $null) ... because it would be redundant. You're expecting the script parser to guess what you meant, and that's a bad idea - far better for you as the scripter to provide clear code. In your case that means $replacex(%reply_message, [username], %[color:red] $+ username)[/color]



Spelling mistakes, grammatical errors, and stupid comments are intentional.
Joined: Oct 2003
Posts: 64
E
Exlax Offline OP
Babel fish
OP Offline
Babel fish
E
Joined: Oct 2003
Posts: 64
Originally Posted By: starbucks_mafia
In your case that means $replacex(%reply_message, [username], %[color:red] $+ username)[/color]


(0) Before anything
Code:
$eval(You are $iif([username] == $null, are not logged in, logged in as [username]) $+ ., 2)


(1) After the replace
Code:
You are $iif(%username == $null, are not logged in, logged in as %username) $+ .


(2) After $eval finishes evaluating this again (in the case where %username is set to "test_username")
Code:
You are logged in as %username.


And this is the message sent to the user. So to put it in words, this fails to work whenever [username] is not delimited by spaces.

Joined: Dec 2002
Posts: 2,962
S
Hoopy frood
Offline
Hoopy frood
S
Joined: Dec 2002
Posts: 2,962
Did you test the code as you're showing it? It works fine here.

Here's a simple test alias. Just use /test_alias username - or omit the username to see what happens when %username is not set.

Code:
alias test_eval {
  if ($1) {
    var %username = $1
  }
  var %moo = You are $!iif([username] == $!null, not logged in, logged in as [username]) $!+ .
  echo -a Value of % $+ moo: %moo
  echo -a $eval($replacex(%moo, [username], % $+ username), 2)
}


Spelling mistakes, grammatical errors, and stupid comments are intentional.
Joined: Oct 2003
Posts: 64
E
Exlax Offline OP
Babel fish
OP Offline
Babel fish
E
Joined: Oct 2003
Posts: 64
I may have used a bad example to make my point.

Code:
alias test_eval {
  if ($1) {
    var %username = $1
  }
  var %moo = You are [username].
  echo -a Value of % $+ moo: %moo
  echo -a $eval($replacex(%moo, [username], % $+ username), 2)
}


This won't work.

Joined: Oct 2005
Posts: 1,741
G
Hoopy frood
Offline
Hoopy frood
G
Joined: Oct 2005
Posts: 1,741
Without reading the whole thread in depth, this seems like an $eval issue.

Using your example as a basis:

Assume %username = abc123

If this:

$replacex(You are [username],[username],$+(%,username))

gives this:

You are %username

---

And this:

$eval([color:green]You are %username,1)[/color]

returns this:

You are abc123

---

Then why, when combined, does this:

$eval([color:red]$replacex(You are [username],[username],$+(%,username)),1)[/color]

return this:

You are %username


?????

-genius_at_work

Joined: Apr 2004
Posts: 759
M
Hoopy frood
Offline
Hoopy frood
M
Joined: Apr 2004
Posts: 759
Not sure if you made this an open answered post for the OP to figure out or not but

$replacex(You are [username],[username],$+(%,username)) is the same as: [color:#3366FF]$eval($replacex(You are [username],[username],$+(%,username)),1)[/color]

so both give You are %username

The difference in the first example is that you explicitly eval the result another time

$replacex(You are [username],[username],$+(%,username))
$eval(You are %username,1)

is the same as: $eval($replacex(You are [username],[username],$+(%,username)),[color:#333333]2)[/color]


To get back to Exlax issue:
Code:
alias test_eval {
  if ($1) {
    var %username = $1
  }
  var %moo = You are [username].
  echo -a Value of % $+ moo: %moo
  echo -a $eval($replacex(%moo, [username], % $+ username), 2)
}


This is not suppose to work. Here's why:

$eval($replacex(%moo, [username], % $+ username), 2)

the replacex results in You are %username. then when you try to re-evaluate that string it will out put You are because %username. is not the right variable and probably empty.

What starbucks_maffia pointed out quite rightly was that instead of replacing with the contents of %username replace with the string %username
so that
You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
instead of turning into
You are [color:#FF0000]$iif(Mpdreamz == $null, not logged in, logged in as Mpdreamz) $+ .[/color]

becomes $iif([color:#006600]%username == $null, not logged in, logged in as %username) $+ .[/color]

which mIRC will evaluate correctly even if %username is indeed null.


$maybe
Joined: Oct 2004
Posts: 8,330
Hoopy frood
Offline
Hoopy frood
Joined: Oct 2004
Posts: 8,330
Personally, I'd save yourself the headache and just throw an IF in there that checks to see if %username == $null and if it does, display something and Return. But that's just me and doesn't answer the actual question about what's happening and what should/shouldn't. smile


Invision Support
#Invision on irc.irchighway.net
Joined: Oct 2003
Posts: 64
E
Exlax Offline OP
Babel fish
OP Offline
Babel fish
E
Joined: Oct 2003
Posts: 64
Originally Posted By: Mpdreamz
What starbucks_maffia pointed out quite rightly was that instead of replacing with the contents of %username replace with the string %username
so that
You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
instead of turning into
You are [color:#FF0000]$iif(Mpdreamz == $null, not logged in, logged in as Mpdreamz) $+ .[/color]

becomes $iif([color:#006600]%username == $null, not logged in, logged in as %username) $+ .[/color]

which mIRC will evaluate correctly even if %username is indeed null.


Yeah I see how that would work. My goal was to place no restrictions on the positioning of "[username]" inside the format-string. In other words, I don't want to require it to be delimited by spaces.

For example, to produce the output...
You are logged in as test_username.

I want to be able to use the input...
You are logged in as [username].

I don't want to require the input to be...
You are logged in as [username] $+ .

With that said, it is clear that the $replacex(...) needs to replace [username] with the actual value of %username instead of the string %username.
Code:
$replacex(You are logged in as [username]., [username], %username)

This will always produce the correct output!

---

With that said, another feature I want to implement is the ability for the input string to contain identifiers. This would require the format-string to be evaluated twice. Conclusion: In order to accomodate both this feature and the one previously mentioned, two things need to happen
  1. Evaluate the format-string
  2. Replace occurrances of [username] with the value of %username
Let's see what happens when we do those 2 steps in that order.
Code:
var %format_string = You are logged in as [username], and the current time is $asctime $+ .
var %reply = $replacex($eval(%format_string, 2), [username], %username)

This works!

But wait. Let's try another format-string. Specifically, let's try one that uses the $iif identifier.
Code:
var %format_string = You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
var %reply = $replacex($eval(%format_string, 2), [username], %username)

Since the evaluation of the if statement occurs before the replacement of [username], we get unexpected output. In this case, the script is testing if the string "[username]" is a null string. Obviously it isn't a null string.

From this example, it becomes clear that we need to do the 2 steps in this order
  1. Replace occurrances of [username] with the value of %username
  2. Evaluate the string


Let's try the last example again, but switch the order in which we do things.
Code:
var %format_string = You are $iif([username] == $null, not logged in, logged in as [username]) $+ .
var %reply = $eval($replacex(%format_string, [username], %username), 2)

This looks like it should work as expected, and it does... under one condition: the value of %username is not null.

When the value of %username is null, the script attempts to evaluate this...
You are $iif( == $null, not logged in, logged in as ) $+ .

The problem is that mIRC doesn't know how to handle ( == $null)
Somebody earlier made the point that this is ambiguous and that it could mean several different things. They concluded that mIRC intentionally doesn't handle this conditional expression because it doesn't know what is meant by it.

My point is... I only see one logical way to interpret ( == $null)
And that is ... "Does the thing on the left (a null string) equal the thing on the right (also a null string)?"

And since there is only one way to interpret this conditional expression, in it's next version, mIRC should be able to evaluate the expression as TRUE, rather than give an error.

Last edited by Exlax; 15/02/08 07:15 PM.
Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
Why dont you just add:

$iif($qt([username]) == "", a, b)

Code:
alias test_eval {
  if ($1) {
    var %username = $1
  }
  var %moo = You are $!iif($qt([username]) == "", not logged in., logged in as [username].)
  echo -a Value of % $+ moo: %moo
  echo -a $eval($replacex(%moo, [username], %username), 2)
}


Frankly, I don't see how this is a bug. mIRC can't tell the difference between "hardcoded" commands and ones generated via script, so I'd rather have /if report invalid syntax in both the hardcoded case and the generated case than neither. It's meant to help people find their bugs-- coding properly (like in the example above) is the better solution to ambiguous parsers-- the solution is not to make the parser even more ambiguous.


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Oct 2003
Posts: 64
E
Exlax Offline OP
Babel fish
OP Offline
Babel fish
E
Joined: Oct 2003
Posts: 64
Hmm... interesting. So that would be...

Code:
var %format_string = You are $iif($qt([username]) == "", not logged in, logged in as [username]) $+ .
var %reply = $eval($replacex(%format_string, [username], %username), 2)


That would work in all cases except when [username] is set to ""
This is because...
$qt() -> ""
$qt("") -> ""

This would work 99.9999999% of the time. There is one easy fix for this. I could do something like...

Code:
var %format_string = You are $iif(_ $+ [username] == _, not logged in, logged in as [username]) $+ .
var %reply = $eval($replacex(%format_string, [username], %username), 2)


This will always work. The only problem is, I would have to document that it MUST be done this way to avoid errors (If I were the only person using this script, it would not be a problem, but this is going to be available to the public, and I don't want to require them to do this).

This is a very good temporary solution, but I still strongly believe that future versions of mIRC should know how to interpret the conditional expression ( == $null)

Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
You don't have to document it.. just abstract it.

Code:
$replacex(%format_string, [username], $+(_,%username,_), $!null, __)


or just make an alias for it:

Code:
alias isnull { return $iif($+(_,$1,_) == __, $true, $false) }


and inform them they should use $isnull([username])


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
To follow up on my "it's not a bug thing"..

"if ( == $null)" is ambiguous. there is no denying that.

The problem with ambiguity is this: YOU might think that "if ( == $null)" means "if empty string equals $null".. YOU might. but *I* might not. In this case, it's obvious-- but what about:

if ( == isnum )

What then? am i testing if == is a number? or am i checking "if an empty string equals 'isnum'"? Which one is it? You might say-- it doesn't make sense to test '==' as a number.. but then you'd be thinking as a human, not as a computer.. computers don't (and shouldn't) think like humans for a simple reason: I might *actually* want to test if == isnum, this may have arisen from the same case as your if ([username] == $null) situation, in which i do:

if ([operator] == isnum)

I might also be testing other operators.. maybe !isnum, which would have made even more sense in this scenario. But it doesn't matter what's "sensical", because that's not for the computer to decide. Computers should not left to be making decisions that we should be making as humans with brains.. this is why ambiguity sucks.

So you can see, it works in one simple scenario... but it doesn't account for all cases. It clearly doesn't make sense in the long run.


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Oct 2003
Posts: 3,918
A
Hoopy frood
Offline
Hoopy frood
A
Joined: Oct 2003
Posts: 3,918
playing around with it more, another solution is just to wrap your literal in $(), that way mirc can properly parse the LHS of your if statement from the RHS without ambiguity:

if ($([username]) == $null)

turns into

if ($() == $null)

which is valid

and that's very readable/obvious code that doesn't really need to be documented.

In fact, I hereby propose that all literal text in if statements should be forcefully wrapped inside $() by the scripter, this would solve all of mIRC's if statement parsing problems.

Consider it like the string quoting that mIRC doesn't have.


- argv[0] on EFnet #mIRC
- "Life is a pointer to an integer without a cast"
Joined: Jan 2003
Posts: 2,523
Q
Hoopy frood
Offline
Hoopy frood
Q
Joined: Jan 2003
Posts: 2,523
Originally Posted By: Exlax
I could do something like...

Code:
var %format_string = You are $iif(_ $+ [username] == _, not logged in, logged in as [username]) $+ .
var %reply = $eval($replacex(%format_string, [username], %username), 2)


This will always work. The only problem is, I would have to document that it MUST be done this way to avoid errors (If I were the only person using this script, it would not be a problem, but this is going to be available to the public, and I don't want to require them to do this).


The following alias should do what you need:
Code:
alias interpolate {
  var %s
  noop $regsub($1,/\\([a-z\d])/gi,\\ $!+ \1,%s)
  return $regsubex($2,/(.*)/, [ $replace(%s,[username],\1) ] )
}
The following example illustrates its usage:

//var -s %username = TEST, %format_string = $eval(You are $iif([username] == $null,not logged in.,logged in as [username].),0) | echo -a $interpolate(%format_string,%username)

However this method, although simple, is limited, in that you can't extend it to support more markers, eg [username] and [password] at the same time; for this you'd probably need an entirely different (and more lengthy/complex) approach.

Another, rather minor, limitation is that the user will not be able to use $regsubex itself properly in the format string.

I don't know how this part is going to be used, so I'll just warn you about one thing: allowing your script to evaluate a %format_string coming from remote users opens up a huge security hole, for example if a user includes $findfile in it. If it's only going to be used locally though (eg a user specifying a format string in the script's settings GUI for outgoing messages) this isn't an issue.


Edit: here's the extended version, turns out it didn't have to be all that different:
Code:
alias interpolate2 {
  if $0 < 3 || $0 !& 1 {
    echo -setic info $!interpolate2: invalid parameters
    halt
  }
  var %i = 2, %vars, %sub, %pattern, %2
  noop $regsub($1,/\\([a-z\d])/gi,\\ $!+ \1,%sub)
  while %i < $0 {
    %sub = $replace(%sub,$eval($ $+ %i,2),\ $+ $calc(%i / 2))
    %2 = $eval($ $+ $calc(%i + 1),2)
    %vars = %vars $+ %2
    %pattern = %pattern $+ (.{ $+ $len(%2) $+ })
    inc %i 2
  }
  return $regsubex(%vars,%pattern, [ %sub ] )
}
Usage is $interpolate2(format string,marker1,var1,marker2,var2,...), for example

$interpolate2(%format_string,[username],%username,[password],%password,[realname],%realname)

The limitation here is that the combined length of the values of all specified variables cannot exceed ~940 characters

An alternative and simpler way would be:

Code:
  ...
  var %s, %markers = username|password|...
  noop $regsub(%format_string,/([^ ])\[( %markers )\]/gix,\1 $!+ [\2],%s) $&
    $regsub(%s,/\[( %markers )\]([^ ])/gix,[\1] $!+ \2,%s) $&
    $regsub(%s,/\[( %markers )\]/gix,% $+ \1,%s) 
  var %reply = $eval(%s,2)
  ...

This assumes that your variables are named after the markers, eg %username for [username] etc. All you need to do here is edit the %markers variable. This method uses 3 calls to $regsub (as opposed to 2 before) but does not suffer from any of the aforementioned limitations and any performance difference should be negligible.

Last edited by qwerty; 16/02/08 02:43 AM.

/.timerQ 1 0 echo /.timerQ 1 0 $timer(Q).com

Link Copied to Clipboard