aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-09-18 22:41:50 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2017-09-18 22:41:50 -0700
commit2c4acdfe67e05fba88d4c48509c8767d2dce358b (patch)
treed72f52122d4b372d832c69bd9a21d0da34323de5 /examples
parent15886aa57978cbd236ff6ac3bc16adf0941ca299 (diff)
More major overhaulage.
Diffstat (limited to 'examples')
-rw-r--r--examples/parser_tests.nom12
-rw-r--r--examples/sample_code.nom48
-rw-r--r--examples/sample_game.nom151
-rw-r--r--examples/tutorial.nom191
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"