if not modules then modules = { } end modules ['toks-ini'] = {
    version   = 1.001,
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

tokens = tokens or { }

local tokens     = tokens
local token      = token -- the built in one
local next       = next
local tonumber   = tonumber
local tostring   = tostring
local utfchar    = utf.char
local char       = string.char
local printtable = table.print
local concat     = table.concat
local format     = string.format

local commands  = token.commands()
tokens.commands = utilities.storage.allocate(table.swapped(commands,commands))
tokens.values   = { }

local scantoks        = token.scan_toks
local scanstring      = token.scan_string
local scanargument    = token.scan_argument
local scandelimited   = token.scan_delimited
local scantokenlist   = token.scan_tokenlist or scanstring
local scaninteger     = token.scan_integer or token.scan_int
local scancardinal    = token.scan_cardinal
local scancode        = token.scan_code
local scantokencode   = token.scan_token_code
local scandimen       = token.scan_dimen
local scanglue        = token.scan_glue
local scanskip        = token.scan_skip
local scankeyword     = token.scan_keyword
local scankeywordcs   = token.scan_keyword_cs or scankeyword
local scantoken       = token.scan_token
local scanbox         = token.scan_box
local scanword        = token.scan_word
local scanletters     = token.scan_letters or scanword -- lmtx
local scankey         = token.scan_key
local scanvalue       = token.scan_value
local scanchar        = token.scan_char
local scannumber      = token.scan_number -- not defined
local scancsname      = token.scan_csname
local scanreal        = token.scan_real
local scanfloat       = token.scan_float
local scanluanumber   = token.scan_luanumber   or scanfloat    -- only lmtx
local scanluainteger  = token.scan_luainteger  or scaninteger  -- only lmtx
local scanluacardinal = token.scan_luacardinal or scancardinal -- only lmtx

local setmacro        = token.set_macro
local setchar         = token.set_char
local setlua          = token.set_lua

local createtoken     = token.create
local newtoken        = token.new
local isdefined       = token.is_defined
local istoken         = token.is_token

tokens.new            = newtoken
tokens.create         = createtoken
tokens.istoken        = istoken
tokens.isdefined      = isdefined
tokens.defined        = isdefined

local bits = {
    escape      = 0x00000001, -- 2^00
    begingroup  = 0x00000002, -- 2^01
    endgroup    = 0x00000004, -- 2^02
    mathshift   = 0x00000008, -- 2^03
    alignment   = 0x00000010, -- 2^04
    endofline   = 0x00000020, -- 2^05
    parameter   = 0x00000040, -- 2^06
    superscript = 0x00000080, -- 2^07
    subscript   = 0x00000100, -- 2^08
    ignore      = 0x00000200, -- 2^09
    space       = 0x00000400, -- 2^10 -- 1024
    letter      = 0x00000800, -- 2^11
    other       = 0x00001000, -- 2^12
    active      = 0x00002000, -- 2^13
    comment     = 0x00004000, -- 2^14
    invalid     = 0x00008000, -- 2^15
    --
    character   = 0x00001800, -- 2^11 + 2^12
    whitespace  = 0x00002400, -- 2^13 + 2^10 --    / needs more checking
    --
    open        = 0x00000402, -- 2^10 + 2^01 -- space + begingroup
    close       = 0x00000404, -- 2^10 + 2^02 -- space + endgroup
}

-- for k, v in next, bits do bits[v] = k end

tokens.bits = bits

-- words are space or \relax terminated and the trailing space is gobbled; a word
-- can contain any non-space letter/other (see archive for implementation in lua)

if not scannumber then

    scannumber = function(base)
        local s = scanword()
        if not s then
            return nil
        elseif base then
            return tonumber(s,base)
        else
            return tonumber(s)
        end
    end

end

local function scanboolean()
    local kw = scanword()
    if kw == "true" then
        return true
    elseif kw == "false" then
        return false
    else
        return nil
    end
end

local function scanverbatim()
    return scanargument(false)
end

if not scanbox then

    local scanlist = token.scan_list
    local putnext  = token.put_next

    scanbox = function(s)
        if s == "hbox" or s == "vbox" or s == "vtop" then
            putnext(createtoken(s))
        end
        return scanlist()
    end

    token.scanbox = scanbox

end

tokens.scanners = { -- these expand
    token          = scantoken,
    toks           = scantoks,
    tokens         = scantoks,
    box            = scanbox,
    hbox           = function() return scanbox("hbox") end,
    vbox           = function() return scanbox("vbox") end,
    vtop           = function() return scanbox("vtop") end,
    dimen          = scandimen,
    dimension      = scandimen,
    glue           = scanglue,
    gluevalues     = function() return scanglue(false,false,true) end,
    gluespec       = scanskip,
    integer        = scaninteger,
    cardinal       = scancardinal,
    real           = scanreal,
    float          = scanfloat,
    luanumber      = scanluanumber,
    luainteger     = scanluainteger,
    luacardinal    = scanluacardinal,
    count          = scaninteger,
    string         = scanstring,
    argument       = scanargument,
    delimited      = scandelimited,
    tokenlist      = scantokenlist,
    verbatim       = scanverbatim, -- detokenize
    code           = scancode,
    tokencode      = scantokencode,
    word           = scanword,
    letters        = scanletters,
    key            = scankey,
    value          = scanvalue,
    char           = scanchar,
    number         = scannumber,
    boolean        = scanboolean,
    keyword        = scankeyword,
    keywordcs      = scankeywordcs,
    csname         = scancsname,

    next           = token.scan_next,
    nextexpanded   = token.scan_next_expanded,

    peek           = token.peek_next,
    peekexpanded   = token.peek_next_expanded,
    peekchar       = token.peek_next_char,

    skip           = token.skip_next,
    skipexpanded   = token.skip_next_expanded,

    cmdchr         = token.scan_cmdchr,
    cmdchrexpanded = token.scan_cmdchr_expanded,

    ischar         = token.is_next_char,
}

tokens.getters = { -- these don't expand
    meaning = token.get_meaning,
    macro   = token.get_macro,
    token   = token.scan_next or token.get_next, -- not here, use scanners.next or token
    cstoken = token.get_cstoken,
    count   = tex.getcount,
    dimen   = tex.getdimen,
    skip    = tex.getglue,
    glue    = tex.getglue,
    skip    = tex.getmuglue,
    glue    = tex.getmuglue,
    box     = tex.getbox,
}

tokens.setters = {
    macro = setmacro,
    char  = setchar,
    lua   = setlua,
    count = tex.setcount,
    dimen = tex.setdimen,
    skip  = tex.setglue,
    glue  = tex.setglue,
    skip  = tex.setmuglue,
    glue  = tex.setmuglue,
    box   = tex.setbox,
}

tokens.accessors = {
    command    = token.get_command,
    cmd        = token.get_command,
    cmdname    = token.get_cmdname,
    name       = token.get_cmdname,
    csname     = token.get_csname,
    index      = token.get_index,
    active     = token.get_active,
    frozen     = token.get_frozen,
    protected  = token.get_protected,
    expandable = token.get_protected,
    user       = token.get_user,
    cmdchrcs   = token.get_cmdchrcs,
    active     = token.get_active,
    range      = token.get_range,
}

if setinspector then

    local simple = { letter = "letter", other_char = "other" }

    local astable = function(t)
        if t and istoken(t) then
            local cmdname = t.cmdname
            local simple  = simple[cmdname]
            if simple then
                return {
                    id         = t.id,
                    category   = simple,
                    character  = utfchar(t.mode) or nil,
                }
            else
                return {
                    command    = t.command,
                    id         = t.id,
                    tok        = t.tok,
                    csname     = t.csname,
                    active     = t.active,
                    expandable = t.expandable,
                    protected  = t.protected,
                    frozen     = t.frozen,
                    mode       = t.mode,
                    index      = t.index,
                    user       = t.user,
                    cmdname    = cmdname,
                }
            end
        end
    end

    tokens.astable = astable

    setinspector("token",function(v) local t = astable(v) if t then printtable(t,tostring(v)) return true end end)

end

tokens.cache = table.setmetatableindex(function(t,k)
    if not isdefined(k) then
        setmacro(k,"","global")
    end
    local v = createtoken(k)
    t[k] = v
    return v
end)

if LUATEXVERSION < 114 then

    local d = tokens.defined
    local c = tokens.create

    function tokens.defined(s,b)
        if b then
            return d(s)
        else
            return c(s).cmd_name == "undefined_cmd"
        end
    end

end

