diff options
author | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-05-13 15:36:22 +0100 |
---|---|---|
committer | Daniel Silverstone <dsilvers@digital-scurf.org> | 2012-05-13 15:36:22 +0100 |
commit | 8f0c55799000c7e62540ae904fa18234f368211e (patch) | |
tree | db1dfa922bf461c6f4816b6e69114a9e5db0914f | |
parent | 883b64e4c546d1ea69075a22b0ff27cd7f11bfaa (diff) | |
download | lace-8f0c55799000c7e62540ae904fa18234f368211e.tar.gz |
Lexer and initial makefile
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | lib/lace/lex.lua | 123 | ||||
-rw-r--r-- | test/test-lace.lex.lua | 39 |
4 files changed, 185 insertions, 0 deletions
@@ -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") |