• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Community Forums
  2. Custom IC SKILL
  3. How can I get a handle to a nested procedure in skill++...

Stats

  • Locked Locked
  • Replies 9
  • Subscribers 143
  • Views 6101
  • Members are here 0
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

How can I get a handle to a nested procedure in skill++?

John Davis
John Davis over 1 year ago

I have an application where I will receive the string name of a procedure that I need to call.

In skill this strait forward,  for example.  (Note this code is stored in a .ils file and loaded via load("foo.ils")

procedure(myFun1a()
  let(()
    println("myFun1a")
  )
)

printf("myFun1a is callable? = %L\n" isCallable('myFun1a)) ; prints t
mySymbol1a = stringToSymbol("myFun1a")
printf("mySymbol1a is callable? = %L\n" isCallable(mySymbol1a)) ; prints t

myFun1a() ; prints myFun1a
funcall(mySymbol1a) ; prints myFun1a
Is there a way to to the same in scheme / skill++?
I can check that the symbol exists in the environment,  but I can't find a way to call the function given it's string name unless I code the function as a lambda.
For example.  (Note this code is stored in a .ils file and loaded via load("foo.ils")
procedure(getPackage()
  let( (myAlias1)

    procedure(myFun1()
      let(()
        println("myFun1")
      )
)

    myFun2 = lambda(()
      let(()
        println("myFun2")
      )
)

    printf("myFun1 is callable? = %L\n" isCallable('myFun1)) ; prints nil
    printf("myFun2 is callable? = %L\n" isCallable('myFun2)) ; prints t
    mySymbol1 = stringToSymbol("myFun1")
    mySymbol2 = stringToSymbol("myFun2")

    printf("mySymbol1 is callable? = %L\n" isCallable(mySymbol1)) ; prints nil
    printf("mySymbol2 is callable? = %L\n" isCallable(mySymbol2)) ; prints t

    printf("is bound = %L\n" boundp('myFun1 theEnvironment())) ; prints t

    myAlias1 = myFun1
    myFun1()
    funcall(myFun1) ; prints myFun1
    funcall('myFun2) ; prints myFun2
    ;funcall(mySymbol1) ; this does not work
    funcall(mySymbol2) ; prints myFun2
    ; funcall('myAlias1) ; this does not work
  )
)
I can use the lambda's if that's the only way,  but it seems like I should be able to get a handle on the procedure from a symbol.  The boundp is able to find it in the theEnvironment().
Is there some way to do this that I am missing?
  • Cancel
  • AaronSymko
    AaronSymko over 1 year ago

    Using legacy SKILL, which is dynamically scoped, you must use either funcall or apply to execute lambda functions.

    However, in SKILL++, it is possible to call function objects directly.  For example, consider the following set of procedures organized into a package:

    /*
      Example of how to organize a package in SKILL++
    
      The procedures are only exposed through the global var (testPackage)
    */
    importSkillVar(testPackage)
    testPackage =
    let(((count 0))
      procedure( increment()
        preincrement(count)
      ); procedure
      procedure( decrement()
        predecrement(count)
      ); procedure
      list(nil
        'increment increment
        'decrement decrement
      )
    ); let


    You can then call the functions directly, such as:

    load "testPackage.ils"
    testPackage->increment()
    testPackage->decrement()
    
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • John Davis
    John Davis over 1 year ago in reply to AaronSymko

    The problem I have is I have the string name for the procedure I want to call.

    In the context of your example,  say I had another procedure in the package,  some how in that procedure I get the string "increment" (maybe it was read from a file or an ipc message),  how do I use that to call the increment procedure?  I guess an other option is to store the function objects in table or DPL like you show and then look them using the string.

    BTW I did see this approach of only exposing the one global variable,  but in my case I don't even need to expose them,  the functions I need to call via a string name are called from within the package,  but I can still use the same approach even if I don't need to use expose them externally.

    Thanks for the reply, it helped!

    Btw,  how do you format code here?  did not seem like the normal markdown worked

    Here is my updated example using both a DPL as you showed and a table like I mentioned above.
    procedure(getPackage()
    let( (myAlias1)

    procedure(myFun1()
    let(()
    println("myFun1")
    )
    )

    myFun2 = lambda(()
    let(()
    println("myFun2")
    )
    )

    api = makeTable("api" nil)
    api["myFun1"] = myFun1
    api2 = list(nil 'myFun1 myFun1)

    printf("myFun1 is callable? = %L\n" isCallable('myFun1)) ; prints nil
    printf("myFun2 is callable? = %L\n" isCallable('myFun2)) ; prints t
    mySymbol1 = stringToSymbol("myFun1")
    mySymbol2 = stringToSymbol("myFun2")

    printf("mySymbol1 is callable? = %L\n" isCallable(mySymbol1)) ; prints nil
    printf("mySymbol2 is callable? = %L\n" isCallable(mySymbol2)) ; prints t

    printf("is bound = %L\n" boundp('myFun1 theEnvironment())) ; prints t

    myAlias1 = myFun1
    myFun1()
    funcall(myFun1) ; prints myFun1
    funcall('myFun2) ; prints myFun2
    ; funcall(mySymbol1) ; this does not work
    funcall(mySymbol2) ; prints myFun2
    ; funcall('myAlias1) ; this does not work
    ; apply(mySymbol1 list()) ; this does not work
    apply(mySymbol2 list()) ; this does not work
    func = api["myFun1"]
    func() ; prints myFun1
    myFun1String = "myFun1"
    func2 = get(api2 myFun1String)
    func2() ; prints myFun2
    )
    )
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to John Davis

    It's not entirely clear (to me at least) what your goal is here. If you create a function within a function using procedure() in SKILL++ it is local to the function - that's intentional (and very useful). Your alias myAlias1 is also local because you put it in a let.

    If you want to make them global (but still lexically scoped) you can use globalProc() instead of procedure. If you don't want to make them global but callable via a string name of the local function within the lexical scope containing the functions, you can do:

    funcall(symeval(stringToSymbol("myFun1") theEnvironent()))

    In other words, use symeval() with a symbol but with the environment passed instead.

    Regards,

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AurelBuche
    AurelBuche over 1 year ago in reply to Andrew Beckett

    Hi Andrew,

    I was about to answer the same but you were faster!

    I would just use concat (and strcat) instead of stringToSymbol (and symbolToString) as they are faster and more flexible (they support both string and symbol inputs [even numbers for concat] and several arguments as well)

    Cheers

    Aurélien

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • Andrew Beckett
    Andrew Beckett over 1 year ago in reply to AurelBuche
    AurelBuche said:
    I would just use concat (and strcat) instead of stringToSymbol (and symbolToString) as they are faster and more flexible

    I even originally used concat in my reply, but changed to stringToSymbol as it's a little more expressive. The performance difference is pretty unlikely to be significant (the difference was ~7s vs 4s for 100 million stringToSymbol/concat calls). But fair enough... I'd probably use concat myself!

    Andrew

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AurelBuche
    AurelBuche over 1 year ago in reply to Andrew Beckett

    I know the difference is extremely little but before answering I used the time profiler and got the following results

    (which makes me think that stringToSymbol uses concat internally)

    (for i 0 1000000 (stringToSymbol "abcdefghijklmnop") (concat "abcdefghijklmnop"))

    Function Name Total Inside CallCount

    ------------- ----- ------ ---------

    TOTAL CPU Time (secs) 0.53 0.53

    toplevel 0.53 0.06 1

    stringToSymbol 0.24 0.24 1000001

    gc 0.14 0.14 1

    concat 0.09 0.09 2000002
    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • John Davis
    John Davis over 1 year ago in reply to Andrew Beckett

    symeval(stringToSymbol("myFun1") theEnvironent())

    That's what I was missing.

    I know it was a contrived example.  In the end the outer function would return one of the nested functions (a "server"),  which the user would invoke.  The "server" would need to invoke some of the inner functions given string name of the function. I nested the functions to keep them local and only expose the "makeServer" outer function.  Hopefully that makes sense..

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • John Davis
    John Davis over 1 year ago in reply to John Davis

    Searching the reference for e_environment is also helpful.  

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel
  • AaronSymko
    AaronSymko over 1 year ago in reply to John Davis

    Hi John,

    Regarding your question about formatting, I use a simple script that Andrew Beckett created back in 2010.  I'm not sure how to share that script, but it basically boils down to this:


    FILE=$1

    echo "Content-type: text/html"
    echo ""
    enscript --color --language=html -Eskill --output=- $FILE


    Then, you can copy-paste the output of that into the type-in field using "Tools->Source Code".

    • Cancel
    • Vote Up 0 Vote Down
    • Cancel

Community Guidelines

The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information