# The following kinds are used in intermediate forms by lowering but are not
# part of the surface syntax
function _register_kinds()
    JuliaSyntax.register_kinds!(JuliaLowering, 1, [
        # "Syntax extensions" - expression kinds emitted by macros or macro
        # expansion, and known to lowering. These are part of the AST API but
        # without having surface syntax.
        "BEGIN_EXTENSION_KINDS"
            # atomic fields or accesses (see `@atomic`)
            "atomic"
            # Flag for @generated parts of a function
            "generated"
            # Temporary rooting of identifiers (GC.@preserve)
            "gc_preserve"
            "gc_preserve_begin"
            "gc_preserve_end"
            # A (quoted) `Symbol`
            "Symbol"
            "inbounds"
            "inbounds_pop" # expr: (inbounds pop) with identifier "pop"
            "boundscheck"
            "inline"
            "noinline"
            "loopinfo"
            "purity"
            "aliasscope"
            "popaliasscope"
            # Call into foreign code
            "foreigncall"
            # Look up a symbol in foreign code
            "foreignglobal"
            # ccall convention
            "cconv"
            # Special form for constructing a function callable from C
            "cfunction"
            # Special form emitted by `Base.Experimental.@opaque`
            "opaque_closure"
            # Test whether a variable is defined
            "isdefined"
            # [K"throw_undef_if_not" var cond]
            # This form is used internally in Core.Compiler but might be
            # emitted by packages such as Diffractor. In principle it needs to
            # be passed through lowering in a similar way to `isdefined`
            "throw_undef_if_not"
            # named labels for `@label` and `@goto`
            "symboliclabel"
            # Goto named label
            "symbolicgoto"
            # Goto named label (old syntax version, no try/finally check)
            "oldsymbolicgoto"
            # Labeled block for `@label name expr` (block break)
            "symbolicblock"
            # Internal initializer for struct types, for inner constructors/functions
            "new"
            "splatnew"
            # Used for converting `esc()`'d expressions arising from old macro
            # invocations during macro expansion (gone after macro expansion)
            "escape"
            # Used for converting the old-style macro hygienic-scope form (gone
            # after macro expansion).
            "hygienic-scope"
            # Only produced by flisp macro expansion (which Core.@doc (cursed)
            # invokes manually)
            "copyast"
            # An expression which will eventually be evaluated "statically" in
            # the context of a CodeInfo and thus allows access only to globals
            # and static parameters. Used for ccall, cfunction, cglobal
            # TODO: Use this for GeneratedFunctionStub also?
            "static_eval"
            "islocal"
            "isglobal"
            "locals"
            "thisfunction"
            "overlay"
            "syntaxquote"
            "syntaxunquote"
        "END_EXTENSION_KINDS"

        # The following kinds are internal to lowering
        "BEGIN_LOWERING_KINDS"
            # Semantic assertions used by lowering. The content of an assertion
            # is not considered to be quoted, so use K"Symbol" etc inside where necessary.
            "assert"
            # Unique identifying integer for bindings (of variables, constants, etc)
            "BindingId"
            # Various heads harvested from flisp lowering.
            # (TODO: May or may not need all these - assess later)
            # Like block, but introduces a lexical scope; used during scope resolution.
            "scope_block"
            # Equivalent to Expr(:softscope).  If found in the top-level thunk,
            # all enclosed neutral scopes become soft scopes.  :hardscope exists
            # too, but is always produced inside scope-blocks, so we represent
            # it with an attribute on our scope-blocks.
            "softscope"
            # [K"always_defined" x] is an assertion that variable `x` is assigned before use
            # ('local-def in flisp implementation is K"local" plus K"always_defined"
            "always_defined"
            # `(relayered_global old::Identifier)` is used to tell scope
            # resolution that any declaration conflicting with `(global old)`
            # should fail, even though `old` was never actually declared
            "relayered_global"
            "_while"
            "_do_while"
            # (_typevar name lb ub).  flisp usually uses 3-long lists for these,
            # usually called `sparams`
            "_typevar"
            "_typevars" # used for supplying already-allocated `TypeVar`s to `where`
            # (_generated_body (quote gen) nongen) to allow arglist-related desugaring
            # to occur before the methods are created
            "_generated_body"
            "with_static_parameters"
            # converted from nothing::K"Value" into desugaring.  flisp: (null)
            "nothing"
            "top"
            "core"
            "lambda"
            # "A source location literal" - a node which exists only to record
            # a sourceref
            "SourceLocation"
            # [K"function_decl" name]
            # Declare a zero-method generic function with global `name` or
            # creates a closure object and assigns it to the local `name`.
            "function_decl"
            # [K"function_type" name]
            # Evaluates to the type of the function or closure with given `name`
            "function_type"
            # [K"method_defs" name [K"block" typevars...] [K"block" body...]]
            # The code in `body` defines methods for generic function `name`.
            # If non-toplevel, all contained methods share a closure type.
            # `typevars` are assigned-once top-level locals only referenced
            # inside `K"method"`, but outside of `K"lambda"`, since any
            # reference inside a lambda should resolve to the lambda's sparam
            # shadowing it.
            "method_defs"
            # [K"typevar" name rhs] appears only in method_defs and gets special
            # scope resolution: a sequence of K"sparam"s are similar to nested
            # let-blocks, but without introducing a local scope.
            "typevar"
            "_opaque_closure"
            # The enclosed statements must be executed at top level
            "toplevel_butfirst"
            # like v = val, except that if `v` turns out global (either
            # implicitly or by explicit `global`), it gains an implicit `const`
            "assign_or_constdecl_if_global"
            "global_if_global"
            "moved_local"
            "label"
            "trycatchelse"
            "tryfinally"
            # The contained block of code causes no side effects and can be
            # removed by a later lowering pass if its value isn't used.
            # (That is, it's removable in the same sense as
            #  `@assume_effects :removable`.)
            "removable"
            # Variable type declaration; `x::T = rhs` will be temporarily
            # desugared to include `(decl x T)`
            "decl"
            # [K"captured_local" index]
            # A local variable captured into a global method. Contains the
            # `index` of the associated `Box` in the rewrite list.
            "captured_local"
            # Causes the linearization pass to conditionally emit a world age increment
            "latestworld_if_toplevel"
            # This has two forms:
            #   [K"constdecl" var val] => declare and assign constant
            #   [K"constdecl" var]     => declare undefined constant
            #                             var is GlobalRef Value or Identifier
            "constdecl"
            # Returned from statements that should error if the result is used.
            "unused_only"
            # Pre-lowered SSA value reference from Expr(:ssavalue, N).
            # Translated to a BindingId during desugaring.
            "ssavalue"
            # Wraps the first argument of a foreigncall / foreignglobal when it
            # should not be lowered (and should mostly be treated as :inert), but
            # requires scope resolution and special conversion to Expr.
            "foreignsymbol"
            "thunk"
            # Options specific to K"lambda"
            "generated_lambda"
            "toplevel_lambda"

            # Options specific to K"scope_block"
            "hard_scope"
            "neutral_scope"

            "LambdaBindings"
            "Slots"
        "END_LOWERING_KINDS"

        # The following kinds are emitted by lowering and used in Julia's untyped IR
        "BEGIN_IR_KINDS"
            # Identifier for a value which is only assigned once
            "SSAValue"
            # Local variable in a `CodeInfo` code object (including lambda arguments)
            "slot"
            # Static parameter to a `CodeInfo` code object ("type parameters" to methods)
            "static_parameter"
            # References/declares a global variable within a module
            "globalref"
            # Unconditional goto
            "goto"
            # Conditional goto
            "gotoifnot"
            # Exception handling
            "enter"
            "leave"
            "pop_exception"
            # Lowering targets for method definitions arising from `function` etc
            "method"
            # (re-)initialize a slot to undef
            # See Core.NewvarNode
            "newvar"
            # Result of lowering a `K"lambda"` after bindings have been
            # converted to slot/globalref/SSAValue.
            "code_info"
            # Internal initializer for opaque closures
            "new_opaque_closure"
            # Wrapper for the lambda of around opaque closure methods
            "opaque_closure_method"
            # World age increment (TODO: use top level assertion and only one latestworld kind)
            "latestworld"
        "END_IR_KINDS"
    ])
end
