Skip to content

Instantly share code, notes, and snippets.

@rameshvarun
Last active July 31, 2021 03:27
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rameshvarun/dbc3e320eedaa0981c73 to your computer and use it in GitHub Desktop.
Save rameshvarun/dbc3e320eedaa0981c73 to your computer and use it in GitHub Desktop.
Basic literate programming in Lua.
local litlua = {}
-- String split function - taken from Penlight
-- https://github.com/stevedonovan/Penlight/blob/master/lua/pl/utils.lua#L172
local function split(s, re, plain, n)
local i1, ls = 1, {}
if not re then re = '%s+' end
if re == '' then return {s} end
while true do
local i2, i3 = s:find(re, i1, plain)
if not i2 then
local last = s:sub(i1)
if last ~= '' then table.insert(ls, last) end
if #ls == 1 and ls[1] == '' then
return {}
else
return ls
end
end
table.insert(ls, s:sub(i1,i2-1))
if n and #ls == n then
ls[#ls] = s:sub(i1)
return ls
end
i1 = i3+1
end
end
-- Local helper function to check if a string is a prefix of another.
local function starts(str, start) return str:sub(1, start:len()) == start end
-- Transforms markdown into a lua file. It simply makes every non-codeblock line into a comment.
-- This preserves line numbers.
function litlua.transform(markdown)
local lines = split(markdown, "[\r\n]")
local output, inCodeBlock = "", false
for _, line in ipairs(lines) do
if inCodeBlock then
if starts(line, "```") then inCodeBlock = false
else output = output .. line .. "\n" end
end
if not inCodeBlock then
output = output .. "-- " .. line .. "\n"
if starts(line, "```lua") then inCodeBlock = true end
end
end
return output
end
function litlua.install()
table.insert(package.searchers, function(name)
local dirsep = "/"
local name_path = name:gsub("%.", dirsep)
local file = nil
for path in package.path:gmatch("[^;]+") do
local file_path = path:gsub("?", name_path) .. ".md"
file = io.open(file_path, 'r')
if file then break end
end
if file then
-- Read in the markdown source.
local markdown = file:read("*a")
file:close()
-- Transform and load the module.
local code = litlua.transform(markdown)
res, err = loadstring(code, file_path)
-- Return the module, or report an error.
if not res then error(file_path .. ": " .. err) end
return res
else
return nil, "Could not find .lua.md file"
end
end)
end
return litlua
require("litlua").install()
require "primes"

First 100 Primes

Dumb example to demonstrate literate programming.

This quick example demonstrates how to write a Lua program that outputs the first 100 prime numbers. Let's start by defining a configurable variable that tells us how many primes to output.

local NUMBER_OF_PRIMES = 100 -- Change this to output more or less primes.

isPrime Helper Function

Now we'll create a helper function that can actually check if a number is prime.

function isPrime(num)
	if num < 2 then return false end
	if num == 2 then return true end
	for i=2,num - 1 do
		if num % i == 0 then return false end
	end
	return true
end

Printing Out The Primes

Finally, we can print out the prime numbers. We create two counters - one holding the number that we are checking (number) and one holding the number of primes that we have found so far (counter). We know that the first prime number is 2, so we start with number = 2.

local count, number = 0, 2
while count < NUMBER_OF_PRIMES do
	if isPrime(number) then
		print(number)
		count = count + 1
	end
	number = number + 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment