Skip to content

Instantly share code, notes, and snippets.

@jdp
Created December 15, 2008 13:30
Show Gist options
  • Save jdp/35953 to your computer and use it in GitHub Desktop.
Save jdp/35953 to your computer and use it in GitHub Desktop.
Beginnings of a basic HAML subset for Lua
require "tprint"
raw_haml = [[%a
%b
%a
%b
%c]]
-- Generate a list of HAML rules
rules = {}
for rule in raw_haml:gfind("[^\n]+") do
local spaces, data = rule:match("^(%s*)(.*)$")
table.insert(rules, {rule = data, depth = spaces:len()/2})
end
table_print(rules)
-- Form a tree representing the HAML
function tree(branches, start, depth, parent)
branches[0].depth = 0
local position = start + 1
while position <= table.maxn(branches) do
if branches[position].depth >= branches[position-1].depth then
io.write(string.rep(" ", branches[position].depth), position, branches[position].rule, "\n")
local node = {
name = "div",
attrs = {},
classes = {},
selector = "",
content = "",
children = {}
}
local scan, haml_rule = 1, branches[position].rule
while scan <= haml_rule:len() do
local token_start
char = haml_rule:sub(scan, scan)
if char == "%" then
token_start = haml_rule:find("[%%#.{%s]", scan + 1) or -1
node.name = haml_rule:sub(scan + 1, token_start - ((token_start == -1) and 0 or 1))
scan = token_start
elseif char == "#" then
token_start = haml_rule:find("[%%#.{%s]", scan + 1) or -1
node.attrs.id = haml_rule:sub(scan + 1, token_start)
scan = token_start
elseif char == "." then
token_start = haml_rule:find("[%%#.{%s]", scan + 1) or -1
table.insert(node.classes, haml_rule:sub(scan + 1, token_start - ((token_start == -1) and 0 or 1)))
scan = token_start
elseif char == "{" then
token_start = haml_rule:find("}", scan + 1) or -1
--io.write("attrs:\t", haml_rule:sub(scan, token_start), "\n")
attrs = loadstring("return (" .. haml_rule:sub(scan, token_start) .. ")")
if attrs ~= nil then
for k,v in pairs(attrs()) do
node.attrs[k] = v
end
end
dummy, scan = haml_rule:find("}%s+")
scan = (scan == nil) and (haml_rule:len() + 1) or (scan + 1)
else
node.content = (scan == -1) and "" or haml_rule:sub(scan, -1)
scan = haml_rule:len() + 1
end
end
if table.maxn(node.classes) > 0 then
node.attrs.class = ""
for i, class in ipairs(node.classes) do
node.attrs.class = node.attrs.class .. class .. " "
end
node.attrs.class = node.attrs.class:sub(1, -2)
end
table.insert(parent.children, node)
tree(branches, position, depth+1, node)
end
position = position + 1
end
end
-- Output HTML from HAML
function html(haml, depth)
for i, child in ipairs(haml.children) do
io.write(string.rep(" ", depth), "<", child.name)
for attr, attr_val in pairs(child.attrs) do
io.write(" ", attr, '="', attr_val, '"')
end
io.write(">\n")
if child.content ~= "" then
io.write(string.rep(" ", depth + 1), child.content, "\n")
end
html(child, depth + 1)
io.write(string.rep(" ", depth), "</", child.name, ">\n")
end
end
root = { children = {} }
tree(rules, 0, 0, root)
--html(root, 0)
--[[haml_delims = "%#."
haml_rule = "%tag#id.class1.class2{href='thing',name='bitch'} zuhhhh"
node.selector = branches[position].rule:match("^(.*)%s*")
for word in node.selector:gmatch("([.#%%]?[^%s.#%%]+)") do
if word:sub(1, 1) == '%' then
node.name = word:sub(2)
elseif word:sub(1, 1) == '#' then
node.attrs.id = word:sub(2)
elseif word:sub(1, 1) == '.' then
table.insert(node.classes, word:sub(2))
end
end]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment