Skip to content

Commit

Permalink
little stackish parser
Browse files Browse the repository at this point in the history
  • Loading branch information
aconbere committed Jun 28, 2012
0 parents commit d17fcf2
Show file tree
Hide file tree
Showing 2 changed files with 222 additions and 0 deletions.
7 changes: 7 additions & 0 deletions src/examples.lua
@@ -0,0 +1,7 @@
local stackish = require("stackish")

local print_table = stackish.print_table
local parse = stackish.parse

print_table(parse([[ [ "abcd" [ "1234 " 5678 454.234 root things ]]))
print_table(parse([[ [ [ "hello" 1 child root ]]))
215 changes: 215 additions & 0 deletions src/stackish.lua
@@ -0,0 +1,215 @@
local quotes = { ["\""] = true,
["\'"] = true,
}

local numerals = { ["0"] = true
, ["1"] = true
, ["2"] = true
, ["3"] = true
, ["4"] = true
, ["5"] = true
, ["6"] = true
, ["7"] = true
, ["8"] = true
, ["9"] = true
}

local whitespace = { [""] = true
, [" "] = true
, ["\t"] = true
, ["\n"] = true
, ["\r"] = true
}

local types = { mark = { name = "mark" }
, string = { name = "string" }
, number = { name = "number" }
, word = { name = "word" }
}

do
local function mktype(t, value)
return { value = value
, __type = types[t]
}
end

for i, t in pairs({ "mark", "string", "number", "word" }) do
types["mk"..t] = function(value) return mktype(t, value) end
end

end

local function print_element(v)
print("el", v.__type.name, v.value)
end

local function print_stack(t)
for i,v in pairs(t) do
print_element(v)
end
end

local function print_table(t, depth)
if not depth then
depth = 0
end

for i,v in pairs(t) do
if type(v) == "table" then
print(string.rep(" ", depth)..tostring(i)..":")
print_table(v, depth+1)
elseif type(v) == "string" then
print(string.rep(" ", depth).."\""..v.."\"")
else
print(string.rep(" ", depth)..tostring(v))
end
end
end

local function peak(s)
if #s == 0 then
return nil
else
return s:sub(1,1)
end
end

local function tail(s)
return s:sub(2, #s)
end

local function chomp(s)
local p = peak(s)

if whitespace[p] then
return chomp(tail(s))
else
return s
end
end

local function take_until(input, u, output)
c = peak(input)
assert(c, "not found: "..u)

if not output then
output = ""
end

if c == u then
return output, tail(input)
else
return take_until(tail(input), u, output..c)
end
end

local function tokenize_string(input)
local c = peak(input)
assert(quotes[c], "not a string")
local str, rest = take_until(tail(input), c)
return types.mkstring(str), rest
end

local function tokenize_number(input, output)
if not output then
output = ""
end

p = peak(input)

if (p == nil) or whitespace[p] then
return types.mknumber(tonumber(output)), tail(input)
else
assert(numerals[p] or (p == "."), "Invalid number")
return tokenize_number(tail(input), output..p)
end
end

local function tokenize_word(input, output)
if not output then
output = ""
end

p = peak(input)

if (p == nil) or whitespace[p] then
return types.mkword(output), tail(input)
else
return tokenize_word(tail(input), output..p)
end
end

local function tokenize(input, stack)
if not stack then
stack = {}
end

local c = peak(input)

if not c then
return stack
end

if c == "[" then
table.insert(stack, types.mkmark(c))
return tokenize(tail(input), stack)
elseif whitespace[c] then
return tokenize(chomp(input), stack)
elseif quotes[c] then
local str, rest = tokenize_string(input)
table.insert(stack, str)
return tokenize(rest, stack)
elseif numerals[c] then
local number, rest = tokenize_number(input)
table.insert(stack, number)
return tokenize(rest, stack)
else
word, rest = tokenize_word(input)
table.insert(stack, word)
return tokenize(rest, stack)
end
end

local function map(itterable, f)
res = {}
for i,v in ipairs(itterable) do
table.insert(res, f(v))
end
return res
end

local function parse_ast(ast, _table, depth)
if not depth then
depth = 0
end

if not _table then
_table = {}
end

if #ast <= 0 then
return _table
end

local current = table.remove(ast)

if current.__type == types.mark then
return _table
elseif current.__type == types.word then
_table[current.value] = parse_ast(ast, {}, depth+1)
return parse_ast(ast, _table, depth)
else
table.insert(_table, current.value)
return parse_ast(ast, _table, depth)
end
end

local function parse(input)
return parse_ast(tokenize(input))
end

return { print_table = print_table
, parse = parse
, tokenize = tokenize
}

0 comments on commit d17fcf2

Please sign in to comment.