diff options
Diffstat (limited to 'examples/tutorial.nom')
| -rw-r--r-- | examples/tutorial.nom | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/examples/tutorial.nom b/examples/tutorial.nom new file mode 100644 index 0000000..1b25f69 --- /dev/null +++ b/examples/tutorial.nom @@ -0,0 +1,211 @@ +(# Comments use (# ... #), and can be nested #) + +(# Import files like so: #) +run file "core.nom" + +(# Numbers: #) +23 +4.5 +(# Since this language cross-compiles to lua, integers and floating point numbers are + both represented using the same primitive. #) + +(# Strings: #) +"asdf" +".." + |This is a multi-line string + |that starts with ".." and includes each indented line that starts with a "|" + |until the indentation ends + +(# Lists: #) +[1,2,3] +[..] + "like multi-line strings, lists have an indented form", "that can use commas too" + "or just newlines to separate items" + 5 + 6,7,8 + +(# Function calls: #) +say "Hello world!" + +(# Function definition: #) +rule "say both %first and also %second": + (# Variables use the "%" sign: #) + say %first + say %second + +(# Function calls can have parts of the function's name spread throughout. + Everything that's not a literal value is treated as part of the function's name #) +say both "Hello" and also "again!" + +(# Functions can even have their name at the end: #) +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 !": + 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) +say (2 ++ 3) + + +(# Code blocks start with ":" and either continue until the end of the line + or are indented blocks #) + +(# One liner: #) +: say "hi" + +(# Block version: #) +: + say "one" + say "two" + +(# So the function definitions above are actually just passing a regular string, like + "say both %first and also %second", and a code block to a function called "rule % %" + that takes two arguments. #) + +(# Line continuations work by either ending a line with ".." and continuing with an indented block: #) +say.. + both "Tom" and + also + "Sawyer" + +(# Or by starting the next line with ".." #) +say both "Bruce" +..and also "Lee" + +(# This can be mixed and matched: #) +say both.. + "Rick" +..and also.. + "Moranis" + +(# And combined with the block forms of literals: #) +say both ".." + |Four score and seven years ago our fathers brought forth, upon this continent, + |a new nation, conceived in liberty, and dedicated to the proposition that + |"all men are created equal" +..and also.. + "-- Abraham Lincoln" + +rule "my favorite number": return 23 +(# Subexpressions are wrapped in parentheses: #) +(# printf takes a list of bits that are converted to strings and concatenated together, and printed #) +printf ["My favorite number is ", my favorite number] +(# There's a multi-line indented block form for subexpressions too: #) +printf [..] + "My favorite number is still ", (..) + my favorite + number + +(# 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: #) +printf ["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): + printf [..] + (%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...") + +sing 9 bottles of beer + + +(# Note that because math and logic operations are just macros, they require a lot + of parentheses to disambiguate. There's no PEMDAS. #) +say (5 + (4 * (- (1 + (6 + 2))))) +(# For convenience, +,*,"and", and "or" have been hand defined to work with up to 4 operands: #) +1 + 2 + 3 + 4 +1 * 2 * 3 * 4 +1 and 2 and 3 and 4 +1 or 2 or 3 or 4 +(# Longer lists can use "sum of %", "product of %", "all of %", and "any of %", respectively, or lots of parentheses. #) +sum of [1,2,3,4,5,6,7] +product of [1,2,3,4,5,6,7] +all of [1,1,1,1,0,1,1] +any of [0,0,0,0,1,0,0] +(# And 3-operand chained inequality comparisons have been defined: #) +1 < 2 <= 3 + + +(# Macros: #) +(# The "lua block %" and "lua expr %" macros can be used to write raw lua code: #) +rule "say time": + lua block ".." + |io.write("The OS time is: ") + |io.write(tostring(os.time()).."\n") +say time +printf ["Math expression: ", lua expr "(1 + 2*3 + 3*4)^2"] +(# In the lua environment, "vars" can be used to get local variables/function args, and "game" + can be used to access the compiler, function defs, and other things #) +rule "square root of %n": + return (lua expr "math.sqrt(vars.n)") +printf ["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": + concat [..] + (# "% as lua expr" and "% as lua block" are two useful helper functions here. #) + "if not (", %condition as lua expr, ") then" + (# Extract the inner part of the code block's body and insert it: #) + "\n ", (lua expr "vars.body.value.value") as lua block + "\nend" + +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": + concat ["(not not (", %value as lua expr, "))"] +macro "yep": "true" + |
