local fibbuf = require "fibonacci-buffer"
local pretty_printer = require "pretty-printer"
local s = pretty_printer.s
local gen = require "terms-generators"
local derivers = require "derivers"
local traits = require "traits"
local U = require "alicorn-utils"
local format = require "format"
local map = gen.declare_map
local array = gen.declare_array
local set = gen.declare_set
local checkable_term = gen.declare_type()
local unanchored_inferrable_term = gen.declare_type()
local anchored_inferrable_term = gen.declare_type()
local typed_term = gen.declare_type()
local free = gen.declare_type()
local strict_value = gen.declare_type()
local stuck_value = gen.declare_type()
local flex_value = gen.declare_type()
local flex_runtime_context_type = gen.declare_type()
local binding = gen.declare_type()
local expression_goal = gen.declare_type()
local Metavariable = {}
function Metavariable:as_stuck()
return U.notail(stuck_value.free(free.metavariable(self)))
end
function Metavariable:as_flex()
return U.notail(flex_value.stuck(self:as_stuck()))
end
local metavariable_mt = { __index = Metavariable }
local metavariable_type = gen.declare_foreign(gen.metatable_equality(metavariable_mt), "Metavariable")
local anchor_type = gen.declare_foreign(gen.metatable_equality(format.anchor_mt), "Anchor")
local span_type = gen.declare_foreign(gen.metatable_equality(format.span_mt), "Span")
traits.diff:implement_on(metavariable_type, {
diff = function(left, right)
print("diffing metavariables:")
if left.value ~= right.value then
print("left value ~= right value: " .. left.value .. " ~= " .. right.value)
end
if left.usage ~= right.usage then
print("left usage ~= right usage: " .. left.usage .. " ~= " .. right.usage)
end
if left.block_level ~= right.block_level then
print("left block_level ~= right block_level: " .. left.block_level .. " ~= " .. right.block_level)
end
if left.trait ~= right.trait then
if left.trait then
print("left metavariable is a trait, but right isn't!")
else
print("right metavariable is a trait, but left isn't!")
end
end
end,
})
local spanned_name = gen.declare_record("spanned_name", {
"name",
gen.builtin_string,
"name_span",
span_type,
})
local FlexRuntimeContext = {}
local RuntimeContextBinding = {
__eq = function(l, r)
return l.name == r.name and l.val == r.val
end,
}
function FlexRuntimeContext:dump_names()
for i = 1, self.bindings:len() do
print(i, self.bindings:get(i).name)
end
end
function FlexRuntimeContext:format_names()
local msg = ""
for i = 1, self.bindings:len() do
msg = msg .. tostring(i) .. "\t" .. self.bindings:get(i).name .. "\n"
end
return msg
end
function FlexRuntimeContext:get(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.val, binding.debuginfo
end
function FlexRuntimeContext:get_name(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.name
end
function FlexRuntimeContext:get_spanned_name(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.debuginfo
end
function FlexRuntimeContext:append(v, name, debuginfo)
if debuginfo == nil then
error("null debuginfo appended to FlexRuntimeContext")
end
name = name or debuginfo.name if name == nil then
error("All variables MUST have debug information!")
end
local copy = {
provenance = self,
stuck_count = self.stuck_count,
bindings = self.bindings:append(
setmetatable({ name = name, val = v, debuginfo = debuginfo }, RuntimeContextBinding)
),
}
if v:is_stuck() then
copy.stuck_count = copy.stuck_count + 1
end
return setmetatable(copy, getmetatable(self))
end
function FlexRuntimeContext:set(index, v)
local old = self.bindings:get(index)
local new = setmetatable({ name = old.name, val = v }, RuntimeContextBinding)
local copy = { provenance = self, stuck_count = self.stuck_count, bindings = self.bindings:set(index, new) }
if old.val:is_stuck() then
copy.stuck_count = copy.stuck_count - 1
end
if v:is_stuck() then
copy.stuck_count = copy.stuck_count + 1
end
return setmetatable(copy, getmetatable(self))
end
function FlexRuntimeContext:eq(other)
local omt = getmetatable(other)
if omt ~= getmetatable(self) then
return false
end
return self.bindings == other.bindings
end
local StrictRuntimeContext = U.shallow_copy(FlexRuntimeContext)
function StrictRuntimeContext:get(index)
return U.notail(FlexRuntimeContext.get(self, index):unwrap_strict())
end
function StrictRuntimeContext:get_name(index)
local binding = self:get(index)
if binding == nil then
return nil
end
return binding.name
end
function StrictRuntimeContext:get_spanned_name(index)
local binding = self:get(index)
if binding == nil then
return nil
end
return binding.debuginfo
end
function StrictRuntimeContext:append(v, name, debuginfo)
if strict_value.value_check(v) ~= true then
error("StrictRuntimeContext:append v must be a strict_value")
end
return U.notail(FlexRuntimeContext.append(self, flex_value.strict(v), name, debuginfo))
end
function StrictRuntimeContext:set(index, v)
if strict_value.value_check(v) ~= true then
error("StrictRuntimeContext:set v must be a strict_value")
end
return U.notail(FlexRuntimeContext.set(self, index, flex_value.strict(v)))
end
local strict_runtime_context_mt = {
__index = StrictRuntimeContext,
__eq = StrictRuntimeContext.eq,
__tostring = function(t)
return "StrictRuntimeContext with " .. t.bindings:len() .. " bindings."
end,
}
local function strict_runtime_context()
return setmetatable({ stuck_count = 0, bindings = fibbuf() }, strict_runtime_context_mt)
end
local flex_runtime_context_mt = {
__index = FlexRuntimeContext,
__eq = FlexRuntimeContext.eq,
__tostring = function(t)
return "FlexRuntimeContext with " .. t.bindings:len() .. " bindings."
end,
}
local function flex_runtime_context()
return setmetatable({ stuck_count = 0, bindings = fibbuf() }, flex_runtime_context_mt)
end
function FlexRuntimeContext:as_strict()
if self.stuck_count > 0 then
error("Cannot convert runtime context to strict, found " .. tostring(self.stuck_count) .. " stuck bindings!")
end
return setmetatable(
{ provenance = self, stuck_count = self.stuck_count, bindings = self.bindings },
strict_runtime_context_mt
)
end
function StrictRuntimeContext:as_flex()
return setmetatable(
{ provenance = self, stuck_count = self.stuck_count, bindings = self.bindings },
flex_runtime_context_mt
)
end
local function runtime_context_diff_fn(left, right)
print("diffing runtime context...")
local rt = getmetatable(right)
if getmetatable(left) ~= rt then
print("unequal types!")
print(getmetatable(left))
print(rt)
print("stopping diff")
return
end
if left.bindings:len() ~= right.bindings:len() then
print("unequal lengths!")
print(left.bindings:len())
print(right.bindings:len())
print("stopping diff")
return
end
local n = 0
local diff_elems = {}
for i = 1, left.bindings:len() do
if left:get(i) ~= right:get(i) then
n = n + 1
diff_elems[n] = i
end
end
if n == 0 then
print("no difference")
print("stopping diff")
return
elseif n == 1 then
local d = diff_elems[1]
print("difference in element: " .. tostring(d))
local diff_impl
if rt == flex_runtime_context_mt then
diff_impl = traits.diff:get(flex_value)
elseif rt == strict_runtime_context_mt then
diff_impl = traits.diff:get(strict_value)
end
return diff_impl.diff(left:get(d), right:get(d))
else
print("difference in multiple elements:")
for i = 1, n do
print("left " .. tostring(diff_elems[i]) .. ": " .. tostring(left:get(diff_elems[i])))
print("right " .. tostring(diff_elems[i]) .. ": " .. tostring(right:get(diff_elems[i])))
end
print("stopping diff")
return
end
end
local typechecking_context_mt
local TypecheckingContext = {}
local function to_runtime_context(ctx)
if getmetatable(ctx) == typechecking_context_mt then
return ctx.runtime_context
end
return ctx
end
local function verify_placeholders(v, ctx, values)
if type(v) ~= "table" then
return true
end
ctx = to_runtime_context(ctx)
if getmetatable(v) and getmetatable(getmetatable(v)) == gen.array_type_mt then
for k, val in ipairs(v) do
if not verify_placeholders(val, ctx, values) then
return false
end
end
return true
end
if not v.kind then
return true
end
if v.kind == "free.placeholder" then
local i, info = v:unwrap_placeholder()
if info then
local source_ctx = ctx
while source_ctx do
if source_ctx == info.ctx then
return true
end
source_ctx = source_ctx.provenance
end
print(
debug.traceback(
"INVALID PROVENANCE: "
.. tostring(info)
.. "\nORIGINAL CTX: "
.. info.ctx:format_names()
.. "\nASSOCIATED CTX: "
.. ctx:format_names()
)
)
os.exit(-1, true)
return false
end
elseif v.kind == "free.metavariable" then
if not values then
error(debug.traceback("FORGOT values PARAMETER!"))
end
local mv = v:unwrap_metavariable()
local source_ctx = ctx
local mv_ctx = to_runtime_context(values[mv.value][3])
while source_ctx do
if source_ctx == mv_ctx then
return true
end
source_ctx = source_ctx.provenance
end
if ctx:get(1) == mv_ctx:get(1) then
return true
end
print("dumping metavariable paths")
source_ctx = ctx
while source_ctx do
print(source_ctx)
source_ctx = source_ctx.provenance
end
print("----")
source_ctx = mv_ctx
while source_ctx do
print(source_ctx)
source_ctx = source_ctx.provenance
end
print(
debug.traceback(
"INVALID METAVARIABLE PROVENANCE: "
.. tostring(v)
.. "\nORIGINAL CTX: "
.. tostring(values[mv.value][3])
.. "\n"
.. values[mv.value][3]:format_names()
.. "\nASSOCIATED CTX: "
.. tostring(ctx)
.. "\n"
.. ctx:format_names()
)
)
os.exit(-1, true)
return false
end
for k, val in pairs(v) do
if k ~= "cause" then
if not verify_placeholders(val, ctx, values) then
return false
end
end
end
return true
end
function TypecheckingContext:get_name(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.name
end
function TypecheckingContext:get_spanned_name(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.debuginfo
end
function TypecheckingContext:dump_names()
for i = 1, self:len() do
print(i, tostring(self:get_name(i)))
end
end
function TypecheckingContext:format_names()
local msg = {}
for i = 1, self:len() do
msg[(i * 3) - 2] = tostring(i)
msg[(i * 3) - 1] = "\t"
msg[i * 3] = tostring(self:get_name(i))
end
return table.concat(msg, "\n")
end
function TypecheckingContext:format_names_and_types()
local msg = {}
for i = 1, self:len() do
msg[(i * 5) - 4] = tostring(i)
msg[(i * 5) - 3] = "\t"
msg[(i * 5) - 2] = tostring(self:get_name(i))
msg[(i * 5) - 1] = "\t:\t"
msg[i * 5] = self:get_type(i):pretty_print(self)
end
return table.concat(msg, "\n")
end
function TypecheckingContext:get_type(index)
local binding = self.bindings:get(index)
if binding == nil then
return nil
end
return binding.type
end
function TypecheckingContext:DEBUG_VERIFY_VALUES(state)
for i = 1, self:len() do
verify_placeholders(self:get_type(i), self, state.values)
end
end
function TypecheckingContext:get_runtime_context()
return self.runtime_context
end
function TypecheckingContext:append(name, type, val, debuginfo)
if gen.builtin_string.value_check(name) ~= true then
error("TypecheckingContext:append parameter 'name' must be a string")
end
if flex_value.value_check(type) ~= true then
print("type", type)
p(type)
for k, v in pairs(type) do
print(k, v)
end
print(getmetatable(type))
error("TypecheckingContext:append parameter 'type' must be a flex_value")
end
if type:is_closure() then
error "BUG!!!"
end
if val ~= nil and flex_value.value_check(val) ~= true then
error("TypecheckingContext:append parameter 'val' must be a flex_value (or nil if given start_anchor)")
end
if debuginfo ~= nil and spanned_name.value_check(debuginfo) ~= true then
error("TypecheckingContext:append parameter 'debuginfo' must be a spanned_name (or nil if given val)")
end
if not val and not debuginfo then
error("TypecheckingContext:append expected either val or debuginfo")
end
if not val then
val = flex_value.stuck(stuck_value.free(free.placeholder(self:len() + 1, debuginfo)))
end
local copy = {
bindings = self.bindings:append({ name = name, type = type }),
runtime_context = self.runtime_context:append(val, name, debuginfo),
}
return setmetatable(copy, typechecking_context_mt)
end
function TypecheckingContext:len()
return U.notail(self.bindings:len())
end
typechecking_context_mt = {
__index = TypecheckingContext,
__len = TypecheckingContext.len,
__tostring = function(t)
return "TypecheckingContext with " .. t.bindings:len() .. " bindings. " .. tostring(t.runtime_context)
end,
}
local function typechecking_context()
return setmetatable({ bindings = fibbuf(), runtime_context = flex_runtime_context() }, typechecking_context_mt)
end
local module_mt = {}
local strict_runtime_context_type =
gen.declare_foreign(gen.metatable_equality(strict_runtime_context_mt), "StrictRuntimeContext")
local flex_runtime_context_type =
gen.declare_foreign(gen.metatable_equality(flex_runtime_context_mt), "FlexRuntimeContext")
local typechecking_context_type =
gen.declare_foreign(gen.metatable_equality(typechecking_context_mt), "TypecheckingContext")
local host_user_defined_id = gen.declare_foreign(function(val)
return type(val) == "table" and type(val.name) == "string"
end, "{ name: string }")
traits.diff:implement_on(strict_runtime_context_type, { diff = runtime_context_diff_fn })
traits.diff:implement_on(flex_runtime_context_type, { diff = runtime_context_diff_fn })
local visibility = gen.declare_enum("visibility", {
{ "explicit" },
{ "implicit" },
})
local purity = gen.declare_enum("purity", {
{ "effectful" },
{ "pure" },
})
local block_purity = gen.declare_enum("block_purity", {
{ "effectful" },
{ "pure" },
{ "dependent", { "val", flex_value } },
{ "inherit" },
})
expression_goal:define_enum("expression_goal", {
{ "infer" },
{ "check", { "goal_type", flex_value } },
{ "mechanism", { "TODO", flex_value } },
})
binding:define_enum("binding", {
{ "let", {
"name", gen.builtin_string,
"debug", spanned_name,
"expr", anchored_inferrable_term,
} },
{ "tuple_elim", {
"names", array(gen.builtin_string),
"debug", array(spanned_name),
"subject", anchored_inferrable_term,
} },
{ "record_elim", {
"binding_anchor", anchor_type,
"subject", anchored_inferrable_term,
"field_names", array(gen.builtin_string),
"field_var_debugs", array(spanned_name),
} },
{ "annotated_lambda", {
"param_name", gen.builtin_string,
"param_annotation", anchored_inferrable_term,
"start_anchor", anchor_type,
"visible", visibility,
"pure", checkable_term,
} },
{ "program_sequence", {
"first", anchored_inferrable_term,
"start_anchor", anchor_type,
} },
})
checkable_term:define_enum("checkable", {
{ "inferrable", { "inferrable_term", anchored_inferrable_term } },
{ "tuple_cons", {
"elements", array(checkable_term),
"debug", array(spanned_name),
} },
{ "host_tuple_cons", {
"elements", array(checkable_term),
"debug", array(spanned_name),
} },
{ "lambda", {
"param_name", gen.builtin_string,
"body", checkable_term,
} },
})
unanchored_inferrable_term:define_enum("unanchored_inferrable", {
{ "bound_variable", { "index", gen.builtin_integer, "debug", spanned_name } },
{ "typed", {
"type", typed_term,
"usage_counts", array(gen.builtin_integer),
"typed_term", typed_term,
} },
{ "annotated_lambda", {
"param_name", gen.builtin_string,
"param_annotation", anchored_inferrable_term,
"body", anchored_inferrable_term,
"start_anchor", anchor_type,
"visible", visibility,
"pure", checkable_term,
} },
{ "pi", {
"param_type", anchored_inferrable_term,
"param_info", checkable_term,
"result_type", anchored_inferrable_term,
"result_info", checkable_term,
} },
{ "application", {
"f", anchored_inferrable_term,
"arg", checkable_term,
} },
{ "tuple_cons", {
"elements", array(anchored_inferrable_term),
"debug", array(spanned_name),
} },
{ "tuple_elim", {
"names", array(gen.builtin_string),
"debug", array(spanned_name),
"subject", anchored_inferrable_term,
"body", anchored_inferrable_term,
} },
{ "tuple_type", { "desc", anchored_inferrable_term } },
{ "record_desc_cons", { "fields", map(gen.builtin_string, anchored_inferrable_term) } },
{ "record_desc_extend_single", { "base", anchored_inferrable_term, "name", anchored_inferrable_term, "val", anchored_inferrable_term } },
{ "record_cons", { "fields", map(gen.builtin_string, anchored_inferrable_term) } },
{ "record_elim", {
"subject", anchored_inferrable_term,
"field_names", array(gen.builtin_string),
"field_var_debugs", array(spanned_name),
"body", anchored_inferrable_term,
} },
{ "record_type", { "desc", anchored_inferrable_term } },
{ "enum_cons", {
"constructor", gen.builtin_string,
"arg", anchored_inferrable_term,
} },
{ "enum_desc_cons", {
"variants", map(gen.builtin_string, anchored_inferrable_term),
"rest", anchored_inferrable_term,
} },
{ "enum_elim", {
"subject", anchored_inferrable_term,
"mechanism", anchored_inferrable_term,
} },
{ "enum_type", { "desc", anchored_inferrable_term } },
{ "enum_case", {
"target", anchored_inferrable_term,
"variants", map(gen.builtin_string, anchored_inferrable_term),
"variant_debug", map(gen.builtin_string, spanned_name), } },
{ "enum_absurd", {
"target", anchored_inferrable_term,
"debug", gen.builtin_string,
} },
{ "object_cons", { "methods", map(gen.builtin_string, anchored_inferrable_term) } },
{ "object_elim", {
"subject", anchored_inferrable_term,
"mechanism", anchored_inferrable_term,
} },
{ "let", {
"name", gen.builtin_string,
"debug", spanned_name,
"expr", anchored_inferrable_term,
"body", anchored_inferrable_term,
} },
{ "operative_cons", {
"operative_type", anchored_inferrable_term,
"userdata", anchored_inferrable_term,
} },
{ "operative_type_cons", {
"userdata_type", anchored_inferrable_term,
"handler", checkable_term,
} },
{ "level_type" },
{ "level0" },
{ "level_suc", { "previous_level", anchored_inferrable_term } },
{ "level_max", {
"level_a", anchored_inferrable_term,
"level_b", anchored_inferrable_term,
} },
{ "annotated", {
"annotated_term", checkable_term,
"annotated_type", anchored_inferrable_term,
} },
{ "host_tuple_cons", {
"elements", array(anchored_inferrable_term),
"debug", array(spanned_name),
} }, { "host_user_defined_type_cons", {
"id", host_user_defined_id, "family_args", array(anchored_inferrable_term), } },
{ "host_tuple_type", { "desc", anchored_inferrable_term } }, { "host_function_type", {
"param_type", anchored_inferrable_term, "result_type", anchored_inferrable_term, "result_info", checkable_term,
} },
{ "host_wrapped_type", { "type", anchored_inferrable_term } },
{ "host_unstrict_wrapped_type", { "type", anchored_inferrable_term } },
{ "host_wrap", { "content", anchored_inferrable_term } },
{ "host_unstrict_wrap", { "content", anchored_inferrable_term } },
{ "host_unwrap", { "container", anchored_inferrable_term } },
{ "host_unstrict_unwrap", { "container", anchored_inferrable_term } },
{ "host_if", {
"subject", checkable_term, "consequent", anchored_inferrable_term,
"alternate", anchored_inferrable_term,
} },
{ "host_intrinsic", {
"source", checkable_term,
"type", anchored_inferrable_term, "start_anchor", anchor_type,
} },
{ "program_sequence", {
"first", anchored_inferrable_term,
"start_anchor", anchor_type,
"continue", anchored_inferrable_term,
"debug_info", spanned_name,
} },
{ "program_end", { "result", anchored_inferrable_term } },
{ "program_type", {
"effect_type", anchored_inferrable_term,
"result_type", anchored_inferrable_term,
} },
})
anchored_inferrable_term:define_record("anchored_inferrable", {
"anchor",
anchor_type,
"term",
unanchored_inferrable_term,
})
local subtype_relation_mt = {}
local SubtypeRelation = gen.declare_foreign(gen.metatable_equality(subtype_relation_mt), "SubtypeRelation")
subtype_relation_mt.__tostring = function(self)
return "«" .. self.debug_name .. "»"
end
local constraintcause = gen.declare_type()
constraintcause:define_enum("constraintcause", {
{ "primitive", {
"description", gen.builtin_string,
"position", anchor_type,
"track", gen.any_lua_type,
} },
{ "composition", {
"left", gen.builtin_integer,
"right", gen.builtin_integer,
"position", anchor_type,
} },
{ "nested", {
"description", gen.builtin_string,
"inner", constraintcause,
} },
{ "leftcall_discharge", {
"call", gen.builtin_integer,
"constraint", gen.builtin_integer,
"position", anchor_type,
} },
{ "rightcall_discharge", {
"constraint", gen.builtin_integer,
"call", gen.builtin_integer,
"position", anchor_type,
} },
{ "lost", { "unique_string", gen.builtin_string,
"stacktrace", gen.builtin_string,
"auxiliary", gen.any_lua_type,
} },
})
local constraintelem = gen.declare_enum("constraintelem", {
{ "sliced_constrain", {
"rel", SubtypeRelation,
"right", typed_term,
"rightctx", typechecking_context_type,
"cause", constraintcause,
} },
{ "constrain_sliced", {
"left", typed_term,
"leftctx", typechecking_context_type,
"rel", SubtypeRelation,
"cause", constraintcause,
} },
{ "sliced_leftcall", {
"arg", typed_term,
"rel", SubtypeRelation,
"right", typed_term,
"rightctx", typechecking_context_type,
"cause", constraintcause,
} },
{ "leftcall_sliced", {
"left", typed_term,
"leftctx", typechecking_context_type,
"arg", typed_term,
"rel", SubtypeRelation,
"cause", constraintcause,
} },
{ "sliced_rightcall", {
"rel", SubtypeRelation,
"right", typed_term,
"rightctx", typechecking_context_type,
"arg", typed_term,
"cause", constraintcause,
} },
{ "rightcall_sliced", {
"left", typed_term,
"leftctx", typechecking_context_type,
"rel", SubtypeRelation,
"arg", typed_term,
"cause", constraintcause,
} },
})
local unique_id = gen.builtin_table
typed_term:define_enum("typed", {
{ "bound_variable", { "index", gen.builtin_integer, "debug", spanned_name } },
{ "literal", { "literal_value", strict_value } },
{ "metavariable", { "metavariable", metavariable_type } },
{ "unique", { "id", unique_id } },
{ "lambda", {
"param_name", gen.builtin_string,
"param_debug", spanned_name,
"body", typed_term,
"capture", typed_term,
"capture_dbg", spanned_name,
"start_anchor", anchor_type,
} },
{ "pi", {
"param_type", typed_term,
"param_info", typed_term,
"result_type", typed_term,
"result_info", typed_term,
} },
{ "application", {
"f", typed_term,
"arg", typed_term,
} },
{ "let", {
"name", gen.builtin_string,
"debug", spanned_name,
"expr", typed_term,
"body", typed_term,
} },
{ "level_type" },
{ "level0" },
{ "level_suc", { "previous_level", typed_term } },
{ "level_max", {
"level_a", typed_term,
"level_b", typed_term,
} },
{ "star", { "level", gen.builtin_integer, "depth", gen.builtin_integer } },
{ "prop", { "level", gen.builtin_integer } },
{ "tuple_cons", { "elements", array(typed_term) } },
{ "tuple_elim", {
"names", array(gen.builtin_string),
"debug", array(spanned_name), "subject", typed_term,
"length", gen.builtin_integer,
"body", typed_term,
} },
{ "tuple_element_access", {
"subject", typed_term,
"index", gen.builtin_integer,
} },
{ "tuple_type", { "desc", typed_term } },
{ "tuple_desc_type", { "universe", typed_term } },
{ "tuple_desc_concat_indep", { "prefix", typed_term, "suffix", typed_term }},
{ "record_cons", { "fields", map(gen.builtin_string, typed_term) } },
{ "record_type", { "desc", typed_term } },
{ "record_desc_cons", {"field_typefns", map(gen.builtin_string, typed_term)}},
{ "record_desc_extend_single", {"base", typed_term, "name", typed_term, "type", typed_term}},
{ "record_desc_extend", {"base", typed_term, "extension", map(gen.builtin_string, typed_term)}},
{ "name_set_of_record_desc", {"desc", typed_term}},
{ "noncolliding_name_type_cons", {"set", typed_term}},
{ "record_extend_single", {"base", typed_term, "name", typed_term, "val", typed_term}},
{ "record_extend", {
"base", typed_term,
"fields", map(gen.builtin_string, typed_term),
} },
{ "record_elim", {
"subject", typed_term,
"field_names", array(gen.builtin_string),
"field_var_debugs", array(spanned_name),
"body", typed_term,
} },
{ "record_field_access", {"subject", typed_term, "name", gen.builtin_string}},
{ "enum_cons", {
"constructor", gen.builtin_string,
"arg", typed_term,
} },
{ "enum_elim", {
"subject", typed_term,
"mechanism", typed_term,
} },
{ "enum_rec_elim", {
"subject", typed_term,
"mechanism", typed_term,
} },
{ "enum_desc_cons", {
"variants", map(gen.builtin_string, typed_term),
"rest", typed_term,
} },
{ "enum_desc_type", {
"univ", typed_term
} },
{ "enum_type", { "desc", typed_term } },
{ "enum_case", {
"target", typed_term,
"variants", map(gen.builtin_string, typed_term),
"variant_debug", map(gen.builtin_string, spanned_name), "default", typed_term,
"default_debug", spanned_name,
} },
{ "enum_absurd", {
"target", typed_term,
"debug", gen.builtin_string,
} },
{ "object_cons", { "methods", map(gen.builtin_string, typed_term) } },
{ "object_corec_cons", { "methods", map(gen.builtin_string, typed_term) } },
{ "object_elim", {
"subject", typed_term,
"mechanism", typed_term,
} },
{ "operative_cons", { "userdata", typed_term } },
{ "operative_type_cons", {
"userdata_type", typed_term,
"handler", typed_term,
} },
{ "host_tuple_cons", { "elements", array(typed_term) } }, { "host_user_defined_type_cons", {
"id", host_user_defined_id,
"family_args", array(typed_term), } },
{ "host_tuple_type", { "desc", typed_term } }, { "host_function_type", {
"param_type", typed_term, "result_type", typed_term, "result_info", typed_term,
} },
{ "host_wrapped_type", { "type", typed_term } },
{ "host_unstrict_wrapped_type", { "type", typed_term } },
{ "host_wrap", { "content", typed_term } },
{ "host_unwrap", { "container", typed_term } },
{ "host_unstrict_wrap", { "content", typed_term } },
{ "host_unstrict_unwrap", { "container", typed_term } },
{ "host_int_fold", {"n", typed_term, "f", typed_term, "acc", typed_term}},
{ "host_user_defined_type", {
"id", host_user_defined_id,
"family_args", array(typed_term),
} },
{ "host_if", {
"subject", typed_term,
"consequent", typed_term,
"alternate", typed_term,
} },
{ "host_intrinsic", {
"source", typed_term,
"start_anchor", anchor_type,
} },
{ "range", {
"lower_bounds", array(typed_term),
"upper_bounds", array(typed_term),
"relation", typed_term, } },
{ "singleton", {
"supertype", typed_term,
"value", typed_term,
} },
{ "program_sequence", {
"first", typed_term,
"continue", typed_term,
"debug_info", spanned_name,
} },
{ "program_end", { "result", typed_term } },
{ "program_invoke", {
"effect_tag", typed_term,
"effect_arg", typed_term,
} },
{ "effect_type", {
"components", array(typed_term),
"base", typed_term,
} },
{ "effect_row", {
"elems", array(typed_term),
"rest", typed_term,
} },
{ "effect_row_resolve", {
"elems", set(unique_id),
"rest", typed_term,
} },
{ "program_type", {
"effect_type", typed_term,
"result_type", typed_term,
} },
{ "srel_type", { "target_type", typed_term } },
{ "variance_type", { "target_type", typed_term } },
{ "variance_cons", {
"positive", typed_term,
"srel", typed_term,
} },
{ "intersection_type", {
"left", typed_term,
"right", typed_term,
} },
{ "union_type", {
"left", typed_term,
"right", typed_term,
} },
{ "constrained_type", {
"constraints", array(constraintelem),
"ctx", typechecking_context_type,
} },
})
local function verify_placeholder_lite(v, ctx, nested)
if type(v) ~= "table" then
return true
end
local v_mt = getmetatable(v)
if v_mt and getmetatable(v_mt) == gen.array_type_mt then
for k, val in ipairs(v) do
local ok, i, info, info_mismatch = verify_placeholder_lite(val, ctx, true)
if not ok then
if not nested then
print(v)
if info_mismatch ~= nil then
print("EXPECTED INFO: " .. info_mismatch)
end
error("AAAAAAAAAAAAAA found " .. tostring(i))
end
return false, i, info
end
end
return true
end
if not v.kind then
return true
end
if v.kind == "free.placeholder" then
local i, info = v:unwrap_placeholder()
if i > ctx:len() or i > ctx.runtime_context.bindings:len() then
return false, i, info
end
local info_target = ctx.runtime_context.bindings:get(i).debuginfo
if info ~= info_target then
return false, i, info, info_target
end
end
for k, val in pairs(v) do
if k ~= "cause" and k ~= "bindings" and k ~= "provenance" then
local ok, i, info, info_mismatch = verify_placeholder_lite(val, ctx, true)
if not ok then
if not nested then
print(v)
if info_mismatch ~= nil then
print("EXPECTED INFO: " .. info_mismatch)
end
error("AAAAAAAAAAAAAA found " .. tostring(i) .. " " .. tostring(info))
end
return false, i, info
end
end
end
return true
end
local orig_literal_constructor = typed_term.literal
local function literal_constructor_check(val)
verify_placeholder_lite(val, typechecking_context())
return U.notail(orig_literal_constructor(val))
end
typed_term.literal = literal_constructor_check
free:define_enum("free", {
{ "metavariable", { "metavariable", metavariable_type } },
{ "placeholder", {
"index", gen.builtin_integer,
"debug", spanned_name,
} },
{ "unique", { "id", unique_id } },
})
local result_info = gen.declare_record("result_info", { "purity", purity })
local Registry = {}
function Registry:register(name, debuginfo)
return {
name = name,
debuginfo = debuginfo,
registry = self,
}
end
local registry_mt = { __index = Registry }
local function new_registry(name)
return setmetatable({ name = name }, registry_mt)
end
local effect_id = gen.declare_type()
effect_id:define_record("effect_id", {
"primary", unique_id,
"extension", set(unique_id), })
local semantic_id = gen.declare_type()
semantic_id:define_record("semantic_id", {
"primary", unique_id,
"extension", set(unique_id), })
local flex_continuation = gen.declare_type()
local strict_continuation = gen.declare_type()
local stuck_continuation = gen.declare_type()
local function replace_flex_type(tag, t)
if type(t) == "string" then
error(debug.traceback("wrong type passed to replace_flex_type"))
end
if t == flex_value then
if tag == "strict" then
return strict_value
elseif tag == "stuck" then
return flex_value
end
error("Unknown tag: " .. tag)
elseif getmetatable(t) == gen.array_type_mt then
return U.notail(array(replace_flex_type(tag, t.value_type)))
elseif getmetatable(t) == gen.map_type_mt then
return U.notail(map(replace_flex_type(tag, t.key_type), replace_flex_type(tag, t.value_type)))
elseif t == flex_runtime_context_type then
if tag == "strict" then
return strict_runtime_context_type
elseif tag == "stuck" then
return flex_runtime_context_type
end
error("Unknown tag: " .. tag)
elseif t == flex_continuation then
if tag == "strict" then
return strict_continuation
elseif tag == "stuck" then
return flex_continuation
end
error("Unknown tag: " .. tag)
end
return t
end
replace_flex_type = U.memoize(replace_flex_type, false)
local function specify_flex_value(arg, t)
if t == flex_value then
if arg:is_stuck() then
return "stuck", arg
end
return "strict", U.notail(arg:unwrap_strict())
elseif getmetatable(t) == gen.array_type_mt then
local arg_value_t = t.value_type
local arg_values, arg_strict_values, arg_values_length = arg.array, {}, arg.n
for i = 1, arg_values_length do
local arg_value_tag
arg_value_tag, arg_strict_values[i] = specify_flex_value(arg_values[i], arg_value_t)
if arg_value_tag == "stuck" then
return "stuck", arg
end
end
local arg_strict_value_t = replace_flex_type("strict", arg_value_t)
return "strict", array(arg_strict_value_t):unchecked_new(arg_strict_values, arg_values_length)
elseif getmetatable(t) == gen.map_type_mt then
local arg_key_t, arg_value_t = t.key_type, t.value_type
local arg_values, arg_strict_values = arg._map, {}
for arg_key, arg_value in pairs(arg_values) do
local arg_key_tag, arg_strict_key = specify_flex_value(arg_key, arg_key_t)
if arg_key_tag == "stuck" then
return "stuck", arg
end
local arg_value_tag
arg_value_tag, arg_strict_values[arg_strict_key] = specify_flex_value(arg_value, arg_value_t)
if arg_value_tag == "stuck" then
return "stuck", arg
end
end
local arg_strict_key_t = replace_flex_type("strict", arg_key_t)
local arg_strict_value_t = replace_flex_type("strict", arg_value_t)
return "strict", map(arg_strict_key_t, arg_strict_value_t):unchecked_new(arg_strict_values)
elseif t == flex_continuation then
if arg:is_stuck() then
return "stuck", arg
end
return "strict", U.notail(arg:unwrap_strict())
elseif t == flex_runtime_context_type then
if arg.stuck_count > 0 then
return "stuck", arg
end
return "strict", U.notail(arg:as_strict())
end
return "strict", arg
end
local function specify_flex_values(args, types)
local strict_args = {}
for i, t in ipairs(types) do
local tag, arg = specify_flex_value(args[i], t)
if tag == "stuck" then
return tag, args
end
table.insert(strict_args, arg)
end
return "strict", strict_args
end
local function unify_already_flex(val)
return val
end
local function unify_flex_type(t)
if t == strict_value then
return flex_value, flex_value.strict
elseif t == stuck_value then
return flex_value, flex_value.stuck
elseif t == strict_continuation then
return flex_continuation, flex_continuation.strict
elseif t == stuck_continuation then
return flex_continuation, flex_continuation.stuck
elseif t == strict_runtime_context_type then
return flex_runtime_context_type, StrictRuntimeContext.as_flex
end
local t_mt = getmetatable(t)
if t_mt == gen.array_type_mt then
local value_t = t.value_type
local flex_value_t, unify_value = unify_flex_type(value_t)
if unify_value == nil then
return t, nil
end
local flex_t = array(flex_value_t)
local function unify(values)
return U.notail(values:map(flex_t, unify_value))
end
return flex_t, unify
elseif t_mt == gen.map_type_mt then
local key_t, value_t = t.key_type, t.value_type
local flex_key_t, unify_key = unify_flex_type(key_t)
local flex_value_t, unify_value = unify_flex_type(value_t)
if unify_key == nil and unify_value == nil then
return t, nil
end
if unify_key == nil then
unify_key = unify_already_flex
end
if unify_value == nil then
unify_value = unify_already_flex
end
local flex_t = map(flex_key_t, flex_value_t)
local function unify(vals)
local flex_vals = {}
for key, val in pairs(vals._map) do
local flex_key, flex_val = unify_key(key), unify_value(val)
flex_vals[flex_key] = flex_val
end
return U.notail(flex_t:unchecked_new(flex_vals))
end
return flex_t, unify
end
return t, nil
end
unify_flex_type = U.memoize(unify_flex_type, false)
local function unify_flex_value(arg)
local arg_mt = getmetatable(arg)
local _strict_t, unify = unify_flex_type(arg_mt)
if unify ~= nil then
return U.notail(unify(arg))
end
return arg
end
local function unify_flex_values(args)
local flex_args = {}
for i, v in ipairs(args) do
flex_args[i] = unify_flex_value(v)
end
return flex_args
end
gen.define_multi_enum(flex_continuation, "flex_continuation", replace_flex_type, specify_flex_values, unify_flex_values,
{ strict = strict_continuation, stuck = stuck_continuation },
{ strict = "strict_continuation", stuck = "stuck_continuation" },
{
{ "empty$strict" },
{ "frame$flex", {
"context", flex_runtime_context_type,
"code", typed_term,
} },
{ "sequence$flex", {
"first", flex_continuation,
"second", flex_continuation,
} },
})
gen.define_multi_enum(
flex_value,
"flex_value",
replace_flex_type,
specify_flex_values,
unify_flex_values,
{ strict = strict_value, stuck = stuck_value },
{ strict = "strict_value", stuck = "stuck_value" },
{
{ "visibility_type$strict" },
{ "visibility$strict", { "visibility", visibility } },
{ "param_info_type$strict" },
{ "param_info$flex", { "visibility", flex_value } },
{ "result_info_type$strict" },
{ "result_info$strict", { "result_info", result_info } },
{ "pi$flex", {
"param_type", flex_value,
"param_info", flex_value, "result_type", flex_value, "result_info", flex_value, }, },
{ "closure$flex", {
"param_name", gen.builtin_string,
"code", typed_term,
"capture", flex_value,
"capture_dbg", spanned_name,
"param_debug", spanned_name,
}, },
{ "range$flex", {
"lower_bounds", array(flex_value),
"upper_bounds", array(flex_value),
"relation", strict_value, }, },
{ "name_type$strict" },
{ "name$strict", { "name", gen.builtin_string } },
{ "name_set$strict", { "names", gen.builtin_string }},
{ "name_set_type$strict"},
{ "name_set_of_record_desc$stuck", { "desc", stuck_value}},
{ "noncolliding_name_type$flex", {"set", flex_value}},
{ "operative_value$flex", { "userdata", flex_value } },
{ "operative_type$flex", {
"handler", flex_value,
"userdata_type", flex_value,
} },
{ "tuple_value$flex", { "elements", array(flex_value) } },
{ "tuple_type$flex", { "desc", flex_value } },
{ "tuple_desc_type$flex", { "universe", flex_value } },
{ "tuple_desc_concat_indep$stuck", { "prefix", flex_value, "suffix", flex_value}},
{ "enum_value$flex", {
"constructor", gen.builtin_string,
"arg", flex_value,
} },
{ "enum_type$flex", { "desc", flex_value } },
{ "enum_desc_type$flex", { "universe", flex_value } },
{ "enum_desc_value$flex", { "variants", gen.declare_map(gen.builtin_string, flex_value) } },
{ "record_value$flex", { "fields", map(gen.builtin_string, flex_value) } },
{ "record_type$flex", { "desc", flex_value } },
{ "record_desc_type$flex", { "universe", flex_value } },
{ "record_desc_value$flex", { "fields", map(gen.builtin_string, flex_value)}},
{ "record_desc_extend_single$stuck", { "base", flex_value, "name", stuck_value, "typefn", flex_value}},
{ "record_desc_extend$stuck", {"base", flex_value, "extension", map(gen.builtin_string, flex_value)}},
{ "record_extend_single$stuck", {"base", flex_value, "name", stuck_value, "val", flex_value}},
{ "record_extend$stuck", {
"base", stuck_value,
"extension", map(gen.builtin_string, flex_value),
}, },
{ "object_value$flex", {
"methods", map(gen.builtin_string, typed_term),
"capture", flex_runtime_context_type,
}, },
{ "object_type$flex", { "desc", flex_value } },
{ "star$strict", { "level", gen.builtin_integer, "depth", gen.builtin_integer } },
{ "prop$strict", { "level", gen.builtin_integer } },
{ "host_value$strict", { "host_value", gen.any_lua_type } },
{ "host_type_type$strict" },
{ "host_number_type$strict" },
{ "host_int_fold$stuck", { "num", stuck_value, "f", flex_value, "acc", flex_value}},
{ "host_bool_type$strict" },
{ "host_string_type$strict" },
{ "host_function_type$flex", {
"param_type", flex_value, "result_type", flex_value, "result_info", flex_value,
}, },
{ "host_wrapped_type$flex", { "type", flex_value } },
{ "host_unstrict_wrapped_type$flex", { "type", flex_value } },
{ "host_user_defined_type$flex", {
"id", host_user_defined_id,
"family_args", array(flex_value),
}, },
{ "host_nil_type$strict" },
{ "host_tuple_value$strict", { "elements", array(gen.any_lua_type) } },
{ "host_tuple_type$flex", { "desc", flex_value } },
{ "singleton$flex", {
"supertype", flex_value,
"value", flex_value,
} },
{ "program_end$flex", { "result", flex_value } },
{ "program_cont$flex", {
"action", unique_id,
"argument", flex_value,
"continuation", flex_continuation,
}, },
{ "effect_elem$strict", { "tag", effect_id } },
{ "effect_type$strict" },
{ "effect_row$strict", {
"components", set(unique_id),
} },
{ "effect_row_extend$stuck", {
"base", flex_value,
"rest", flex_value,
} },
{ "effect_row_type$strict" },
{ "program_type$flex", {
"effect_sig", flex_value,
"base_type", flex_value,
} },
{ "srel_type$flex", { "target_type", flex_value } },
{ "variance_type$flex", { "target_type", flex_value } },
{ "intersection_type$flex", {
"left", flex_value,
"right", flex_value,
} },
{ "union_type$flex", {
"left", flex_value,
"right", flex_value,
} },
{ "free$stuck", { "free", free } },
{ "application$stuck", {
"f", stuck_value,
"arg", flex_value,
} },
{ "tuple_element_access$stuck", {
"subject", stuck_value,
"index", gen.builtin_integer,
} },
{ "record_field_access$stuck", {
"subject", stuck_value,
"field_name", gen.builtin_string,
}, },
{ "host_application$stuck", {
"function", gen.any_lua_type,
"arg", stuck_value,
} },
{ "host_tuple$stuck", {
"leading", array(gen.any_lua_type),
"stuck_element", stuck_value,
"trailing", array(flex_value), }, },
{ "host_if$stuck", {
"subject", stuck_value,
"consequent", flex_value,
"alternate", flex_value,
}, },
{ "host_intrinsic$stuck", {
"source", stuck_value,
"start_anchor", anchor_type,
} },
{ "host_wrap$stuck", { "content", stuck_value } },
{ "host_unwrap$stuck", { "container", stuck_value } },
},
function(_)
local orig_host_value_constructor = strict_value.host_value
local function host_value_constructor_check(val)
if stuck_value.value_check(val) or flex_value.value_check(val) then
error("Tried to put flex or stuck value into strict_value.host_value!" .. tostring(val))
end
return U.notail(orig_host_value_constructor(val))
end
strict_value.host_value = host_value_constructor_check
local orig_host_tuple_value_constructor = strict_value.host_tuple_value
local function host_tuple_value_constructor_check(val)
for _, v in ipairs(val) do
if stuck_value.value_check(v) or flex_value.value_check(v) then
error("Tried to put flex or stuck value into strict_value.host_tuple_value!" .. tostring(v))
end
end
return U.notail(orig_host_tuple_value_constructor(val))
end
strict_value.host_tuple_value = host_tuple_value_constructor_check
end
)
for _, t in ipairs {
metavariable_type,
anchor_type,
span_type,
flex_runtime_context_type,
strict_runtime_context_type,
typechecking_context_type,
host_user_defined_id,
SubtypeRelation,
} do
traits.freeze:implement_on(t, {
freeze = function(_, val)
return val
end,
})
end
local host_syntax_type = strict_value.host_user_defined_type({ name = "syntax" }, array(strict_value)())
local host_environment_type = strict_value.host_user_defined_type({ name = "environment" }, array(strict_value)())
local host_typed_term_type = strict_value.host_user_defined_type({ name = "typed_term" }, array(strict_value)())
local host_goal_type = strict_value.host_user_defined_type({ name = "goal" }, array(strict_value)())
local host_inferrable_term_type =
strict_value.host_user_defined_type({ name = "inferrable_term" }, array(strict_value)())
local host_checkable_term_type = strict_value.host_user_defined_type({ name = "checkable_term" }, array(strict_value)())
local host_purity_type = strict_value.host_user_defined_type({ name = "purity" }, array(strict_value)())
local host_block_purity_type = strict_value.host_user_defined_type({ name = "block_purity" }, array(strict_value)())
local host_lua_error_type = strict_value.host_user_defined_type({ name = "lua_error_type" }, array(strict_value)())
local DescCons =
{
cons = "cons",
empty = "empty",
}
local typed_term_array = array(typed_term)
local anchored_inferrable_term_array = array(anchored_inferrable_term)
local unanchored_inferrable_term_array = array(unanchored_inferrable_term)
local flex_value_array = array(flex_value)
local strict_value_array = array(strict_value)
local stuck_value_array = array(stuck_value)
local spanned_name_array = array(spanned_name)
local function tup_val(...)
return U.notail(flex_value.tuple_value(flex_value_array(...)))
end
local function cons(prefix, next_elem, ...)
if select("#", ...) > 0 then
error(("%d extra arguments passed to terms.cons"):format(select("#", ...)))
end
return U.notail(flex_value.enum_value(DescCons.cons, tup_val(prefix, next_elem)))
end
local empty = flex_value.enum_value(DescCons.empty, tup_val())
local function uncons(desc)
local constructor, arg = desc:unwrap_enum_value()
if constructor ~= DescCons.cons then
error(string.format("expected constructor DescCons.cons, got %s: %s", s(constructor), s(desc)))
end
local elements = arg:unwrap_tuple_value()
if elements:len() ~= 2 then
error(
string.format("enum_value with constructor DescCons.cons should have 2 args, but has %s", s(elements:len()))
)
end
return elements[1], elements[2]
end
local function unempty(desc)
local constructor = desc:unwrap_enum_value()
if constructor ~= DescCons.empty then
error(string.format("expected constructor DescCons.empty, got %s: %s", s(constructor), s(desc)))
end
end
local function tuple_desc(...)
local a = empty
for i = 1, select("#", ...) do
local e = select(i, ...)
if e ~= nil then
a = cons(a, e)
end
end
return a
end
local function strict_tup_val(...)
return U.notail(strict_value.tuple_value(strict_value_array(...)))
end
local function strict_cons(prefix, next_elem, ...)
if select("#", ...) > 0 then
error(("%d extra arguments passed to terms.strict_cons"):format(select("#", ...)))
end
return U.notail(strict_value.enum_value(DescCons.cons, strict_tup_val(prefix, next_elem, ...)))
end
local strict_empty = empty:unwrap_strict()
local function strict_tuple_desc(...)
local a = strict_empty
for i = 1, select("#", ...) do
local e = select(i, ...)
if e ~= nil then
a = strict_cons(a, e)
end
end
return a
end
local function inferrable_cons(start_anchor, prefix, debug_prefix, next_elem, debug_next_elem, ...)
if select("#", ...) > 0 then
error(("%d extra arguments passed to terms.inferrable_cons"):format(select("#", ...)))
end
return U.notail(
anchored_inferrable_term(
start_anchor,
unanchored_inferrable_term.enum_cons(
DescCons.cons,
anchored_inferrable_term(
start_anchor,
unanchored_inferrable_term.tuple_cons(
anchored_inferrable_term_array(prefix, next_elem),
spanned_name_array(debug_prefix, debug_next_elem)
)
)
)
)
)
end
local inferrable_empty = anchored_inferrable_term(
format.anchor_here(),
unanchored_inferrable_term.enum_cons(
DescCons.empty,
anchored_inferrable_term(
format.anchor_here(),
unanchored_inferrable_term.tuple_cons(anchored_inferrable_term_array(), spanned_name_array())
)
)
)
local debug_inferrable_empty = spanned_name("terms.inferrable_empty", format.span_here())
local function inferrable_tuple_desc(start_anchor, ...)
local a = inferrable_empty
local debug_a = debug_inferrable_empty
local span = format.span_here(2)
for i = 1, select("#", ...), 2 do
local e, debug_e = select(i, ...), select(i + 1, ...)
if e ~= nil then
if debug_e == nil then
error(("inferrable_tuple_desc: missing spanned_name at argument %d"):format(i + 1))
end
a, debug_a =
inferrable_cons(start_anchor, a, debug_a, e, debug_e),
spanned_name(("terms.inferrable_tuple_desc.varargs[%d]"):format(i), span)
end
end
return a
end
local function typed_cons(prefix, next_elem, ...)
if select("#", ...) > 0 then
error(("%d extra arguments passed to terms.typed_cons"):format(select("#", ...)))
end
return U.notail(typed_term.enum_cons(DescCons.cons, typed_term.tuple_cons(typed_term_array(prefix, next_elem))))
end
local typed_empty = typed_term.enum_cons(DescCons.empty, typed_term.tuple_cons(typed_term_array()))
local function typed_tuple_desc(...)
local a = typed_empty
for i = 1, select("#", ...) do
local e = select(i, ...)
if e ~= nil then
a = typed_cons(a, e)
end
end
return a
end
local RecordDescCons =
{
cons = "cons",
empty = "empty",
}
local function record_uncons(desc)
local constructor, arg = desc:unwrap_enum_value()
if constructor ~= RecordDescCons.cons then
error(string.format("expected constructor RecordDescCons.cons, got %s: %s", s(constructor), s(desc)))
end
local elements = arg:unwrap_tuple_value()
if elements:len() ~= 3 then
error(
string.format(
"enum_value with constructor RecordDescCons.cons should have 3 args, but has %s",
s(elements:len())
)
)
end
return elements[1], elements[2], elements[3]
end
local function record_unempty(desc)
local constructor = desc:unwrap_enum_value()
if constructor ~= DescCons.empty then
error(string.format("expected constructor RecordDescCons.empty, got %s: %s", s(constructor), s(desc)))
end
end
local tristate = gen.declare_enum("tristate", {
{ "success" },
{ "continue" },
{ "failure" },
})
local unique_id_set = set(unique_id)
local unit_type = strict_value.tuple_type(empty:unwrap_strict())
local unit_val = strict_tup_val()
local effect_registry = new_registry("effect")
local TCState =
effect_id(effect_registry:register("TCState", "effects that manipulate the typechecker state"), unique_id_set())
local lua_prog = effect_id(effect_registry:register("lua_prog", "running effectful lua code"), unique_id_set())
local terms = {
metavariable_mt = metavariable_mt,
checkable_term = checkable_term, anchored_inferrable_term = anchored_inferrable_term, anchored_inferrable_term_array = anchored_inferrable_term_array, unanchored_inferrable_term = unanchored_inferrable_term, typed_term = typed_term, typed_term_array = typed_term_array,
free = free,
visibility = visibility,
purity = purity,
block_purity = block_purity,
result_info = result_info,
flex_value = flex_value,
flex_value_array = flex_value_array,
strict_value = strict_value,
strict_value_array = strict_value_array,
stuck_value = stuck_value,
stuck_value_array = stuck_value_array,
binding = binding,
expression_goal = expression_goal,
host_syntax_type = host_syntax_type,
host_environment_type = host_environment_type,
host_typed_term_type = host_typed_term_type,
host_goal_type = host_goal_type,
host_inferrable_term_type = host_inferrable_term_type,
host_checkable_term_type = host_checkable_term_type,
host_purity_type = host_purity_type,
host_block_purity_type = host_block_purity_type,
host_lua_error_type = host_lua_error_type,
unique_id = unique_id,
unique_id_set = unique_id_set,
spanned_name = spanned_name,
spanned_name_array = spanned_name_array,
flex_runtime_context = flex_runtime_context,
strict_runtime_context = strict_runtime_context,
typechecking_context = typechecking_context,
module_mt = module_mt,
strict_runtime_context_type = strict_runtime_context_type,
flex_runtime_context_type = flex_runtime_context_type,
typechecking_context_type = typechecking_context_type,
subtype_relation_mt = subtype_relation_mt,
SubtypeRelation = SubtypeRelation,
constraintelem = constraintelem,
constraintcause = constraintcause,
DescCons = DescCons,
tup_val = tup_val,
cons = cons,
empty = empty,
uncons = uncons,
unempty = unempty,
tuple_desc = tuple_desc,
strict_tup_val = strict_tup_val,
strict_cons = strict_cons,
strict_empty = strict_empty,
strict_tuple_desc = strict_tuple_desc,
typed_cons = typed_cons,
typed_empty = typed_empty,
typed_tuple_desc = typed_tuple_desc,
inferrable_cons = inferrable_cons,
inferrable_empty = inferrable_empty,
inferrable_tuple_desc = inferrable_tuple_desc,
RecordDescCons = RecordDescCons,
record_empty = record_empty,
record_uncons = record_uncons,
unit_type = unit_type,
unit_val = unit_val,
effect_id = effect_id,
flex_continuation = flex_continuation,
strict_continuation = strict_continuation,
stuck_continuation = stuck_continuation,
effect_registry = effect_registry,
TCState = TCState,
lua_prog = lua_prog,
verify_placeholders = verify_placeholders,
verify_placeholder_lite = verify_placeholder_lite,
tristate = tristate,
}
local override_prettys = require "terms-pretty"(terms)
local checkable_term_override_pretty = override_prettys.checkable_term_override_pretty
local unanchored_inferrable_term_override_pretty = override_prettys.unanchored_inferrable_term_override_pretty
local typed_term_override_pretty = override_prettys.typed_term_override_pretty
local flex_value_override_pretty = override_prettys.flex_value_override_pretty
local stuck_value_override_pretty = override_prettys.stuck_value_override_pretty
local binding_override_pretty = override_prettys.binding_override_pretty
local spanned_name_override_pretty = override_prettys.spanned_name_override_pretty
checkable_term:derive(derivers.pretty_print, checkable_term_override_pretty)
anchored_inferrable_term:derive(derivers.pretty_print)
unanchored_inferrable_term:derive(derivers.pretty_print, unanchored_inferrable_term_override_pretty)
typed_term:derive(derivers.pretty_print, typed_term_override_pretty)
visibility:derive(derivers.pretty_print)
free:derive(derivers.pretty_print)
flex_value:derive(derivers.pretty_print, flex_value_override_pretty)
strict_value:derive(derivers.pretty_print, flex_value_override_pretty)
stuck_value:derive(derivers.pretty_print, flex_value_override_pretty)
binding:derive(derivers.pretty_print, binding_override_pretty)
expression_goal:derive(derivers.pretty_print)
spanned_name:derive(derivers.pretty_print, spanned_name_override_pretty)
purity:derive(derivers.pretty_print)
result_info:derive(derivers.pretty_print)
constraintcause:derive(derivers.pretty_print)
flex_continuation:derive(derivers.pretty_print)
strict_continuation:derive(derivers.pretty_print)
stuck_continuation:derive(derivers.pretty_print)
local glsl_print = require "glsl-print"
typed_term:derive(glsl_print.glsl_print_deriver, glsl_print.typed_term_glsl)
local pretty_printer = require "pretty-printer"
typed_term.methods.glsl_print = pretty_printer.glsl_print
local internals_interface = require "internals-interface"
internals_interface.terms = terms
return setmetatable(terms, {
__index = function(_, k)
error(debug.traceback("'" .. k .. "' doesn't exist in terms!"))
end,
})