main = (argv) { given {argv:1} { when /hello/ { say "yo" } when /what up/ { say "just chilling" } } } script main * * * shout = () { say "GOOD MORNING" } shout = () { say "HELLO WORLD!" } script shout - should print "HELLO WORLD!" * * * #!/usr/bin/env pluvo % 009-case.lu - More Testing Author: Sean B. Palmer, inamidst.com def main(argv) { example { main ("--first") => "One\n" } test { argv = ("--second"); => "Two\n" } test { argv = ("--third"); -> "Three\n" } --first { say "One" } or --second { say "Two" } or --third { return "Three" } } check main script main @@ script on anon functions script { main = () { ... } } @@ A warner to check that globals and variables don't have an intersection. people = ("Chris" "Cody" "Morbus") for people { add salutations { & "Hello " arg "!" } } * * * #!/usr/bin/env pluvo % grep.lu - Grep-A-Like Author: Sean B. Palmer, inamidst.com main = (argv) { for <@2> { if {/@1/ arg} { out arg } } } script main Or, better: main = (argv) { if {{length argv} < 3} { help } for (fn) {argv:2:} { for <$fn> { if {/@1/ arg} { out arg } } } } options { -h/--help "Display a help message" } if {-h or {{length argv} < 3}} { help } Or, using array context... if {-h or {argv < 3}} { help } Where to put the trickery? The optdef/flagspec stuff could go in either options, -h, or /, and the call stuff could be in -h or or. Probably best to use options and -h. But then either -h has to support or, or we do this: if {{-h} or {argv < 3}} { help } Which I suppose isn't too bad, especially with the longarg: if {{--help} or {argv < 3}} { help } There's always the booleaning of itself, of course: --help or {argv < 3} { help } Which is handy given the idea of --first/--second/--third above. Otherwise, anding would be the obvious approach. options { --help "Print out a help message" } main = (argv) { --help or {argv < 3} { help } for (filename) {argv:2:} { for <$filename> { if {/@1/ arg} { out arg } } } } * * * #!/usr/bin/env pluvo % grep.lu - Grep Some Files Author: Sean B. Palmer, inamidst.com usage "grep.lu [options] " options { -h/--help "Display a help message" -t/--test "Perform code tests" } grep = (filenames pattern) { % "Grep through filenames for pattern" example { grep(("pluvo://doc") "pqr") => "1. pqrst" } for (fn) filenames { for <$fn> { if {/@pattern/ arg} { out arg } } } } main = (argv) { --help or {argv < 3} { help } --test { check grep; quit } grep {argv:2:} @1 } script main * * * Paths: env.PATH, varpath (variables, globals, locals), stdpath (for @ modules), and path (for $ modules). A code block can do three things, flow-wise: return, give a status, or give a control note. Returns can be strong (return and don't execute any more commands in the block--set result and exit), weak (note the current object for return, execute the rest of the statements, then return it--set provide), or automatic (return the last thing that was evaluated--set result). example = () { --first { return { first } } # Strong return --second { provide { second } } # Weak return third # Automatic return } If --first, it'll return the return value of first; if --second it'll return the return value of second after having executed third; if neither, it'll return the return value of third. Statuses are, like in Plan9, strings. They can be used to chain stuff: example = () { if { ... } { ... } # Uses return value something or somethingelse # Uses status value } One of their main uses is for exceptions. Pluvo file extension: .lu Pluvo compiled file extension: .clu Rationale: I've done rm *.py before when I've missed the c. Whoopa. Control is for stuff like for. for { if {/pqr/ arg} { break } } Break sets control to "break", which gets passed up to everything until it's a for, essentially. globvar = "False" first = () { return "First function" } second = () { return "Second function" } third = () { globvar = "True" return "Third function" } test = (arg) { if {arg == "First"} { return { first } } or if (arg == "Second"} { provide { second } } third } main = (argv) { result = { test "First" } if {{result == "First function"} and {globvar == "False"}} { say "Test one passed" } result = { test "Second" } if {{result == "Second function"} and {globvar == "True"}} { say "Test two passed" } result = { test "Third" } if {{result == "Third function"} and {globvar == "True"}} { say "Test three passed" } } @@ Passing already bound args in argspecs. something = "Hello, world!" def test(something) { say something } test "Test passed" set syntax: { Set 1, 2, 3 } or just: { 1, 2, 3 } as long as there are no execables. So, Of Control, there are at least three kinds of control: return/exit: exit this block now break/exit-loop: exit this block and all upper blocks until for/while quit: quit this whole program now Because of the (result, status, control) tuple, we'll have to couple the commands properly. So: return -> (null, "", "return/exit") return arg -> (arg, "", "return/exit") exit -> (null, "", "return/exit") exit arg -> (null, arg, "return/exit") break -> (null, "", "break/exit-loop") quit -> (null, "", "quit") Note that there are holes, and it's messy. What if you want to break with a result? break arg is the obvious approach. So what if you want to break with a status? What if you want to return/exit with both a result and a status? You can actually use provide for that; provide is a sort of orthogonal hack though. Ooh, if a URI has no name it can be autoclosed? So: f = bytes = { join "" f } f close # Must be closed here Hmm, EOL comment problem there. Oh well. for { say arg } # Does not need to be closed, will autoclose This, in the example above, is for's responsibility. There would be a similar responsibility for all other file users, e.g. read: bytes = { read } Prototyping seems to be the right way to do OOP in Pluvo. This is a bit of an annoyance though because of ".". Ship = (name) { sail = () { ... } dock = () { ... } } "new" will simply be a closure copy, so: daphne = { new Ship "Daphne" } say { daphne.name } # Prints Daphne" So . just accesses something's variables. This means that you're screwed if you want to create an instance of Function though! It also means that the "methods" are going to leak into one another, variable-wise. I suppose there could be something like "let" for really local assignment. beer = () { % "Cf. http://www.99-bottles-of-beer.net/lyrics.html" for (i) {range 99 1} { say "$i bottles of beer on the wall, $i bottles of beer." bottles = { j = i - 1 if {j == 1} { return "1 bottle" } else { return "$j bottles" } } say "Take one down and pass it around, $bottles of beer on the wall." } say "No more bottles of beer on the wall, no more bottles of beer." say "Go to the store and buy some more, 99 bottles of beer on the wall." } The language is zero based at the moment. range 5 would return six elements... answer result status [ control ] yadda = () { answer null "Yadda-yadda" "exit" } sub = (barename block) ( global barename barename = () block } sub test { ... } def yadda(env): return (None, "Yadda-yadda", "exit") sub yadda { answer (status="Yadda-yadda") } exit = (status) { answer (status=status, control="exit") } return = (result=null) { answer (result=result) } sub break { answer (control="break/exit-loop") } Hmm, perhaps a basics.lu is possible even now. Example: say = (*args) { out args out "\n" } Hmm, no *args implementation yet. And it wouldn't work anyway. Oh, well how about this: grandparent = () { return { {stack}:-5 } } More traditional case: main = (argv) { case {argv:1} ( /hello/ { say "yo" } /what up/ { say "just chilling" } ) } Or possibly given instead of case--it's a bit more descriptive. Hmm... since return and exit are equivalent without arguments, we could just use return for that, and use "error" or "barf" etc. for when we do want a particular status. if { not { os.exists filename } } { error "Couldn't find $filename" } Argh, that's meant to exit out of the if too. Well, that's what if does though: it passes on its block's result, so that's no problem. Oh, the interpreter should try to sys.exit(program["status"]), if it can coerce it to an int somehow. Perhaps just map "" to 0 and everything else to 1. So we have: return, error, break, quit, and answer. And probably continue, since actually return needs to be passed all the way up to the calling block to some level. Ergh, actually, that won't work will it. Eek! So we'd need a stronger return for that too, unless the block doesn't get counted--what we can do is have for check for it, I suppose. My way of doing for is cool since you could pass an already made function as the third argument. for say beer = () { % "Cf. http://www.99-bottles-of-beer.net/lyrics.html" for (i) {range 99 1} { say "$i bottles of beer on the wall, $i bottles of beer." j = { i - 1 } if {j == 1} { bottles = "1 bottle" } else { bottles = "$j bottles" } say "Take one down and pass it around, $bottles of beer on the wall." say } say "No more bottles of beer on the wall, no more bottles of beer." say "Go to the store and buy some more, 99 bottles of beer on the wall." } When you can't do something in some way limited by the language, it's difficult to avoid changing the language rather than the code. The original beer block could be a kind of run assignment, which equals fernagles: eight = run { i = { 2 + 3 } i + 3 } Equals ought to check for equality to run, there, rather than just the name, so that you could do: myrun = run eight = myrun { ... } Hmm, interpolation must be done at runtime. -- Sean B. Palmer, inamidst.com