Search code examples
arraysstackfactor-lang

Unpack an array to the stack at runtime


I have an array:

{ 1 2 3 4 }

I want to push its contents to the stack.

I tried:

(sc) { 1 2 3 4 } dup length firstn
1
2
3
4

Great!

Inside a word, though:

: explode ( a -- * ) dup length firstn ; inline

Throws an error Cannot apply “firstn” to a run-time computed value, because firstn calls call and

Words which call an input parameter must be declared inline so that a caller which passes in a literal quotation can have a static stack effect.

... and because of call 's semantics it's hard to compute quotations at runtime.

There must be a way to accomplish this. What is it?


Solution

  • As Björn Lindqvist said, Factor won't let you do that1, but there are some workarounds.

    The most direct way is perhaps using a vector as a stack:

    : explode ( v s -- v ) dupd [ swap push ] with each ;
    V{ } "somestring" explode
    ==> V{ 115 111 109 101 115 116 114 105 110 103 }
    

    Of course, this means redesigning all related functions to work with this.

    Maybe better than vectors, there are also string buffers, that can behave like a stack too.

    "somestring" >sbuf
    ==> SBUF" somestring"
    "-abcd" [ over push ] each
    ==> "somestring-abcd"
    

    (Alternatively SBUF" somesbuf")

    If you need to keep working with the content as if it were the input to some other words passed on the stack, you can use with-datastack:

    "somestring-abcd" [ 5 ndrop 3dup ] with-datastack >string
    ==> "somestringing"
    

    But think of this as if it where a regular non-stack-based language. Each word takes a fixed number of parameters and outputs a fixed number of results.

    [1]. There must be some metaprogramming ways to do this. I don't imagine there's an easy practical way, though.