# HG changeset patch # User Matthew Wild # Date 1441460543 -3600 # Node ID 2e31b584f8d9290ffbddefcd6bb00a36b7d534c7 It is better to write and run incomplete tests than not to run complete tests. -- Martin Fowler diff -r 000000000000 -r 2e31b584f8d9 main.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.lua Sat Sep 05 14:42:23 2015 +0100 @@ -0,0 +1,26 @@ +#!/usr/bin/env lua5.1 + +local parser = require "scansion.parser"; + +io.input(arg[1]); +local script_data = io.read("*a"); + +local script = assert(parser.parse(script_data)); + +local c = 0; +for name, object in pairs(script.objects) do + local o = require("scansion.objects."..object.type); + object.handler = o; + o._validate(object); + c = c + 1; +end + +print("Script defines "..c.." objects, and "..#script.actions.." actions"); + +for _, action in pairs(script.actions) do + local object = script.objects[action.object_name]; + local handler = object.handler; + assert(handler[action.action], "Objects of type '"..object.type.."' do not support action '"..action.action.."'"); + + handler[action.action](object, action.extra); +end diff -r 000000000000 -r 2e31b584f8d9 scansion/objects/client.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scansion/objects/client.lua Sat Sep 05 14:42:23 2015 +0100 @@ -0,0 +1,24 @@ +local verse = require "verse"; +local parse_xml = require "scansion.xml".parse; +return { + _validate = function (client) + assert(client.jid, "No JID specified"); + client.stream = verse.new(); + end; + + connects = function (client) + client.stream:connect(client.jid, client.password); + end; + + sends = function (client, data) + print(("%q"):format(table.concat(data))) + print(parse_xml(table.concat(data))); + print(stanza) + end; + + receives = function (client, data) + end; + + disconnects = function (client) + end; +} diff -r 000000000000 -r 2e31b584f8d9 scansion/parser.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scansion/parser.lua Sat Sep 05 14:42:23 2015 +0100 @@ -0,0 +1,57 @@ +local function parse(data) + local parsed = { + objects = {}; + actions = {}; + }; + + local line_number = 0; + local last_object; + + for line in data:gmatch("([^\r\n]+)\r?\n") do + line_number = line_number + 1; + print(line_number, line); + if line:sub(1,1) == "[" then + local obj_type, name, extra = line:match("^%[(%a+)%] (.+)$"); + + if parsed.objects[name] then + return nil, "Duplicate definition of "..name.." on line "..line_number; + end + parsed.objects[name] = { + type = obj_type:lower(); + name = name; + defined_line = line_number; + }; + last_object = parsed.objects[name]; + print(("%q"):format(obj_type)) + elseif line:match("^%s+%a+:.+$") then + if not last_object then + return nil, "Line "..line_number.. "unexpected outside of an object definition"; + end + local k, v = line:match("^%s+(%a+):(.+)$") + last_object[k] = v; + elseif #parsed.actions > 0 and line:sub(1,1) == "\t" then + table.insert(parsed.actions[#parsed.actions].extra, line:sub(2)); + elseif line:match("^%s*$") or line:match("^#") or line:match("^([/-])%1") then + -- Blank line or comment + else + last_object = nil; + local name, action, extra = line:match("^(%a+) (%a+):?%s?(.*)$"); + if not name then + return nil, "Unable to parse action on line "..line_number; + end + if not parsed.objects[name] then + return nil, "The object '"..name.."' used on line "..line_number.." was not declared"; + end + table.insert(parsed.actions, { + object_name = name; + action = action:lower(); + extra = {#extra>0 and extra or nil}; + }); + end + end + return parsed; +end + +return { + parse = parse; +}; diff -r 000000000000 -r 2e31b584f8d9 scansion/xml.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scansion/xml.lua Sat Sep 05 14:42:23 2015 +0100 @@ -0,0 +1,59 @@ + +local st = require "util.stanza"; +local lxp = require "lxp"; + +local _ENV = nil; + +local parse_xml = (function() + local ns_prefixes = { + ["http://www.w3.org/XML/1998/namespace"] = "xml"; + }; + local ns_separator = "\1"; + local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$"; + return function(xml) + --luacheck: ignore 212/self + local handler = {}; + local stanza = st.stanza("root"); + function handler:StartElement(tagname, attr) + local curr_ns,name = tagname:match(ns_pattern); + if name == "" then + curr_ns, name = "", curr_ns; + end + if curr_ns ~= "" then + attr.xmlns = curr_ns; + end + for i=1,#attr do + local k = attr[i]; + attr[i] = nil; + local ns, nm = k:match(ns_pattern); + if nm ~= "" then + ns = ns_prefixes[ns]; + if ns then + attr[ns..":"..nm] = attr[k]; + attr[k] = nil; + end + end + end + stanza:tag(name, attr); + end + function handler:CharacterData(data) + stanza:text(data); + end + function handler:EndElement() + stanza:up(); + end + local parser = lxp.new(handler, "\1"); + local ok, err, line, col = parser:parse(xml); + if ok then ok, err, line, col = parser:parse(); end + --parser:close(); + if ok then + return stanza.tags[1]; + else + return ok, err.." (line "..line..", col "..col..")"; + end + end; +end)(); + +return { + parse = parse_xml; +}; diff -r 000000000000 -r 2e31b584f8d9 scripts/basic.scs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/basic.scs Sat Sep 05 14:42:23 2015 +0100 @@ -0,0 +1,15 @@ +[Client] Romeo + jid: romeo@server + +--------- + +Romeo connects + +Romeo sends: + + +Romeo receives: + + +Romeo disconnects +