Product Documentation
Cadence SKILL IDE User Guide
Product Version IC23.1, August 2023

Advanced Rule Macros

Cadence provides the following advanced rule macros for your convenience:

SK_CHANGED_IN( t_release )

This macro is used to specify the release version (e.g. "500" for IC5.0.0) that a function is changed. The SK_CHANGED_IN macro must be embedded as the second argument of SK_RULE. For example:

SK_RULE( myFunc
SK_CHANGED_IN("500")
SK_INFO( myFunc
. . .
)

SK_CHANGED_IN evaluates to non-nil if the code being checked, as specified with the sklint argument ?codeVersion, is from an earlier release than the release specified through the argument of SK_CHANGED_IN and the SKILL Lint rules message that describes function change (only) will be reported. The argument must me a numeric string of the release version (for example, 500 for IC 5.0.0). If ?codeVersion is not specified, SK_CHANGED_IN will always evaluate to non-nil and a function change rules message will be reported.

This macro is useful when the user wants to restrict reporting of function change rule messages which occurred after the release for which the code being checked was written. When users check the code in IC500 they will not be interesting in seeing the information about the change in IC 4.4.5, since that was before they wrote the code (or perhaps before it was migrated).

If the function changes more than once, then there should be a separate SKILL Lint rule for each change, each with a different SK_CHANGED_IN macro.

SK_CHANGED_IN should only be used for filtering out function changed rule messages. Function deleted rule messages should always be reported.

SK_CHECK_STRINGFORM( t_stringForm )

This macro is similar to SK_CHECK_FORM but it is used to check SKILL form in strings (e.g. callback string). This macro is added to deal with the problem that when a string form is converted to a SKILL form, the line number of the string form will be messed up and causes an incorrect line number to be reported.

An example of usage:

procedure( test()
let( (c)
c = myFunc(
"foreach(i ’(1 2 3 4) a=i)"
)
c
)
)
SK_RULE( myFunc
t
SK_CHECK_STRINGFORM( SK_ARGS() )
)
The argument to SK_CHECK_STRINGFORM must be a string.

SK_RULE( SK_CONTROL ... )

The SK_RULE macro has an optional first argument which is the keyword SK_CONTROL. When this keyword is given, it means that this rule is a “controlling” rule. This means that the arguments to the function are not themselves checked by SKILL Lint. Usually, SKILL Lint will first apply checking to all the arguments of a function call and then to the call itself. However, if there is a controlling rule, then the arguments are not checked automatically. This type of rule is usually needed for nlambda expression (for example nprocedures) where only some of the arguments are evaluated.

SK_CHECK_FORM( l_form )

This macro can be used to apply checking to a statement. This is usually useful within a controlling rule. The argument is a list whose first element is the SKILL code to be checked.

For example, consider a rule to be written for the if function (ignoring for the moment that there are internal rules for if.) This function evaluates all its arguments at one time or another, except for the then and else keywords. Writing a rule for if would require a controlling rule, which would call this macro to check all the arguments except for the then and else. For example:

SK_RULE( SK_CONTROL if 
t
foreach(map statement SK_ARGS()
unless(memq(car(statement) ‘(then else)) SK_CHECK_FORM(statement))
)
)

The SK_CONTROL keyword means that the arguments to if will not be checked automatically. The test in this case is t, which means that the rule will be applied to all calls to if. The rule command is a call to foreach, with map as the first argument. Each time through the loop the statement is a new cdr of the arguments. We check that this is not a then or else, and if not, then call SK_CHECK_FORM to check the argument.

The argument to SK_CHECK_FORM must be a list whose first element is the statement to check, not the statement itself.

It is important to call the checker on all appropriate arguments to a function, even if they are just symbols, because the checker handles trapping of variables which are unused, or are illegal globals and so forth.

There should only be a single control rule for any function.

SK_PUSH_FORM( l_form ) SK_POP_FORM()

These two macros are used to indicate an extra level of evaluation, such as is introduced by the various branches of a cond or case function call. These macros should not be needed by most user rules. They are used in rare circumstances to indicate to the dead-code spotting routines where branches occur in the code.

SK_PUSH_VAR( s_var )

Declares a new variable. For example, the rules for let, setof, etc. declare the variables in their first argument using this function. The function should be called before calling SK_CHECK_FORM on the statements in the body of the routine.

SK_POP_VAR( s_var [dont_check] )

Pops a variable that was previously declared by SK_PUSH_VAR. Unless the second argument is t, the variable is checked to see whether it was used by any of the statements which were checked between the calls to SK_PUSH_VAR and SK_POP_VAR.

For example, consider a new function called realSetOf. Assume this function works just like setof, except that it removes any duplicates from the list that is returned. The rule is a control rule which pushes the variable given as the first argument, checks the rest of the arguments, and then pops the variable, checking that it was used within the loop:

SK_RULE( SK_CONTROL realSetOf 
t
SK_PUSH_VAR(car(SK_ARGS()))
map(‘SK_CHECK_FORM cdr(SK_ARGS()) )
SK_POP_VAR(car(SK_ARGS()))
)

SK_USE_VAR( s_var )

Marks the given variable as having been used. Usually a variable is marked as having been used if it is passed to a function. However, if a function has a controlling rule, and does not call SK_CHECK_FORM then it might wish to mark a variable as having been used. For example, the rule for putprop marks the first argument as having been used. The same rule ignores the third argument (the property name) and calls the checker on the second argument. If putprop did not have a controlling rule, then the symbol used for the property name would get marked as having been used and would probably be reported as an error global.

SK_ALIAS( s_function s_alias )

This macro can be used where one function should be checked with the same rules as another function. For example, it is fairly common to see functions replacing printf, which add a standard prefix to the function. For example:

procedure( ERROR(fmt @rest args) 
fmt = strcat(“ERROR: “ fmt)
apply(‘printf cons(fmt args))
)

It would be nice to check calls to ERROR with the same rules as are used for printf (mainly to check that the number of arguments matches that expected by the format string.) This can be achieved using the following call:

SK_ALIAS( ERROR printf ) 

This macro, like SK_REGISTER, is used outside of any rule definitions.

Related Topics

SKILL Lint Rules

Rule Structure - SK_RULE Macro

Rule Access Macros

Rule Reporting Macros

Advanced Rule Macros


Return to top
 ⠀
X