[ create a new paste ] login | about

Link: http://codepad.org/fKjjQT4b    [ raw code | output | fork ]

Corsix - Lua, pasted on Feb 9:
#! /usr/local/bin/lua

-- Helper functions to encode VM operations
local function int(value) -- convert value to a 32-bit unsigned little-endian integer
  local b1, b2, b3, b4
  b1 = value % 0x100
  value = (value - b1) / 0x100
  b2 = value % 0x100
  value = (value - b2) / 0x100
  b3 = value % 0x100
  value = (value - b3) / 0x100
  b4 = value % 0x100
  return string.char(b1, b2, b3, b4)
end

local function ABC(op, a, b, c) -- create an ABC VM instruction
  local value = op + a * 2^6 + c * 2^14 + b * 2^23
  return int(value)
end

-- factory for count_raw
local function make_count_raw()
  local sentinel = {}
  local nxt
  -- raw: function(count, test, ...)
  -- if type(test) ~= "none", returns raw(count + 1, ...)
  -- otherwise returns count
  local raw = function(...)
    local null, count, sent
    sent = sentinel
    null = {...} -- this line gets modified
    -- after modification, ... is loaded into count, sent, etc. and then setlisted into
    -- a nil value to correct L->top. If we had a vararg, then sent will no longer be
    -- sentinel. (also note that after modification, no tables are created)
    if sent == sentinel then
      return count
    else
      -- we cannot trim a value off the front of the varargs ourselves, so proxy it
      return nxt(...)
    end
  end
  -- nxt: helper for raw
  nxt = function(count, a, ...)
    return raw(count + 1, ...)
  end
  return raw
end

-- tweak the factory to work as intended
do
  make_count_raw = string.dump(make_count_raw)
  local to_find = ABC(4 , 3, 0, 0) -- GETUPVAL sentinel
               .. ABC(10, 4, 0, 0) -- NEWTABLE
               .. ABC(37, 5, 0, 0) -- VARARG
               .. ABC(34, 4, 0, 1) -- SETLIST
               .. ABC(0 , 1, 4, 0) -- MOVE 1, 4
  local to_rep = ABC(4 , 3, 0, 0) -- GETUPVAL sentinel
              .. ABC(0 , 0, 0, 0) -- NOP
              .. ABC(37, 2, 0, 0) -- VARARG (sets count, *may* overwrite sent)
              .. ABC(34, 1, 0, 1) -- SETLIST (into a nil, so it does nothing)
              .. ABC(0 , 0, 0, 0) -- NOP
  local first, last = make_count_raw:find(to_find, 1, true)
  make_count_raw = make_count_raw:sub(1, first - 1) .. to_rep .. make_count_raw:sub(last + 1)
  make_count_raw = assert(loadstring(make_count_raw))
end

-- create count_raw and define count
local count_raw = make_count_raw()

function count(...)
  return count_raw(0, ...)
end

-- show it working
print(count("a", "b", "c")) --> 3
print(count(nil, "d", nil, nil)) --> 4
print(count("e", nil, nil, "f", nil, nil, nil)) --> 7
print(count()) --> 0
print(count(nil)) --> 1


Output:
1
2
3
4
5
3
4
7
0
1


Create a new paste based on this one


Comments: