Search code examples
factor-langconcatenative-language

Input quotation to loop doesn't match expected effect


I'm trying to write a text editor to mimic the input format of ed. In ed, you write your input one line at a time and finish when you input a single . on a line. Here's what I came up with:

0 [
    [ readln [ "." = not ] keep swap ] dip 1 + swap
] loop
nip 1 - narray

This snippet gets input from the user one line at a time, stops when it reaches a single dot, and returns an array of strings.

I don't get any errors when it's on its own, but as soon as I try to put it into a word:

: getinput ( -- input )
    0 [
        [ readln [ "." = not ] keep swap ] dip 1 + swap
    ] loop
    nip 1 -
    narray
;

I get the following error:

The input quotation to “loop” doesn't match its expected effect
Input                            Expected         Got
[ ~quotation~ dip 1 + swap ] ( ... -- ... ? ) ( x -- x x x )
(U) Quotation: [ c-to-factor -> ]
...

I think it might be something to do with the compiler not caring about the stack declaration when it's not in a word as opposed to when it is. Is it unhappy about modifying the stack underneath loop? I know about call( ), but if I need to use it here, how?


Edit: I also just tried the following:

:: getinput ( -- input )
    0 :> count!
    [ [ "." = not ] keep swap ]
    [ readln count 1 + count! ] do while
    drop count 1 - narray
;

I get a similar error, however the stack effects are slightly different:

The input quotations to “while” don't match their expected effects
Input                                                               Expected         Got
[ ~quotation~ keep swap ]                                           ( ..a -- ..b ? ) ( x -- x x )
[ _ 1 load-locals readln 0 get-local local-value 1 + 0 get-local... ( ..b -- ..a )   ( -- x )
(U) Quotation: [ c-to-factor -> ]
...

Again, fine on its own, but in a word, it doesn't compile.


Solution

  • Less roundabout and doesn't use locals, huzzah

    ! get input as array of lines
    : getinput ( -- input )
        { } [
            readln
            ! stop on .
            [ "." = ] keep swap
            [
                drop f
            ] [
                 1array append
                 t
            ] if
        ] loop
    ;
    

    I think the error had to do with the fact that factor has pretty strict stack effect stuff, even with simple branching.