Difference between revisions of "IF"
From ICE Enterprises
ConvertBot (talk | contribs) (implements a logical block if-then-else function in a macro) |
(No difference)
|
Latest revision as of 17:04, 27 April 2020
implements a logical block if-then-else function in a macro
<VALUE> Left side of expression
<TEST> Logical test to be performed.
<VALUE> Right side of expression
There are two forms of the IF statement; both can only be used in a macro.
The first form is the block IF, the second is the one-line IF.
Block IF Statement:
The block IF statement evaluates a logical expression and, if the logical
expression is true, executes the set of statements following. If the logical
expression is false, control transfers to the next ELSE, ELSEIF, or ENDIF
statement at the same IF level. The syntax is as follows (optional items are
in braces):
IF <conditional> THEN
<action>
[ELSEIF <conditional> THEN
<action>
]
[ELSE
<action>
]
ENDIF
IF-ELSEIF-ELSEIF-...-ELSE-ENDIF blocks can be nested without limit. Note that
"THEN" is technically optional, but highly recommended.
One-Line IF Statement:
The one-line IF requires that the <action> be a single executable Midas
command, such as GOTO, BREAK, ENDMODE, CALC, etc. It should not be the start
or end of a structure (such as WHILE,ENDWHILE,LOOP,ENDLOOP,IF,ENDIF,etc), or
an operating system command. For those, the block IF should be used.
IF <conditional> THEN <action>
Prior releases indicated that the THEN was optional for the one-line IF;
this is not always the case. Since NeXtMidas 2.1.2 the THEN is required for
one-line IF statements.
WARNING: When using a one-line IF statement the <action> may be cleaned (i.e.
converted to uppercase) before execution. If this is a problem, use
the multi-line IF syntax.
Conditional Expressions:
A <conditional> expression has the following form:
<value1> <test1> <value2> [ <conjunction> <value3> <test2> <value4> ... ]
where <conjunction> is either AND or OR.
Tests:
A EQ B Numeric A is equal to B
A == B Numeric A is equal to B (since 2.5.0)
A NE B Numeric A is not equal to B
A != B Numeric A is not equal to B (since 2.5.0)
A GT B Numeric A is greater than B
A > B Numeric A is greater than B (since 2.5.0)
A LT B Numeric A is less than B
A < B Numeric A is less than B (since 2.5.0)
A GE B Numeric A is greater or equal to B
A >= B Numeric A is greater or equal to B (since 2.5.0)
A LE B Numeric A is less or equal to B
A <= B Numeric A is less or equal to B (since 2.5.0)
A EQT B Alias for EQ/T, see below for details.
A ~= B Alias for EQ/T, see below for details. (since 2.5.0)
A EQTOL B Old alias for EQ/T (rarely used any more).
***********************************************************
* Note: Prior to NeXtMidas 3.3.2 the above tests assumed *
* scalar input values and only considered the first part *
* of any non-scalar input. This behavior was deprecated *
* in NeXtMidas 2.7.0 and removed in NeXtMidas 3.3.2. Now *
* all entries in a non-scalar value are considered. *
***********************************************************
**************************************************************
* The following test modifiers for EQ can be combined (e.g. *
* "A EQ/M/T B" compare magnitude of A and B with a tolerance.*
**************************************************************
A EQ/S B Makes sure both have the same number of elements (size). This
is almost always combined with /M or /V.
A EQ/B B Use a binary data comparison. Use with caution since this
will return false if even the slightest thing is different
(e.g. "1 EQ/B 1.0" -- which compares a L: to a D: will fail)
A EQ/T B Numeric A is equal to B within tolerance.
By default this will use a relative tolerance check using
the system-wide tolerance (usually 1e-6). This can be
overridden using the following switches:
/TOL=<tol> - Use *relative* tolerance <tol>
/DELTA=<tol> - Use *absolute* tolerance <tol> (since 3.3)
See nxm.sys.libm.Tolerance for more info on "relative".
A EQ/M B Compare the magnitude of the values of each atom
(refer to nxm.sys.lib.Data.getMagnitude()).
A EQ/V B Compare each value in an atom one-by-one. This is the same as
computing vector equality in Euclidean space.
A NE/? B Same as NEQ/? where ? is any valid modifier(s) for EQ.
A GT/M B Numeric A has greater magnitude than B
A LT/M B Numeric A has less magnitude than B
A GE/M B Numeric A has greater or equal magnitude than B
A LE/M B Numeric A has less or equal magnitude than B
A ANYBITS B Integer A contains any of the bits set in integer B
A ALLBITS B Integer A contains all of the bits set in integer B
***********************************************************
* Note: String tests ignore case unless /CS is present! *
***********************************************************
A ENDS B A ends with B. TRUE if A ends with all the characters in B.
This is same as A.endsWith(B). (Since NeXtMidas 3.1.2)
A EQS B String A equal to string B in length and content
A EQSS B EQual Shortest String: Equality is checked only up to the
length of the shorter of A or B
A SEQS B String A equal to String B (alias for EQS)
A STARTS B A starts with B. TRUE if A starts with all the chars in B.
This is same as A.startsWith(B). (Since NeXtMidas 3.5.0)
A SUBS B A is a substring of B. TRUE if all the characters of A are
found in their entirety and in order somewhere within B.
A FEXISTS The file named A exists (note that the file existence tests
can be customized in the case of a URL, see javadocs for
HttpResource for more info).
A DEXISTS The directory named A exists
A REXISTS The results parameter named A exists
A PEXISTS The parameter or switch named A or /A exists for this macro
A ISNULL The object A is NULL or does not exist
A ISTRUE The state of A resolves to true. [This is the DEFAULT test.]
(TRUE states include: Y|YES|T|TRUE|ON|1|PASS|SUCCESS|ABSC|AB)
A ISFALSE The state of A resolves to false
(FALSE states include: N|NO|F|FALSE|OFF|0|FAIL|INDEX|IN)
A FEQ B File A is equal to File B (same as FEQ/H/D/S, files must be
equal in size)
A FEQ/B B File A is equal to File B - BINARY comparison
A FEQ/D B File A DATA is equal to File B DATA
A FEQ/H B File A HEADER is equal to File B HEADER
A FEQ/K B File A *extended* header KEYWORDS are equal to File B extended
header KEYWORDS.
A FEQ/L B File A is equal to File B (limits length of binary or data
comparison to size of shorter file, when applicable)
(Since NeXtMidas 3.7.0)
A FEQ/S B File A is equal in size to File B
A FEQ/T B File A is equal within *relative* tolerance to File B.
See notes about /TOL=<tol> with IF/T (above).
A OEQ B Object A is equal to Object B
A TYPEOF B The result A matches the type specified in B (see below).
A INSTANCEOF B The result A is an instance of class B (see below).
A CONTAINS B This is the same as CONTAINS/K test.
A CONTAINS/K B The table A contains the key B (String). -or-
Since 3.5.4, the Map A contains the key B (any Object).
FALSE if A is not a java.util.Map. Table is a Map.
Since 3.5.4, supports /CS switch to do a case-sensitive key B
containment check on the Table.
NOTE: Key B containment on Map that is NOT a table, always
does an Object check (and hence it is case-sensitive).
A CONTAINS/V B The Map/Table A contains the value B (via Object.equals).
FALSE if A is not a java.util.Map. (Since NeXtMidas 3.5.4)
Putting an "N" on the beginning of any test (except for the "C-style" numeric
tests) will test for its logical opposite, for example:
A NEQS B String A does not equal B
A NEQ B Numeric A is not equal to B (same as NE)
A NFEQ B The files differ
A N< B Not allowed
If the <test> is omitted, the ISTRUE state test is assumed.
Note that ANDs and ORs are short-circuiting; as soon as a condition is
evaluated which can stop evaluation, evaluation will stop.
TYPEOF vs INSTANCEOF:
INSTANCEOF matches the Java instanceof operator. The right-hand-argument is
always the (case sensitive) name of a class or interface. The test will
return true for "a INSTANCEOF b" if...
(1) The class of a is the same as b
(2) The class of a is a subclass of b
(3) The class of a is a implements of b where b is an interface
Due to this "a INSTANCEOF java.lang.Object" will always return true since
all objects are subclasses of java.lang.Object.
TYPEOF has two sets of functionality. The first takes in the name of a
Java class as the right-hand-argument and checks to see if the class
is an *exact* match. In this form, "a TYPEOF b" maps to the Java code
a.getClass().getName().equalsIgnoreCase(b). The second form takes in the
name of a Midas format type (e.g. 'D'=double,'F'=float,...) or digraph (e.g.
"SF"=ScalarFloat,"VD"=VectorDouble,"3D"=ThreeDouble). This test will return
true for "a TYPEOF b": if...
(1) The class of a is the same as b (ignoring the case of b)
(2) The class of a is String and b is "S" (special case)
(3) The class of a is Data and the type of a matches b where b is a
single-letter type specifier
(4) The class of a is Data and the format digraph of a matches b where
b is a two-letter format digraph (note that this does an "exactness"
check where "VD" is *not* the same as "3D")
Due to this "a TYPEOF b" will always return false when b is the name of an
interface or abstract class since it is doing an exactness check.
Precedence Rules:
The precedence rules is LEFT to RIGHT between conjunctions (AND|OR).
Additionally, the logical test will short-circuit when an OR conjunction is
used and the result is TRUE on the LEFT side, hence all tests to the right
of the OR conjunction will be ignored and not processed.
The test will also short-circuit when an AND conjunction is used and the
result is FALSE on the LEFT side, hence all tests to the right of the AND
conjunction will be ignored and not processed.
IF 1 LT 2 OR 2 GT 3 AND 3 EQ 4 ! TRUE (all tests after OR are skipped)
IF 1 EQ 2 AND "A" EQ "B" OR 3 EQ 3 ! FALSE (all tests after AND are skipped)
Current versions of NeXtMidas permit parenthesis around the test cases which
give more control over the precedence.
IF ( (1 LT 2) OR (2 GT 3) AND (3 EQ 4)) ! TRUE
IF (((1 LT 2) OR (2 GT 3)) AND (3 EQ 4)) ! FALSE
String Rules:
The following rules apply to the string comparisons (SUBS,EQSS,EQS,etc.):
- String tests are Case Insensitive unless the /CS switch is used.
- Length of a string literal is the number of characters between the quotes.
- Trailing spaces are not trimmed.
- If an argument to a string test is a switch name and that switch is not
present the string will contain the text "NULL" and can be tested
appropriately.
WARNING: The results of EQS, EQSS and SUBS comparisons are different from
X-Midas, since X-Midas treats "" and " " as being equal, NeXtMidas
does not do this.
Examples:
Numeric Tests:
Given that D1=D:1.0, D2=D:1.00001, L1=L:1
IF D1 EQ D2 ! FALSE (Different numbers)
IF D1 EQ L1 ! TRUE (Same numbers)
IF D1 EQ/B L1 ! FALSE (Different bits for D: vs L:)
IF D1 EQT D2 ! FALSE (use default tolerance, normally 1e-6)
IF D1 EQT D2 /TOL=1e-5 ! TRUE (use relative tolerance of 1e-5)
IF 100 EQ/T 99.95 /TOL=1e-6 ! FALSE (relative tolerance)
IF 100 EQ/T 99.999999 /TOL=1e-6 ! TRUE (relative tolerance)
IF 100 EQ/T 99.95 /DELTA=0.2 ! TRUE (absolute tolerance)
IF 100 EQ/T 99.999999 /DELTA=0.0000002 ! FALSE (absolute tolerance)
String Tests:
Given that LS is the MAX of LA and LB. A EQS B is TRUE if LA equals LB and
all characters of both strings are the same.
RESULTS A:S1 "A " ! S1 has length 2
RESULTS A:S2 " " ! S2 has length 1
IF "A" EQS "A " ! FALSE (Different lengths)
IF "aBc" EQS "ABC" ! TRUE (defaults to non-case sensitive comparison)
IF "AA" EQS "aa" /CS ! FALSE (case sensitive comparison)
IF " " EQS "" ! FALSE (empty string and blank are different!)
IF "" EQS "A" ! FALSE ("" does not equal "A")
IF S1 EQS "A" ! FALSE
IF S1 EQS "A " ! TRUE
IF S2 EQS "" ! FALSE (empty string and blank are different!)
IF S2 EQS " " ! TRUE
IF S2 EQS "A" ! FALSE
IF "A" EQSS "A " ! TRUE (the first chars are the same)
IF "A " EQSS "A" ! TRUE (same as above, order is not important)
IF S1 EQSS "A " ! TRUE (same as above)
IF " " EQSS "" ! TRUE (empty string is EQSS with any string)
IF "ABC" EQSS "" ! TRUE (same as above)
IF S2 EQSS "ABC" ! FALSE (S2 starts with a ' ')
IF S1 EQSS S2 ! FALSE (S2 starts with a ' ')
IF "A " EQSS " A" ! FALSE (leading space is important)
IF "A" EQSS " A" ! FALSE (leading space is important)
IF "AB" EQSS "BAB" ! FALSE (first 2 characters not the same)
IF "A " EQSS "AB " ! FALSE (first 2 characters not the same)
IF "A" EQSS "AB" ! TRUE (first character is the same)
IF " AB" EQSS " " ! TRUE
IF "ABC" STARTS "A" ! TRUE (First string starts with "A")
IF "Abc" STARTS "b" ! FALSE
IF "Abc" STARTS "a" /CS! FALSE (Fails case sensitive starts with check.)
IF "A" SUBS "A " ! TRUE ("A" found in the first character)
IF "A" SUBS "BCDA" ! TRUE ("A" found at the 4th character)
IF S1 SUBS "A" ! FALSE
IF "^S1" SUBS "A" ! FALSE
IF "A " SUBS "A" ! FALSE
IF "A " SUBS "CA B" ! TRUE ("A " found at the second character)
IF " " SUBS "" ! FALSE (no space at all on right hand side)
IF S1 SUBS S2 ! FALSE (no leading string "A" in an empty string)
IF S2 SUBS S1 ! TRUE
IF "BCD" SUBS "ABCDE" ! TRUE
Invoking methods on a java.lang.String results to do comparisons.
IF "".isEmpty() ! ERROR (not supported at this time)
IF S1.isEmpty() ! FALSE
IF S1.contains("A") ! TRUE (same as "A" SUBS S1)
IF S1.contains("a") ! FALSE (since 3.5.0 lower case passed correctly)
IF S1.contains(s2) ! TRUE (same as S2 SUBS S1)
IF S1.matches("A.") ! TRUE (using regex - 'A' followed by any char)
IF S1.matches("A*") ! FALSE (using regex - zero or more 'A's)
IF S1.matches("A.*") ! TRUE (using regex)
IF S1.startsWith(" ",1) ! TRUE (prefix,toffset)
IF S1.startsWith("A",1) ! FALSE
IF S1.regionMatches(1,"ABC ",3,1) ! TRUE (toffset,other,ooffset,len)
IF S1.regionMatches(1,"ABC ",3,2) ! FALSE (len does not match)
IF S1.regionMatches(1,S2,0,1) ! TRUE
IF S1.regionMatches(0,"TMA ",2,2) ! TRUE
IF S1.regionMatches(0,"Da ",1,1) ! FALSE (since 3.5.0 lower case 'a')
IF S1.regionMatches(true,0,"Da",1,1) ! TRUE (ignore case)
File/Directory Tests:
Gracefully deletes a Midas file. Note that this is a one-line IF.
IF file FEXISTS THEN ERASE file
Recalculates the maximum of the file "myfile", if either REDO has been set
to 1, or the result "filemax" does NOT exist and the file DOES exist:
IF redo EQ 1 OR filemax NREXIST AND myfile FEXIST THEN
MAXMIN myfile filemax
ENDIF
Switches:
/CS - Perform a CASE SENSITIVE test. For EQS, EQSS, ENDS, SEQS,
STARTS, SUBS, and CONTAINS (in Table) only. [DEF=IgnoreCase]
/DELTA=<tol> - The *absolute* tolerance for the EQ/T, and FEQ/T tests. This
will override any use of /TOL= without warning (this permits
/TOL= to be given at top of macro to override system-wide
relative tolerance without restricting use of /DELTA=). If
/DELTA= is not specified *relative* tolerance checks will be
used. [DEF=<use relative tol>] (since NeXtMidas 3.3.2)
/TOL=<tol> - The *relative* tolerance for the EQ/T, and FEQ/T tests. If not
specified (and /DELTA= is not specified) the system-wide
*relative* tolerance (usually 1e-6) will be used.
SEE ALSO: ELSE, ELSEIF, ENDIF, nxm.sys.libm.Tolerance, nxm.sys.lib.Args,
nxm.sys.lib.Data