aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-01-22 16:15:25 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-01-22 16:16:53 -0800
commitf746ba34d799e6560df1aad1cad15a70b34914d1 (patch)
tree3829ce9bd8469e59d1a51470823d510dc808e1c7
parenta596195f6cfb6731f1e778e4bc304028ecd9bf08 (diff)
Moved all the text method stuff into text.moon instead of splitting
across string2/containers. Modified the type stuff to output better type names and use (a Dict) and (a List) instead of (Dict) and (List). (Text) now also has a proper constructor. (assume) now also handles a bunch of different assumptions with smart error messages.
-rw-r--r--Makefile4
-rw-r--r--README.md2
-rw-r--r--containers.lua112
-rw-r--r--containers.moon55
-rw-r--r--lib/compatibility/compatibility.nom2
-rw-r--r--lib/core/control_flow.nom2
-rw-r--r--lib/core/errors.nom84
-rw-r--r--lib/core/metaprogramming.nom36
-rw-r--r--lib/core/text.nom2
-rwxr-xr-x[-rw-r--r--]lib/tools/tutorial.nom83
-rw-r--r--nomsu.lua5
-rwxr-xr-xnomsu.moon3
-rw-r--r--nomsu_compiler.lua16
-rw-r--r--nomsu_compiler.moon12
-rw-r--r--nomsu_environment.lua10
-rw-r--r--nomsu_environment.moon5
-rw-r--r--pretty_errors.lua17
-rw-r--r--pretty_errors.moon17
-rw-r--r--string2.lua204
-rw-r--r--string2.moon106
20 files changed, 173 insertions, 604 deletions
diff --git a/Makefile b/Makefile
index 6aaf528..b95b926 100644
--- a/Makefile
+++ b/Makefile
@@ -13,10 +13,10 @@ UNINSTALL_VERSION=
MOON_FILES= code_obj.moon error_handling.moon files.moon nomsu.moon nomsu_compiler.moon \
syntax_tree.moon containers.moon bitops.moon parser.moon pretty_errors.moon \
- string2.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon
+ text.moon nomsu_decompiler.moon nomsu_environment.moon bootstrap.moon
LUA_FILES= code_obj.lua error_handling.lua files.lua nomsu.lua nomsu_compiler.lua \
syntax_tree.lua containers.lua bitops.lua parser.lua pretty_errors.lua \
- string2.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua
+ text.lua nomsu_decompiler.lua nomsu_environment.lua bootstrap.lua
CORE_NOM_FILES=$(shell cat lib/core/init.nom | sed -n 's;export "\(.*\)";lib/\1.nom;p') lib/core/init.nom
CORE_LUA_FILES= $(patsubst %.nom,%.lua, $(CORE_NOM_FILES))
COMPAT_NOM_FILES=$(wildcard lib/compatibility/*.nom)
diff --git a/README.md b/README.md
index 23299b7..aba91cf 100644
--- a/README.md
+++ b/README.md
@@ -60,8 +60,8 @@ All `.moon` files have been precompiled into corresponding `.lua` files, so you
* [error\_handling.moon](error_handling.moon) - The logic for producing good error messages within Lua that reference the Nomsu source code that led to them.
* [files.moon](files.moon) - A library for interacting with the filesystem.
* [pretty_errors.moon](pretty_errors.moon) - A simple library for displaying errors in a more visually pleasing/readable way.
-* [string2.moon](string2.moon) - A library defining some extra functionality for strings.
* [syntax\_tree.moon](syntax_tree.moon) - Datastructures used for Nomsu Abstract Syntax Trees.
+* [text.moon](text.moon) - A library defining some extra functionality for strings.
* [examples/how\_do\_i.nom](examples/how_do_i.nom) - A simple walkthrough of some of the features of Nomsu, written in Nomsu code. **This is a good place to start.**
* [lib/\*/\*.nom](lib) - Language libraries, including the core language stuff like control flow, operators, and metaprogramming (in [lib/core](lib/core)) and optional language libraries for stuff you might want.
* [lib/compatibility/\*.nom](compatibility) - Code for automatically upgrading Nomsu code from old versions to the current version.
diff --git a/containers.lua b/containers.lua
index 85f201c..8f34e73 100644
--- a/containers.lua
+++ b/containers.lua
@@ -82,7 +82,7 @@ local _list_mt = {
end)(), ", ") .. "]"
end,
as_lua = function(self)
- return "List{" .. concat((function()
+ return "a_List{" .. concat((function()
local _accum_0 = { }
local _len_0 = 1
for _index_0 = 1, #self do
@@ -299,7 +299,7 @@ local _dict_mt = {
end)(), ", ") .. "}"
end,
as_lua = function(self)
- return "Dict{" .. concat((function()
+ return "a_Dict{" .. concat((function()
local _accum_0 = { }
local _len_0 = 1
for k, v in pairs(self) do
@@ -408,114 +408,6 @@ Dict = function(t)
return error("Unsupported Dict type: " .. type(t))
end
end
-do
- local reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep
- do
- local _obj_0 = string
- reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep = _obj_0.reverse, _obj_0.upper, _obj_0.lower, _obj_0.find, _obj_0.byte, _obj_0.match, _obj_0.gmatch, _obj_0.gsub, _obj_0.sub, _obj_0.format, _obj_0.rep
- end
- local string2 = require('string2')
- local lines, line, line_at, as_lua_id, is_lua_id
- lines, line, line_at, as_lua_id, is_lua_id = string2.lines, string2.line, string2.line_at, string2.as_lua_id, string2.is_lua_id
- local text_methods = {
- formatted_with = format,
- byte = byte,
- position_of = (function(...)
- return (find(...))
- end),
- position_of_1_after = (function(...)
- return (find(...))
- end),
- as_a_lua_identifier = as_lua_id,
- is_a_lua_identifier = is_lua_id,
- as_a_lua_id = as_lua_id,
- is_a_lua_id = is_lua_id,
- bytes_1_to = function(self, start, stop)
- return List({
- byte(tostring(self), start, stop)
- })
- end,
- [as_lua_id("with 1 ->")] = function(...)
- return (gsub(...))
- end,
- bytes = function(self)
- return List({
- byte(tostring(self), 1, -1)
- })
- end,
- lines = function(self)
- return List(lines(self))
- end,
- line = line,
- wrapped_to = function(self, maxlen)
- local _lines = { }
- local _list_0 = self:lines()
- for _index_0 = 1, #_list_0 do
- local line = _list_0[_index_0]
- while #line > maxlen do
- local chunk = line:sub(1, maxlen)
- local split = chunk:find(' ', maxlen - 8) or maxlen
- chunk = line:sub(1, split)
- line = line:sub(split + 1, -1)
- _lines[#_lines + 1] = chunk
- end
- _lines[#_lines + 1] = line
- end
- return table.concat(_lines, "\n")
- end,
- line_at = function(self, i)
- return (line_at(self, i))
- end,
- line_number_at = function(self, i)
- return select(2, line_at(self, i))
- end,
- line_position_at = function(self, i)
- return select(3, line_at(self, i))
- end,
- matches = function(self, patt)
- return match(self, patt) and true or false
- end,
- matching = function(self, patt)
- return (match(self, patt))
- end,
- matching_groups = function(self, patt)
- return List({
- match(self, patt)
- })
- end,
- [as_lua_id("* 1")] = function(self, n)
- return rep(self, n)
- end,
- all_matches_of = function(self, patt)
- local result = { }
- local stepper, x, i = gmatch(self, patt)
- while true do
- local tmp = List({
- stepper(x, i)
- })
- if #tmp == 0 then
- break
- end
- i = tmp[1]
- result[#result + 1] = (#tmp == 1) and tmp[1] or tmp
- end
- return List(result)
- end,
- from_1_to = sub,
- from = sub,
- character = function(self, i)
- return sub(self, i, i)
- end
- }
- setmetatable(text_methods, {
- __index = string2
- })
- getmetatable("").__methods = text_methods
- getmetatable("").__index = text_methods
- getmetatable("").__add = function(self, x)
- return tostring(self) .. tostring(x)
- end
-end
return {
List = List,
Dict = Dict
diff --git a/containers.moon b/containers.moon
index e0a4b07..2a9ee4b 100644
--- a/containers.moon
+++ b/containers.moon
@@ -37,7 +37,7 @@ _list_mt =
as_nomsu: =>
"["..concat([as_nomsu(b) for b in *@], ", ").."]"
as_lua: =>
- "List{"..concat([as_lua(b) for b in *@], ", ").."}"
+ "a_List{"..concat([as_lua(b) for b in *@], ", ").."}"
__lt: (other)=>
assert type(@) == 'table' and type(other) == 'table', "Incompatible types for comparison"
for i=1,math.max(#@, #other)
@@ -125,7 +125,7 @@ _dict_mt =
as_nomsu: =>
"{"..concat([".#{as_nomsu(k)} = #{as_nomsu(v)}" for k,v in pairs @], ", ").."}"
as_lua: =>
- "Dict{"..concat(["[ #{as_lua(k)}]= #{as_lua(v)}" for k,v in pairs @], ", ").."}"
+ "a_Dict{"..concat(["[ #{as_lua(k)}]= #{as_lua(v)}" for k,v in pairs @], ", ").."}"
__band: (other)=>
Dict{k,v for k,v in pairs(@) when other[k] != nil}
__bor: (other)=>
@@ -163,55 +163,4 @@ Dict = (t)->
return d
else error("Unsupported Dict type: "..type(t))
-
-do
- {:reverse, :upper, :lower, :find, :byte, :match, :gmatch, :gsub, :sub, :format, :rep} = string
- string2 = require 'string2'
- {:lines, :line, :line_at, :as_lua_id, :is_lua_id} = string2
- text_methods =
- formatted_with:format, byte:byte,
- position_of:((...)->(find(...))), position_of_1_after:((...)->(find(...))),
- as_a_lua_identifier: as_lua_id, is_a_lua_identifier: is_lua_id,
- as_a_lua_id: as_lua_id, is_a_lua_id: is_lua_id,
- bytes_1_to: (start, stop)=> List{byte(tostring(@), start, stop)}
- [as_lua_id "with 1 ->"]: (...)-> (gsub(...))
- bytes: => List{byte(tostring(@), 1, -1)},
- lines: => List(lines(@))
- line: line
- wrapped_to: (maxlen)=>
- _lines = {}
- for line in *@lines!
- while #line > maxlen
- chunk = line\sub(1, maxlen)
- split = chunk\find(' ', maxlen-8) or maxlen
- chunk = line\sub(1, split)
- line = line\sub(split+1, -1)
- _lines[#_lines+1] = chunk
- _lines[#_lines+1] = line
- return table.concat(_lines, "\n")
-
- line_at: (i)=> (line_at(@, i))
- line_number_at: (i)=> select(2, line_at(@, i))
- line_position_at: (i)=> select(3, line_at(@, i))
- matches: (patt)=> match(@, patt) and true or false
- matching: (patt)=> (match(@, patt))
- matching_groups: (patt)=> List{match(@, patt)}
- [as_lua_id "* 1"]: (n)=> rep(@, n)
- all_matches_of: (patt)=>
- result = {}
- stepper,x,i = gmatch(@, patt)
- while true
- tmp = List{stepper(x,i)}
- break if #tmp == 0
- i = tmp[1]
- result[#result+1] = (#tmp == 1) and tmp[1] or tmp
- return List(result)
- from_1_to: sub, from: sub,
- character: (i)=> sub(@, i, i)
-
- setmetatable(text_methods, {__index:string2})
- getmetatable("").__methods = text_methods
- getmetatable("").__index = text_methods
- getmetatable("").__add = (x)=> tostring(@)..tostring(x)
-
return {:List, :Dict}
diff --git a/lib/compatibility/compatibility.nom b/lib/compatibility/compatibility.nom
index 45ea1d6..b72997e 100644
--- a/lib/compatibility/compatibility.nom
+++ b/lib/compatibility/compatibility.nom
@@ -43,7 +43,7 @@ external:
($t is syntax tree):
$args = []
for $k = $v in $t:
- if ((type of $k) == "a number"):
+ if ((type of $k) == "a Number"):
$args, add (make tree $v)
..else:
$args, add "\($k)=\(make tree $v)"
diff --git a/lib/core/control_flow.nom b/lib/core/control_flow.nom
index 2ad7ec7..bf044d9 100644
--- a/lib/core/control_flow.nom
+++ b/lib/core/control_flow.nom
@@ -485,7 +485,7 @@ test:
$lua =
Lua ("
do
- local _stack_\($var as lua expr) = List{\($structure as lua expr)}
+ local _stack_\($var as lua expr) = a_List{\($structure as lua expr)}
while #_stack_\($var as lua expr) > 0 do
\($var as lua expr) = table.remove(_stack_\($var as lua expr), 1)
\($body as lua)
diff --git a/lib/core/errors.nom b/lib/core/errors.nom
index a84b580..e24c012 100644
--- a/lib/core/errors.nom
+++ b/lib/core/errors.nom
@@ -14,31 +14,67 @@ use "core/control_flow"
))
")
-(assume $condition) compiles to ("
- if not \($condition as lua expr) then
- at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This was not true.")
- end
-")
-
-(assume $a == $b) compiles to ("
- do
- local _a, _b = \($a as lua expr), \($b as lua expr)
- if _a ~= _b then
- at_1_fail(\(quote "\($a.source)"),
- "Assumption failed: This value was "..tostring(_a).." but it was expected to be "..tostring(_b)..".")
- end
- end
-")
+(assume $condition) compiles to:
+ if ($condition.type == "Action"):
+ when $condition.stub is:
+ "1 ==":
+ return
+ LuaCode ("
+ do
+ local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr)
+ if _a ~= _b then
+ _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a)
+ _b = type_of(_b) == 'Text' and _b:as_lua() or tostring(_b)
+ at_1_fail(\(quote "\($condition.1.source)"),
+ "Assumption failed: This value was ".._a.." but it was expected to be ".._b..".")
+ end
+ end
+ ")
+ "1 !=":
+ return
+ LuaCode ("
+ do
+ local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr)
+ if _a == _b then
+ _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a)
+ at_1_fail(\(quote "\($condition.1.source)"),
+ "Assumption failed: This value was ".._a.." but it wasn't expected to be.")
+ end
+ end
+ ")
+ "1 >" "1 <" "1 >=" "1 <=":
+ return
+ LuaCode ("
+ do
+ local _a, _b = \($condition.1 as lua expr), \($condition.3 as lua expr)
+ if _a ~= _b then
+ _a = type_of(_a) == 'Text' and _a:as_lua() or tostring(_a)
+ _b = type_of(_b) == 'Text' and _b:as_lua() or tostring(_b)
+ at_1_fail(\(quote "\($condition.1.source)"),
+ "Assumption failed: This value was ".._a..", but it was expected to be \($condition.3)".._b..".")
+ end
+ end
+ ")
+ "1 is":
+ return
+ LuaCode ("
+ do
+ local _ta, _tb = type_of(\($condition.1 as lua expr)), \($condition.3 as lua expr)
+ if _ta ~= _tb then
+ at_1_fail(\(quote "\($condition.1.source)"),
+ "Assumption failed: This value was ".._ta.." but it was expected to be ".._tb..".")
+ end
+ end
+ ")
+ return
+ LuaCode ("
+ if not \($condition as lua expr) then
+ at_1_fail(\(quote "\($condition.source)"), "Assumption failed: This assumption did not hold.")
+ end
+ ")
-(assume $a != $b) compiles to ("
- do
- local _a, _b = \($a as lua expr), \($b as lua expr)
- if _a == _b then
- at_1_fail(\(quote "\($a.source)"),
- "Assumption failed: This value was "..tostring(_a).." but it wasn't expected to be.")
- end
- end
-")
+(assume $a == $b) parses as (assume ($a == $b))
+(assume $a != $b) parses as (assume ($a != $b))
test:
try: fail
diff --git a/lib/core/metaprogramming.nom b/lib/core/metaprogramming.nom
index bfcc0bf..c7d3787 100644
--- a/lib/core/metaprogramming.nom
+++ b/lib/core/metaprogramming.nom
@@ -26,7 +26,8 @@ lua> ("
lua> ("
COMPILE_RULES["1 ->"] = function(\(nomsu environment), _tree, \$args, \$body)
- if \$args and not \$body then \$args, \$body = {}, \$args end
+ if not \$args and not \$body then \$args, \$body = {}, SyntaxTree{type='Action', "do", "nothing"}
+ elseif \$args and not \$body then \$args, \$body = {}, \$args end
local body_lua = SyntaxTree:is_instance(\$body) and \(nomsu environment):compile(\$body) or \$body
if SyntaxTree:is_instance(\$body) and \$body.type ~= "Block" then body_lua:prepend("return ") end
local lua = LuaCode("(function(")
@@ -88,7 +89,7 @@ test:
lua> ("
COMPILE_RULES["1 compiles to"] = function(\(nomsu environment), \(this tree), \$action, \$body)
- local \$args = List{"\(nomsu environment)", "\(this tree)"}
+ local \$args = a_List{"\(nomsu environment)", "\(this tree)"}
if \$body.type == "Text" then
\$body = SyntaxTree{source=\$body.source, type="Action", "Lua", \$body}
end
@@ -121,18 +122,18 @@ lua> ("
at_1_fail(\$actions, "Compile error: This should be a list of actions.")
end
local lua = \(\($actions.1 compiles to $body) as lua)
- local \$args = List{"\(nomsu environment)", "\(this tree)", unpack(\$actions[1]:get_args())}
- local \$compiled_args = List{"\(nomsu environment)", "\(this tree)"};
+ local \$args = a_List{"\(nomsu environment)", "\(this tree)", unpack(\$actions[1]:get_args())}
+ local \$compiled_args = a_List{"\(nomsu environment)", "\(this tree)"};
for i=3,#\$args do \$compiled_args[i] = \(nomsu environment):compile(\$args[i]) end
for i=2,#\$actions do
local alias = \$actions[i]
- local \$alias_args = List{"\(nomsu environment)", "\(this tree)", unpack(alias:get_args())}
+ local \$alias_args = a_List{"\(nomsu environment)", "\(this tree)", unpack(alias:get_args())}
lua:add("\\nCOMPILE_RULES[", alias:get_stub():as_lua(), "] = ")
if \$alias_args == \$args then
lua:add("COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "]")
else
lua:add("function(")
- local \$compiled_alias_args = List{"\(nomsu environment)", "\(this tree)"};
+ local \$compiled_alias_args = a_List{"\(nomsu environment)", "\(this tree)"};
for i=3,#\$alias_args do \$compiled_alias_args[i] = \(nomsu environment):compile(\$alias_args[i]) end
lua:concat_add(\$compiled_alias_args, ", ")
lua:add(") return COMPILE_RULES[", \$actions[1]:get_stub():as_lua(), "](")
@@ -183,10 +184,10 @@ test:
local first_def = (\$actions[1].type == "MethodCall"
and LuaCode(\(nomsu environment):compile(\$actions[1][1]), ".", \$actions[1]:get_stub():as_lua_id())
or LuaCode(\$actions[1]:get_stub():as_lua_id()))
- local \$args = List(\$actions[1]:get_args())
+ local \$args = a_List(\$actions[1]:get_args())
for i=2,#\$actions do
local alias = \$actions[i]
- local \$alias_args = List(alias:get_args())
+ local \$alias_args = a_List(alias:get_args())
lua:add("\\n")
if alias.type == "MethodCall" then
lua:add(\(nomsu environment):compile(alias[1]), ".", alias:get_stub():as_lua_id())
@@ -392,10 +393,10 @@ external:
external:
(match $tree with $patt) means:
lua> ("
- if \$patt.type == "Var" then return Dict{[\$patt:as_var()]=\$tree} end
+ if \$patt.type == "Var" then return a_Dict{[\$patt:as_var()]=\$tree} end
if \$patt.type == "Action" and \$patt:get_stub() ~= \$tree:get_stub() then return nil end
if #\$patt ~= #\$tree then return nil end
- local matches = Dict{}
+ local matches = a_Dict{}
for \($i)=1,#\$patt do
if SyntaxTree:is_instance(\$tree[\$i]) then
local submatch = \(match $tree.$i with $patt.$i)
@@ -425,6 +426,9 @@ test:
assume ({} is "a Dict")
assume ("" is text)
assume ("" is "Text")
+ assume (5 is "a Number")
+ assume ((->) is "an Action")
+ assume ((yes) is "a Boolean")
assume ("" isn't "a Dict")
external:
@@ -432,14 +436,12 @@ external:
[$ is not text, $ isn't text] all mean (=lua "\(lua type of $) ~= 'string'")
(type of $) means:
lua> ("
+ local mt = getmetatable(\$)
+ if mt and mt.__type then return mt.__type end
+ if \$ == nil then return 'nil' end
local lua_type = \(lua type of $)
- if lua_type == 'string' then return 'Text'
- elseif lua_type == 'nil' then return 'nil'
- elseif lua_type == 'table' or lua_type == 'userdata' then
- local mt = getmetatable(\$)
- if mt and mt.__type then return mt.__type end
- end
- return 'a '..lua_type
+ if lua_type == 'function' then return "an Action" end
+ return 'a '..lua_type:capitalized()
")
($ is $type) parses as ((type of $) == $type)
diff --git a/lib/core/text.nom b/lib/core/text.nom
index a1fcaae..1401cf2 100644
--- a/lib/core/text.nom
+++ b/lib/core/text.nom
@@ -46,7 +46,7 @@ test:
return
Lua ("
(function()
- local \(mangle "comprehension") = List{}
+ local \(mangle "comprehension") = a_List{}
for \($match as lua expr) in (\($text as lua expr)):gmatch(\($patt as lua expr)) do
\(mangle "comprehension")[#\(mangle "comprehension")+1] = \($expr as lua)
end
diff --git a/lib/tools/tutorial.nom b/lib/tools/tutorial.nom
index e8295c2..3cdb10c 100644..100755
--- a/lib/tools/tutorial.nom
+++ b/lib/tools/tutorial.nom
@@ -26,10 +26,10 @@ $lessons = [
# In Nomsu, variables have a "$" prefix, and you can just assign to them
without declaring them first:
$x = 10
- assume $x == 10
+ assume ($x == 10)
# Variables which have not yet been set have the value (nil)
- assume $foobar == (nil)
+ assume ($foobar == (nil))
# Variables can be nameless:
$ = 99
@@ -40,7 +40,7 @@ $lessons = [
# Figure out what value $my_var should have:
$my_var = 100
$my_var = ($my_var + $x + $(my favorite number))
- assume (???) == $my_var
+ assume ($my_var == (???))
lesson "Actions":
# Fix this action so the tests pass, then save and quit.
@@ -48,8 +48,8 @@ $lessons = [
($x doubled) means ((???) * $x)
# Tests:
- assume (2 doubled) == 4
- assume (-5 doubled) == -10
+ assume ((2 doubled) == 4)
+ assume ((-5 doubled) == -10)
lesson "Blocks":
# When you need to do multiple things inside an action, use a block.
@@ -69,17 +69,17 @@ $lessons = [
# Make this action return "big" if its argument
# is bigger than 99, otherwise return "small"
(the size of $n) means:
- if (<your code here>):
+ if (???):
<your code here>
..else:
<your code here>
# Tests:
for $small_number in [0, 1, -5, -999, 99]:
- assume (the size of $small_number) == "small"
+ assume ((the size of $small_number) == "small")
for $big_number in [9999, 100]:
- assume (the size of $big_number) == "big"
+ assume ((the size of $big_number) == "big")
lesson "Loops":
# Fix this action so the tests pass:
@@ -92,14 +92,14 @@ $lessons = [
return $sum
# Tests:
- assume (the sum of [1, 2, 3, 4, 5]) == 15
- assume (the sum of [100, 200]) == 300
+ assume ((the sum of [1, 2, 3, 4, 5]) == 15)
+ assume ((the sum of [100, 200]) == 300)
# You can also loop over a number range like this:
$total = 0
for $i in 1 to 3:
$total = ($total + $i)
- assume (???) == $total
+ assume ($total == (???))
lesson "Variable Scopes":
# Nomsu's variables are local by default, and actions have their own scopes:
@@ -110,17 +110,17 @@ $lessons = [
(do something) means:
# The variable $y is never set in this action, so it has the same value
it has outside this action.
- assume (???) == $y
+ assume ($y == (???))
# $x is set inside this action, and actions have their own scopes.
$x = $y
# What number should $x be here?
- assume (???) == $x
+ assume ($x == (???))
# After running the action, what value should $x have?
do something
- assume (???) == $x
+ assume ($x == (???))
lesson "More Variable Scopes":
# Loops and conditionals do *not* have their own scopes:
@@ -130,13 +130,13 @@ $lessons = [
$z = 2
# After assigning in a conditional, what should $z be?
- assume (???) == $z
+ assume ($z == (???))
for $ in 1 to 1:
# Set $z inside a loop:
$z = 3
# After assigning in a loop, what should $z be?
- assume (???) == $z
+ assume ($z == (???))
lesson "Externals":
# The 'external' block lets you modify variables outside an action:
@@ -146,7 +146,7 @@ $lessons = [
do something
# After running the action that sets $x in an 'external' block, what should $x be?
- assume (???) == $x
+ assume ($x == (???))
lesson "Locals":
# The 'with' block lets you create a local scope for the variables you list:
@@ -157,8 +157,8 @@ $lessons = [
$z = 2
# After setting $y and $z in the 'with [$y]' block, what should $y and $z be?
- assume (???) == $y
- assume (???) == $z
+ assume ($y == (???))
+ assume ($z == (???))
lesson "Failure and Recovery":
$what_happened = "nothing"
@@ -172,7 +172,7 @@ $lessons = [
$what_happened = "success"
# What do you think happened?
- assume (???) == $what_happened
+ assume ($what_happened == (???))
# Note: a 'try' block will silence failures, so this has no effect:
try: fail
@@ -180,11 +180,11 @@ $lessons = [
lesson "Indexing":
# Nomsu uses the "." operator to access things inside an object:
$dictionary = {.dog = "A lovable doofus", .cat = "An internet superstar"}
- assume $dictionary.dog == "A lovable doofus"
- assume (???) == $dictionary.cat
+ assume ($dictionary.dog == "A lovable doofus")
+ assume ($dictionary.cat == (???))
# If you try to access a key that's not in an object, the result is (nil):
- assume (???) == $dictionary.mimsy
+ assume ($dictionary.mimsy == (???))
# $dictionary.dog is just a shorthand for $dictionary."dog".
You may need to use the longer form for strings with spaces:
@@ -195,22 +195,22 @@ $lessons = [
$dictionary.5 = "The number five"
$dictionary.five = 5
$dictionary.myself = $dictionary
- assume (???) == $dictionary.myself
+ assume ($dictionary.myself == (???))
# Lists are similar, but use square brackets ([])
and can only have numbers as keys, starting at 1:
$list = ["first", "second", 999]
- assume $list.1 == "first"
- assume (???) == $list.2
- assume (???) == $list.3
+ assume ($list.1 == "first")
+ assume ($list.2 == (???))
+ assume ($list.3 == (???))
# Hint: 4 should be a missing key
- assume (???) == $list.4
- assume (???) == $list.foobar
+ assume ($list.4 == (???))
+ assume ($list.foobar == (???))
# The "#" action gets the number of items inside something:
- assume (???) == (#$list)
- assume (???) == (#{.x = 10, .y = 20})
+ assume ((#$list) == (???))
+ assume ((#{.x = 10, .y = 20}) == (???))
lesson "Methods":
# The "," is used for method calls, which means calling an action
@@ -218,17 +218,17 @@ $lessons = [
# Lists have an "add" method that puts new items at the end:
$list = [-4, -6, 5]
$list, add 3
- assume $list == [-4, -6, 5, 3]
+ assume ($list == [-4, -6, 5, 3])
$list, add 7
- assume $list == [???]
+ assume ($list == [???])
# Text also has some methods like:
$name = "Harry Tuttle"
- assume ($name, character 7) == "T"
- assume (???) == ($name, with "Tuttle" -> "Buttle")
+ assume (($name, character 7) == "T")
+ assume (($name, with "Tuttle" -> "Buttle") == (???))
# Methods can be chained too:
- assume (???) == ($name, with "Tuttle" -> "Buttle", character 7)
+ assume (($name, with "Tuttle" -> "Buttle", character 7) == (???))
lesson "Object Oriented Programming":
# Object Oriented Programming deals with things that have
@@ -244,17 +244,14 @@ $lessons = [
($self, add $bit) means:
$bits, add $bit
- ($self, length) means:
- # Write some code that returns the total length of all
- the bits on this buffer.
- # Hint: the length operator (#$foo) works on text
- <your code here>
+ # Write a method called ($self, length) that returns the total
+ length of all the bits in the buffer:
+ <your code here>
$b = (a Buffer)
$b, add "xx"
$b, add "yyy"
- assume ($b, length) == 5
- assume ($b, joined) == "xxyyy"
+ assume (($b, length) == 5)
]
command line program with $args:
diff --git a/nomsu.lua b/nomsu.lua
index ad5c72e..814065d 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -39,11 +39,12 @@ do
local _obj_0 = require("code_obj")
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
-local List, Dict, Text
+local List, Dict
do
local _obj_0 = require('containers')
- List, Dict, Text = _obj_0.List, _obj_0.Dict, _obj_0.Text
+ List, Dict = _obj_0.List, _obj_0.Dict
end
+local Text = require('text')
local sep = "\3"
local parser = re.compile([[ args <- {| (flag %sep)*
{:files: {|
diff --git a/nomsu.moon b/nomsu.moon
index eeca678..f71f5e0 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -41,7 +41,8 @@ if not ok
os.exit(EXIT_FAILURE)
Files = require "files"
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
-{:List, :Dict, :Text} = require 'containers'
+{:List, :Dict} = require 'containers'
+Text = require 'text'
sep = "\3"
parser = re.compile([[
diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua
index 542afe5..0b7de81 100644
--- a/nomsu_compiler.lua
+++ b/nomsu_compiler.lua
@@ -1,8 +1,3 @@
-local List, Dict, Text
-do
- local _obj_0 = require('containers')
- List, Dict, Text = _obj_0.List, _obj_0.Dict, _obj_0.Text
-end
local unpack = unpack or table.unpack
local match, sub, gsub, format, byte, find
do
@@ -232,7 +227,7 @@ compile = function(self, tree)
bit = bit[1]
end
if bit.type == "Block" then
- bit_lua = LuaCode:from(bit.source, "List(function(add)", "\n ", bit_lua, "\nend):joined()")
+ bit_lua = LuaCode:from(bit.source, "a_List(function(add)", "\n ", bit_lua, "\nend):joined()")
elseif bit.type ~= "Text" then
bit_lua = LuaCode:from(bit.source, "tostring(", bit_lua, ")")
end
@@ -257,8 +252,9 @@ compile = function(self, tree)
end
return lua
elseif "List" == _exp_0 or "Dict" == _exp_0 then
+ local typename = "a_" .. tree.type
if #tree == 0 then
- return LuaCode:from(tree.source, tree.type, "{}")
+ return LuaCode:from(tree.source, typename, "{}")
end
local lua = LuaCode:from(tree.source)
local chunks = 0
@@ -268,7 +264,7 @@ compile = function(self, tree)
if chunks > 0 then
lua:add(" + ")
end
- lua:add(tree.type, "(function(", (tree.type == 'List' and "add" or ("add, " .. ("add 1 ="):as_lua_id())), ")")
+ lua:add(typename, "(function(", (tree.type == 'List' and "add" or ("add, " .. ("add 1 ="):as_lua_id())), ")")
lua:add("\n ", self:compile(tree[i]), "\nend)")
chunks = chunks + 1
i = i + 1
@@ -301,9 +297,9 @@ compile = function(self, tree)
i = i + 1
end
if items_lua:is_multiline() then
- lua:add(LuaCode:from(items_lua.source, tree.type, "{\n ", items_lua, "\n}"))
+ lua:add(LuaCode:from(items_lua.source, typename, "{\n ", items_lua, "\n}"))
else
- lua:add(LuaCode:from(items_lua.source, tree.type, "{", items_lua, "}"))
+ lua:add(LuaCode:from(items_lua.source, typename, "{", items_lua, "}"))
end
chunks = chunks + 1
end
diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon
index e17d5e2..b224fad 100644
--- a/nomsu_compiler.moon
+++ b/nomsu_compiler.moon
@@ -1,7 +1,6 @@
--
-- This file contains the source code of the Nomsu compiler.
--
-{:List, :Dict, :Text} = require 'containers'
unpack or= table.unpack
{:match, :sub, :gsub, :format, :byte, :find} = string
{:LuaCode, :Source} = require "code_obj"
@@ -180,7 +179,7 @@ compile = (tree)=>
if bit.type == "Block" and #bit == 1
bit = bit[1]
if bit.type == "Block"
- bit_lua = LuaCode\from bit.source, "List(function(add)",
+ bit_lua = LuaCode\from bit.source, "a_List(function(add)",
"\n ", bit_lua,
"\nend):joined()"
elseif bit.type != "Text"
@@ -199,8 +198,9 @@ compile = (tree)=>
return lua
when "List", "Dict"
+ typename = "a_"..tree.type
if #tree == 0
- return LuaCode\from tree.source, tree.type, "{}"
+ return LuaCode\from tree.source, typename, "{}"
lua = LuaCode\from tree.source
chunks = 0
@@ -208,7 +208,7 @@ compile = (tree)=>
while tree[i]
if tree[i].type == 'Block'
lua\add " + " if chunks > 0
- lua\add tree.type, "(function(", (tree.type == 'List' and "add" or ("add, "..("add 1 =")\as_lua_id!)), ")"
+ lua\add typename, "(function(", (tree.type == 'List' and "add" or ("add, "..("add 1 =")\as_lua_id!)), ")"
lua\add "\n ", @compile(tree[i]), "\nend)"
chunks += 1
i += 1
@@ -234,9 +234,9 @@ compile = (tree)=>
sep = ', '
i += 1
if items_lua\is_multiline!
- lua\add LuaCode\from items_lua.source, tree.type, "{\n ", items_lua, "\n}"
+ lua\add LuaCode\from items_lua.source, typename, "{\n ", items_lua, "\n}"
else
- lua\add LuaCode\from items_lua.source, tree.type, "{", items_lua, "}"
+ lua\add LuaCode\from items_lua.source, typename, "{", items_lua, "}"
chunks += 1
return lua
diff --git a/nomsu_environment.lua b/nomsu_environment.lua
index d9014c3..08fd662 100644
--- a/nomsu_environment.lua
+++ b/nomsu_environment.lua
@@ -3,11 +3,12 @@ do
local _obj_0 = require("code_obj")
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
-local List, Dict, Text
+local List, Dict
do
local _obj_0 = require('containers')
- List, Dict, Text = _obj_0.List, _obj_0.Dict, _obj_0.Text
+ List, Dict = _obj_0.List, _obj_0.Dict
end
+local Text = require('text')
local SyntaxTree = require("syntax_tree")
local Files = require("files")
local Errhand = require("error_handling")
@@ -121,8 +122,9 @@ nomsu_environment = Importer({
jit = jit,
_VERSION = _VERSION,
bit = (jit or _VERSION == "Lua 5.2") and require('bitops') or nil,
- List = List,
- Dict = Dict,
+ a_List = List,
+ a_Dict = Dict,
+ Text = Text,
lpeg = lpeg,
re = re,
Files = Files,
diff --git a/nomsu_environment.moon b/nomsu_environment.moon
index f26a7e9..1ace227 100644
--- a/nomsu_environment.moon
+++ b/nomsu_environment.moon
@@ -1,7 +1,8 @@
-- This file defines the environment in which Nomsu code runs, including some
-- basic bootstrapping functionality.
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
-{:List, :Dict, :Text} = require 'containers'
+{:List, :Dict} = require 'containers'
+Text = require 'text'
SyntaxTree = require "syntax_tree"
Files = require "files"
Errhand = require "error_handling"
@@ -55,7 +56,7 @@ nomsu_environment = Importer{
:pairs, :ipairs, :jit, :_VERSION
bit: (jit or _VERSION == "Lua 5.2") and require('bitops') or nil
-- Nomsu types:
- List:List, Dict:Dict,
+ a_List:List, a_Dict:Dict, Text:Text,
-- Utilities and misc.
lpeg:lpeg, re:re, Files:Files,
:SyntaxTree, TESTS: Dict({}), globals: Dict({}),
diff --git a/pretty_errors.lua b/pretty_errors.lua
index addb42b..6a248d1 100644
--- a/pretty_errors.lua
+++ b/pretty_errors.lua
@@ -1,5 +1,5 @@
require("containers")
-local string2 = require('string2')
+local Text = require('text')
local box
box = function(text)
local max_line = 0
@@ -15,7 +15,7 @@ end
local format_error
format_error = function(err)
local context = err.context or 2
- local err_line, err_linenum, err_linepos = string2.line_at(err.source, err.start)
+ local err_line, err_linenum, err_linepos = err.source:line_info_at(err.start)
local err_size = math.min((err.stop - err.start), (#err_line - err_linepos) + 1)
local nl_indicator = (err_linepos > #err_line) and " " or ""
local fmt_str = " %" .. tostring(#tostring(err_linenum + context)) .. "d|"
@@ -26,9 +26,10 @@ format_error = function(err)
pointer = (" "):rep(err_linepos + #fmt_str:format(0) - 1) .. "⬆"
end
local err_msg = "\027[33;41;1m" .. tostring(err.title or "Error") .. " at " .. tostring(err.filename or '???') .. ":" .. tostring(err_linenum) .. "," .. tostring(err_linepos) .. "\027[0m"
+ local lines = err.source:lines()
for i = err_linenum - context, err_linenum - 1 do
do
- local line = string2.line(err.source, i)
+ local line = lines[i]
if line then
err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0m" .. tostring(line) .. "\027[0m"
end
@@ -41,14 +42,14 @@ format_error = function(err)
err_line = "\027[0m" .. tostring(before) .. "\027[41;30m" .. tostring(during) .. tostring(nl_indicator) .. "\027[0m" .. tostring(after)
err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(err_linenum)) .. tostring(err_line) .. "\027[0m"
end
- local _, err_linenum_end, err_linepos_end = string2.line_at(err.source, err.stop)
+ local _, err_linenum_end, err_linepos_end = err.source:line_info_at(err.stop)
err_linenum_end = err_linenum_end or err_linenum
if err_linenum_end == err_linenum then
err_msg = err_msg .. "\n" .. tostring(pointer)
else
for i = err_linenum + 1, err_linenum_end do
do
- local line = string2.line(err.source, i)
+ local line = lines[i]
if line then
if i == err_linenum_end then
local during, after = line:sub(1, err_linepos_end - 1), line:sub(err_linepos_end, -1)
@@ -65,14 +66,14 @@ format_error = function(err)
end
end
local box_width = 70
- local err_text = "\027[47;31;1m" .. tostring(string2.wrap(" " .. err.error, box_width, 16):gsub("\n", "\n\027[47;31;1m "))
+ local err_text = "\027[47;31;1m" .. tostring(" " .. err.error:wrapped_to(box_width, 16):gsub("\n", "\n\027[47;31;1m "))
if err.hint then
- err_text = err_text .. "\n\027[47;30m" .. tostring(string2.wrap(" Suggestion: " .. tostring(err.hint), box_width, 16):gsub("\n", "\n\027[47;30m "))
+ err_text = err_text .. "\n\027[47;30m" .. tostring((" Suggestion: " .. tostring(err.hint)):wrapped_to(box_width, 16):gsub("\n", "\n\027[47;30m "))
end
err_msg = err_msg .. ("\n\027[33;1m " .. box(err_text):gsub("\n", "\n "))
for i = err_linenum_end + 1, err_linenum_end + context do
do
- local line = string2.line(err.source, i)
+ local line = lines[i]
if line then
err_msg = err_msg .. "\n\027[2m" .. tostring(fmt_str:format(i)) .. "\027[0m" .. tostring(line) .. "\027[0m"
end
diff --git a/pretty_errors.moon b/pretty_errors.moon
index e83f0fb..6b0d561 100644
--- a/pretty_errors.moon
+++ b/pretty_errors.moon
@@ -1,7 +1,7 @@
-- This file has code for converting errors to user-friendly format, with colors,
-- line numbers, code excerpts, and so on.
require "containers"
-string2 = require 'string2'
+Text = require 'text'
box = (text)->
max_line = 0
@@ -14,7 +14,7 @@ box = (text)->
format_error = (err)->
context = err.context or 2
- err_line, err_linenum, err_linepos = string2.line_at(err.source, err.start)
+ err_line, err_linenum, err_linepos = err.source\line_info_at(err.start)
-- TODO: better handle multi-line errors
err_size = math.min((err.stop - err.start), (#err_line-err_linepos) + 1)
nl_indicator = (err_linepos > #err_line) and " " or ""
@@ -24,8 +24,9 @@ format_error = (err)->
else
(" ")\rep(err_linepos+#fmt_str\format(0)-1).."⬆"
err_msg = "\027[33;41;1m#{err.title or "Error"} at #{err.filename or '???'}:#{err_linenum},#{err_linepos}\027[0m"
+ lines = err.source\lines!
for i=err_linenum-context,err_linenum-1
- if line = string2.line(err.source, i)
+ if line = lines[i]
err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0m#{line}\027[0m"
if err_line
before = err_line\sub(1, err_linepos-1)
@@ -33,13 +34,13 @@ format_error = (err)->
after = err_line\sub(err_linepos+err_size, -1)
err_line = "\027[0m#{before}\027[41;30m#{during}#{nl_indicator}\027[0m#{after}"
err_msg ..= "\n\027[2m#{fmt_str\format(err_linenum)}#{err_line}\027[0m"
- _, err_linenum_end, err_linepos_end = string2.line_at(err.source, err.stop)
+ _, err_linenum_end, err_linepos_end = err.source\line_info_at(err.stop)
err_linenum_end or= err_linenum
if err_linenum_end == err_linenum
err_msg ..= "\n#{pointer}"
else
for i=err_linenum+1,err_linenum_end
- if line = string2.line(err.source, i)
+ if line = lines[i]
if i == err_linenum_end
during, after = line\sub(1,err_linepos_end-1), line\sub(err_linepos_end,-1)
err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0;41;30m#{during}\027[0m#{after}"
@@ -50,13 +51,13 @@ format_error = (err)->
break
box_width = 70
- err_text = "\027[47;31;1m#{string2.wrap(" "..err.error, box_width, 16)\gsub("\n", "\n\027[47;31;1m ")}"
+ err_text = "\027[47;31;1m#{" "..err.error\wrapped_to(box_width, 16)\gsub("\n", "\n\027[47;31;1m ")}"
if err.hint
- err_text ..= "\n\027[47;30m#{string2.wrap(" Suggestion: #{err.hint}", box_width, 16)\gsub("\n", "\n\027[47;30m ")}"
+ err_text ..= "\n\027[47;30m#{(" Suggestion: #{err.hint}")\wrapped_to(box_width, 16)\gsub("\n", "\n\027[47;30m ")}"
err_msg ..= "\n\027[33;1m "..box(err_text)\gsub("\n", "\n ")
for i=err_linenum_end+1,err_linenum_end+context
- if line = string2.line(err.source, i)
+ if line = lines[i]
err_msg ..= "\n\027[2m#{fmt_str\format(i)}\027[0m#{line}\027[0m"
return err_msg
diff --git a/string2.lua b/string2.lua
deleted file mode 100644
index 429ab7f..0000000
--- a/string2.lua
+++ /dev/null
@@ -1,204 +0,0 @@
-local reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep, char
-do
- local _obj_0 = string
- reverse, upper, lower, find, byte, match, gmatch, gsub, sub, format, rep, char = _obj_0.reverse, _obj_0.upper, _obj_0.lower, _obj_0.find, _obj_0.byte, _obj_0.match, _obj_0.gmatch, _obj_0.gsub, _obj_0.sub, _obj_0.format, _obj_0.rep, _obj_0.char
-end
-local isplit
-isplit = function(self, sep)
- if sep == nil then
- sep = '%s+'
- end
- local step
- step = function(self, i)
- local start = self.pos
- if not (start) then
- return
- end
- i = i + 1
- local nl = find(self.str, self.sep, start)
- self.pos = nl and (nl + 1) or nil
- local line = sub(self.str, start, nl and (nl - 1) or #self.str)
- return i, line, start, (nl and (nl - 1) or #self.str)
- end
- return step, {
- str = self,
- pos = 1,
- sep = sep
- }, 0
-end
-local lua_keywords = {
- ["and"] = true,
- ["break"] = true,
- ["do"] = true,
- ["else"] = true,
- ["elseif"] = true,
- ["end"] = true,
- ["false"] = true,
- ["for"] = true,
- ["function"] = true,
- ["goto"] = true,
- ["if"] = true,
- ["in"] = true,
- ["local"] = true,
- ["nil"] = true,
- ["not"] = true,
- ["or"] = true,
- ["repeat"] = true,
- ["return"] = true,
- ["then"] = true,
- ["true"] = true,
- ["until"] = true,
- ["while"] = true
-}
-local is_lua_id
-is_lua_id = function(str)
- return match(str, "^[_a-zA-Z][_a-zA-Z0-9]*$") and not lua_keywords[str]
-end
-local string2 = {
- isplit = isplit,
- uppercase = upper,
- lowercase = lower,
- reversed = reverse,
- is_lua_id = is_lua_id,
- capitalized = function(self)
- return gsub(self, '%l', upper, 1)
- end,
- byte = byte,
- bytes = function(self, i, j)
- return {
- byte(self, i or 1, j or -1)
- }
- end,
- split = function(self, sep)
- local _accum_0 = { }
- local _len_0 = 1
- for i, chunk in isplit(self, sep) do
- _accum_0[_len_0] = chunk
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end,
- starts_with = function(self, s)
- return sub(self, 1, #s) == s
- end,
- ends_with = function(self, s)
- return #self >= #s and sub(self, #self - #s, -1) == s
- end,
- lines = function(self)
- local _accum_0 = { }
- local _len_0 = 1
- for i, line in isplit(self, '\n') do
- _accum_0[_len_0] = line
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end,
- line = function(self, line_num)
- for i, line, start in isplit(self, '\n') do
- if i == line_num then
- return line
- end
- end
- end,
- line_at = function(self, pos)
- assert(type(pos) == 'number', "Invalid string position")
- for i, line, start, stop in isplit(self, '\n') do
- if stop + 1 >= pos then
- return line, i, (pos - start + 1)
- end
- end
- end,
- wrap = function(self, maxlen, buffer)
- if maxlen == nil then
- maxlen = 80
- end
- if buffer == nil then
- buffer = 8
- end
- local lines = { }
- local _list_0 = self:lines()
- for _index_0 = 1, #_list_0 do
- local line = _list_0[_index_0]
- while #line > maxlen do
- local chunk = sub(line, 1, maxlen)
- local split = find(chunk, ' ', maxlen - buffer, true) or maxlen
- chunk = sub(line, 1, split)
- line = sub(line, split + 1, -1)
- lines[#lines + 1] = chunk
- end
- lines[#lines + 1] = line
- end
- return table.concat(lines, "\n")
- end,
- indented = function(self, indent)
- if indent == nil then
- indent = " "
- end
- return indent .. (gsub(self, "\n", "\n" .. indent))
- end,
- as_lua = function(self)
- local escaped = gsub(self, "\\", "\\\\")
- escaped = gsub(escaped, "\n", "\\n")
- escaped = gsub(escaped, '"', '\\"')
- escaped = gsub(escaped, "[^ %g]", function(c)
- return format("\\%03d", byte(c, 1))
- end)
- return '"' .. escaped .. '"'
- end,
- as_nomsu = function(self)
- local escaped = gsub(self, "\\", "\\\\")
- escaped = gsub(escaped, "\n", "\\n")
- escaped = gsub(escaped, '"', '\\"')
- escaped = gsub(escaped, "[^ %g]", function(c)
- return format("\\%03d", byte(c, 1))
- end)
- return '"' .. escaped .. '"'
- end,
- as_lua_id = function(str)
- str = gsub(str, "x([0-9A-F][0-9A-F])", "x78%1")
- str = gsub(str, "%W", function(c)
- if c == ' ' then
- return '_'
- else
- return format("x%02X", byte(c))
- end
- end)
- if not (is_lua_id(match(str, "^_*(.*)$"))) then
- str = "_" .. str
- end
- return str
- end,
- from_lua_id = function(str)
- if not (is_lua_id(match(str, "^_*(.*)$"))) then
- str = sub(str, 2, -1)
- end
- str = gsub(str, "_", " ")
- str = gsub(str, "x([0-9A-F][0-9A-F])", function(hex)
- return char(tonumber(hex, 16))
- end)
- return str
- end
-}
-for k, v in pairs(string) do
- string2[k] = string2[k] or v
-end
-local _list_0 = {
- "",
- "_",
- " ",
- "return",
- "asdf",
- "one two",
- "one_two",
- "Hex2Dec",
- "He-ec",
- "\3"
-}
-for _index_0 = 1, #_list_0 do
- local test = _list_0[_index_0]
- local lua_id = string2.as_lua_id(test)
- assert(is_lua_id(lua_id), "failed to convert '" .. tostring(test) .. "' to a valid Lua identifier (got '" .. tostring(lua_id) .. "')")
- local roundtrip = string2.from_lua_id(lua_id)
- assert(roundtrip == test, "Failed lua_id roundtrip: '" .. tostring(test) .. "' -> '" .. tostring(lua_id) .. "' -> '" .. tostring(roundtrip) .. "'")
-end
-return string2
diff --git a/string2.moon b/string2.moon
deleted file mode 100644
index de2980d..0000000
--- a/string2.moon
+++ /dev/null
@@ -1,106 +0,0 @@
--- Expand the capabilities of the built-in strings
-{:reverse, :upper, :lower, :find, :byte, :match, :gmatch, :gsub, :sub, :format, :rep, :char} = string
-
-isplit = (sep='%s+')=>
- step = (i)=>
- start = @pos
- return unless start
- i += 1
- nl = find(@str, @sep, start)
- @pos = nl and (nl+1) or nil
- line = sub(@str, start, nl and (nl-1) or #@str)
- return i, line, start, (nl and (nl-1) or #@str)
- return step, {str:@, pos:1, :sep}, 0
-
-lua_keywords = {
- ["and"]:true, ["break"]:true, ["do"]:true, ["else"]:true, ["elseif"]:true, ["end"]:true,
- ["false"]:true, ["for"]:true, ["function"]:true, ["goto"]:true, ["if"]:true,
- ["in"]:true, ["local"]:true, ["nil"]:true, ["not"]:true, ["or"]:true, ["repeat"]:true,
- ["return"]:true, ["then"]:true, ["true"]:true, ["until"]:true, ["while"]:true
-}
-is_lua_id = (str)->
- match(str, "^[_a-zA-Z][_a-zA-Z0-9]*$") and not lua_keywords[str]
-
-string2 = {
- :isplit, uppercase:upper, lowercase:lower, reversed:reverse, :is_lua_id
- capitalized: => gsub(@, '%l', upper, 1)
- byte: byte, bytes: (i, j)=> {byte(@, i or 1, j or -1)}
- split: (sep)=> [chunk for i,chunk in isplit(@, sep)]
- starts_with: (s)=> sub(@, 1, #s) == s
- ends_with: (s)=> #@ >= #s and sub(@, #@-#s, -1) == s
- lines: => [line for i,line in isplit(@, '\n')]
- line: (line_num)=>
- for i, line, start in isplit(@, '\n')
- return line if i == line_num
-
- line_at: (pos)=>
- assert(type(pos) == 'number', "Invalid string position")
- for i, line, start, stop in isplit(@, '\n')
- if stop+1 >= pos
- return line, i, (pos-start+1)
-
- wrap: (maxlen=80, buffer=8)=>
- lines = {}
- for line in *@lines!
- while #line > maxlen
- chunk = sub(line, 1, maxlen)
- split = find(chunk, ' ', maxlen-buffer, true) or maxlen
- chunk = sub(line, 1, split)
- line = sub(line, split+1, -1)
- lines[#lines+1] = chunk
- lines[#lines+1] = line
- return table.concat(lines, "\n")
-
- indented: (indent=" ")=>
- indent..(gsub(@, "\n", "\n"..indent))
-
- as_lua: =>
- escaped = gsub(@, "\\", "\\\\")
- escaped = gsub(escaped, "\n", "\\n")
- escaped = gsub(escaped, '"', '\\"')
- escaped = gsub(escaped, "[^ %g]", (c)-> format("\\%03d", byte(c, 1)))
- return '"'..escaped..'"'
-
- as_nomsu: =>
- escaped = gsub(@, "\\", "\\\\")
- escaped = gsub(escaped, "\n", "\\n")
- escaped = gsub(escaped, '"', '\\"')
- escaped = gsub(escaped, "[^ %g]", (c)-> format("\\%03d", byte(c, 1)))
- return '"'..escaped..'"'
-
- -- Convert an arbitrary text into a valid Lua identifier. This function is injective,
- -- but not idempotent. In logic terms: (x != y) => (as_lua_id(x) != as_lua_id(y)),
- -- but not (as_lua_id(a) == b) => (as_lua_id(b) == b).
- as_lua_id: (str)->
- -- Escape 'x' (\x78) when it precedes something that looks like an uppercase hex sequence.
- -- This way, all Lua IDs can be unambiguously reverse-engineered, but normal usage
- -- of 'x' won't produce ugly Lua IDs.
- -- i.e. "x" -> "x", "oxen" -> "oxen", but "Hex2Dec" -> "Hex782Dec" and "He-ec" -> "Hex2Dec"
- str = gsub str, "x([0-9A-F][0-9A-F])", "x78%1"
- -- Map spaces to underscores, and everything else non-alphanumeric to hex escape sequences
- str = gsub str, "%W", (c)->
- if c == ' ' then '_'
- else format("x%02X", byte(c))
-
- unless is_lua_id(match(str, "^_*(.*)$"))
- str = "_"..str
- return str
-
- -- from_lua_id(as_lua_id(str)) == str, but behavior is unspecified for inputs that
- -- did not come from as_lua_id()
- from_lua_id: (str)->
- unless is_lua_id(match(str, "^_*(.*)$"))
- str = sub(str,2,-1)
- str = gsub(str, "_", " ")
- str = gsub(str, "x([0-9A-F][0-9A-F])", (hex)-> char(tonumber(hex, 16)))
- return str
-}
-for k,v in pairs(string) do string2[k] or= v
-
-for test in *{"", "_", " ", "return", "asdf", "one two", "one_two", "Hex2Dec", "He-ec", "\3"}
- lua_id = string2.as_lua_id(test)
- assert is_lua_id(lua_id), "failed to convert '#{test}' to a valid Lua identifier (got '#{lua_id}')"
- roundtrip = string2.from_lua_id(lua_id)
- assert roundtrip == test, "Failed lua_id roundtrip: '#{test}' -> '#{lua_id}' -> '#{roundtrip}'"
-
-return string2