diff --git a/src/bindings/lua/hammer.lua b/src/bindings/lua/hammer.lua index 6c82afcdb3f86d50c7d0ddfe8646c10ce429ff21..568d7e9d7e78d0287d4807f9df0cb0e4c67cfaba 100644 --- a/src/bindings/lua/hammer.lua +++ b/src/bindings/lua/hammer.lua @@ -140,16 +140,32 @@ local function append(a, ...) return helper(a, select('#', ...), ...) end --- local parser local mt = { __index = { parse = function(p, str) return h.h_parse(p, str, #str) end, }, } --- parser = ffi.metatype("HParser", mt) - local hammer = {} hammer.parser = ffi.metatype("HParser", mt) + +local counted_array +local arr_mt = { + __index = function(table, key) + return table.elements[key] + end, + __len = function(table) return table.used end, + __ipairs = function(table) + local i, n = 0, #table + return function() + i = i + 1 + if i <= n then + return i, table.elements[i] + end + end + end +} +counted_array = ffi.metatype("HCountedArray", arr_mt) + function hammer.token(str) return h.h_token(str, #str) end diff --git a/src/bindings/lua/test.lua b/src/bindings/lua/test.lua index f5b77e5d948d6831b047602c73115ada5725dae1..7b0b8cfa573a94444a824fd42db1235be67e41ac 100644 --- a/src/bindings/lua/test.lua +++ b/src/bindings/lua/test.lua @@ -13,7 +13,7 @@ describe("Combinator tests", function() local parser = hammer.token("95" .. string.char(0xa2)) it("parses a token", function() local ret = parser:parse("95" .. string.char(0xa2)) - assert.are.same(ret.ast.bytes, "95" .. string.char(0xa2)) + assert.are.same("95" .. string.char(0xa2), ret.ast.bytes) end) it("does not parse an incomplete token", function() local ret = parser:parse("95") @@ -25,7 +25,7 @@ describe("Combinator tests", function() local parser = hammer.ch(0xa2) it("parses a matching char", function() local ret = parser:parse(string.char(0xa2)) - assert.are.same(ret.ast.uint, string.char(0xa2)) + assert.are.same(string.char(0xa2), ret.ast.uint) end) it("rejects a non-matching char", function() local ret = parser:parse(string.char(0xa3)) @@ -37,7 +37,7 @@ describe("Combinator tests", function() local parser = hammer.ch_range("a", "c") it("parses a char in the range", function() local ret = parser:parse("b") - assert.are.same(ret.ast.uint, "b") + assert.are.same("b", ret.ast.uint) end) it("rejects a char outside the range", function() local ret = parser:parse("d") @@ -49,7 +49,7 @@ describe("Combinator tests", function() local parser = hammer.int64() it("parses a valid 64-bit int", function() local ret = parser:parse(string.char(0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00)) - assert.are.same(ret.ast.sint, -0x200000000) + assert.are.same(-0x200000000, ret.ast.sint) end) it("does not parse an invalid 64-bit int", function() local ret = parser:parse(string.char(0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00)) @@ -61,7 +61,7 @@ describe("Combinator tests", function() local parser = hammer.int32() it("parses a valid 32-bit int", function() local ret = parser:parse(string.char(0xff, 0xfe, 0x00, 0x00)) - assert.are.same(ret.ast.sint, -0x20000) + assert.are.same(-0x20000, ret.ast.sint) end) it("does not parse an invalid 32-bit int", function() local ret = parser:parse(string.char(0xff, 0xfe, 0x00)) @@ -73,7 +73,7 @@ describe("Combinator tests", function() local parser = hammer.int16() it("parses a valid 16-bit int", function() local ret = parser:parse(string.char(0xfe, 0x00)) - assert.are.same(ret.ast.sint, -0x200) + assert.are.same(-0x200, ret.ast.sint) end) it("does not parse an invalid 16-bit int", function() local ret = parser:parse(string.char(0xfe)) @@ -85,7 +85,7 @@ describe("Combinator tests", function() local parser = hammer.int8() it("parses a valid 8-bit int", function() local ret = parser:parse(string.char(0x88)) - assert.are.same(ret.ast.sint, -0x78) + assert.are.same(-0x78, ret.ast.sint) end) it("does not parse an invalid 8-bit int", function() local ret = parser:parse("") @@ -97,7 +97,7 @@ describe("Combinator tests", function() local parser = hammer.uint64() it("parses a valid 64-bit unsigned int", function() local ret = parser:parse(string.char(0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00)) - assert.are.same(ret.ast.uint, 0x200000000) + assert.are.same(0x200000000, ret.ast.uint) end) it("does not parse an invalid 64-bit unsigned int", function() local ret = parser:parse(string.char(0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00)) @@ -109,7 +109,7 @@ describe("Combinator tests", function() local parser = hammer.uint32() it("parses a valid 32-bit unsigned int", function() local ret = parser:parse(string.char(0x00, 0x02, 0x00, 0x00)) - assert.are.same(ret.ast.uint, 0x20000) + assert.are.same(0x20000, ret.ast.uint) end) it("does not parse an invalid 32-bit unsigned int", function() local ret = parser:parse(string.char(0x00, 0x02, 0x00)) @@ -121,7 +121,7 @@ describe("Combinator tests", function() local parser = hammer.uint16() it("parses a valid 16-bit unsigned int", function() local ret = parser:parse(string.char(0x02, 0x00)) - assert.are.same(ret.ast.uint, 0x200) + assert.are.same(0x200, ret.ast.uint) end) it("does not parse an invalid 16-bit unsigned int", function() local ret = parser:parse(string.char(0x02)) @@ -133,7 +133,7 @@ describe("Combinator tests", function() local parser = hammer.uint8() it("parses a valid 8-bit unsigned int", function() local ret = parser:parse(string.char(0x78)) - assert.are.same(ret.ast.uint, 0x78) + assert.are.same(0x78, ret.ast.uint) end) it("does not parse an invalid 8=bit unsigned int", function() local ret = parser:parse("") @@ -145,7 +145,7 @@ describe("Combinator tests", function() local parser = hammer.int_range(hammer.uint8(), 3, 10) it("parses a value in the range", function() local ret = parser:parse(string.char(0x05)) - assert.are.same(ret.ast.uint, 5) + assert.are.same(5, ret.ast.uint) end) it("does not parse a value outside the range", function() local ret = parser:parse(string.char(0xb)) @@ -158,19 +158,19 @@ describe("Combinator tests", function() local parser2 = hammer.whitespace(hammer.end_p()) it("parses a string with no whitespace", function() local ret = parser:parse("a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("parses a string with a leading space", function() local ret = parser:parse(" a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("parses a string with leading spaces", function() local ret = parser:parse(" a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("parses a string with a leading tab", function() local ret = parser:parse("\ta") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("does not parse a string with a leading underscore", function() local ret = parser:parse("_a") @@ -178,11 +178,11 @@ describe("Combinator tests", function() end) it("parses an empty string", function() local ret = parser2:parse("") - assert.are.same(ret.ast, nil) + assert.are.same(nil, ret.ast) end) it("parses a whitespace-only string", function() local ret = parser2:parse(" ") - assert.are.same(ret.ast, nil) + assert.are.same(nil, ret.ast) end) it("does not parse a string with leading whitespace and a trailing character", function() local ret = parser2:parse(" x") @@ -194,7 +194,7 @@ describe("Combinator tests", function() local parser = hammer.left(hammer.ch("a"), hammer.ch(" ")) it("parses the leftmost character", function() local ret = parser:parse("a ") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("does not parse a string that is too short", function() local ret = parser:parse("a") @@ -214,7 +214,7 @@ describe("Combinator tests", function() local parser = hammer.right(hammer.ch(" "), hammer.ch("a")) it("parses the rightmost character", function() local ret = parser:parse(" a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("does not parse a string that starts with the wrong character", function() local ret = parser:parse("a") @@ -234,7 +234,7 @@ describe("Combinator tests", function() local parser = hammer.middle(hammer.ch(" "), hammer.ch("a"), hammer.ch(" ")) it("parses the middle character", function() local ret = parser:parse(" a ") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("does not parse a string that is too short", function() local ret = parser:parse("a") @@ -262,7 +262,7 @@ describe("Combinator tests", function() describe("Semantic action tests", function() local function upcase(result, user_data) - local chars = result.ast.seq.elements + local chars = result.ast.seq local ret = "" for i, v in ipairs(chars) do ret = ret .. string.char(v.uint):upper() @@ -272,14 +272,14 @@ describe("Combinator tests", function() local parser = hammer.action(hammer.sequence(hammer.choice(hammer.ch("a"), hammer.ch("A")), hammer.choice(hammer.ch("b"), hammer.ch("B"))), upcase, nil) it("converts a lowercase 'ab' to uppercase", function() local ret = parser:parse("ab") - assert.are.same(ret.ast.seq, {"A", "B"}) + assert.are.same({"A", "B"}, ret.ast.seq) end) it("accepts an uppercase 'AB' unchanged", function() local ret = parser:parse("AB") - assert.are.same(ret.ast.seq, {"A", "B"}) + assert.are.same({"A", "B"}, ret.ast.seq) end) it("rejects strings that don't match the underlying parser", function() - local ret = parser:parse() + local ret = parser:parse("XX") assert.is_falsy(ret) end) end) @@ -288,7 +288,7 @@ describe("Combinator tests", function() local parser = hammer.in_({"a", "b", "c"}) it("parses a character that is in the included set", function() local ret = parser:parse("b") - assert.are.same(ret.ast.uint, "b") + assert.are.same("b", ret.ast.uint) end) it("does not parse a character that is not in the included set", function() local ret = parser:parse("d") @@ -300,7 +300,7 @@ describe("Combinator tests", function() local parser = hammer.not_in({"a", "b", "c"}) it("parses a character that is not in the excluded set", function() local ret = parser:parse("d") - assert.are.same(ret.ast.uint, "d") + assert.are.same("d", ret.ast.uint) end) it("does not parse a character that is in the excluded set", function() local ret = parser:parse("a") @@ -312,7 +312,7 @@ describe("Combinator tests", function() local parser = hammer.sequence(hammer.ch("a"), hammer.end_p()) it("parses a string that ends where it is expected to", function() local ret = parser:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) end) it("does not parse a string that is too long", function() local ret = parser:parse("aa") @@ -333,7 +333,7 @@ describe("Combinator tests", function() local parser2 = hammer.sequence(hammer.ch("a"), hammer.whitespace(hammer.ch("b"))) it("parses a string matching the sequence", function() local ret = parser:parse("ab") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) end) it("does not parse a string that is too short", function() local ret = parser:parse("a") @@ -345,14 +345,14 @@ describe("Combinator tests", function() end) it("parses a whitespace-optional string with no whitespace", function() local ret = parser2:parse("ab") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) end) -- it("parses a whitespace-optional string containing whitespace", function() -- local ret = parser:parse("a b") - -- assert.are.same(ret.ast.seq, {"a", "b"}) -- this is the line that segfaults + -- assert.are.same({"a", "b"}, ret.ast.seq) -- this is the line that segfaults -- print("in sequence") -- ret = parser:parse("a b") - -- assert.are.same(ret.ast.seq, {"a", "b"}) + -- assert.are.same({"a", "b"}, ret.ast.seq) -- end) end) @@ -360,9 +360,9 @@ describe("Combinator tests", function() local parser = hammer.choice(hammer.ch("a"), hammer.ch("b")) it("parses a character in the choice set", function() local ret = parser:parse("a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) ret = parser:parse("b") - assert.are.same(ret.ast.uint, "b") + assert.are.same("b", ret.ast.uint) end) it("does not parse a character not in the choice set", function() local ret = parser:parse("c") @@ -375,9 +375,9 @@ describe("Combinator tests", function() local parser2 = hammer.butnot(hammer.ch_range("0", "9"), hammer.ch("6")) it("succeeds when 'a' matches but 'ab' doesn't", function() local ret = parser:parse("a") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) ret = parser:parse("aa") - assert.are.same(ret.ast.uint, "a") + assert.are.same("a", ret.ast.uint) end) it("fails when p2's result is longer than p1's", function() local ret = parser:parse("ab") @@ -393,7 +393,7 @@ describe("Combinator tests", function() local parser = hammer.difference(hammer.token("ab"), hammer.ch("a")) it("succeeds when 'ab' matches and its result is longer than the result for 'a'", function() local ret = parser:parse("ab") - assert.are.same(ret.ast.bytes, "ab") + assert.are.same("ab", ret.ast.bytes) end) it("fails if 'ab' doesn't match", function() local ret = parser:parse("a") @@ -405,11 +405,11 @@ describe("Combinator tests", function() local parser = hammer.xor(hammer.ch_range("0", "6"), hammer.ch_range("5", "9")) it("parses a value only in the first range", function() local ret = parser:parse("0") - assert.are.same(ret.ast.uint, "0") + assert.are.same("0", ret.ast.uint) end) it("parses a value only in the second range", function() local ret = parser:parse("9") - assert.are.same(ret.ast.uint, "9") + assert.are.same("9", ret.ast.uint) end) it("does not parse a value inside both ranges", function() local ret = parser:parse("5") @@ -425,17 +425,17 @@ describe("Combinator tests", function() local parser = hammer.many(hammer.choice(hammer.ch("a"), hammer.ch("b"))) it("parses an empty string", function() local ret = parser:parse("") - assert.are.same(ret.ast.seq, {}) + assert.are.same({}, ret.ast.seq) end) it("parses a single repetition of the pattern", function() local ret = parser:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) ret = parser:parse("b") - assert.are.same(ret.ast.seq, {"b"}) + assert.are.same({"b"}, ret.ast.seq) end) it("parses multiple repetitions of the pattern", function() local ret = parser:parse("aabbaba") - assert.are.same(ret.ast.seq, {"a", "a", "b", "b", "a", "b", "a"}) + assert.are.same({"a", "a", "b", "b", "a", "b", "a"}, ret.ast.seq) end) end) @@ -447,13 +447,13 @@ describe("Combinator tests", function() end) it("parses a single repetition of the pattern", function() local ret = parser:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) ret = parser:parse("b") - assert.are.same(ret.ast.seq, {"b"}) + assert.are.same({"b"}, ret.ast.seq) end) it("parses multiple repetitions of the pattern", function() local ret = parser:parse("aabbaba") - assert.are.same(ret.ast.seq, {"a", "a", "b", "b", "a", "b", "a"}) + assert.are.same({"a", "a", "b", "b", "a", "b", "a"}, ret.ast.seq) end) it("does not parse a string that does not start with one of the patterns to repeat", function() local ret = parser:parse("daabbabadef") @@ -469,7 +469,7 @@ describe("Combinator tests", function() end) it("parses a string containing the correct number of repetitions", function() local ret = parser:parse("abdef") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) end) it("does not parse a string that does not start with a character in the repetition set", function() local ret = parser:parse("dabdef") @@ -481,17 +481,17 @@ describe("Combinator tests", function() local parser = hammer.sequence(hammer.ch("a"), hammer.optional(hammer.choice(hammer.ch("b"), hammer.ch("c"))), hammer.ch("d")) it("parses a string containing either optional character", function() local ret = parser:parse("abd") - assert.are.same(ret.ast.seq, {"a", "b", "d"}) + assert.are.same({"a", "b", "d"}, ret.ast.seq) ret = parser:parse("acd") - assert.are.same(ret.ast.seq, {"a", "c", "d"}) + assert.are.same({"a", "c", "d"}, ret.ast.seq) end) it("parses a string missing one of the optional characters", function() local ret = parser:parse("ad") - assert.are.same(ret.ast.seq, {"a", {}, "d"}) + assert.are.same({"a", {}, "d"}, ret.ast.seq) end) it("does not parse a string containing a character not among the optional ones", function() local ret = parser:parse("aed") - assert.is_falsy(ret) + assert.is_falsy(ret.ast) end) end) @@ -499,7 +499,7 @@ describe("Combinator tests", function() local parser = hammer.sequence(hammer.ch("a"), hammer.ignore(hammer.ch("b")), hammer.ch("c")) it("parses a string containing the pattern to ignore, and leaves that pattern out of the result", function() local ret = parser:parse("abc") - assert.are.same(ret.ast.seq, {"a", "c"}) + assert.are.same({"a", "c"}, ret.ast.seq) end) it("does not parse a string not containing the pattern to ignore", function() local ret = parser:parse("ac") @@ -511,23 +511,23 @@ describe("Combinator tests", function() local parser = hammer.sepBy(hammer.choice(hammer.ch("1"), hammer.ch("2"), hammer.ch("3")), hammer.ch(",")) it("parses an ordered list", function() local ret = parser:parse("1,2,3") - assert.are.same(ret.ast.seq, {"1", "2", "3"}) + assert.are.same({"1", "2", "3"}, ret.ast.seq) end) it("parses an unordered list", function() local ret = parser:parse("1,3,2") - assert.are.same(ret.ast.seq, {"1", "3", "2"}) + assert.are.same({"1", "3", "2"}, ret.ast.seq) end) it("parses a list not containing all options", function() local ret = parser:parse("1,3") - assert.are.same(ret.ast.seq, {"1", "3"}) + assert.are.same({"1", "3"}, ret.ast.seq) end) it("parses a unary list", function() local ret = parser:parse("3") - assert.are.same(ret.ast.seq, {"3"}) + assert.are.same({"3"}, ret.ast.seq) end) it("parses an empty list", function() local ret = parser:parse("") - assert.are.same(ret.ast.seq, {}) + assert.are.same({}, ret.ast.seq) end) end) @@ -535,20 +535,20 @@ describe("Combinator tests", function() local parser = hammer.sepBy1(hammer.choice(hammer.ch("1"), hammer.ch("2"), hammer.ch("3")), hammer.ch(",")) it("parses an ordered list", function() local ret = parser:parse("1,2,3") - assert.are.same(ret.ast.seq, {"1", "2", "3"}) + assert.are.same({"1", "2", "3"}, ret.ast.seq) end) it("parses an unordered list", function() local ret = parser:parse("1,3,2") - assert.are.same(ret.ast.seq, {"1", "3", "2"}) + assert.are.same({"1", "3", "2"}, ret.ast.seq) end) it("parses a list not containing all options", function() local ret = parser:parse("1,3") - assert.are.same(ret.ast.seq, {"1", "3"}) + assert.are.same({"1", "3"}, ret.ast.seq) end) -- it("parses a unary list", function() -- local ret = parser:parse("3") -- print("in sepBy1") - -- assert.are.same(ret.ast.seq, {"3"}) -- this line also segfaults + -- assert.are.same({"3"}, ret.ast.seq) -- this line also segfaults -- end) it("does not parse an empty list", function() local ret = parser:parse("") @@ -562,15 +562,15 @@ describe("Combinator tests", function() local parser3 = hammer.sequence(hammer.ch("a"), hammer.epsilon_p()) it("parses an empty string between two characters", function() local ret = parser:parse("ab") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) end) it("parses an empty string before a character", function() local ret = parser2:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) end) it("parses a ", function() local ret = parser3:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) end) end) @@ -581,9 +581,10 @@ describe("Combinator tests", function() local parser = hammer.attr_bool(hammer.many1(hammer.choice(hammer.ch("a"), hammer.ch("b"))), equals) it("parses successfully when both characters are the same (i.e., the validation function succeeds)", function() local ret = parser:parse("aa") - assert.are.same(ret.ast.seq, {"a", "a"}) + assert.are.same({"a", "a"}, ret.ast.seq) + print("in attr_bool") ret = parser:parse("bb") - assert.are.same(ret.ast.seq, {"b", "b"}) + assert.are.same({"b", "b"}, ret.ast.seq) end) it("does not parse successfully when the characters are different (i.e., the validation function fails)", function() local ret = parser:parse("ab") @@ -597,7 +598,7 @@ describe("Combinator tests", function() local parser3 = hammer.sequence(hammer.ch("1"), hammer.and_(hammer.ch("2"))) it("parses successfully when the lookahead matches the next character to parse", function() local ret = parser:parse("0") - assert.are.same(ret.ast.seq, {"0"}) + assert.are.same({"0"}, ret.ast.seq) end) it("does not parse successfully when the lookahead does not match the next character to parse", function() local ret = parser2:parse("0") @@ -605,7 +606,7 @@ describe("Combinator tests", function() end) it("parses successfully when the lookahead is there", function() local ret = parser3:parse("12") - assert.are.same(ret.ast.seq, {"1"}) + assert.are.same({"1"}, ret.ast.seq) end) end) @@ -614,7 +615,7 @@ describe("Combinator tests", function() local parser2 = hammer.sequence(hammer.ch("a"), hammer.choice(hammer.sequence(hammer.ch("+"), hammer.not_(hammer.ch("+"))), hammer.token("++")), hammer.ch("b")) it("parses a single plus correctly in the 'choice' example", function() local ret = parser:parse("a+b") - assert.are.same(ret.ast.seq, {"a", "+", "b"}) + assert.are.same({"a", "+", "b"}, ret.ast.seq) end) it("does not parse a double plus correctly in the 'choice' example", function() local ret = parser:parse("a++b") @@ -622,11 +623,11 @@ describe("Combinator tests", function() end) it("parses a single plus correctly in the 'not' example", function() local ret = parser2:parse("a+b") - assert.are.same(ret.ast.seq, {"a", {"+"}, "b"}) + assert.are.same({"a", {"+"}, "b"}, ret.ast.seq) end) it("parses a double plus correctly in the 'not' example", function() local ret = parser2:parse("a++b") - assert.are.same(ret.ast.seq, {"a", "++", "b"}) + assert.are.same({"a", "++", "b"}, ret.ast.seq) end) end) @@ -635,15 +636,15 @@ describe("Combinator tests", function() hammer.bind_indirect(parser, hammer.choice(hammer.sequence(parser, hammer.ch("a")), hammer.ch("a"))) it("parses the base case", function() local ret = parser:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) end) it("parses one level of recursion", function() local ret = parser:parse("aa") - assert.are.same(ret.ast.seq, {"a", "a"}) + assert.are.same({"a", "a"}, ret.ast.seq) end) it("parses two levels of recursion", function() local ret = parser:parse("aaa") - assert.are.same(ret.ast.seq, {{"a", "a"}, "a"}) + assert.are.same({{"a", "a"}, "a"}, ret.ast.seq) end) end) @@ -652,15 +653,15 @@ describe("Combinator tests", function() hammer.bind_indirect(parser, hammer.choice(hammer.sequence(hammer.ch("a"), parser), hammer.epsilon_p())) it("parses the base case", function() local ret = parser:parse("a") - assert.are.same(ret.ast.seq, {"a"}) + assert.are.same({"a"}, ret.ast.seq) end) it("parses one level of recursion", function() local ret = parser:parse("aa") - assert.are.same(ret.ast.seq, {"a", {"a"}}) + assert.are.same({"a", {"a"}}, ret.ast.seq) end) it("parses two levels of recursion", function() local ret = parser:parse("aaa") - assert.are.same(ret.ast.seq, {"a", {"a", {"a"}}}) + assert.are.same({"a", {"a", {"a"}}}, ret.ast.seq) end) end) @@ -682,25 +683,25 @@ describe("Combinator tests", function() local parser8 = hammer.with_endianness(lb, u5) it("parses big-endian cases", function() local ret = parser1:parse("abcd") - assert.are.same(ret.ast.uint, 0x61626364) + assert.are.same(0x61626364, ret.ast.uint) ret = parser2:parse("abcd") - assert.are.same(ret.ast.uint, 0xc) + assert.are.same(0xc, ret.ast.uint) end) it("parses little-endian cases", function() local ret = parser3:parse("abcd") - assert.are.same(ret.ast.uint, 0x61626364) + assert.are.same(0x61626364, ret.ast.uint) ret = parser4:parse("abcd") - assert.are.same(ret.ast.uint, 0xc) + assert.are.same(0xc, ret.ast.uint) end) it("parses mixed-endian cases", function() local ret = parser5:parse("abcd") - assert.are.same(ret.ast.uint, 0x61626364) + assert.are.same(0x61626364, ret.ast.uint) ret = parser6:parse("abcd") - assert.are.same(ret.ast.uint, 0x1) + assert.are.same(0x1, ret.ast.uint) ret = parser7:parse("abcd") - assert.are.same(ret.ast.uint, 0x64636261) + assert.are.same(0x64636261, ret.ast.uint) ret = parser8:parse("abcd") - assert.are.same(ret.ast.uint, 0xc) + assert.are.same(0xc, ret.ast.uint) end) end) @@ -708,11 +709,11 @@ describe("Combinator tests", function() local parser = hammer.sequence(hammer.put_value(hammer.uint8(), "size"), hammer.token("foo"), hammer.length_value(hammer.get_value("size"), hammer.uint8())) it("parses a string that has enough bytes for the specified length", function() local ret = parser:parse(string.char(0x06) .. "fooabcdef") - assert.are.same(ret.ast.seq.elements[1].bytes, "foo") - assert.are.same(ret.ast.seq.elements[2].seq, {0x61, 0x62, 0x63, 0x64, 0x65, 0x66}) + assert.are.same("foo", ret.ast.seq[2]) + assert.are.same({0x61, 0x62, 0x63, 0x64, 0x65, 0x66}, ret.ast.seq[3]) end) it("does not parse a string that does not have enough bytes for the specified length", function() - local ret = parser:parse() + local ret = parser:parse(string.char(0x06) .. "fooabcde") assert.is_falsy(ret) end) end) @@ -721,17 +722,17 @@ describe("Combinator tests", function() local parser = hammer.permutation(hammer.ch("a"), hammer.ch("b"), hammer.ch("c")) it("parses a permutation of 'abc'", function() local ret = parser:parse("abc") - assert.are.same(ret.ast.seq, {"a", "b", "c"}) + assert.are.same({"a", "b", "c"}, ret.ast.seq) ret = parser:parse("acb") - assert.are.same(ret.ast.seq, {"a", "c", "b"}) + assert.are.same({"a", "c", "b"}, ret.ast.seq) ret = parser:parse("bac") - assert.are.same(ret.ast.seq, {"b", "a", "c"}) + assert.are.same({"b", "a", "c"}, ret.ast.seq) ret = parser:parse("bca") - assert.are.same(ret.ast.seq, {"b", "c", "a"}) + assert.are.same({"b", "c", "a"}, ret.ast.seq) ret = parser:parse("cab") - assert.are.same(ret.ast.seq, {"c", "a", "b"}) + assert.are.same({"c", "a", "b"}, ret.ast.seq) ret = parser:parse("cba") - assert.are.same(ret.ast.seq, {"c", "b", "a"}) + assert.are.same({"c", "b", "a"}, ret.ast.seq) end) it("does not parse a string that is not a permutation of 'abc'", function() local ret = parser:parse("a") @@ -744,21 +745,21 @@ describe("Combinator tests", function() parser = hammer.permutation(hammer.ch("a"), hammer.ch("b"), hammer.optional(hammer.ch("c"))) it("parses a string that is a permutation of 'ab[c]'", function() local ret = parser:parse("abc") - assert.are.same(ret.ast.seq, {"a", "b", "c"}) + assert.are.same({"a", "b", "c"}, ret.ast.seq) ret = parser:parse("acb") - assert.are.same(ret.ast.seq, {"a", "c", "b"}) + assert.are.same({"a", "c", "b"}, ret.ast.seq) ret = parser:parse("bac") - assert.are.same(ret.ast.seq, {"b", "a", "c"}) + assert.are.same({"b", "a", "c"}, ret.ast.seq) ret = parser:parse("bca") - assert.are.same(ret.ast.seq, {"b", "c", "a"}) + assert.are.same({"b", "c", "a"}, ret.ast.seq) ret = parser:parse("cab") - assert.are.same(ret.ast.seq, {"c", "a", "b"}) + assert.are.same({"c", "a", "b"}, ret.ast.seq) ret = parser:parse("cba") - assert.are.same(ret.ast.seq, {"c", "b", "a"}) + assert.are.same({"c", "b", "a"}, ret.ast.seq) ret = parser:parse("ab") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) ret = parser:parse("ba") - assert.are.same(ret.ast.seq, {"b", "a"}) + assert.are.same({"b", "a"}, ret.ast.seq) end) it("does not parse a string that is not a permutation of 'ab[c]'", function() local ret = parser:parse("a") @@ -781,21 +782,21 @@ describe("Combinator tests", function() parser = hammer.permutation(hammer.optional(hammer.ch("c")), hammer.ch("a"), hammer.ch("b")) it("parses a string that is a permutation of '[c]ab'", function() local ret = parser:parse("abc") - assert.are.same(ret.ast.seq, {"a", "b", "c"}) + assert.are.same({"a", "b", "c"}, ret.ast.seq) ret = parser:parse("acb") - assert.are.same(ret.ast.seq, {"a", "c", "b"}) + assert.are.same({"a", "c", "b"}, ret.ast.seq) ret = parser:parse("bac") - assert.are.same(ret.ast.seq, {"b", "a", "c"}) + assert.are.same({"b", "a", "c"}, ret.ast.seq) ret = parser:parse("bca") - assert.are.same(ret.ast.seq, {"b", "c", "a"}) + assert.are.same({"b", "c", "a"}, ret.ast.seq) ret = parser:parse("cab") - assert.are.same(ret.ast.seq, {"c", "a", "b"}) + assert.are.same({"c", "a", "b"}, ret.ast.seq) ret = parser:parse("cba") - assert.are.same(ret.ast.seq, {"c", "b", "a"}) + assert.are.same({"c", "b", "a"}, ret.ast.seq) ret = parser:parse("ab") - assert.are.same(ret.ast.seq, {"a", "b"}) + assert.are.same({"a", "b"}, ret.ast.seq) ret = parser:parse("ba") - assert.are.same(ret.ast.seq, {"b", "a"}) + assert.are.same({"b", "a"}, ret.ast.seq) end) it("does not parse a string that is not a permutation of '[c]ab'", function() local ret = parser:parse("a") @@ -820,7 +821,7 @@ describe("Combinator tests", function() -- describe("Monadic binding tests", function() -- local function continuation(allocator, result, env) -- local val = 0 - -- for k, v in result.seq.elements + -- for k, v in result.seq -- do val = val*10 + v->uint - 48 -- end -- if val > 26 then