aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/control_flow.nom46
-rw-r--r--core/id.nom56
-rw-r--r--core/metaprogramming.nom29
-rw-r--r--core/operators.nom22
-rw-r--r--core/text.nom6
5 files changed, 107 insertions, 52 deletions
diff --git a/core/control_flow.nom b/core/control_flow.nom
index a786f44..0c38485 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -139,9 +139,10 @@ test:
repeat 10 times: %x += 1
assume (%x == 10)
compile [repeat %n times %body] to:
+ define mangler
%lua = (..)
Lua ".."
- for i=1,\(%n as lua expr) do
+ for \(mangle "i")=1,\(%n as lua expr) do
\(%body as lua statements)
if (%body has subtree \(do next)):
@@ -242,9 +243,10 @@ compile [for %var in %iterable %body] to:
# This uses Lua's approach of only allowing loop-scoped variables in a loop
unless (%var.type is "Var"):
compile error at %var.source "Loop expected variable, not: %s"
+ define mangler
%lua = (..)
Lua ".."
- for i,\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
+ for \(mangle "i"),\(%var as lua identifier) in ipairs(\(%iterable as lua expr)) do
\(%body as lua statements)
if (%body has subtree \(do next)):
@@ -391,6 +393,7 @@ compile [if %branch_value is %body, when %branch_value is %body] to:
%code = (Lua "")
%clause = "if"
%else_allowed = (yes)
+ define mangler
unless (%body.type is "Block"):
compile error at %body.source "'if' expected a Block, but got: %s"
for %line in %body:
@@ -426,7 +429,7 @@ compile [if %branch_value is %body, when %branch_value is %body] to:
if (%i > 1):
%code::append " or "
- %code::append "branch_value == \(%line.%i as lua expr)"
+ %code::append "\(mangle "branch value") == \(%line.%i as lua expr)"
%code::append ".."
then
@@ -440,7 +443,7 @@ compile [if %branch_value is %body, when %branch_value is %body] to:
return (..)
Lua ".."
do --if % is
- local branch_value = \(%branch_value as lua expr)
+ local \(mangle "branch value") = \(%branch_value as lua expr)
\%code
end --if % is
@@ -461,18 +464,20 @@ test:
..and if it barfs: do nothing
assume (%d.x == "good")
-compile [do %action then always %final_action] to (..)
- Lua ".."
- do
- local fell_through = false
- local ok, ret = pcall(function()
- \(%action as lua statements)
- fell_through = true
- end)
- \(%final_action as lua statements)
- if not ok then error(ret, 0) end
- if not fell_through then return ret end
- end
+compile [do %action then always %final_action] to:
+ define mangler
+ return (..)
+ Lua ".."
+ do
+ local \(mangle "fell_through") = false
+ local \(mangle "ok"), \(mangle "ret") = pcall(function()
+ \(%action as lua statements)
+ \(mangle "fell_through") = true
+ end)
+ \(%final_action as lua statements)
+ if not \(mangle "ok") then error(ret, 0) end
+ if not \(mangle "fell_through") then return ret end
+ end
test:
assume ((result of (: return 99)) == 99)
@@ -493,14 +498,15 @@ test:
# Recurion control flow
compile [for %var in recursive %structure %body] to (..)
with local compile actions:
+ define mangler
compile [recurse %v on %x] to (..)
- Lua "table.insert(stack\(%v as lua id), \(%x as lua expr))"
+ Lua "table.insert(\(mangle "stack \(%v.1)"), \(%x as lua expr))"
%lua = (..)
Lua ".."
do
- local stack\(%var as lua id) = list{\(%structure as lua expr)}
- while #stack\(%var as lua id) > 0 do
- \(%var as lua expr) = table.remove(stack\(%var as lua id), 1)
+ local \(mangle "stack \(%var.1)") = _List{\(%structure as lua expr)}
+ while #\(mangle "stack \(%var.1)") > 0 do
+ \(%var as lua expr) = table.remove(\(mangle "stack \(%var.1)"), 1)
\(%body as lua statements)
if (%body has subtree \(do next)):
diff --git a/core/id.nom b/core/id.nom
new file mode 100644
index 0000000..80d40f0
--- /dev/null
+++ b/core/id.nom
@@ -0,0 +1,56 @@
+#!/usr/bin/env nomsu -V3.7.5.6
+#
+ A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt
+
+use "core/metaprogramming.nom"
+use "core/math.nom"
+use "core/collections.nom"
+use "core/control_flow.nom"
+
+%NaN_surrogate = {}
+%nil_surrogate = {}
+%obj_by_id = {}
+set %obj_by_id's metatable to {__mode: "v"}
+%id_by_obj = {}
+set %id_by_obj's metatable to {..}
+ __mode: "k"
+ __index: (..)
+ [%self, %key] ->:
+ if (%key == (nil)): return %self.%nil_surrogate
+ if (%key != %key): return %self.%NaN_surrogate
+ --- %retry ---
+ %id = (uuid)
+ if (%obj_by_id.%id != (nil)): go to %retry
+ %self.%key = %id
+ %obj_by_id.%id = %key
+ return %id
+
+local action [uuid]:
+ # Set all the other bits to randomly (or pseudo-randomly) chosen values.
+ %bytes = [..]
+ randint (2^(4*8)), # time-low
+ randint (2^(2*8)), # time-mid
+ randint (2^(2*8 - 4)), # time-high-and-version
+ randint (2^(1*8 - 2)), # clock-seq-and-reserved
+ randint (2^(1*8)), # clock-seq-low
+ randint (2^(3*8)), randint (2^(3*8)), # node
+ # Set the four most significant bits (bits 12 through 15) of the
+ # time_hi_and_version field to the 4-bit version number from
+ # Section 4.1.3.
+ %bytes.3 += 0x4000
+ # Set the two most significant bits (bits 6 and 7) of the
+ # clock_seq_hi_and_reserved to zero and one, respectively.
+ %bytes.4 += 0xC0
+ return (=lua "('%08x-%04x-%04x-%02x%02x-%6x%6x'):format(unpack(\%bytes))")
+
+# For strict identity checking, use (%x's id) == (%y's id)
+test:
+ assume (([] == []) and ((id of []) != (id of [])))
+ seed random with 0
+ %x = []
+ assume ((id of %x) == (id of %x))
+ seed random with 0
+ assume ((id of %x) != (id of []))
+ seed random
+
+action [id of %, %'s id, %' id] %id_by_obj.%
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index 0f64bac..c978bf8 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -5,6 +5,20 @@
lua> "NOMSU_CORE_VERSION = 7"
lua> ".."
+ do
+ local mangle_index = 0
+ function mangler()
+ local my_mangle_index = mangle_index
+ mangle_index = mangle_index + 1
+ return function(varname)
+ return string.as_lua_id(varname..(("\\3%X"):format(my_mangle_index)))
+ end
+ end
+ end
+ COMPILE_ACTIONS["define mangler"] = function(nomsu, tree)
+ return LuaCode(tree.source, "local mangle_1 = mangler()")
+ end
+lua> ".."
COMPILE_ACTIONS["1 -> 2"] = function(nomsu, tree, \%args, \%body)
local lua = LuaCode.Value(tree.source, "(function(")
if AST.is_syntax_tree(\%args, "Action") then \%args = \%args:get_args() end
@@ -34,7 +48,7 @@ test:
compile [five] to (Lua value "5")
test:
assume ((five) == 5) or barf "Compile to expression failed."
- compile [loc x] to (Lua "local _x = 99;")
+ compile [loc x] to (Lua "local x = 99;")
test:
lua> "do"
loc x
@@ -158,7 +172,7 @@ compile [parse %actions as %body] to (..)
if replacements[t[1]] then
return replacements[t[1]]
else
- return t.type.."{"..repr(t[1].." \\0").."..('%X'):format(__MANGLE_INDEX), source="..repr(tostring(t.source)).."}"
+ return t.type.."{mangle("..repr(t[1]).."), source="..repr(tostring(t.source)).."}"
end
elseif AST.is_syntax_tree(t) then
local ret = {}
@@ -181,7 +195,7 @@ compile [parse %actions as %body] to (..)
end
end
local \%new_body = LuaCode(\%body.source,
- "__MANGLE_INDEX = (__MANGLE_INDEX or 0) + 1",
+ "local mangle = mangler()",
"\\nlocal tree = ", make_tree(\%body),
"\\nlocal lua = nomsu:compile(tree)",
"\\nreturn lua")
@@ -223,8 +237,9 @@ compile [%tree as inline nomsu] to (..)
action [%var as lua identifier, %var as lua id] (..)
lua> ".."
if type(\%var) == 'string' then return string.as_lua_id(\%var)
- elseif \%var.type == 'Var' then return "_"..string.as_lua_id(\%var[1])
- elseif \%var.type == 'Action' then return string.as_lua_id(\%var.stub)
+ elseif AST.is_syntax_tree(\%var, 'Var') then return string.as_lua_id(\%var[1])
+ elseif AST.is_syntax_tree(\%var, 'Action') then return string.as_lua_id(\%var.stub)
+ else error("Unknown type: "..tostring(\%var))
end
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -266,10 +281,10 @@ compile [%tree has subtree %match_tree] to (..)
action [match %tree with %patt]:
lua> ".."
- if \%patt.type == "Var" then return dict{[\%patt[1]]=\%tree} end
+ if \%patt.type == "Var" then return _Dict{[\%patt[1]]=\%tree} end
if \%patt.type == "Action" and \%patt.stub ~= \%tree.stub then return nil end
if #\%patt ~= #\%tree then return nil end
- local matches = dict{}
+ local matches = _Dict{}
for \%i=1,#\%patt do
if AST.is_syntax_tree(\%tree[\%i]) then
local submatch = \(match %tree.%i with %patt.%i)
diff --git a/core/operators.nom b/core/operators.nom
index 7e30705..9395d9d 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -19,28 +19,6 @@ compile [%a is %b, %a == %b] to (..)
compile [%a isn't %b, %a is not %b, %a not= %b, %a != %b] to (..)
Lua value "(\(%a as lua expr) ~= \(%b as lua expr))"
-# For strict identity checking, use (%x's id) is (%y's id)
-test:
- assume (([] == []) and (([] 's id) != ([] 's id)))
-lua> ".."
- do
- local new_uuid = require('uuid')
- local NaN_surrogate = {}
- local nil_surrogate = {}
- IDS = setmetatable({}, {
- __mode = "k",
- __index = function(self, key)
- if key == nil then return self[nil_surrogate]
- elseif key ~= key then return self[NaN_surrogate] end
- local id = new_uuid()
- self[key] = id
- return id
- end
- })
- end
-
-compile [% 's id, id of %] to (Lua value "IDS[\(% as lua expr)]")
-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test:
diff --git a/core/text.nom b/core/text.nom
index 0232b7d..d9d85b5 100644
--- a/core/text.nom
+++ b/core/text.nom
@@ -47,7 +47,7 @@ compile [byte %i of %text] to (..)
compile [bytes %start to %stop of %text] to (..)
Lua value ".."
- list{(\(%text as lua expr)):byte(\(%start as lua expr), \(%stop as lua expr))}
+ _List{(\(%text as lua expr)):byte(\(%start as lua expr), \(%stop as lua expr))}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -82,7 +82,7 @@ test:
..== ["one", "two"]
action [lines in %text, lines of %text] (..)
lua> ".."
- local result = list{}
+ local result = _List{}
for line in (\%text):gmatch('[^\\n]+') do
result[#result+1] = line
end
@@ -99,7 +99,7 @@ compile [for %match in %text matching %patt %body] to (..)
compile [%expr for %match in %text matching %patt] to (..)
Lua value ".."
(function()
- local ret = list{}
+ local ret = _List{}
for \(%match as lua expr) in (\(%text as lua expr)):gmatch(\(..)
%patt as lua expr
..) do