diff options
| author | Bruce Hill <bitbucket@bruce-hill.com> | 2017-09-18 22:41:50 -0700 |
|---|---|---|
| committer | Bruce Hill <bitbucket@bruce-hill.com> | 2017-09-18 22:41:50 -0700 |
| commit | 2c4acdfe67e05fba88d4c48509c8767d2dce358b (patch) | |
| tree | d72f52122d4b372d832c69bd9a21d0da34323de5 /examples | |
| parent | 15886aa57978cbd236ff6ac3bc16adf0941ca299 (diff) | |
More major overhaulage.
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/parser_tests.nom | 12 | ||||
| -rw-r--r-- | examples/sample_code.nom | 48 | ||||
| -rw-r--r-- | examples/sample_game.nom | 151 | ||||
| -rw-r--r-- | examples/tutorial.nom | 191 |
4 files changed, 302 insertions, 100 deletions
diff --git a/examples/parser_tests.nom b/examples/parser_tests.nom index 000b8de..81608b7 100644 --- a/examples/parser_tests.nom +++ b/examples/parser_tests.nom @@ -9,21 +9,23 @@ test: say (4) ..yields ".." | 4 test: - rule "fart" =: say "poot" + rule: fart ..=: say "poot" ..yields ".." |Call [rule % = %]: - | "fart" + | Thunk: + | Call [fart]! | Thunk: | Call [say %]: | "poot" test: - rule "doublefart": + rule: doublefart ..=: say "poot" say "poot" ..yields ".." - |Call [rule % %]: - | "doublefart" + |Call [rule % = %]: + | Thunk: + | Call [doublefart]! | Thunk: | Call [say %]: | "poot" diff --git a/examples/sample_code.nom b/examples/sample_code.nom index 2917be1..4f4d2dd 100644 --- a/examples/sample_code.nom +++ b/examples/sample_code.nom @@ -11,7 +11,7 @@ say (4) #.. "rule" is just a function that takes a function call spec and a block of code to run, and stores the function definition -rule "fart": say "poot" +rule: fart ..=: say "poot" fart @@ -33,13 +33,13 @@ say ".." |(done) | -rule "doublefart": # this farts twice +rule: doublefart ..=: # this farts twice say "poot" say "poot" doublefart -rule "subex work": return "subexpressions work" +rule: subex work ..=: "subexpressions work" say (subex work) @@ -54,7 +54,7 @@ say [..] 1, 2 3 -rule "say both %one and %two": +rule: say both %one and %two ..=: say %one say %two @@ -68,7 +68,7 @@ say both.. "hello" and "world" -rule "three": return 3 +rule: three ..=: 3 say both .. "a list:" and [..] @@ -79,16 +79,16 @@ if 1: yes if 1: yes ..else: no -say (do: return 5) +say (do: return: 5) -rule "do %one also %two": +rule: do %one also %two ..=: do %one do %two do: say "one liner" ..also: say "another one liner" -say (do: return "wow") +say (do: return: "wow") say (1 + (-(2 * 3))) @@ -110,27 +110,23 @@ say ".." | with multiple lines | and an interpolated expression: \2 + 5\ -rule "%n bottles": - lua block [..] - ".." - |do - | print("running raw lua code...") - | local n = - .., %n, ".." - | - | for i=n,1,-1 do - | print(tostring(i).." bottles of beer on the wall. Take one down, pass it around,") - | end - | print("no more bottles of beer on the wall.") - |end +rule: %n bottles ..=: + lua block ".." + |do + | print("running raw lua code...") + | for i=\%n\,1,-1 do + | print(tostring(i).." bottles of beer on the wall. Take one down, pass it around,") + | end + | print("no more bottles of beer on the wall.") + |end nil 9 bottles -rule "dumsum %nums": - let "sum" = 0 - for "n" in %nums: - let "sum" = (%sum + %n) - return %sum +rule: dumsum %nums ..=: + %sum =: 0 + for %n in %nums: + %sum +=: %n + return: %sum say (dumsum [1,2,3]) diff --git a/examples/sample_game.nom b/examples/sample_game.nom index a316b77..87f2c60 100644 --- a/examples/sample_game.nom +++ b/examples/sample_game.nom @@ -1,4 +1,155 @@ run file "core.nom" +run file "lib/secrets.nom" + + +with secrets: + rule: pending proposal ..=: + secret %pending + + rule: propose source %src ..=: + secret %pending =: %src + say ".." + |Proposal\%src\ + + macro block: propose %action ..=: ".." + |compiler:call("propose source %", \repr (%action's "src")\) + + rule: approve ..=: + if (pending proposal): + say ".." + |Running\pending proposal\ + do (..) + eval ".." + |return: \pending proposal\ + ..else: + say "No action pending" + +propose: + say "motion passed." + rule: fart ..=: + say "poot" + +approve +fart + +# Users: +with secrets: + secret %users =: lua expr "require('users')" + rule: find user %name ..=: + lua expr "secrets.users.by_name(vars.name) or compiler:error('Failed to find user: '..tostring(vars.name))" + rule: add user %name ..=: + lua expr "secrets.users.add(vars.name)" + macro: @ %name_block ..=: + %name_str =: lua expr "vars.name_block.value.value.src" + ".."|compiler:call("find user %", \repr %name_str\) + +say ".."|A user looks like: \@:spill\ +say ".."|A user looks like: \@:spill\ +add user "dave" +say ".."|A user looks like: \@:dave\ +add user "moloch" +say ".."|A user looks like: \@:moloch\ +add user "bruce" + +# Inventory: +with secrets: + secret %inventory =: lua expr ".." + |setmetatable({}, {__index=function(self,key) + | local t = {} + | self[key] = t + | return t + |end}) + with secrets: + lua block ".." + |local endings = setmetatable({x="es",c="es",s="es"}, {__index=function() return "s" end}) + |secrets.plurals = setmetatable({}, {__index=function(self,key) + | return key..endings[key:sub(-1)] + |end}) + |secrets.singulars = setmetatable({}, {__index=function(self,key) + | if key:sub(-2) == "es" and rawget(endings, key:sub(-3,-3)) then return key:sub(1,-3) end + | if key:sub(-1) == "s" then return key:sub(1,-2) end + | return key + |end}) + |secrets.canonicals = setmetatable({}, {__index=function(self,key) + | if key:sub(-1) == "s" then return secrets.singulars[key] end + | return key + |end}) + + rule: the plural of %singular is %plural ..=: + (secret %plurals)->%singular =: %plural + (secret %singulars)->%plural =: %singular + (secret %canonicals)->%plural =: %singular + + rule: singular %plural ..=: + %plural in (secret %singulars) + + rule: plural %singular ..=: + %singular in (secret %plurals) + + rule: canonicalize %item-name ..=: + %item-name in (secret %canonicals) + + rule: %person's inventory ..=: + (secret %inventory)->%person + + rule: %person's stock of %item ..=: + %item =: canonicalize %item + ((%person's inventory)->%item) or 0 + + rule: %person's stock of %item as str ..=: + %item =: canonicalize %item + %count =: %person's stock of %item + ".." + |\%count\ \(singular %item) if (%count == 1) else (plural %item)\ + + rule: give %person %count %item ..=: + %item =: canonicalize %item + (%person's inventory)-> %item =: (%person's stock of %item) + %count + + rule: give %person %count %item from %donor ..=: + %item =: canonicalize %item + if ((%donor's stock of %item) < %count): + say ".." + |\%donor\ does not have enough \%item\ to transfer + ..else: + (%person's inventory)->%item =: (%person's stock of %item) + %count + (%donor's inventory)->%item =: (%donor's stock of %item) - %count + + rule: + %person has %item + %person has a %item + %person has an %item + ..=: + (%person's stock of %item) > 0 + +give (@:bruce) 3 "hats" +give (@:bruce) 3 "hats" +give (@:dave) 1 "hat" from (@:bruce) +say ".."|Bruce has \(@:bruce)'s stock of "hats" as str\ +say ".."|Dave has \(@:dave)'s stock of "hats" as str\ +give (@:dave) 1 "box" +say ".."|Dave has \(@:dave)'s stock of "boxes" as str\ +the plural of "goose" is "geese" +give (@:dave) 1 "goose" +say ".."|Dave has \(@:dave)'s stock of "geese" as str\ +give (@:dave) 1 "goose" +say ".."|Dave has \(@:dave)'s stock of "geese" as str\ + +do: + lua block "math.randomseed(os.time())" + repeat until ((random number) < 0.01): + say "tick" + say "tock" + + + + + + + + + + # A basic key-value store that's only accessible through these functions: lua block ".." |do -- Use a closure to hide this behind the accessor rules diff --git a/examples/tutorial.nom b/examples/tutorial.nom index 7106f94..5f0acb3 100644 --- a/examples/tutorial.nom +++ b/examples/tutorial.nom @@ -25,7 +25,7 @@ run file "core.nom" 5 6,7,8 -# Dicts: +# Dictionaries (AKA hash maps): dict [["x", 99], ["y", 101]] dict [..] ["z", 222] @@ -34,22 +34,105 @@ dict [..] # Function calls: say "Hello world!" +# Variables use the % sign: +%str =: "Hello again" +say %str + +# There are +=:, -=:, *=:, /=:, ^=:, and=:, or=:, and mod=: operators for updating variables +%x =: 1 +%x +=: 100 +say %x + +# Conditionals look like this: +if (1 < 10): + say "1 is indeed < 10" + +if (1 > 10): + say "this won't print" +..else: + say "this will print" + +if (1 > 3): + say "this won't print" +..else: if (1 < 2): + say "this won't print" +..else: + say "this will print" + +# Loops look like this: +for %x in [1,2,3]: + say ".."|for loop over list #\%x\ + +# If you want to iterate over a numeric range, you can use some built in functions like this: +for %x in (1 through 3): + say ".."|for loop over number range #\%x\ + +# While loops: +%x =: 1 +repeat while (%x <= 3): + say ".."|repeat while loop #\%x\ + %x +=: 1 + +%x =: 1 +repeat until (%x > 3): + say ".."|repeat until loop #\%x\ + %x +=: 1 + +# Infinite loop: +%x =: 1 +repeat: + say ".."|repeat loop #\%x\ + %x +=: 1 + if (%x > 3): + break + +# GOTOs: +do: + %x =: 1 + -> %again + say ".."|go to loop #\%x\ + %x +=: 1 + if (%x <= 3): + go to %again + say "finished going to" + + # Function definition: -rule "say both %first and also %second": - # Variables use the "%" sign: +rule: + say both %first and also %second +..=: + # Function arguments are accessed just like variables say %first say %second -rule "get x from %dict": - #.. Functions can return values explicitly, but if not, the last line in the function - is the return value. - return (%dict's "x") +# The last line of a function is the return value +rule: + add %x and %y +..=: + %result =: %x + %y + %result + +# Functions can use "return" to return a value early +rule: + first fibonacci above %n +..=: + %f1 =: 0 + %f2 =: 1 + repeat: + %tmp =: %f1 + %f2 + %f1 =: %f2 + %f2 =: %tmp + if (%f2 > %n): + return: %f2 + +say (first fibonacci above 10) # Functions can have aliases, which may or may not have the arguments in different order -rule [..] - "I hate %worse-things more than %better-things", "I think %worse-things are worse than %better-things" - "I like %better-things more than %worse-things" -..: +rule: + I hate %worse-things more than %better-things + I think %worse-things are worse than %better-things + I like %better-things more than %worse-things +..=: say ".."|\%better-things capitalized\ rule and \%worse-things\ drool! I like "dogs" more than "cats" @@ -61,24 +144,33 @@ I think "chihuahuas" are worse than "corgis" say both "Hello" and also "again!" # Functions can even have their name at the end: -rule "%what-she-said is what she said": +rule: + %what-she-said is what she said +..=: say %what-she-said say "-- she said" + "Howdy pardner" is what she said #.. The language only reserves []{}().,:;% as special characters, so functions and variables can have really funky names! -rule ">> %foo-bar$$$^ --> %@@& _~-^-~_~-^ %1 !": +rule: + >> %foo-bar$$$^ --> %@@& _~-^-~_~-^ %1 ! +..=: say %foo-bar$$$^ say %@@& say %1 + >> "wow" --> "so flexible!" _~-^-~_~-^ "even numbers can be variables!" ! -# Though literals can't be used in function names # Math and logic operations are just treated the same as function calls in the syntax say (2 + 3) # So it's easy to define your own operators -rule "%a ++ %b": 2 * (%a + %b) +rule: + %a ++ %b +..=: + 2 * (%a + %b) + say (2 ++ 3) @@ -121,7 +213,7 @@ say both ".." ..and also.. "-- Abraham Lincoln" -rule "my favorite number": return 23 +rule: my favorite number ..=: 21 + 2 # Subexpressions are wrapped in parentheses: say (my favorite number) @@ -139,48 +231,10 @@ say ".." number ..\, but this time it uses an indented subexpression! -#.. There's a few macros in the language for things like conditional branches and logic/math - operations, but they can be thought of as basically the same as functions. - There are no keywords in the language! -if (1 < 10): - say "One is less than ten" -..else: - say "One is not less than ten" - -#.. Breakdown of the above: - Function call (actually a macro) to "if % % else %" - First argument is a subexpression that is a function call (also a macro) to "% < %" - that performs a comparison on its arguments, 1 and 10 - Second argument is a block of code that includes a function call to "say %", the "if" body - Third argument is a block of code that includes a different function call to "say %", the "else" body - -# Line continuations can be used for "elseif" -if (1 > 10): - say "First condition" -..else: if (1 > 5): - say "Second condition" -..else: - say "Last condition" - -# ^that's the same as: -if (1 > 10): - say "First condition" -..else: - if (1 > 5): - say "Second condition" - ..else: - say "Last condition" - -# Variables are modified with a macro, "let % = %" -let "numbers" = [5,6,7] - -# Looping: -say ".."|Looping over \%numbers\: -for "number" in %numbers: - say (%number + 100) - -rule "sing %starting-bottles bottles of beer": - for "n" in (%starting-bottles down through 0): +rule: + sing %starting-bottles bottles of beer +..=: + for %n in (%starting-bottles down through 0): say ".." |\%n if (%n > 0) else "No more"\ \"bottle" if (%n == 1) else "bottles"\ of beer on the wall. |\"" if (%n == 0) else " Take one down, pass it around..."\ @@ -206,7 +260,7 @@ any of [0,0,0,0,1,0,0] # Macros: # The "lua block %" and "lua expr %" macros can be used to write raw lua code: -rule "say the time": +rule: say the time ..=: lua block ".." |io.write("The OS time is: ") |io.write(tostring(os.time()).."\\n") @@ -215,24 +269,23 @@ say ".."|Math expression result is: \lua expr "(1 + 2*3 + 3*4)^2"\ #.. In the lua environment, "vars" can be used to get local variables/function args, and "compiler" can be used to access the compiler, function defs, and other things -rule "square root of %n": - return (lua expr "math.sqrt(vars.n)") +rule: square root of %n ..=: + lua expr "math.sqrt(vars.n)" say ".."|The square root of 2 is \square root of 2\ # Macros can be defined as functions that take unprocessed syntax trees and return lua code # "macro block %" is for defining macros that produce blocks of code, not values -macro block "unless %condition %body": - ".." - |if not (\%condition as lua expr\) then - | \(lua expr "vars.body.value.value") as lua block\ - |end +macro block: unless %condition %body ..=: ".." + |if not (\%condition as lua expr\) then + | \(lua expr "vars.body.value.value") as lua block\ + |end unless (1 > 10): say "Macros work!" say "It looks like a keyword, but there's no magic here!" # and "macro %" is for defining macros that produce an expression -macro "%value as a boolean": - ".."|(not not (\%value as lua expr\)) -macro "yep": "true" +macro: %value as a boolean ..=: ".." + |(not not (\%value as lua expr\)) +macro: yep ..=: "true" |
