git @ Cat's Eye Technologies Decoy / master lib / lua / list.lua
master

Tree @master (Download .tar.gz)

list.lua @masterraw · history · blame

-- SPDX-FileCopyrightText: Chris Pressey, the original author of this work, has dedicated it to the public domain.
-- For more information, please refer to <https://unlicense.org/>
-- SPDX-License-Identifier: Unlicense

math = require "math"

require "decoy.model"
local Module = require "decoy.module"


local make_list_module = function()
    local env = {}

    env["car"] = function(args)
        return args[1]:head()
    end

    env["cdr"] = function(args)
        return args[1]:tail()
    end

    env["cons"] = function(args)
        return Cons.new(args[1], args[2])
    end

    local list_p
    list_p = function(value)
        if type(value) == "function" then
            return False
        elseif value == Nil then
            return True
        elseif Cons.is_class_of(value) then
            return list_p(value:tail())
        else
            return False
        end
    end
    env["list?"] = function(args)
        return list_p(args[1])
    end

    env["pair?"] = function(args)
        if Cons.is_class_of(args[1]) then
            return True
        else
            return False
        end
    end

    env["null?"] = function(args)
        if args[1] == Nil then
            return True
        else
            return False
        end
    end

    env["list"] = function(args)
        return Cons.table_to_list(args)
    end

    env["length"] = function(args)
        local c = args[1]
        local n = 0
        while c ~= Nil do
            if Cons.is_class_of(c) then
                n = n + 1
                c = c:tail()
            else
                c = Nil
            end
        end
        return Number.new(n)
    end

    env["map"] = function(args)
        local fn = args[1]
        local c = 0
        local t = {}
        while c ~= Nil do
            if Cons.is_class_of(c) then
                table.insert(t, c) -- FIXME fn(c) !!
                c = c.tail()
            else
                c = Nil
            end
        end
        return Cons.table_to_list(t)
    end

    -- Note: not in R5RS
    env["fold"] = function(args)
        local fn = args[1]
        local acc = args[2]
        local c = args[3]
        while c ~= Nil do
            if Cons.is_class_of(c) then
                acc = fn({ c:head(), acc })
                c = c:tail()
            else
                c = Nil
            end
        end
        return acc
    end

    env["list-ref"] = function(args)
        local c = args[1]
        local n = args[2]
        while n > 0 do
            if Cons.is_class_of(c) then
                n = n - 1
                c = c:tail()
            else
                n = 0
            end
        end
        return c:head()
    end

    local m = Module.new()
    -- FIXME this is horrible
    m.symbols = env
    return m
end

return make_list_module