diff options
Diffstat (limited to 'core')
| -rw-r--r-- | core/control_flow.nom | 46 | ||||
| -rw-r--r-- | core/id.nom | 56 | ||||
| -rw-r--r-- | core/metaprogramming.nom | 29 | ||||
| -rw-r--r-- | core/operators.nom | 22 | ||||
| -rw-r--r-- | core/text.nom | 6 |
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 |
