-- The poor man's record update

local structname, fields = dofile(assert(arg[1]))
local usedFields = {}
for _, s in ipairs(fields) do
  usedFields[s] = true
end

local fname = "f"
local counter = 0
while usedFields[fname] do
  fname = "f" .. tostring(counter)
  counter = counter + 1
end

local out = io.stdout
out:write([[
(* -*- mode: sml; mode: read-only -*- *)
(* This file was generated by util/record.lua. Do not edit by hand! *)
]])
out:write(string.format([[
structure %s = struct
  structure set = struct
]], structname))
local values = {} -- {"a = a", "b = b"}
for _, field in ipairs(fields) do
  table.insert(values, string.format("%s = %s", field, field))
end
local values_s = table.concat(values, ", ")
for _, field in ipairs(fields) do
  local pats = {}
  for _, field2 in ipairs(fields) do
    if field == field2 then
      table.insert(pats, string.format("%s = _", field2))
    else
      table.insert(pats, string.format("%s", field2))
    end
  end
  out:write(string.format("     val %s = fn %s => fn { %s } => { %s }\n", field, field, table.concat(pats, ", "), values_s))
end
out:write([[
  end
  structure update = struct
]])
local pats = table.concat(fields, ", ")
for _, field in ipairs(fields) do
  local values = {}
  for _, field2 in ipairs(fields) do
    if field == field2 then
      table.insert(values, string.format("%s = %s %s", field, fname, field))
    else
      table.insert(values, string.format("%s = %s", field2, field2))
    end
  end
  out:write(string.format("     val %s = fn %s => fn { %s } => { %s }\n", field, fname, pats, table.concat(values, ", ")))
end
out:write([[
  end
end;
]])

--[[
struct MyRecord = struct
  structure set = struct
    val a = fn a => fn { a = _, b } => { a = a, b = b }
    val b = fn b => fn { a, b = _ } => { a = a, b = b }
  end
  structurue update = struct
    val a = fn f => fn { a, b } => { a = f a, b = b }
    val b = fn f => fn { a, b } => { a = a, b = f b }
  end
end;
]]
