# One liner comments start with # and go till end of line #.. Multi-line comments start with #.. and continue until dedent # 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 with a #.. fake comment |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 the time": lua block ".." |io.write("The OS time is: ") |io.write(tostring(os.time()).."\n") say the time printf ["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)") 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"