S-Expressions

var t = frequire('Text::Balanced')

func sexpr(txt) {
    txt.trim!

    var m = txt.match(/^\((.*)\)$/s) || die "Invalid: <<#{txt}>>"
    txt = m[0]

    var w
    var ret = []
    while (!txt.is_empty) {
        given (txt.first) {
            when('(') {
                (w, txt) = t.extract_bracketed(txt, '()');
                w = sexpr(w)
            }
            when ('"') {
                (w, txt) = t.extract_delimited(txt, '"')
                w.sub!(/^"(.*)"/, {|s1| s1 })
            }
            default {
                txt.sub!(/^(\S+)/, {|s1| w = s1; '' })
            }
        }
        ret << w
        txt.trim_beg!
    }
    return ret
}

func sexpr2txt(String e) {
    e ~~ /[\s"\(\)]/ ? do { e.gsub!('"', '\\"'); %Q("#{e}") } : e
}

func sexpr2txt(expr) {
    '(' + expr.map {|e| sexpr2txt(e) }.join(' ') + ')'
}

var s = sexpr(%q{

((data "quoted data" 123 4.5)
 (data ([email protected]# (4.5) "(more" "data)")))

})

say s               # dump structure
say sexpr2txt(s)    # convert back

Output:

[["data", "quoted data", "123", "4.5"], ["data", ["[email protected]#", ["4.5"], "(more", "data)"]]]
((data "quoted data" 123 4.5) (data ([email protected]# (4.5) "(more" "data)")))