aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/collections.nom13
-rw-r--r--lib/control_flow.nom84
-rw-r--r--lib/core.nom8
-rw-r--r--lib/math.nom79
-rw-r--r--lib/metaprogramming.nom20
-rw-r--r--lib/operators.nom136
-rw-r--r--lib/text.nom105
-rw-r--r--lib/training_wheels.nom5
-rw-r--r--lib/utils.nom95
-rw-r--r--lib/utils2.nom63
10 files changed, 327 insertions, 281 deletions
diff --git a/lib/collections.nom b/lib/collections.nom
index e4b0eed..52e6675 100644
--- a/lib/collections.nom
+++ b/lib/collections.nom
@@ -1,5 +1,8 @@
+#..
+ This file contains code that supports manipulating and using collections like lists
+ and dictionaries.
+
use "lib/metaprogramming.nom"
-use "lib/utils.nom"
use "lib/control_flow.nom"
use "lib/operators.nom"
@@ -148,6 +151,13 @@ immediately:
return comprehension;
end)(nomsu)
+# Sorting:
+compile [sort %items] to: "table.sort(\(%items as lua))"
+compile [sort %items by %key_expr] to: ".."
+ nomsu.utils.sort(\(%items as lua), function(\(\% as lua))
+ return \(%key_expr as lua);
+ end)
+
action [%items sorted]:
%copy = (% for all %items)
sort %copy
@@ -156,6 +166,7 @@ action [%items sorted by %key]:
%copy = (% for all %items)
sort %copy by %key
return %copy
+
action [unique %items]:
[%k for %k=%v in {%=(yes) for all %items}]
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index fbc373f..f2500c5 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -1,6 +1,19 @@
+#..
+ This file contains compile-time actions that define basic control flow structures
+ like "if" statements and loops.
+
use "lib/metaprogramming.nom"
+use "lib/text.nom"
use "lib/operators.nom"
-use "lib/utils.nom"
+
+# No-Op
+immediately:
+ compile [do nothing] to code: ""
+
+# Return
+immediately:
+ compile [return] to code: "do return; end"
+ compile [return %return_value] to code: "do return \(%return_value as lua); end"
# Conditionals
immediately:
@@ -17,10 +30,33 @@ immediately:
\(%else_body as lua statements)
end --end if
-# Return
+# Conditional expression (ternary operator)
+#.. Note: this uses a function instead of "(condition and if_expr or else_expr)"
+ because that breaks if %if_expr is falsey, e.g. "x < 5 and false or 99"
immediately:
- compile [return] to code: "do return; end"
- compile [return %return_value] to code: "do return \(%return_value as lua); end"
+ compile [..]
+ %when_true_expr if %condition else %when_false_expr
+ %when_true_expr if %condition otherwise %when_false_expr
+ %when_false_expr unless %condition else %when_true_expr
+ %when_false_expr unless %condition then %when_true_expr
+ ..to:
+ local %safe
+ #.. If %when_true_expr is guaranteed to be truthy, we can use Lua's idiomatic
+ equivalent of a conditional expression: (cond and if_true or if_false)
+ if ({Text=yes, List=yes, Dict=yes, Number=yes}->(%when_true_expr's "type")):
+ return "(\(%condition as lua) and \(%when_true_expr as lua) or \(%when_false_expr as lua))"
+ ..else:
+ #.. Otherwise, need to do an anonymous inline function (yuck, too bad lua
+ doesn't have a proper ternary operator!)
+ To see why this is necessary consider: (random()<.5 and false or 99)
+ return ".."
+ (function(nomsu)
+ if \(%condition as lua) then
+ return \(%when_true_expr as lua);
+ else
+ return \(%when_false_expr as lua);
+ end
+ end)(nomsu)
# GOTOs
immediately:
@@ -212,7 +248,7 @@ immediately:
set %first = (yes)
for %func_call in (%body's "value"):
local [%tokens, %star, %condition, %action]
- assume ((%func_call's "type") == "FunctionCall") or barf ".."
+ assume ((%func_call's "type") is "FunctionCall") or barf ".."
Invalid format for 'when' statement. Only '*' blocks are allowed.
set %tokens = (%func_call's "value")
set %star = (%tokens -> 1)
@@ -308,7 +344,7 @@ immediately:
..to code: ".."
do
local fell_through = false;
- local ok, ret1, ret2 = pcall(function(nomsu)
+ local ok, ret = pcall(function(nomsu)
\(%action as lua statements)
fell_through = true;
end, nomsu);
@@ -318,7 +354,7 @@ immediately:
if not ok then
\(%fallback as lua statements)
elseif not fell_through then
- return ret1, ret2;
+ return ret;
end
end
parse [try %action] as:
@@ -332,20 +368,48 @@ immediately:
# Do/finally:
immediately:
+ compile [do %action] to code:
+ (%action as lua statements) if ((%action's "type") is "Block")
+ ..else "(\(%action as lua))(nomsu);"
+
compile [do %action then always %final_action] to code: ".."
do
local fell_through = false;
- local ok, ret1, ret2 = pcall(function(nomsu)
+ local ok, ret1 = pcall(function(nomsu)
\(%action as lua statements)
fell_through = true;
end, nomsu);
- local ok2, _ = pcall(function(nomsu)
+ local ok2, ret2 = pcall(function(nomsu)
\(%final_action as lua statements)
end, nomsu);
if not ok then nomsu:error(ret1); end
if not ok2 then nomsu:error(ret2); end
if not fell_through then
- return ret1, ret2;
+ return ret1;
end
end
+immediately:
+ compile [with %assignments %action] to code:
+ local [%lua, %olds, %old_vals, %new_vals]
+ set {%temp_vars=[], %old_vals=[], %new_vals=[]}
+ for %i=%assignment in (%assignments' "value"):
+ set (%temp_vars->%i) = "temp\%i"
+ set (%old_vals->%i) = ((%assignment's "dict_key") as lua)
+ set (%new_vals->%i) = ((%assignment's "dict_value") as lua)
+ return ".."
+ do
+ local \(join %temp_vars with ", ") = \(join %old_vals with ", ");
+ \(join %old_vals with ", ") = \(join %new_vals with ", ");
+ local fell_through = false;
+ local ok, ret = pcall(function(nomsu)
+ do
+ \(%action as lua statements)
+ end
+ fell_through = true;
+ end, nomsu);
+ \(join %old_vals with ", ") = \(join %temp_vars with ", ");
+ if not ok then error(ret, 0); end
+ if not fell_through then return ret end
+ end
+
diff --git a/lib/core.nom b/lib/core.nom
index 6714cdf..3b1644c 100644
--- a/lib/core.nom
+++ b/lib/core.nom
@@ -1,7 +1,11 @@
+#..
+ This file imports all the commonly used library files, which can be convenient for
+ avoiding retyping the whole list.
+
use "lib/metaprogramming.nom"
-use "lib/utils.nom"
+use "lib/text.nom"
use "lib/operators.nom"
use "lib/control_flow.nom"
+use "lib/math.nom"
use "lib/collections.nom"
-use "lib/utils2.nom"
lua> "nomsu.core_defs = nomsu.__class.def_number;"
diff --git a/lib/math.nom b/lib/math.nom
new file mode 100644
index 0000000..85e8ac5
--- /dev/null
+++ b/lib/math.nom
@@ -0,0 +1,79 @@
+#..
+ This file defines some common math literals and functions
+
+use "lib/metaprogramming.nom"
+use "lib/control_flow.nom"
+
+# Literals:
+compile [infinity, inf] to: "math.huge"
+compile [not a number, NaN, nan] to: "(0/0)"
+compile [pi, Pi, PI] to: "math.pi"
+compile [tau, Tau, TAU] to: "(2*math.pi)"
+compile [golden ratio] to: "((1+math.sqrt(5))/2)"
+compile [e] to: "math.e"
+
+# Functions:
+compile [% as number] to: "tonumber(\(% as lua))"
+compile [absolute value %, | % |, abs %] to: "math.abs(\(% as lua))"
+compile [square root %, √%, sqrt %] to: "math.sqrt(\(% as lua))"
+compile [sine %, sin %] to: "math.sin(\(% as lua))"
+compile [cosine %, cos %] to: "math.cos(\(% as lua))"
+compile [tangent %, tan %] to: "math.tan(\(% as lua))"
+compile [arc sine %, asin %] to: "math.asin(\(% as lua))"
+compile [arc cosine %, acos %] to: "math.acos(\(% as lua))"
+compile [arc tangent %, atan %] to: "math.atan(\(% as lua))"
+compile [arc tangent %y/%x, atan2 %y %x] to: "math.atan2(\(%y as lua), \(%x as lua))"
+compile [hyperbolic sine %, sinh %] to: "math.sinh(\(% as lua))"
+compile [hyperbolic cosine %, cosh %] to: "math.cosh(\(% as lua))"
+compile [hyperbolic tangent %, tanh %] to: "math.tanh(\(% as lua))"
+compile [e^%, exp %] to: "math.exp(\(% as lua))"
+compile [natural log %, ln %, log %] to: "math.log(\(% as lua))"
+compile [log % base %base, log_%base %, log base %base %] to: "math.log(\(% as lua), \(%base as lua))"
+compile [floor %] to: "math.floor(\(% as lua))"
+compile [ceiling %, ceil %] to: "math.ceil(\(% as lua))"
+compile [round %, % rounded] to: "math.floor(\(% as lua) + .5)"
+action [%n to the nearest %rounder]:
+ =lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"
+
+# Any/all/none
+compile [all of %items, all %items] to:
+ "(\(join ((% as lua) for all (%items' "value")) with " and "))"
+ ..if ((%items' "type") is "List") else "nomsu.utils.all(\(%items as lua))"
+parse [not all of %items, not all %items] as: not (all of %items)
+compile [any of %items, any %items] to:
+ "(\(join ((% as lua) for all (%items' "value")) with " or "))"
+ ..if ((%items' "type") is "List") else "nomsu.utils.any(\(%items as lua))"
+parse [none of %items, none %items] as: not (any of %items)
+compile [sum of %items, sum %items] to:
+ "(\(join ((% as lua) for all (%items' "value")) with " + "))"
+ ..if ((%items' "type") is "List") else "nomsu.utils.sum(\(%items as lua))"
+compile [product of %items, product %items] to:
+ "(\(join ((% as lua) for all (%items' "value")) with " * "))"
+ ..if ((%items' "type") is "List") else "nomsu.utils.product(\(%items as lua))"
+action [avg of %items, average of %items]:
+ =lua "(nomsu.utils.sum(\%items)/#\%items)"
+compile [min of %items, smallest of %items, lowest of %items] to:
+ "nomsu.utils.min(\(%items as lua))"
+compile [max of %items, biggest of %items, largest of %items, highest of %items] to:
+ "nomsu.utils.max(\(%items as lua))"
+compile [min of %items by %value_expr] to: ".."
+ nomsu.utils.min(\(%items as lua), function(\(\% as lua))
+ return \(%value_expr as lua)
+ end)
+compile [max of %items by %value_expr] to: ".."
+ nomsu.utils.max(\(%items as lua), function(\(\% as lua))
+ return \(%value_expr as lua)
+ end)
+
+# Random functions
+action [seed random with %]:
+ lua> ".."
+ math.randomseed(\%);
+ for i=1,20 do; math.random(); end;
+parse [seed random] as: seed random with (=lua "os.time()")
+compile [random number, random, rand] to: "math.random()"
+compile [random int %n, random integer %n, randint %n] to: "math.random(\(%n as lua))"
+compile [random from %low to %high, random number from %low to %high, rand %low %high] to:
+ "math.random(\(%low as lua), \(%high as lua))"
+action [random choice from %elements, random choice %elements, random %elements]:
+ =lua "\%elements[math.random(#\%elements)]"
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index a9c2ecf..55e9bea 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -176,3 +176,23 @@ parse [parse tree %code] as: nomsu "tree_to_str" [\%code]
parse [enable debugging] as: lua> "nomsu.debug = true"
parse [disable debugging] as: lua> "nomsu.debug = false"
+
+compile [say %str] to:
+ lua> ".."
+ if \%str.type == "Text" then
+ return "nomsu:writeln("..\(%str as lua)..")";
+ else
+ return "nomsu:writeln(nomsu:stringify("..\(%str as lua).."))";
+ end
+
+# Error functions
+compile [barf!] to: "error(nil, 0)"
+compile [barf %msg] to: "error(\(%msg as lua), 0)"
+compile [assume %condition] to: "assert(\(%condition as lua))"
+compile [assume %condition or barf %msg] to: "assert(\(%condition as lua), \(%msg as lua))"
+
+# Literals
+compile [yes] to: "true"
+compile [no] to: "false"
+compile [nothing, nil, null] to: "nil"
+
diff --git a/lib/operators.nom b/lib/operators.nom
index 9f93a39..89f940e 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -1,71 +1,61 @@
+#..
+ This file contains definitions of operators like "+" and "and".
+
use "lib/metaprogramming.nom"
-# Literals
-compile [yes] to: "true"
-compile [no] to: "false"
-compile [nil, null] to: "nil"
-compile [infinity, inf] to: "math.huge"
-compile [not a number, NaN, nan] to: "(0/0)"
-compile [pi, Pi, PI] to: "math.pi"
-compile [tau, Tau, TAU] to: "(2*math.pi)"
-compile [phi, Phi, PHI, golden ratio] to: "((1+math.sqrt(5))/2)"
-compile [do nothing] to code: ""
+# Indexing:
+immediately:
+ compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
-# Ternary operator
-#.. Note: this uses a function instead of "(condition and if_expr or else_expr)"
- because that breaks if %if_expr is falsey, e.g. "x < 5 and false or 99"
-compile [..]
- %when_true_expr if %condition else %when_false_expr
- %when_true_expr if %condition otherwise %when_false_expr
- %when_false_expr unless %condition else %when_true_expr
- %when_false_expr unless %condition then %when_true_expr
-..to:
- lua> ".."
- local condition = nomsu:tree_to_lua(\%condition).expr;
- local when_true = nomsu:tree_to_lua(\%when_true_expr).expr;
- local when_false = nomsu:tree_to_lua(\%when_false_expr).expr;
- local safe = {Text=true, List=true, Dict=true, Number=true};
- if safe[\%when_true_expr.type] then
- return "("..condition.." and "..when_true.." or "..when_false..")";
- else
- return ([[
- (function(nomsu)
- if %s then
- return %s;
+# Comparison Operators
+immediately:
+ compile [%x < %y] to: "(\(%x as lua) < \(%y as lua))"
+ compile [%x > %y] to: "(\(%x as lua) > \(%y as lua))"
+ compile [%x <= %y] to: "(\(%x as lua) <= \(%y as lua))"
+ compile [%x >= %y] to: "(\(%x as lua) >= \(%y as lua))"
+ compile [%a is %b, %a = %b, %a == %b] to:
+ lua> ".."
+ local safe = {Text=true, Number=true};
+ local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
+ if safe[\%a.type] or safe[\%b.type] then
+ return "("..a_lua.." == "..b_lua..")";
else
- return %s;
+ return "nomsu.utils.equivalent("..a_lua..", "..b_lua..")";
end
- end)(nomsu)]]):format(condition, when_true, when_false);
- end
-
-# Indexing:
-compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
-
-# Substring
-# TODO: improve this syntax
-compile [%str |%start|] to: "\(%str as lua):sub(\(%start as lua), \(%start as lua))"
-compile [%str |%start - %stop|] to: "\(%str as lua):sub(\(%start as lua), \(%stop as lua))"
+ compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to:
+ lua> ".."
+ local safe = {Text=true, Number=true};
+ local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
+ if safe[\%a.type] or safe[\%b.type] then
+ return "("..a_lua.." ~= "..b_lua..")";
+ else
+ return "(not nomsu.utils.equivalent("..a_lua..", "..b_lua.."))";
+ end
+ # For strict identity checking, use (%x's id) is (%y's id)
+ compile [%'s id, id of %] to: "nomsu.ids[\(% as lua)]"
# Variable assignment operator, and += type versions
-compile [local %vars] to code:
- lua> ".."
- local locals = \%vars.type == "List" and \%vars.value or {\%vars};
- local identifiers = {};
- for i,x in ipairs(locals) do
- identifiers[i] = nomsu:tree_to_lua(x).expr;
- end
- return "local "..table.concat(identifiers, ", ");
-compile [set %var = %val] to code:
- lua> ".."
- if \%var.type == 'List' and \%val.type == 'List' then
- local lhs = {};
- for i,x in ipairs(\%var.value) do lhs[i] = nomsu:tree_to_lua(x).expr; end
- local rhs = {};
- for i,x in ipairs(\%val.value) do rhs[i] = nomsu:tree_to_lua(x).expr; end
+immediately:
+ compile [local %vars] to code:
+ lua> ".."
+ local locals = \%vars.type == "List" and \%vars.value or {\%vars};
+ local identifiers = {};
+ for i,x in ipairs(locals) do
+ identifiers[i] = nomsu:tree_to_lua(x).expr;
+ end
+ return "local "..table.concat(identifiers, ", ");
+ compile [set %var = %val] to code: "\(%var as lua) = \(%val as lua);"
+ compile [set %assignments] to code:
+ assume ((%assignments' "type") is "Dict") or barf "Expected Dict, but got \(%assignments' "type")"
+ lua> ".."
+ local lhs, rhs = {}, {};
+ for i,entry in ipairs(\%assignments.value) do
+ lhs[i] = nomsu:tree_to_lua(entry.dict_key).expr;
+ rhs[i] = nomsu:tree_to_lua(entry.dict_value).expr;
+ end
return table.concat(lhs, ", ").." = "..table.concat(rhs, ", ")..";";
- else
- return \(%var as lua).." = "..\(%val as lua)..";";
- end
+
+# Update assignment operators
compile [%var += %val] to code: "\(%var as lua) = \(%var as lua) + \(%val as lua);"
compile [%var -= %val] to code: "\(%var as lua) = \(%var as lua) - \(%val as lua);"
compile [%var *= %val] to code: "\(%var as lua) = \(%var as lua) * \(%val as lua);"
@@ -84,32 +74,6 @@ compile [%x / %y] to: "(\(%x as lua) / \(%y as lua))"
compile [%x ^ %y] to: "(\(%x as lua) ^ \(%y as lua))"
compile [%x wrapped around %y, %x mod %y] to: "(\(%x as lua) % \(%y as lua))"
-# Comparison Operators
-compile [%x < %y] to: "(\(%x as lua) < \(%y as lua))"
-compile [%x > %y] to: "(\(%x as lua) > \(%y as lua))"
-compile [%x <= %y] to: "(\(%x as lua) <= \(%y as lua))"
-compile [%x >= %y] to: "(\(%x as lua) >= \(%y as lua))"
-compile [%a is %b, %a = %b, %a == %b] to:
- lua> ".."
- local safe = {Text=true, Number=true};
- local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
- if safe[\%a.type] or safe[\%b.type] then
- return "("..a_lua.." == "..b_lua..")";
- else
- return "nomsu.utils.equivalent("..a_lua..", "..b_lua..")";
- end
-compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to:
- lua> ".."
- local safe = {Text=true, Number=true};
- local a_lua, b_lua = nomsu:tree_to_lua(\%a).expr, nomsu:tree_to_lua(\%b).expr;
- if safe[\%a.type] or safe[\%b.type] then
- return "("..a_lua.." ~= "..b_lua..")";
- else
- return "(not nomsu.utils.equivalent("..a_lua..", "..b_lua.."))";
- end
-# For strict identity checking, use (%x's id) is (%y's id)
-compile [%'s id, id of %] to: "nomsu.ids[\(% as lua)]"
-
# 3-part chained comparisons
# (uses a lambda to avoid re-evaluating middle value, while still being an expression)
parse [%x < %y < %z] as: =lua "(function(x,y,z) return x < y and y < z; end)(\%x,\%y,\%z)"
diff --git a/lib/text.nom b/lib/text.nom
index 7fa1a2c..7c06d07 100644
--- a/lib/text.nom
+++ b/lib/text.nom
@@ -1,32 +1,89 @@
+#..
+ This file contains some definitions of text escape sequences, including ANSI console
+ color codes.
+
use "lib/metaprogramming.nom"
-use "lib/control_flow.nom"
-use "lib/collections.nom"
-local [%ansi, %colors]
-set %ansi = {..}
- nl="\\n", newline="\\n", tab="\\t", bell="\\a", cr="\\r", "carriage return"="\\r"
- backspace="\\b", "form feed"="\\f", formfeed="\\f", "vertical tab"="\\v"
+# Text functions
+action [join %strs with %glue]:
+ lua> ".."
+ local str_bits = {}
+ for i,bit in ipairs(\%strs) do str_bits[i] = nomsu:stringify(bit) end
+ return table.concat(str_bits, \%glue)
+parse [join %strs] as: join %strs with ""
-set %colors = {..}
- "reset color"="\\27[0m", bright="\\27[1m", dim="\\27[2m", underscore="\\27[4m"
- blink="\\27[5m", inverse="\\27[7m", hidden="\\27[8m"
+compile [capitalize %str, %str capitalized] to:
+ "(\(%str as lua)):gsub('%l', string.upper, 1)"
- black="\\27[30m", red="\\27[31m", green="\\27[32m", yellow="\\27[33m", blue="\\27[34m"
- magenta="\\27[35m", cyan="\\27[36m", white="\\27[37m"
+compile [%str with %patt replaced with %sub, %str s/%patt/%sub] to:
+ "((\(%str as lua)):gsub(\(%patt as lua), \(%sub as lua)))"
+compile [%str with %patt replaced with %sub %n times, %str s/%patt/%sub/%n] to:
+ "((\(%str as lua)):gsub(\(%patt as lua), \(%sub as lua), \(%n as lua)))"
- "on black"="\\27[40m", "on red"="\\27[41m", "on green"="\\27[42m", "on yellow"="\\27[43m"
- "on blue"="\\27[44m", "on magenta"="\\27[45m", "on cyan"="\\27[46m", "on white"="\\27[47m"
+# Substring
+# TODO: improve this syntax
+compile [%str |%start|] to: "\(%str as lua):sub(\(%start as lua), \(%start as lua))"
+compile [%str |%start - %stop|] to: "\(%str as lua):sub(\(%start as lua), \(%stop as lua))"
-for %name=%str in %ansi:
- lua> ".."
- local e = "'"..\%str.."'";
- nomsu:define_compile_action(\%name, \(__line_no__), function(nomsu) return {expr=e}; end, \(__src__ 1));
+# Text literals
+lua do> ".."
+ local escapes = {
+ nl="\\\\n", newline="\\\\n", tab="\\\\t", bell="\\\\a", cr="\\\\r", ["carriage return"]="\\\\r",
+ backspace="\\\\b", ["form feed"]="\\\\f", formfeed="\\\\f", ["vertical tab"]="\\\\v",
+ };
+ local colors = {
+ ["reset color"]="\\\\27[0m", bright="\\\\27[1m", dim="\\\\27[2m", underscore="\\\\27[4m",
+ blink="\\\\27[5m", inverse="\\\\27[7m", hidden="\\\\27[8m",
-for %name=%str in %colors:
- lua> ".."
- local e = "'"..\%str.."'";
- local reset = "'"..\(%colors->"reset color").."'";
- nomsu:define_compile_action(\%name, \(__line_no__), function(nomsu) return {expr=e}; end, \(__src__ 1));
- nomsu:define_compile_action(\%name.." %", \(__line_no__), function(nomsu, _)
- return {expr=e..".."..nomsu:tree_to_lua(_).expr..".."..reset};
+ black="\\\\27[30m", red="\\\\27[31m", green="\\\\27[32m", yellow="\\\\27[33m", blue="\\\\27[34m",
+ magenta="\\\\27[35m", cyan="\\\\27[36m", white="\\\\27[37m",
+
+ ["on black"]="\\\\27[40m", ["on red"]="\\\\27[41m", ["on green"]="\\\\27[42m", ["on yellow"]="\\\\27[43m",
+ ["on blue"]="\\\\27[44m", ["on magenta"]="\\\\27[45m", ["on cyan"]="\\\\27[46m", ["on white"]="\\\\27[47m",
+ };
+ for name, e in pairs(escapes) do
+ local lua = "'"..e.."'";
+ nomsu:define_compile_action(name, \(__line_no__), function() return {expr=str}; end, \(__src__ 1));
+ end
+ for name, c in pairs(colors) do
+ local color = "'"..c.."'";
+ local reset = "'"..colors["reset color"].."'";
+ nomsu:define_compile_action(name, \(__line_no__), function() return {expr=color}; end, \(__src__ 1));
+ nomsu:define_compile_action(name.." %", \(__line_no__), function(nomsu, _)
+ return {expr=color..".."..nomsu:tree_to_lua(_).expr..".."..reset};
end, \(__src__ 1));
+ end
+
+#..
+ use "lib/control_flow.nom"
+ use "lib/collections.nom"
+ local [%ansi, %colors]
+ set %ansi = {..}
+ nl="\\n", newline="\\n", tab="\\t", bell="\\a", cr="\\r", "carriage return"="\\r"
+ backspace="\\b", "form feed"="\\f", formfeed="\\f", "vertical tab"="\\v"
+
+ set %colors = {..}
+ "reset color"="\\27[0m", bright="\\27[1m", dim="\\27[2m", underscore="\\27[4m"
+ blink="\\27[5m", inverse="\\27[7m", hidden="\\27[8m"
+
+ black="\\27[30m", red="\\27[31m", green="\\27[32m", yellow="\\27[33m", blue="\\27[34m"
+ magenta="\\27[35m", cyan="\\27[36m", white="\\27[37m"
+
+ "on black"="\\27[40m", "on red"="\\27[41m", "on green"="\\27[42m", "on yellow"="\\27[43m"
+ "on blue"="\\27[44m", "on magenta"="\\27[45m", "on cyan"="\\27[46m", "on white"="\\27[47m"
+
+ for %name=%str in %ansi:
+ lua> ".."
+ local e = "'"..\%str.."'";
+ nomsu:define_compile_action(\%name, \(__line_no__), function(nomsu) return {expr=e}; end, \(__src__ 1));
+
+ for %name=%str in %colors:
+ lua> ".."
+ local e = "'"..\%str.."'";
+ local reset = "'"..\(%colors->"reset color").."'";
+ nomsu:define_compile_action(\%name, \(__line_no__), function(nomsu) return {expr=e}; end, \(__src__ 1));
+ nomsu:define_compile_action(\%name.." %", \(__line_no__), function(nomsu, _)
+ return {expr=e..".."..nomsu:tree_to_lua(_).expr..".."..reset};
+ end, \(__src__ 1));
+
+# FIXME
diff --git a/lib/training_wheels.nom b/lib/training_wheels.nom
index e5fec96..ad4e8df 100644
--- a/lib/training_wheels.nom
+++ b/lib/training_wheels.nom
@@ -1,3 +1,7 @@
+#..
+ This file contains a set of definitions that bring some familiar language features
+ from other languages into nomsu (e.g. "==" and "continue")
+
use "lib/core.nom"
parse [%a == %b] as: %a is %b
@@ -20,3 +24,4 @@ parse [let %assignments in %action] as: with %assignemnts %action
parse [error!, panic!, fail!, abort!] as: barf!
parse [error %, panic %, fail %, abort %] as: barf %
parse [assert %condition %message] as: assume %condition or barf %message
+parse [%cond ? %if_true %if_false] as: %if_true if %cond else %if_false
diff --git a/lib/utils.nom b/lib/utils.nom
deleted file mode 100644
index 2b72080..0000000
--- a/lib/utils.nom
+++ /dev/null
@@ -1,95 +0,0 @@
-use "lib/metaprogramming.nom"
-
-# Error functions
-action [barf!]:
- nomsu "error" []
-action [barf %msg]:
- nomsu "error"[%msg]
-compile [assume %condition or barf %msg] to code: ".."
- if not (\(%condition as lua)) then
- nomsu:error(\(%msg as lua));
- end
-
-parse [assume %condition] as: assume %condition or barf (nil)
-
-# Text functions
-action [join %strs with glue %glue]:
- lua do> ".."
- local str_bits = {}
- for i,bit in ipairs(\%strs) do str_bits[i] = nomsu:stringify(bit) end
- return table.concat(str_bits, \%glue)
-parse [join %strs] as: join %strs with glue ""
-
-compile [capitalize %str, %str capitalized] to:
- "(\(%str as lua)):gsub('%l', string.upper, 1)"
-
-compile [%str with %patt replaced with %sub, %str s/%patt/%sub] to:
- "((\(%str as lua)):gsub(\(%patt as lua), \(%sub as lua)))"
-compile [%str with %patt replaced with %sub %n times, %str s/%patt/%sub/%n] to:
- "((\(%str as lua)):gsub(\(%patt as lua), \(%sub as lua), \(%n as lua)))"
-
-# Number ranges
-compile [%start to %stop by %step, %start to %stop via %step] to: ".."
- nomsu.utils.range(\(%start as lua), \(%stop as lua), \(%step as lua))
-
-parse [%start to %stop] as: %start to %stop by 1
-
-# Random functions
-lua> ".." # Seed
- math.randomseed(os.time());
- for i=1,20 do; math.random(); end;
-compile [random number, random, rand] to: "math.random()"
-compile [random int %n, random integer %n, randint %n] to: "math.random(\(%n as lua))"
-compile [random from %low to %high, random number from %low to %high, rand %low %high] to:
- "math.random(\(%low as lua), \(%high as lua))"
-action [random choice from %elements, random choice %elements, random %elements]:
- =lua "\%elements[math.random(#\%elements)]"
-
-# Math functions
-compile [% as number] to: "tonumber(\(% as lua))"
-compile [abs %, absolute value of %, | % |] to: "math.abs(\(% as lua))"
-compile [sqrt %, square root of %] to: "math.sqrt(\(% as lua))"
-compile [sin %, sine %] to: "math.sin(\(% as lua))"
-compile [cos %, cosine %] to: "math.cos(\(% as lua))"
-compile [tan %, tangent %] to: "math.tan(\(% as lua))"
-compile [asin %, arc sine %] to: "math.asin(\(% as lua))"
-compile [acos %, arc cosine %] to: "math.acos(\(% as lua))"
-compile [atan %, arc tangent %] to: "math.atan(\(% as lua))"
-compile [atan2 %y %x] to: "math.atan2(\(%y as lua), \(%x as lua))"
-compile [sinh %, hyperbolic sine %] to: "math.sinh(\(% as lua))"
-compile [cosh %, hyperbolic cosine %] to: "math.cosh(\(% as lua))"
-compile [tanh %, hyperbolic tangent %] to: "math.tanh(\(% as lua))"
-compile [ceil %, ceiling %] to: "math.ceil(\(% as lua))"
-compile [exp %, e^ %] to: "math.exp(\(% as lua))"
-compile [log %, ln %, natural log %] to: "math.log(\(% as lua))"
-compile [log % base %base] to: "math.log(\(% as lua), \(%base as lua))"
-compile [floor %] to: "math.floor(\(% as lua))"
-compile [round %, % rounded] to: "math.floor(\(% as lua) + .5)"
-action [%n rounded to the nearest %rounder]:
- =lua "(\%rounder)*math.floor((\%n / \%rounder) + .5)"
-compile [tau] to: "(2*math.pi)"
-compile [pi] to: "math.pi"
-compile [e] to: "math.e"
-compile [golden ratio, phi] to: "((1 + math.sqrt(5)) / 2)"
-
-# Common utility functions
-action [avg of %items, average of %items]:
- =lua "(nomsu.utils.sum(\%items)/#\%items)"
-compile [min of %items, smallest of %items, lowest of %items] to:
- "nomsu.utils.min(\(%items as lua))"
-compile [max of %items, biggest of %items, largest of %items, highest of %items] to:
- "nomsu.utils.max(\(%items as lua))"
-compile [min of %items by %value_expr] to: ".."
- nomsu.utils.min(\(%items as lua), function(\(\% as lua))
- return \(%value_expr as lua)
- end)
-compile [max of %items by %value_expr] to: ".."
- nomsu.utils.max(\(%items as lua), function(\(\% as lua))
- return \(%value_expr as lua)
- end)
-compile [sort %items] to: "table.sort(\(%items as lua))"
-compile [sort %items by %key_expr] to: ".."
- nomsu.utils.sort(\(%items as lua), function(\(\% as lua))
- return \(%key_expr as lua);
- end)
-
diff --git a/lib/utils2.nom b/lib/utils2.nom
deleted file mode 100644
index c5da98e..0000000
--- a/lib/utils2.nom
+++ /dev/null
@@ -1,63 +0,0 @@
-use "lib/metaprogramming.nom"
-use "lib/utils.nom"
-use "lib/control_flow.nom"
-use "lib/operators.nom"
-use "lib/collections.nom"
-
-
-compile [say %str] to:
- "nomsu:writeln(\(%str as lua))" if ((%str's "type") is "Text")
- ..else "nomsu:writeln(nomsu:stringify(\(%str as lua)))"
-
-compile [do %action] to code:
- (%action as lua statements) if ((%action's "type") is "Block")
- ..else "(\(%action as lua))(nomsu);"
-
-# With statement
-compile [with %assignments %action] to code:
- set %data = []
- for %i = %assignment in (%assignments' "value"):
- set %tokens = (%assignment's "value")
- set %var = (%tokens -> 1)
- set %eq = (%tokens -> 2)
- assume (=lua "\%eq and \%eq.type == 'Word' and \%eq.value == '='") or barf ".."
- Invalid format for 'with' statement. List entries must have the form %var = (value)
- set %value = (%tokens -> 3)
- add {i=%i, var=%var, value=%value} to %data
- set %setup = (..)
- join (..)
- "local old_value\(%->"i") = \((%->"var") as lua); \((%->"var") as lua) = \((%->"value") as lua);"
- ..for all %data
- ..with glue "\n "
- return ".."
- do
- \%setup
- local fell_through = false;
- local ok, ret1, ret2 = pcall(function(nomsu)
- \(%action as lua statements);
- fell_through = true;
- end, nomsu);
- \(join ("\((%->"var") as lua) = old_value\(%->"i");" for all %data) with glue "\n ")
- if not ok then nomsu:error(ret1); end
- if not fell_through then
- return ret1, ret2;
- end
- end
-parse [with %thing = %value %action] as: with [%thing = %value] %action
-
-# Any/all/none
-compile [all of %items, all %items] to:
- "(\(join ((% as lua) for all (%items' "value")) with glue " and "))"
- ..if ((%items' "type") is "List") else "nomsu.utils.all(\(%items as lua))"
-parse [not all of %items, not all %items] as: not (all of %items)
-compile [any of %items, any %items] to:
- "(\(join ((% as lua) for all (%items' "value")) with glue " or "))"
- ..if ((%items' "type") is "List") else "nomsu.utils.any(\(%items as lua))"
-parse [none of %items, none %items] as: not (any of %items)
-
-compile [sum of %items, sum %items] to:
- "(\(join ((% as lua) for all (%items' "value")) with glue " + "))"
- ..if ((%items' "type") is "List") else "nomsu.utils.sum(\(%items as lua))"
-compile [product of %items, product %items] to:
- "(\(join ((% as lua) for all (%items' "value")) with glue " * "))"
- ..if ((%items' "type") is "List") else "nomsu.utils.product(\(%items as lua))"