aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-12-13 16:29:15 -0800
committerBruce Hill <bitbucket@bruce-hill.com>2017-12-13 16:29:15 -0800
commit536a3ba64931946f81140e6a6d13f612a47a41d9 (patch)
treefdf6975057207af248d5c345671e09be79498318
parent0c1c406ce0d1c19508653181d8cef75f976677a5 (diff)
Got it working.
-rw-r--r--lib/collections.nom62
-rw-r--r--lib/control_flow.nom196
-rw-r--r--lib/metaprogramming.nom145
-rw-r--r--lib/operators.nom133
-rw-r--r--lib/scopes.nom6
-rw-r--r--lib/utils.nom95
-rw-r--r--lib/utils2.nom28
-rw-r--r--nomsu.lua47
-rwxr-xr-xnomsu.moon34
9 files changed, 377 insertions, 369 deletions
diff --git a/lib/collections.nom b/lib/collections.nom
index 02729c5..41710a6 100644
--- a/lib/collections.nom
+++ b/lib/collections.nom
@@ -20,12 +20,12 @@ parse [last in %list, last %list] as: 1 st to last in %list
# Dict iteration convenience function. This could also be accomplished with: for all (entries in %dict): ...
compile [for %key = %value in %dict %body] to code: ".."
- |do;
- | for k, v in pairs(\(%dict as lua)) do;
- | \(%key as lua), \(%value as lua) = k, v;
- | \(%body as lua statements)
- | end;
- |end;
+ do
+ for k, v in pairs(\(%dict as lua)) do
+ \(%key as lua), \(%value as lua) = k, v;
+ \(%body as lua statements)
+ end
+ end
# Membership testing
rule [%item is in %list, %list contains %item, %list has %item] =:
@@ -43,7 +43,7 @@ rule [..]
return (yes)
compile [%list has key %index, %list has index %index] to: ".."
- |((\(%list as lua))[\(%index as lua)] ~= nil)
+ ((\(%list as lua))[\(%index as lua)] ~= nil)
compile [..]
%list doesn't have key %index, %list does not have key %index
@@ -56,7 +56,7 @@ compile [length of %list, size of %list, size %list, number of %list, len %list]
# Chained lookup
compile [%list ->* %indices] to:
assert ((%indices's "type") == "List") ".."
- |Expected List for chained lookup, not \(%indices's "type")
+ Expected List for chained lookup, not \(%indices's "type")
%ret = "\(%list as lua)"
for %index in (%indices's "value"):
%ret join= "[\(%index as lua)]"
@@ -98,20 +98,20 @@ compile [dict %items, d %items] to:
%item_codes = []
for %func_call in (%items's "value"):
assert ((%func_call's "type") == "FunctionCall") ".."
- |Invalid format for 'dict' expression. Only literals are allowed.
+ Invalid format for 'dict' expression. Only literals are allowed.
%tokens = (%func_call's "value")
%equals = (%tokens -> 2)
assert (=lua "#\(%tokens) == 3 and \(%equals) and \(%equals).type == 'Word' and \(%equals).value == '='") ".."
- |Invalid format for 'dict' expression. Lines must only have the "% = %" format, not \(%func_call's "src")
+ Invalid format for 'dict' expression. Lines must only have the "% = %" format, not \(%func_call's "src")
%key = (%tokens -> 1)
lua> ".."
- |if \(%key).type == "Word" and \(%key).value:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
- | \(%key_code) = \(%key).value;
- |elseif \(%key).type == "Word" then
- | \(%key_code) = "["..nomsu:repr(\(%key).value).."]";
- |else
- | \(\{%key_code = "[\((%key as lua))]"} as lua statements)
- |end
+ if \(%key).type == "Word" and \(%key).value:match("^[a-zA-Z_][a-zA-Z0-9_]*$") then
+ \(%key_code) = \(%key).value;
+ elseif \(%key).type == "Word" then
+ \(%key_code) = "["..nomsu:repr(\(%key).value).."]";
+ else
+ \(\{%key_code = "[\((%key as lua))]"} as lua statements)
+ end
add "\(%key_code) = \((%tokens -> 3) as lua)" to %item_codes
return "{\(join %item_codes with glue ",\n")}"
..else:
@@ -139,16 +139,16 @@ rule [values in %dict] =:
# List Comprehension
compile [%expression for %var in %iterable] to:
assert ((%var's "type") == "Var") ".."
- |List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%var's "type")
+ List comprehension has the wrong type for the loop variable. Expected Var, but got: \(%var's "type")
".."
- |(function(game, vars);
- | local comprehension = {};
- | for i,value in ipairs(\(%iterable as lua)) do;
- | \(%var as lua) = value;
- | comprehension[i] = \(%expression as lua);
- | end;
- | return comprehension;
- |end)(game, setmetatable({}, {__index=vars}))
+ (function(game, vars);
+ local comprehension = {};
+ for i,value in ipairs(\(%iterable as lua)) do;
+ \(%var as lua) = value;
+ comprehension[i] = \(%expression as lua);
+ end;
+ return comprehension;
+ end)(game, setmetatable({}, {__index=vars}))
parse [%expression for all %iterable] as: %expression for % in %iterable
rule [%items sorted] =:
@@ -165,11 +165,11 @@ rule [unique %items] =:
# Metatable stuff
compile [counter] to: "setmetatable({}, {__index=function() return 0; end})"
compile [default dict] to: ".."
- |setmetatable({}, {__index=function(self, key)
- | t = {};
- | self[key] = t;
- | return t;
- |end})"
+ setmetatable({}, {__index=function(self, key)
+ t = {};
+ self[key] = t;
+ return t;
+ end})"
rule [chain %dict to %fallback] =:
when (type of %fallback) == ?:
* "table":
diff --git a/lib/control_flow.nom b/lib/control_flow.nom
index 2d1a6a4..b7b5f19 100644
--- a/lib/control_flow.nom
+++ b/lib/control_flow.nom
@@ -4,20 +4,20 @@ require "lib/utils.nom"
# Conditionals
compile [if %condition %if_body] to code: ".."
- |if \(%condition as lua) then
- |\(%if_body as lua statements)
- |end --end if
+ if \(%condition as lua) then
+ \(%if_body as lua statements)
+ end --end if
compile [unless %condition %body] to code: ".."
- |if not (\(%condition as lua)) then
- |\(%body as lua statements)
- |end --end if
+ if not (\(%condition as lua)) then
+ \(%body as lua statements)
+ end --end if
compile [if %condition %if_body else %else_body, unless %condition %else_body else %if_body] to code: ".."
- |if \(%condition as lua) then
- |\(%if_body as lua statements)
- |else
- |\(%else_body as lua statements)
- |end --end if
+ if \(%condition as lua) then
+ \(%if_body as lua statements)
+ else
+ \(%else_body as lua statements)
+ end --end if
# Return
compile [return] to code: "do return; end"
@@ -25,20 +25,20 @@ compile [return %return_value] to code: "do return \(%return_value as lua); end"
# GOTOs
compile [-> %label] to code: ".."
- |::label_\(nomsu "var_to_lua_identifier" [%label])::;
+ ::label_\(nomsu "var_to_lua_identifier" [%label])::;
compile [go to %label] to code: ".."
- |goto label_\(nomsu "var_to_lua_identifier" [%label]);
+ goto label_\(nomsu "var_to_lua_identifier" [%label]);
rule [tree %tree has function call %call] =:
lua> ".."
- |local target = (\(%call)).value;
- |for subtree,_ in coroutine.wrap(function() nomsu:walk_tree(\(%tree)); end) do
- | if type(subtree) == 'table' and subtree.type == "FunctionCall"
- | and nomsu.utils.equivalent(subtree.value, target, 2) then
- | return true;
- | end
- |end
- |do return false; end
+ local target = (\(%call)).value;
+ for subtree,_ in coroutine.wrap(function() nomsu:walk_tree(\(%tree)); end) do
+ if type(subtree) == 'table' and subtree.type == "FunctionCall"
+ and nomsu.utils.equivalent(subtree.value, target, 2) then
+ return true;
+ end
+ end
+ do return false; end
# While loops
compile [do next repeat-loop] to code: "goto continue_repeat;"
@@ -47,15 +47,15 @@ compile [repeat while %condition %body] to code:
%continue_labels = (..)
"\n::continue_repeat::;" if (tree %body has function call \(do next repeat-loop)) else ""
%code = ".."
- |while \(%condition as lua) do
- |\(%body as lua statements)\(%continue_labels)
- |end --while-loop
+ while \(%condition as lua) do
+ \(%body as lua statements)\(%continue_labels)
+ end --while-loop
if (tree %body has function call \(stop repeat-loop)):
return ".."
- |do --while-loop label scope
- |\(%code)
- |::stop_repeat::;
- |end --while-loop label scope
+ do --while-loop label scope
+ \(%code)
+ ::stop_repeat::;
+ end --while-loop label scope
return %code
parse [repeat %body] as: repeat while (true) %body
parse [repeat until %condition %body] as: repeat while (not %condition) %body
@@ -63,10 +63,10 @@ parse [repeat until %condition %body] as: repeat while (not %condition) %body
# For loop control flow:
compile [stop for-loop] to code: "goto stop_for;"
compile [stop %var] to code: ".."
- |goto stop_\(nomsu "var_to_lua_identifier" [%var]);
+ goto stop_\(nomsu "var_to_lua_identifier" [%var]);
compile [do next for-loop] to code: "goto continue_for;"
compile [do next %var] to code: ".."
- |goto continue_\(nomsu "var_to_lua_identifier" [%var]);
+ goto continue_\(nomsu "var_to_lua_identifier" [%var]);
# Numeric range for loops
compile [..]
@@ -78,21 +78,21 @@ compile [..]
%continue_labels join= "\n::continue_for::;"
if (tree %body has function call (nomsu "replaced_vars" [\(do next %), =lua "{['']=\(%var)}"])):
%continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ # This trashes the loop variables, just like in Python.
%code = ".."
- |for i=\(%start as lua),\(%stop as lua),\(%step as lua) do
- # This trashes the loop variables, just like in Python.
- |\(%var as lua) = i;
- |\(%body as lua statements)\(%continue_labels)
- |end --numeric for-loop
+ for i=\(%start as lua),\(%stop as lua),\(%step as lua) do
+ \(%var as lua) = i;
+ \(%body as lua statements)\(%continue_labels)
+ end --numeric for-loop
%stop_labels = ""
if (tree %body has function call \(stop for-loop)):
%stop_labels join= "\n::stop_for::;"
if (tree %body has function call (nomsu "replaced_vars" [\(stop %), =lua "{['']=\(%var)}"])):
%stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
if (%stop_labels != ""): ".."
- |do --for-loop label scope
- |\(%code)\(%stop_labels)
- |end --for-loop label scope
+ do --for-loop label scope
+ \(%code)\(%stop_labels)
+ end --for-loop label scope
..else: %code
parse [for %var from %start to %stop %body] as: for %var from %start to %stop via 1 %body
parse [..]
@@ -107,21 +107,21 @@ compile [for %var in %iterable %body] to code:
%continue_labels join= "\n::continue_for::;"
if (tree %body has function call (nomsu "replaced_vars" [\(do next %), =lua "{['']=\(%var)}"])):
%continue_labels join= "\n::continue_\(nomsu "var_to_lua_identifier" [%var])::;"
+ # This trashes the loop variables, just like in Python.
%code = ".."
- |for i,value in ipairs(\(%iterable as lua)) do
- # This trashes the loop variables, just like in Python.
- |\(%var as lua) = value;
- |\(%body as lua statements)\(%continue_labels)
- |end --foreach-loop
+ for i,value in ipairs(\(%iterable as lua)) do
+ \(%var as lua) = value;
+ \(%body as lua statements)\(%continue_labels)
+ end --foreach-loop
%stop_labels = ""
if (tree %body has function call \(stop for-loop)):
%stop_labels join= "\n::stop_for::;"
if (tree %body has function call (nomsu "replaced_vars" [\(stop %), =lua "{['']=\(%var)}"])):
%stop_labels join= "\n::stop_\(nomsu "var_to_lua_identifier" [%var])::;"
if (%stop_labels != ""): ".."
- |do --for-loop label scope
- |\(%code)\(%stop_labels)
- |end --for-loop label scope
+ do --for-loop label scope
+ \(%code)\(%stop_labels)
+ end --for-loop label scope
..else: %code
parse [for all %iterable %body] as: for % in %iterable %body
@@ -133,15 +133,15 @@ compile [when %body] to code:
%first = (yes)
for %func_call in (%body's "value"):
assert ((%func_call's "type") == "FunctionCall") ".."
- |Invalid format for 'when' statement. Only '*' blocks are allowed.
+ Invalid format for 'when' statement. Only '*' blocks are allowed.
%tokens = (%func_call's "value")
%star = (%tokens -> 1)
assert (=lua "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".."
- |Invalid format for 'when' statement. Lines must begin with '*'
+ Invalid format for 'when' statement. Lines must begin with '*'
%condition = (%tokens -> 2)
assert %condition ".."
- |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
%action = (%tokens -> 3)
if (%action == (nil)):
@@ -150,18 +150,18 @@ compile [when %body] to code:
if (=lua "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
%result join= ".."
- |
- |else
- |\(%action as lua statements)
+
+ else
+ \(%action as lua statements)
stop for-loop
..else:
%condition = (%condition as lua)
for all %fallthroughs:
%condition join= " or \(% as lua)"
%result join= ".."
- |
- |\("if" if %first else "elseif") \(%condition) then
- |\(%action as lua statements)
+
+ \("if" if %first else "elseif") \(%condition) then
+ \(%action as lua statements)
%fallthroughs = []
%first = (no)
@@ -177,15 +177,15 @@ compile [when %branch_value == ? %body] to code:
%first = (yes)
for %func_call in (%body's "value"):
assert ((%func_call's "type") == "FunctionCall") ".."
- |Invalid format for 'when' statement. Only '*' blocks are allowed.
+ Invalid format for 'when' statement. Only '*' blocks are allowed.
%tokens = (%func_call's "value")
%star = (%tokens -> 1)
assert (=lua "vars.star and vars.star.type == 'Word' and vars.star.value == '*'") ".."
- |Invalid format for 'when' statement. Lines must begin with '*'
+ Invalid format for 'when' statement. Lines must begin with '*'
%condition = (%tokens -> 2)
assert %condition ".."
- |Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
+ Invalid format for 'when' statement. Lines must begin with '*' and have a condition or the word "else"
%action = (%tokens -> 3)
if (%action == (nil)):
@@ -194,28 +194,28 @@ compile [when %branch_value == ? %body] to code:
if (=lua "vars.condition.type == 'Word' and vars.condition.value == 'else'"):
%result join= ".."
- |
- |else
- |\(%action as lua statements)
+
+ else
+ \(%action as lua statements)
stop for-loop
..else:
%condition = "branch_value == (\(%condition as lua))"
for all %fallthroughs:
%condition join= " or (branch_value == \(% as lua))"
%result join= ".."
- |
- |\("if" if %first else "elseif") \(%condition) then
- |\(%action as lua statements)
+
+ \("if" if %first else "elseif") \(%condition) then
+ \(%action as lua statements)
%fallthroughs = []
%first = (no)
if (%result != ""):
%result = ".."
- |do --when == ?
- |local branch_value = \(%branch_value as lua);\(%result)
- |end
- |end --when == ?
+ do --when == ?
+ local branch_value = \(%branch_value as lua);\(%result)
+ end
+ end --when == ?
%result
# Try/except
@@ -223,21 +223,21 @@ compile [..]
try %action and if it succeeds %success or if it fails %fallback
try %action and if it fails %fallback or if it succeeds %success
..to code: ".."
- |do
- | local fell_through = false;
- | local ok, ret1, ret2 = pcall(function(nomsu, vars)
- | \(%action as lua statements)
- | fell_through = true;
- | end, nomsu, vars);
- | if ok then
- | \(%success as lua statements)
- | end
- | if not ok then
- | \(%fallback as lua statements)
- | elseif not fell_through then
- | return ret1, ret2;
- | end
- |end
+ do
+ local fell_through = false;
+ local ok, ret1, ret2 = pcall(function(nomsu, vars)
+ \(%action as lua statements)
+ fell_through = true;
+ end, nomsu, vars);
+ if ok then
+ \(%success as lua statements)
+ end
+ if not ok then
+ \(%fallback as lua statements)
+ elseif not fell_through then
+ return ret1, ret2;
+ end
+ end
parse [try %action] as:
try %action and if it succeeds {pass} or if it fails {pass}
parse [try %action and if it fails %fallback] as:
@@ -247,19 +247,19 @@ parse [try %action and if it succeeds %success] as:
# Do/finally:
compile [do %action then always %final_action] to code: ".."
- |do
- | local fell_through = false;
- | local ok, ret1, ret2 = pcall(function(nomsu, vars)
- | \(%action as lua statements)
- | fell_through = true;
- | end, nomsu, vars);
- | local ok2, _ = pcall(function(nomsu, vars)
- | \(%final_action as lua statements)
- | end, nomsu, vars);
- | if not ok then nomsu:error(ret1); end
- | if not ok2 then nomsu:error(ret2); end
- | if not fell_through then
- | return ret1, ret2;
- | end
- |end
+ do
+ local fell_through = false;
+ local ok, ret1, ret2 = pcall(function(nomsu, vars)
+ \(%action as lua statements)
+ fell_through = true;
+ end, nomsu, vars);
+ local ok2, _ = pcall(function(nomsu, vars)
+ \(%final_action as lua statements)
+ end, nomsu, vars);
+ if not ok then nomsu:error(ret1); end
+ if not ok2 then nomsu:error(ret2); end
+ if not fell_through then
+ return ret1, ret2;
+ end
+ end
diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom
index 90e5985..29a4ebd 100644
--- a/lib/metaprogramming.nom
+++ b/lib/metaprogramming.nom
@@ -4,66 +4,67 @@
# Rule to make rules:
lua> ".."
- |nomsu:defmacro("rule %signature = %body", (function(nomsu, vars)
- | local signature = {};
- | for i, alias in ipairs(nomsu:typecheck(vars, "signature", "List").value) do
- | signature[i] = alias.src;
- | end
- | local body = nomsu:typecheck(vars, "body", "Thunk");
- | local src = nomsu:source_code(0);
- | return nil, ([[
- |nomsu:def(%s, %s, %s)
- |]]):format(nomsu:repr(signature), nomsu:tree_to_lua(body), nomsu:repr(nomsu:dedent(src)));
- |end), \(__src__ 1));
+ nomsu:defmacro("rule %signature = %body", (function(nomsu, vars)
+ local signature = {};
+ for i, alias in ipairs(nomsu:typecheck(vars, "signature", "List").value) do
+ signature[i] = alias.src;
+ end
+ local body = nomsu:typecheck(vars, "body", "Thunk");
+ local src = nomsu:source_code(0);
+ return nil, ([[
+ nomsu:def(%s, %s, %s)
+ ]]):format(nomsu:repr(signature), nomsu:tree_to_lua(body), nomsu:repr(nomsu:dedent(src)));
+ end), \(__src__ 1));
# Rule to make lua macros:
rule [compile \%macro_def to \%body] =:
lua> ".."
- |local signature = {};
- |for i, alias in ipairs(nomsu:typecheck(vars, "macro_def", "List").value) do
- | signature[i] = alias.src;
- |end
- |local body = nomsu:typecheck(vars, "body", "Thunk");
- |local thunk = nomsu:tree_to_value(body);
- |nomsu:defmacro(signature, thunk, ("compile %s\\n..to %s"):format(vars.macro_def.src, body.src));
+ local signature = {};
+ for i, alias in ipairs(nomsu:typecheck(vars, "macro_def", "List").value) do
+ signature[i] = alias.src;
+ end
+ local body = nomsu:typecheck(vars, "body", "Thunk");
+ local thunk = nomsu:tree_to_value(body);
+ nomsu:defmacro(signature, thunk, ("compile %s\\n..to %s"):format(vars.macro_def.src, body.src));
+
rule [compile \%macro_def to code \%body] =:
lua> ".."
- |local signature = {};
- |for i, alias in ipairs(nomsu:typecheck(vars, "macro_def", "List").value) do
- | signature[i] = alias.src;
- |end
- |local body = nomsu:typecheck(vars, "body", "Thunk");
- |local thunk = nomsu:tree_to_value(body);
- |local thunk_wrapper = function(nomsu, vars) return nil, thunk(nomsu, vars); end
- |nomsu:defmacro(signature, thunk_wrapper, ("compile %s\\n..to code %s"):format(vars.macro_def.src, body.src));
+ local signature = {};
+ for i, alias in ipairs(nomsu:typecheck(vars, "macro_def", "List").value) do
+ signature[i] = alias.src;
+ end
+ local body = nomsu:typecheck(vars, "body", "Thunk");
+ local thunk = nomsu:tree_to_value(body);
+ local thunk_wrapper = function(nomsu, vars) return nil, thunk(nomsu, vars); end
+ nomsu:defmacro(signature, thunk_wrapper, ("compile %s\\n..to code %s"):format(vars.macro_def.src, body.src));
# Rule to make nomsu macros:
lua> ".."
- |nomsu:defmacro("parse %shorthand as %longhand", (function(nomsu, vars)
- | local signature = {};
- | for i, alias in ipairs(nomsu:typecheck(vars, "shorthand", "List").value) do
- | signature[i] = alias.src;
- | end
- | local template = {};
- | for i, line in ipairs(nomsu:typecheck(vars, "longhand", "Thunk").value) do
- | template[i] = nomsu:dedent(line.src);
- | end
- | signature, template = nomsu:repr(signature), nomsu:repr(table.concat(template, "\\n"));
- | return nil, ([[
- |nomsu:defmacro(%s, (function(nomsu, vars)
- | local template = nomsu:parse(%s, %s);
- | if #template.value == 1 then template = template.value[1]; end
- | local replacement = nomsu:replaced_vars(template, vars);
- | return nomsu:tree_to_lua(replacement);
- |end), %s)]]):format(signature, template, nomsu:repr(vars.shorthand.line_no), nomsu:repr(nomsu:source_code(0)));
- |end), \(__src__ 1));
+ nomsu:defmacro("parse %shorthand as %longhand", (function(nomsu, vars)
+ local signature = {};
+ for i, alias in ipairs(nomsu:typecheck(vars, "shorthand", "List").value) do
+ signature[i] = alias.src;
+ end
+ local template = {};
+ for i, line in ipairs(nomsu:typecheck(vars, "longhand", "Thunk").value) do
+ template[i] = nomsu:dedent(line.src);
+ end
+ signature, template = nomsu:repr(signature), nomsu:repr(table.concat(template, "\\n"));
+ return nil, ([[
+ nomsu:defmacro(%s, (function(nomsu, vars)
+ local template = nomsu:parse(%s, %s);
+ if #template.value == 1 then template = template.value[1]; end
+ local replacement = nomsu:replaced_vars(template, vars);
+ return nomsu:tree_to_lua(replacement);
+ end), %s)]]):format(signature, template, nomsu:repr(vars.shorthand.line_no), nomsu:repr(nomsu:source_code(0)));
+ end), \(__src__ 1));
rule [remove rule %stub] =:
lua> ".."
- |local def = nomsu.defs[\(%stub)];
- |for _, alias in ipairs(def.aliases) do
- | nomsu.defs[alias] = false;
- |end
+ local def = nomsu.defs[\(%stub)];
+ for _, alias in ipairs(def.aliases) do
+ nomsu.defs[alias] = false;
+ end
rule [%tree as lua] =:
=lua "nomsu:tree_to_lua(\(%tree))"
@@ -81,18 +82,18 @@ parse [lua do> %block] as:
rule [%tree as lua statement] =:
lua do> ".."
- |local _,statement = nomsu:tree_to_lua(\(%tree));
- |return statement;
+ local _,statement = nomsu:tree_to_lua(\(%tree));
+ return statement;
rule [%tree as lua statements] =:
lua do> ".."
- |local lua_bits = {};
- |local statements = nomsu:typecheck(vars, "tree", "Thunk").value;
- |for _,bit in ipairs(statements) do
- | local expr, statement = nomsu:tree_to_lua(bit);
- | if statement then table.insert(lua_bits, statement); end
- | if expr then table.insert(lua_bits, "ret = "..expr..";"); end
- |end
- |return table.concat(lua_bits, "\\n");
+ local lua_bits = {};
+ local statements = nomsu:typecheck(vars, "tree", "Thunk").value;
+ for _,bit in ipairs(statements) do
+ local expr, statement = nomsu:tree_to_lua(bit);
+ if statement then table.insert(lua_bits, statement); end
+ if expr then table.insert(lua_bits, "ret = "..expr..";"); end
+ end
+ return table.concat(lua_bits, "\\n");
compile [nomsu] to: "nomsu"
compile [nomsu's %key] to: "nomsu[\(%key as lua)]"
@@ -104,25 +105,25 @@ parse [rule %signature] as:
# Get the source code for a function
rule [help %rule] =:
lua do> ".."
- |local fn_def = nomsu.defs[nomsu:get_stub(vars.rule)]
- |if not fn_def then
- | nomsu:writeln("Rule not found: "..nomsu:repr(vars.rule));
- |else
- | nomsu:writeln(fn_def.src or "<unknown source code>");
- |end
+ local fn_def = nomsu.defs[nomsu:get_stub(vars.rule)]
+ if not fn_def then
+ nomsu:writeln("Rule not found: "..nomsu:repr(vars.rule));
+ else
+ nomsu:writeln(fn_def.src or "<unknown source code>");
+ end
# Compiler tools
parse [eval %code, run %code] as: nomsu "run" [%code]
rule [source code from tree %tree] =:
lua do> ".."
- |local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S");
- |if leading_space then
- | local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)");
- | chunk2 = chunk2:gsub("\\n"..leading_space, "\\n");
- | return chunk1..chunk2.."\\n";
- |else
- | return vars.tree.src:match(":%s*(%S.*)").."\\n";
- |end
+ local _,_,leading_space = vars.tree.src:find("\\n(%s*)%S");
+ if leading_space then
+ local chunk1, chunk2 = vars.tree.src:match(":%s*([^\\n]*)(\\n.*)");
+ chunk2 = chunk2:gsub("\\n"..leading_space, "\\n");
+ return chunk1..chunk2.."\\n";
+ else
+ return vars.tree.src:match(":%s*(%S.*)").."\\n";
+ end
parse [source code %body] as: source code from tree \%body
parse [parse tree %code] as: nomsu "tree_to_str" [\%code]
diff --git a/lib/operators.nom b/lib/operators.nom
index d9880fe..1fcb42a 100644
--- a/lib/operators.nom
+++ b/lib/operators.nom
@@ -12,21 +12,21 @@ compile [phi, PHI, golden ratio] to: "((1+math.sqrt(5))/2)"
compile [nop, pass] to code: ""
# Ternary operator
+#.. Note: this uses a function instead of (condition and if_expr or else_expr)
+ because that breaks if %if_expr is falsey.
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: ".."
- #.. Note: this uses a function instead of (condition and if_expr or else_expr)
- because that breaks if %if_expr is falsey.
- |(function(nomsu, vars)
- | if \(%condition as lua) then
- | return \(%when_true_expr as lua);
- | else
- | return \(%when_false_expr as lua);
- | end
- |end)(nomsu, vars)
+ (function(nomsu, vars)
+ if \(%condition as lua) then
+ return \(%when_true_expr as lua);
+ else
+ return \(%when_false_expr as lua);
+ end
+ end)(nomsu, vars)
# Indexing:
compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]"
@@ -45,16 +45,17 @@ compile [%var mod= %val] to code: "\(%var as lua) = \(%var as lua) % \(%val as l
# Binary Operators
lua do> ".."
- |local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}};
- |for _,op in ipairs(binops) do
- | local nomsu_alias = op;
- | if type(op) == 'table' then;
- | nomsu_alias, op = unpack(op);
- | end
- | nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars)
- | return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")";
- | end), [["(\\(%a) ]]..op..[[ \\(%b))"]]);
- |end
+ local binops = {"-","/","<","<=",">",">=","^",{"===","=="},{"!==","~="},{"mod","%"}};
+ for _,op in ipairs(binops) do
+ local nomsu_alias = op;
+ if type(op) == 'table' then;
+ nomsu_alias, op = unpack(op);
+ end
+ nomsu:defmacro("%a "..nomsu_alias.." %b", (function(nomsu, vars)
+ return "("..nomsu:tree_to_lua(vars.a).." "..op.." "..nomsu:tree_to_lua(vars.b)..")";
+ end), [["(\\(%a) ]]..op..[[ \\(%b))"]]);
+ end
+
# TODO: implement OR, XOR, AND for multiple operands
compile [%a OR %b, %a | %b] to: "bit32.bor(\(%a as lua), \(%b as lua))"
compile [%a XOR %b] to: "bit32.bxor(\(%a as lua), \(%b as lua))"
@@ -70,56 +71,56 @@ compile [%a != %b] to: "(not nomsu.utils.equivalent(\(%a as lua), \(%b as lua)))
# Commutative Operators defined for up to 8 operands
# TODO: work out solution for commutative operators using more clever macros
lua do> ".."
- |local max_operands = 8;
- |local comops = {"+","*","and","or"};
- |for _,_op in ipairs(comops) do
- | local op = _op;
- | local spec = "%1 ";
- | for n=2,max_operands do
- | spec = spec .." "..op.." %"..tostring(n);
- | nomsu:defmacro(spec, (function(nomsu, vars)
- | local bits = {};
- | for i=1,n do
- | table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)])));
- | end
- | return "("..table.concat(bits, " "..op.." ")..")";
- | end));
- | end
- |end
+ local max_operands = 8;
+ local comops = {"+","*","and","or"};
+ for _,_op in ipairs(comops) do
+ local op = _op;
+ local spec = "%1 ";
+ for n=2,max_operands do
+ spec = spec .." "..op.." %"..tostring(n);
+ nomsu:defmacro(spec, (function(nomsu, vars)
+ local bits = {};
+ for i=1,n do
+ table.insert(bits, (nomsu:tree_to_lua(vars[tostring(i)])));
+ end
+ return "("..table.concat(bits, " "..op.." ")..")";
+ end));
+ end
+ end
# Chained compairsions (e.g. x < y <= z) are defined up to 3 operands
lua do> ".."
- |local max_operands = 3;
- |for _,chainers in ipairs({{"<","<="},{">",">="}}) do
- | local function recurse(chainers, chain)
- # The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense
- | if #chain >= 2 then;
- | local spec = "%1";
- | for i,op in ipairs(chain) do
- | spec = spec .. " "..op.." %"..tostring(i+1);
- | end
- # Chained comparisons need to be functions to avoid re-evaluating their arguments :\
- | nomsu:def(spec, function(nomsu, vars)
- | for i,op in ipairs(chain) do
- | local a, b, result = vars[i], vars[i+1];
- | if op == "<" then; result = a < b;
- | elseif op == "<=" then; result = a <= b;
- | elseif op == ">" then; result = a > b;
- | elseif op == ">=" then; result = a >= b; end
- # Short circuit
- | if not result then; return false; end
- | end
- | end);
- | end
- | if #chain + 1 >= max_operands then; return; end
- | for _,c in ipairs(chainers) do
- | table.insert(chain, c);
- | recurse(chainers, chain);
- | table.remove(chain);
- | end
- | end
- | recurse(chainers, {});
- |end
+ local max_operands = 3;
+ for _,chainers in ipairs({{"<","<="},{">",">="}}) do
+ local function recurse(chainers, chain)
+ -- The 1-op versions are already more efficiently defined, and a 0-op version doesnt make sense
+ if #chain >= 2 then;
+ local spec = "%1";
+ for i,op in ipairs(chain) do
+ spec = spec .. " "..op.." %"..tostring(i+1);
+ end
+ -- Chained comparisons need to be functions to avoid re-evaluating their arguments :
+ nomsu:def(spec, function(nomsu, vars)
+ for i,op in ipairs(chain) do
+ local a, b, result = vars[i], vars[i+1];
+ if op == "<" then; result = a < b;
+ elseif op == "<=" then; result = a <= b;
+ elseif op == ">" then; result = a > b;
+ elseif op == ">=" then; result = a >= b; end
+ -- Short circuit
+ if not result then; return false; end
+ end
+ end);
+ end
+ if #chain + 1 >= max_operands then; return; end
+ for _,c in ipairs(chainers) do
+ table.insert(chain, c);
+ recurse(chainers, chain);
+ table.remove(chain);
+ end
+ end
+ recurse(chainers, {});
+ end
# Unary operators
compile [- %] to: "-(\(% as lua))"
diff --git a/lib/scopes.nom b/lib/scopes.nom
index 362a8c5..8555287 100644
--- a/lib/scopes.nom
+++ b/lib/scopes.nom
@@ -3,7 +3,7 @@ require "lib/operators.nom"
require "lib/control_flow.nom"
compile [<%var> = %value] to code: ".."
- |nomsu.defs['#vars'][\(repr (%var's "value"))] = \(%value as lua);
+ nomsu.defs['#vars'][\(repr (%var's "value"))] = \(%value as lua);
compile [<%var>] to: "nomsu.defs['#vars'][\(repr (%var's "value"))]"
@@ -17,8 +17,8 @@ parse [using %scoped do %actions] as:
with (nomsu's "defs") = %scope:
do %scoped
lua> ".."
- |getmetatable(nomsu.defs).__newindex = getmetatable(nomsu.defs).__index;
- |getmetatable(nomsu.defs["#vars"]).__newindex = getmetatable(nomsu.defs["#vars"]).__index;
+ getmetatable(nomsu.defs).__newindex = getmetatable(nomsu.defs).__index;
+ getmetatable(nomsu.defs["#vars"]).__newindex = getmetatable(nomsu.defs["#vars"]).__index;
do %actions
parse [scoped %actions] as: using %actions do {pass}
diff --git a/lib/utils.nom b/lib/utils.nom
index ef0e61e..11f0ccf 100644
--- a/lib/utils.nom
+++ b/lib/utils.nom
@@ -6,17 +6,18 @@ rule [error!, panic!, fail!, abort!] =:
rule [error %msg] =:
nomsu "error"[%msg]
compile [assert %condition %msg] to code: ".."
- |if not (\(%condition as lua)) then
- | nomsu:error(\(%msg as lua))
- |end
+ if not (\(%condition as lua)) then
+ nomsu:error(\(%msg as lua))
+ end
+
parse [assert %condition] as: assert %condition (nil)
# String functions
rule [join %strs with glue %glue] =:
lua do> ".."
- |local str_bits = {}
- |for i,bit in ipairs(vars.strs) do str_bits[i] = nomsu:stringify(bit) end
- |return table.concat(str_bits, vars.glue)
+ local str_bits = {}
+ for i,bit in ipairs(vars.strs) do str_bits[i] = nomsu:stringify(bit) end
+ return table.concat(str_bits, vars.glue)
parse [join %strs] as: join %strs with glue ""
compile [capitalize %str, %str capitalized] to:
@@ -29,13 +30,14 @@ compile [%str with %patt replaced with %sub %n times, %str s/%patt/%sub/%n] to:
# 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))
+ 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;
+ 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:
@@ -81,52 +83,43 @@ 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(item)
- | local vars = setmetatable({['']=item}, {__index=vars})
- | return \(%value_expr as lua)
- |end)
-compile [max of %items by %value_expr] to:
- ".."
- |nomsu.utils.max(\(%items as lua), function(item)
- | local vars = setmetatable({['']=item}, {__index=vars})
- | return \(%value_expr as lua)
- |end)
+compile [min of %items by %value_expr] to: ".."
+ nomsu.utils.min(\(%items as lua), function(item)
+ local vars = setmetatable({['']=item}, {__index=vars})
+ return \(%value_expr as lua)
+ end)
+compile [max of %items by %value_expr] to: ".."
+ nomsu.utils.max(\(%items as lua), function(item)
+ local vars = setmetatable({['']=item}, {__index=vars})
+ return \(%value_expr as lua)
+ end)
compile [sort %items] to: "table.sort(\(%items as lua))"
rule [sort %items by %key] =: =lua ".."
- |nomsu.utils.sort(\(%items), function(x)
- | return (\(%key))(nomsu, {['']=x});
- |end)
+ nomsu.utils.sort(\(%items), function(x)
+ return (\(%key))(nomsu, {['']=x});
+ end)
# String utilities
-compile [nl, newline, line feed, linefeed, lf] to: ".."
- |"\n"
-compile [tab] to: ".."
- |"\t"
-compile [bell] to: ".."
- |"\a"
-compile [cr, carriage return] to: ".."
- |"\r"
-compile [backspace] to: ".."
- |"\b"
-compile [form feed, formfeed] to: ".."
- |"\f"
-compile [vertical tab] to: ".."
- |"\v"
+compile [nl, newline, line feed, linefeed, lf] to: "'\\n'"
+compile [tab] to: "'\\t'"
+compile [bell] to: "'\\a'"
+compile [cr, carriage return] to: "'\\r'"
+compile [backspace] to: "'\\b'"
+compile [form feed, formfeed] to: "'\\f'"
+compile [vertical tab] to: "'\\v'"
lua> ".."
- |do;
- | local colors = {
- | ["reset color"] = 0, bright = 1, dim = 2, underscore = 4, blink = 5,
- | inverse = 7, hidden = 8, black = 30, red = 31, green = 32, yellow = 33,
- | blue = 34, magenta = 35, cyan = 36, white = 37, ["on black"] = 40,
- | ["on red"] = 41, ["on green"] = 42, ["on yellow"] = 43, ["on blue"] = 44,
- | ["on magenta"] = 45, ["on cyan"] = 46, ["on white"] = 47,
- | };
- | for name,code in pairs(colors) do;
- | local escape = "\\"\\\\27["..tostring(code).."m\\""
- | nomsu:defmacro(name, function() return escape end, "");
- | end;
- |end;
+ do
+ local colors = {
+ ["reset color"] = 0, bright = 1, dim = 2, underscore = 4, blink = 5,
+ inverse = 7, hidden = 8, black = 30, red = 31, green = 32, yellow = 33,
+ blue = 34, magenta = 35, cyan = 36, white = 37, ["on black"] = 40,
+ ["on red"] = 41, ["on green"] = 42, ["on yellow"] = 43, ["on blue"] = 44,
+ ["on magenta"] = 45, ["on cyan"] = 46, ["on white"] = 47,
+ };
+ for name,code in pairs(colors) do
+ local escape = "\\"\\\\27["..tostring(code).."m\\""
+ nomsu:defmacro(name, function() return escape end, "");
+ end
+ end
diff --git a/lib/utils2.nom b/lib/utils2.nom
index c31d5ab..def8854 100644
--- a/lib/utils2.nom
+++ b/lib/utils2.nom
@@ -25,7 +25,7 @@ compile [with %assignments %action] to code:
%var = (%tokens -> 1)
%eq = (%tokens -> 2)
assert (=lua "vars.eq and vars.eq.type == 'Word' and vars.eq.value == '='") ".."
- |Invalid format for 'with' statement. List entries must have the form %var = (value)
+ Invalid format for 'with' statement. List entries must have the form %var = (value)
%value = (%tokens -> 3)
add (d{i=%i; var=%var; value=%value}) to %data
%foo = (..)
@@ -34,18 +34,18 @@ compile [with %assignments %action] to code:
..for all %data
..with glue "\n "
".."
- |do
- | \(%foo)
- | local fell_through = false;
- | local ok, ret1, ret2 = pcall(function(nomsu, vars)
- | \(%action as lua statements);
- | fell_through = true;
- | end, nomsu, vars);
- | \(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
+ do
+ \(%foo)
+ local fell_through = false;
+ local ok, ret1, ret2 = pcall(function(nomsu, vars)
+ \(%action as lua statements);
+ fell_through = true;
+ end, nomsu, vars);
+ \(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
diff --git a/nomsu.lua b/nomsu.lua
index 151243d..6ab5df9 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -47,26 +47,32 @@ local STRING_ESCAPES = {
local indent_stack = {
0
}
-local check_indent
-check_indent = function(subject, end_pos, spaces)
+local indent_patt = P(function(self, start)
+ local spaces = self:match("[ \t]*", start)
if #spaces > indent_stack[#indent_stack] then
insert(indent_stack, #spaces)
- return end_pos
+ return start + #spaces
end
-end
-local check_dedent
-check_dedent = function(subject, end_pos, spaces)
+end)
+local dedent_patt = P(function(self, start)
+ local spaces = self:match("[ \t]*", start)
if #spaces < indent_stack[#indent_stack] then
remove(indent_stack)
- return end_pos
+ return start
end
-end
-local check_nodent
-check_nodent = function(subject, end_pos, spaces)
+end)
+local nodent_patt = P(function(self, start)
+ local spaces = self:match("[ \t]*", start)
if #spaces == indent_stack[#indent_stack] then
- return end_pos
+ return start + #spaces
end
-end
+end)
+local gt_nodent_patt = P(function(self, start)
+ local spaces = self:match("[ \t]*", start)
+ if #spaces >= indent_stack[#indent_stack] + 4 then
+ return start + indent_stack[#indent_stack] + 4
+ end
+end)
local nomsu = [=[ file <- ({{| shebang?
(ignored_line %nl)*
statements (nodent statements)*
@@ -120,12 +126,12 @@ local nomsu = [=[ file <- ({{| shebang?
({~ (("\\" -> "\") / ('\"' -> '"') / ("\n" -> "
") / (!string_interpolation [^%nl"]))+ ~}
/ string_interpolation)* |} '"' }) -> String
- indented_string <- ({ '".."' indent {|
- indented_string_line (nodent {~ "" -> "
-" ~} indented_string_line)*
- |} (dedent / (({.+} ("" -> "Error while parsing String")) => error))
+
+ indented_string <- ({ '".."' %ws? line_comment? %nl %gt_nodented? {|
+ ({~ (("\\" -> "\") / (%nl+ {~ %gt_nodented -> "" ~}) / [^%nl\]) ~} / string_interpolation)*
+ |} ((!.) / (&(%nl+ !%gt_nodented)) / (({.+} ("" -> "Error while parsing String")) => error))
}) -> String
- indented_string_line <- "|" ({~ (("\\" -> "\") / (!string_interpolation [^%nl]))+ ~} / string_interpolation)*
+
string_interpolation <- "\" ((noeol_expression dotdot?) / dotdot)
number <- ({ (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber) }) -> Number
@@ -169,9 +175,10 @@ local defs = {
tonumber = tonumber,
operator = operator,
plain_word = plain_word,
- indented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_indent),
- nodented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_nodent),
- dedented = Cmt(S(" \t") ^ 0 * (#(P(1) - S(" \t\n") + (-P(1)))), check_dedent),
+ indented = indent_patt,
+ nodented = nodent_patt,
+ dedented = dedent_patt,
+ gt_nodented = gt_nodent_patt,
line_no = function(src, pos)
local line_no = 1
for _ in src:sub(1, pos):gmatch("\n") do
diff --git a/nomsu.moon b/nomsu.moon
index 38480e9..0aec352 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -46,17 +46,25 @@ STRING_ESCAPES = n:"\n", t:"\t", b:"\b", a:"\a", v:"\v", f:"\f", r:"\r"
-- NOTE: this treats tabs as equivalent to 1 space
indent_stack = {0}
-check_indent = (subject,end_pos,spaces)->
+indent_patt = P (start)=>
+ spaces = @match("[ \t]*", start)
if #spaces > indent_stack[#indent_stack]
insert(indent_stack, #spaces)
- return end_pos
-check_dedent = (subject,end_pos,spaces)->
+ return start + #spaces
+dedent_patt = P (start)=>
+ spaces = @match("[ \t]*", start)
if #spaces < indent_stack[#indent_stack]
remove(indent_stack)
- return end_pos
-check_nodent = (subject,end_pos,spaces)->
+ return start
+nodent_patt = P (start)=>
+ spaces = @match("[ \t]*", start)
if #spaces == indent_stack[#indent_stack]
- return end_pos
+ return start + #spaces
+gt_nodent_patt = P (start)=>
+ -- Note! This assumes indent is 4 spaces!!!
+ spaces = @match("[ \t]*", start)
+ if #spaces >= indent_stack[#indent_stack] + 4
+ return start + indent_stack[#indent_stack] + 4
-- TYPES:
-- Number 1, "String", %Var, [List], (expression), {Thunk}, \Nomsu, FunctionCall, File
@@ -115,12 +123,12 @@ nomsu = [=[
({~ (("\\" -> "\") / ('\"' -> '"') / ("\n" -> "
") / (!string_interpolation [^%nl"]))+ ~}
/ string_interpolation)* |} '"' }) -> String
- indented_string <- ({ '".."' indent {|
- indented_string_line (nodent {~ "" -> "
-" ~} indented_string_line)*
- |} (dedent / (({.+} ("" -> "Error while parsing String")) => error))
+
+ indented_string <- ({ '".."' %ws? line_comment? %nl %gt_nodented? {|
+ ({~ (("\\" -> "\") / (%nl+ {~ %gt_nodented -> "" ~}) / [^%nl\]) ~} / string_interpolation)*
+ |} ((!.) / (&(%nl+ !%gt_nodented)) / (({.+} ("" -> "Error while parsing String")) => error))
}) -> String
- indented_string_line <- "|" ({~ (("\\" -> "\") / (!string_interpolation [^%nl]))+ ~} / string_interpolation)*
+
string_interpolation <- "\" ((noeol_expression dotdot?) / dotdot)
number <- ({ (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber) }) -> Number
@@ -164,9 +172,7 @@ utf8_char = (
plain_word = (R('az','AZ','09') + S("_") + utf8_char)^1
defs =
ws:whitespace, nl: P("\n"), :tonumber, :operator, :plain_word
- indented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_indent)
- nodented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_nodent)
- dedented: Cmt(S(" \t")^0 * (#(P(1)-S(" \t\n") + (-P(1)))), check_dedent)
+ indented: indent_patt, nodented: nodent_patt, dedented: dedent_patt, gt_nodented: gt_nodent_patt
line_no: (src, pos)->
line_no = 1
for _ in src\sub(1,pos)\gmatch("\n") do line_no += 1