wryun / es-shell

es: a shell with higher-order functions
http://wryun.github.io/es-shell/
Other
307 stars 25 forks source link

assert failure on closure mania #6

Open wryun opened 12 years ago

wryun commented 12 years ago

error:

closure.c:72: assertion failed (k == nWord || k == nQword || k == nPrim)

Produced by my somewhat psychotic startup file after two 'es -l':

let (ls = `{which ls}) fn ls {`{which ls} --color\=auto $*}

fn pwd {
    if {~ $#cwd 0} {
        noexport = $noexport cwd
        cwd = `` \n /bin/pwd
    }
    echo $cwd
}

# symlink cd ..
let (cd = $fn-cd) fn cd dir {
    if {~ $#cwd 0} {
        noexport = $noexport cwd
    }
    if {~ $#dir 0} {
        $cd
        cwd = ~
    } {
        let (current = <={
            if {~ $dir /*} {
                result
            } {
                if {~ $#cwd 0} {
                    cwd = `` \n /bin/pwd
                }
                %split / $cwd
            }
        }) {
            for (name = <={%split / $dir}) {
                if {~ $name ..} {
                    if {!~ $#current 0} {
                        let (x = 1 $current) current = $x(2 ... $#current)
                    }
                } {!~ $name . ''} {
                    current = $current $name
                }
            }
            let (path = / ^ <={ %flatten / $current }) {
                $cd $path
                cwd = $path
            }
        }
    }
}

# go back -N directories in cd (cd -1 prints stack, cd - goes to previous)
#
let (cd = $fn-cd; cd-stack = (. . . . . . . . . .)) fn cd dir { 
    if {~ $dir -*} {
        let (index = <={%split - $dir}) {
            if {~ $#index 0} {
                index = 2
            }
            if {~ $index [2-9]} {
                dir = $cd-stack($index)
            } {~ $index 1} {
                echo $cd-stack >[1=2]
                return 0
            } {
                throw error cd 'cd: invalid argument'
            }
        }
    }
    $cd $dir
    cd-stack = (`pwd $cd-stack(1 ... 9))
}

# colourful prompt
let (cd = $fn-cd; c = \1\033; z=\2) fn cd {
    $cd $*;
    let (w = `pwd) {
        if {~ $^w $home^*} {
            w = '~'^<={~~ $^w $home^*}
        }
        prompt = $c[4\;35m$z`{hostname}^$c[0m$z:$c[1\;34m$z$^w$c[0m$z^'; '
    }
}

# when we start, we should 'cd .' to set the colourful prompt
fn %prompt {
    cd .
    fn %prompt # now lose the prompt function
}

CC=colorgcc
jpco commented 6 months ago

Oh! Here's a rather simpler repro:

; '%closure (a = {}) {}'
closure.c:72: assertion failed (k == nWord || k == nQword || k == nPrim)

(note the quotes).

I've actually triggered this several times myself; I'm surprised I didn't connect the dots before now.

My goal at the time was to reduce the exponential blowup of quote characters (you know how when you print some heavily-overloaded functions you end up with something like %closure (fn-foo = ''''''''$&foo'''''''') {...}?) What happens when you do that, though, is that the next time the shell tries to parse a %closure string, the extract() function expects one of the following three options as every definition: a word, the pseudo-primitive $&nestedbinding, or anything else wrapped up in quotes; so giving it something else, like the unquoted {} in the example above, causes it to choke.

I'm not quite sure how you managed to trigger the behavior without either a hand-crafted %closure string or editing the source, though. Impressive!

The most "complete" fix seems to be doing a full-on glom() of the definition during extract(). It's a little tricky, though, because glom() expects the GC to be on, while extract() expects the GC to be off. Maybe that's a sign that glom() during extract() isn't actually correct. It might also be reasonable to just make some more of the tree types -- nLambda, nThunk, nPrim, nList, maybe nConcat -- valid and not worry (yet) about fully glomming things like nCall.