Known Limitations¶
Due to the way ipt works it can’t accept all code which Igor Pro allows. In some cases this was also done to avoid excessive effort for what we considered niche issues.
And some limitations are listed here according to our philosophy.
UTF8 source code¶
ipt can only read source files that are encoded in UTF-8 or ASCII. All non UTF-8 code must therefore converted to UTF-8 first.
You can convert the encoding using Igor Pro by following these steps:
Open the code file in Igor Pro
On the bottom left corner of the text editor is a button that tells you the current encoding. Click on it.
A new window opens and asks you to select an encoding. Select
UTF-8
.Click on
Convert to Encoding
Save your file.
Statements outside of functions¶
All statements have to be inside a function, a macro or inside the call statement of a menu item.
print 1 // not supported in ipt, ignored in Igor Pro
Function foo()
print 2 // supported in ipt and Igor Pro
End
Statements before the first case of a switch statement¶
A switch statement is used to execute code depending on a variable or string. Similar like a long chain of if statements but nicer to read. In Igor Pro you can write any statement before the first case of a switch statement. Such code is not allowed according to the documentation but it is ignored by the Igor Pro parser. In ipt such code is not allowed.
switch(var)
print "before" // not supported in ipt, ignored in Igor Pro
case 1:
print "first case"
break
endswitch
Unbalanced parenthesis¶
In Igor Pro it is possible to omit closing parenthesis or add additional ones at certain places. In ipt all parenthesis must be balanced! Unbalanced parenthesis are treated as an error.
// note the missing parenthesis here: -------------------------v
MatrixOP/FREE rms = sqrt(sumSqr(data - avg[0]) / numRows(data)
Context breaking #if
statements¶
#if
denotes if the contained code should be compiled or not. This
is done in Igor Pro before the contained code is compiled. In ipt all code
is compiled into an AST first.
Therefore some code has to be written differently:
switch(var)
case 1:
#if condition
case 2:
#endif
print "<=2"
endswitch
switch(var)
#if condition
case 2:
#endif
case 1:
print "<=2"
endswitch
Other statements have to be refactored:
// Difficult to understand even for the user
if(var)
print "some work"
#if condition
endif
#endif
print "other work"
#if !condition
endif
#endif
// A variant on how this can be refactored
if(var)
print "some work"
print "other work"
else
#if condition
print "other work"
#endif
endif
End Function
and End Macro
¶
Those are not supported in ipt and not allowed according to the Igor
documentation. The Igor Pro parser itself ignores everything after the End
.
If you want to mark if this is a macro or function, just use EndMacro
for
macros (as documented) or write a normal comment.
Function test()
End Function
Superfluous #else
branches¶
In some scenarios it is possible to have multiple #else
expressions in Igor
Pro. This is not supported in ipt.
#if condition
Function TestA() // will be visible if condition != 0
End
#else
Function TestB() // will be visible if condition == 0
End
#else
Function TestC() // will never be visible
End
#endif
Omitting commas in function arguments¶
Each argument of a function call must be delimited with a single comma. In Igor Pro its possible to omit some of them.
stringmatch(S_MarqueeWin"Graph")
// missing comma here: ^
Superfluous commas in declarations¶
Igor Pro allows commas between the type and the first name, allthough the documentation doesn’t support that idea. In ipt this isn’t supported.
STRUCT MyStructureName, myStr
// superfluous comma: ^
Division in some operation arguments¶
The symbol /
is used in Igor for division and as a marker for operation
flags. Some operations can also have argument flags that are only applied
to that specific argument.
Only certain operations do allow flags for their arguments and ipt does only
allow flags for these operations. If a flag is allowed for the current argument,
ipt consideres every /
as a start of the argument flag and no division is
allowed.
// considered as the start of the argument flag
// v
Differentiate/EP=0 sourcewave/D=testwave
// ^^^^^^^^^^^
// (argument flag)
You can circumvent this limitation by surrounding the expression with parenthesis:
// Lets ignore that this code is invalid Igor code but this is how you would
// circumvent the limitations for arguments that do allow operation flags
// and you want to have a division:
// v
Differentiate/EP=0 (sourcewave/D)
If this argument is a key value pair, all /
are considered as
argument flags in the key part and all /
are considered as division in the
value part.
// This argument consists of a key value pair and has two / with different
// usages: start of flag division
// v v
Make $nameForOutputWave/WAVE=w = p / 2.0
// ^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^
// key of argument value of argument
If argument flags are not allowed (default in most cases) all /
are parsed
as divisions.
// Always a division:
// v
print nameOfVar / 2
Operators in flag values¶
Flags can have values attached like in /Name=value
. In ipt you cannot
use operations like +
, -
, *
or /
in value
. If you
want to use them, you have to surround it with parentheses as in /Name=(value1 + value2)
.
This is the case for most operations in Igor Pro.
If you use reference strings you can always use the +
operator to add more
parts (like /Name=$part1 + part2
) . Although good style suggests to write that in
a separate statement.
Function calls in flag values¶
ipt doesn’t allow function calls in plain flag values, so you have to add parentheses:
// This call
DoAlert/T=func(0) ""
// would be interepreted by ipt as
DoAlert/T=(func) (0), ""
// ^^^^^^^^^ ^^^ ^^
// flag 1st arg 2nd arg
// This call would be interpreted correctly by ipt
DoAlert/T=(func(0)) ""
// ^^^^^^^^^^^^ ^^
// flag 1st arg
AS and VS as variable names¶
AS
and VS
are used as reserved keywords in operations and ipt doesn’t
allow their usage as variable names. This limitation doesn’t exists in Igor Pro.
Encrypted code¶
Encrypted code is not supported in ipt and results in an error.
Double assignments¶
Double assignments are not allowed and will be treated as error. In Igor Pro its allowed in some operations currently:
MatrixOp/O wv1=wv2=sum(w)
Return values in macros¶
According to the Igor Pro documentation return
can not be used inside
macros. In ipt this is considered an error, in Igor Pro that is ignored.
Macro Test()
return 1 // no return value allowed
EndMacro
Some global statements require whitespaces¶
The global statements #include
, #pragma
, #ifdef
, #ifndef
,
#if
, #elif
and #define
must have at least one whitespace character
following:
#include "tools"
Merge of operation flag value with first operation argument¶
In some cases is the value of the operation flag merged with the first operation argument.
WAVE/SDFR=root: bigWave
WAVE/SDFR=root:bigWave
This is due to our parsing strategy that ignores the existence of spaces in most places. To temporary fix this problem, you have to add parenthesis to your operation flag value.
WAVE/SDFR=(root:) bigWave
Recursive re-evaluation of linting rules¶
Some linting rules do not produce the optimal fix for the given code. This can happen if another rule can be applied to the first rule’s fix, or if the behavior of a rule changes if the fix were present in the first place. To illustrate this, let’s assume we have the following code:
if(condition1)
if(condition2)
return result1
else
return result2
endif
else
print "something"
endif
After calling ipt lint for the first time, we get the following result:
ipt lint --fix
¶if(condition1)
if(condition2)
return result1
endif
return result2
else
print "something"
endif
And calling ipt lint again, we get:
ipt lint --fix
¶if(condition1)
if(condition2)
return result1
endif
return result2
endif
print "something"
This recursive dependency is not limited to the applied fixes. This can also apply to error messages, as it can be seen here:
switch(value)
case CASE_1:
if(condition)
return result1
else
return result2
endif
endswitch
In the first iteration of calling ipt lint
you will get an error message
from the rule CodeStyleFallthroughCaseRequireComment
that a break
is
missing for the switch case CASE_1
. This is because the rule only checks
top-level statements and does not create a full control flow graph.
ipt lint --fix
¶switch(value)
case CASE_1:
if(condition)
return result1
endif
return result2
endswitch
After calling ipt lint again on the previous output of ipt lint --fix
, there
will be no longer an error message from the rule
CodeStyleFallthroughCaseRequireComment
.
This limitation does only apply to ipt lint --fix
. If you do not specify
--fix
, there is no implication. The best workaround for this limitation is,
to just execute ipt lint --fix
multiple times until they are no changes to
the fixed files and use the error messages from the last iteration.