summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Silverstone <dsilvers@digital-scurf.org>2012-05-13 15:36:22 +0100
committerDaniel Silverstone <dsilvers@digital-scurf.org>2012-05-13 15:36:22 +0100
commit8f0c55799000c7e62540ae904fa18234f368211e (patch)
treedb1dfa922bf461c6f4816b6e69114a9e5db0914f
parent883b64e4c546d1ea69075a22b0ff27cd7f11bfaa (diff)
downloadlace-8f0c55799000c7e62540ae904fa18234f368211e.tar.gz
Lexer and initial makefile
-rw-r--r--.gitignore3
-rw-r--r--Makefile20
-rw-r--r--lib/lace/lex.lua123
-rw-r--r--test/test-lace.lex.lua39
4 files changed, 185 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index b25c15b..6a58e30 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,4 @@
*~
+luacov.stats.out
+luacov.report.out
+
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4a00955
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+all: test
+
+TEST_MODULES := lace.lex
+
+LUA := LUA_PATH="$(shell pwd)/lib/?.lua;$(shell pwd)/extras/luacov/src/?.lua;$(HOME)/dev-bzr/luxio/?.lua;;" LUA_CPATH="$(HOME)/dev-bzr/luxio/?.so;;" lua5.1
+
+clean:
+ $(RM) luacov.report.out luacov.stats.out
+
+distclean: clean
+ find . -name "*~" -delete
+
+.PHONY: test
+test:
+ @$(RM) luacov.stats.out
+ @for MOD in $(TEST_MODULES); do \
+ echo "$${MOD}:"; \
+ $(LUA) test/test-$${MOD}.lua; \
+ done
+ @$(LUA) extras/luacov/src/bin/luacov -X test. $(TEST_MODULES)
diff --git a/lib/lace/lex.lua b/lib/lace/lex.lua
new file mode 100644
index 0000000..c768d08
--- /dev/null
+++ b/lib/lace/lex.lua
@@ -0,0 +1,123 @@
+-- lib/lace/lex.lua
+--
+-- Lua Access Control Engine -- Ruleset lexer
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For Licence terms, see COPYING
+--
+
+local sio = require "luxio.simple"
+
+local function lex_one_line(line)
+ local r = {}
+ local acc = ""
+ local c
+ local escaping = false
+ local quoting = false
+ local spos, cpos = 1, 0
+ while #line > 0 do
+ c, line = line:match("^(.)(.*)$")
+ cpos = cpos + 1
+ if escaping then
+ if quoting then
+ if c == "n" then
+ acc = acc .. "\n"
+ elseif c == "t" then
+ acc = acc .. "\t"
+ else
+ acc = acc .. c
+ end
+ else
+ acc = acc .. c
+ end
+ escaping = false
+ else
+ if c == "'" and quoting == false then
+ -- Start single quotes
+ quoting = c
+ elseif c == '"' and quoting == false then
+ -- Start double quotes
+ quoting = c
+ elseif c == "'" and quoting == c then
+ -- End single quotes
+ quoting = false
+ elseif c == '"' and quoting == c then
+ -- End double quotes
+ quoting = false
+ elseif c == "\\" then
+ -- A backslash, entering escaping mode
+ escaping = true
+ elseif quoting then
+ -- Within quotes, so accumulate
+ acc = acc .. c
+ elseif c == " " or c == "\t" then
+ -- A space (or tab) and not quoting, so clear the accumulator
+ if acc ~= "" then
+ r[#r+1] = { spos, acc }
+ spos = cpos + 1
+ end
+ acc = ""
+ else
+ acc = acc .. c
+ end
+ end
+ end
+ if acc ~= "" then
+ r[#r+1] = { spos, acc }
+ end
+
+ local warnings = {}
+ if quoting then
+ warnings[#warnings+1] = "Un-terminated quoted string"
+ end
+ if escaping then
+ warnings[#warnings+1] = "Un-used escape at end"
+ end
+ if #r == 0 then
+ warnings[#warnings+1] = "No command found?"
+ end
+
+ return r, warnings
+end
+
+local function lex_a_ruleset(ruleset, sourcename)
+ local lines = {}
+ local ret = { source = sourcename, lines = lines }
+ local n = 1
+ local warn
+ for oneline in ruleset:gmatch("([^\n]*)\n") do
+ local linetab = { original = oneline }
+ if linetab:find("^[ \t]*#") or
+ linetab:find("^[ \t]*//") or
+ linetab:find("^[ \t]*%-%-") then
+ linetab.type = "comment"
+ elseif linetab:find("^[ \t]*$") then
+ linetab.type = "whitespace"
+ else
+ linetab.type = "rule"
+ linetab.content, warn = lex_one_line(oneline)
+ if #warn then
+ linetab.warnings = warn
+ end
+ end
+ lines[n] = linetab
+ n = n + 1
+ end
+ return lines
+end
+
+local function lex_a_file(filename)
+ local fh, err = sio.open(filename, "r")
+ if not fh then
+ return nil, "Unable to open " .. tostring(filename) .. ": " .. tostring(err)
+ end
+ local ruleset = fh:read("*a")
+ fh:close()
+ return lex_a_string(ruleset, "@" .. filename)
+end
+
+return {
+ file = lex_a_file,
+ string = lex_a_ruleset,
+}
diff --git a/test/test-lace.lex.lua b/test/test-lace.lex.lua
new file mode 100644
index 0000000..e0119e4
--- /dev/null
+++ b/test/test-lace.lex.lua
@@ -0,0 +1,39 @@
+-- test/test-lex.lua
+--
+-- Lua Access Control Engine -- Tests for the lexer
+--
+-- Copyright 2012 Daniel Silverstone <dsilvers@digital-scurf.org>
+--
+-- For Licence terms, see COPYING
+--
+
+-- Step one, start coverage
+
+local luacov = require 'luacov'
+
+local lex = require 'lace.lex'
+
+local suite = {}
+
+function suite.test_01_empty_string()
+end
+
+local testnames = {}
+for k in pairs(suite) do
+ testnames[#testnames+1] = k
+end
+table.sort(testnames)
+
+local count_ok = 0
+for _, testname in ipairs(testnames) do
+ local ok, err = xpcall(suite[testname], debug.traceback)
+ if not ok then
+ print(testname .. ":")
+ print(err)
+ print()
+ else
+ count_ok = count_ok + 1
+ end
+end
+
+print("Lex: " .. tostring(count_ok) .. "/" .. tostring(#testnames) .. " OK")