/* ----------------------------------------------------------------------------- Copyright 2023-2024 Kevin P. Barry Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ----------------------------------------------------------------------------- */ // Author: Kevin P. Barry [ta0kira@gmail.com] testcase "parsing tests" { success TestChecker } concrete ParsingTester { @type new (ZeoliteParseContext) -> (ParsingTester) @value checkParsesAs (String, DefaultOrder) -> () } unittest parseZeoliteWhitespace { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ " \t \r\n" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " \t \r\n")) \ " test" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) } unittest parseZeoliteLineComment { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include()) \ "//12345\n//54321" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteLineComment", content: "//12345")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n")) .append(ZeoliteParsed.leaf(label: "ZeoliteLineComment", content: "//54321")) \ "/ /" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteBlockComment { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include()) \ "/*/12345\n54321* */" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*/12345\n54321* */")) \ "/*comment*/ " `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*comment*/")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) \ "/*forever " `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*forever ")) \ "/ *" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteUpperSymbol { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "Hello123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "Hello123")) \ "String" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinCategory", content: "String")) \ "Hello_123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "Hello")) \ "hello" `tester.checkParsesAs` AlwaysEmpty.default() \ "123Hello" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteLowerSymbol { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "hello123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionOrVariableName", content: "hello123")) \ "hello123:" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteArgLabel", content: "hello123:")) \ "cleanup" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteControlKeyword", content: "cleanup")) \ "immutable" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteTypeKeyword", content: "immutable")) \ "concrete" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteContainKeyword", content: "concrete")) \ "optional" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteStorageKeyword", content: "optional")) \ "unittest" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteScopeQualifier", content: "unittest")) \ "any" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinCategory", content: "any")) \ "identify" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinFunction", content: "identify")) \ "empty" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinConstant", content: "empty")) \ "hello_123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionOrVariableName", content: "hello")) // Only has a special label in testcase. \ "compiler" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionOrVariableName", content: "compiler")) \ "empty123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionOrVariableName", content: "empty123")) \ "identify:" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinFunction", content: "identify")) \ "Hello" `tester.checkParsesAs` AlwaysEmpty.default() \ "123hello" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteScopeQualifier { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "@value" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteScopeQualifier", content: "@value")) \ "@type" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteScopeQualifier", content: "@type")) \ "@category" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteScopeQualifier", content: "@category")) \ "@value something" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteScopeQualifier", content: "@value")) \ "@local" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "@local")) } unittest parseZeoliteOperator { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "<-" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteAssignment", content: "<-")) \ "<-|" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteAssignment", content: "<-|")) \ "<->" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteAssignment", content: "<->")) \ "->" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteAssignment", content: "->")) \ ":" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionCall", content: ":")) \ "." `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionCall", content: ".")) \ "&." `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionCall", content: "&.")) \ "?" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionCall", content: "?")) \ "<<" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: "<<")) \ ":.!%^&*-+|<>?=" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: ":.!%^&*-+|<>?=")) \ "<-||" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: "<-||")) \ "&.call()" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteFunctionCall", content: "&.")) } unittest parseZeoliteParamName { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "#param123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteParamName", content: "#param123")) \ "#self" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteBuiltinParam", content: "#self")) \ "#param_123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteParamName", content: "#param")) \ "#self123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteParamName", content: "#self123")) \ "param" `tester.checkParsesAs` AlwaysEmpty.default() \ "#Param" `tester.checkParsesAs` AlwaysEmpty.default() \ "#123param" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteStringLiteral { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "\"hello\\n\\t\\0123\\xABC\\Q \\09c goodbye\"" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteStringLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "hello")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\n")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\t")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\012")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "3")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\xAB")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "C")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "\\Q")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "\\0")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "9c goodbye")) .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")))) \ "\"forever" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteStringLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "forever")))) } unittest parseZeoliteCharLiteral { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "'a'" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "a")) .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")))) \ "'\\''" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\'")) .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")))) \ "'\\n'" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\n")) .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")))) \ "'\\xAB'" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\xAB")) .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")))) \ "'\\Q'" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "\\Q")) .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")))) \ "''" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "'")))) \ "'forever" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteCharLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteSingleQuote", content: "'")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "f")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "o")))) } unittest parseZeoliteNumber { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123")) \ "123.456" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123.456")) \ "123.456E123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123.456E123")) \ "+123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "+123")) \ "-123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "-123")) \ "123.456E+123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123.456E+123")) \ "123.456E-123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123.456E-123")) \ "\\b101.010" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\b101.010")) \ "\\o123.456" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\o123.456")) \ "\\d123.456" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\d123.456")) \ "\\x123.abc" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\x123.abc")) \ "123A" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "123")) \ "\\b0123" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\b01")) .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "23")) \ "\\o12389" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\o123")) .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "89")) \ "\\d123A" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\d123")) \ "\\xABCqq" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedNumber", content: "\\xABC")) \ "-" `tester.checkParsesAs` AlwaysEmpty.default() \ "+" `tester.checkParsesAs` AlwaysEmpty.default() \ "\\" `tester.checkParsesAs` AlwaysEmpty.default() \ "\\b" `tester.checkParsesAs` AlwaysEmpty.default() \ "\\o" `tester.checkParsesAs` AlwaysEmpty.default() \ "\\d" `tester.checkParsesAs` AlwaysEmpty.default() \ "\\h" `tester.checkParsesAs` AlwaysEmpty.default() } unittest parseZeoliteBraceSection { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include() .include()) \ "{ /*hello*/ }" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteBraceSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "{")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*hello*/")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: "}")))) \ "{ /*forever*/" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteBraceSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "{")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*forever*/")))) } unittest parseZeoliteParenSection { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include() .include()) \ "( /*hello*/ )" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteParenSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "(")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*hello*/")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: ")")))) \ "( /*forever*/" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteParenSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "(")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*forever*/")))) } unittest parseZeoliteSquareSection { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include() .include()) \ "[ /*hello*/ ]" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteSquareSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "[")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*hello*/")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: "]")))) \ "[ /*forever*/" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteSquareSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "[")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*forever*/")))) } unittest parseZeoliteTestcase { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include() .include() .include() .include() .include() .include() // ZeoliteTestcase also uses the above if available. .include() // These should be after ZeoliteTestcase. .include() .include()) String data <- "testcase \"my test\" { success Checker<[A&B]> // <- enables lib/testing support require compiler \"something\" timeout 30 }" \ data `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteTestcase", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteContainKeyword", content: "testcase")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.section(label: "ZeoliteStringLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "my test")) .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")))) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.section(label: "ZeoliteTestcaseSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "{")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n ")) .append(ZeoliteParsed.leaf(label: "ZeoliteTestcaseKeyword", content: "success")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "Checker")) .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: "<")) .append(ZeoliteParsed.section(label: "ZeoliteSquareSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "[")) .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "A")) .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: "&")) .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "B")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: "]")))) .append(ZeoliteParsed.leaf(label: "ZeoliteOperator", content: ">")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteLineComment", content: "// <- enables lib/testing support")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n ")) .append(ZeoliteParsed.leaf(label: "ZeoliteTestcaseKeyword", content: "require")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteTestcaseKeyword", content: "compiler")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.section(label: "ZeoliteStringLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "something")) .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")))) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n ")) .append(ZeoliteParsed.leaf(label: "ZeoliteTestcaseKeyword", content: "timeout")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteNumber", content: "30")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n ")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: "}")))))) \ "testcase { }" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteTestcase", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteContainKeyword", content: "testcase")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")))) } unittest parseZeolitePragma { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "$NoArgs$" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaName", content: "NoArgs")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")))) \ "$SomeArgs[a, b, 123]$" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaName", content: "SomeArgs")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaArgOpen", content: "[")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaArg", content: "a, b, 123")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaArgClose", content: "]")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")))) \ "$NoArgs" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaName", content: "NoArgs")))) \ "$foo$" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")))) \ "$NoArgs#" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaName", content: "NoArgs")) .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "#")))) \ "$SomeArgs[args" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeolitePragma", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeolitePragmaDelim", content: "$")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaName", content: "SomeArgs")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaArgOpen", content: "[")) .append(ZeoliteParsed.leaf(label: "ZeolitePragmaArg", content: "args")))) } unittest parseZeoliteExtras { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include()) \ "_" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteIgnore", content: "_")) \ "\\" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDiscard", content: "\\")) \ "`" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteTick", content: "`")) \ "," `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteComma", content: ",")) \ ";" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: ";")) \ "#" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "#")) \ "@" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteError", content: "@")) } unittest integration { ParsingTester tester <- ParsingTester.new(ZeoliteParseContext.new() .include() .include() .include() .include() .include() .include() .include() .include() .include() .include() .include()) \ "{Category #param}\"string\\n\" /*/ done*/\n" `tester.checkParsesAs` Vector.new() .append(ZeoliteParsed.section(label: "ZeoliteBraceSection", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteOpenDelim", content: "{")) .append(ZeoliteParsed.leaf(label: "ZeoliteCategoryName", content: "Category")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteParamName", content: "#param")) .append(ZeoliteParsed.leaf(label: "ZeoliteCloseDelim", content: "}")))) .append(ZeoliteParsed.section(label: "ZeoliteStringLiteral", Vector.new() .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")) .append(ZeoliteParsed.leaf(label: "ZeoliteQuotedChars", content: "string")) .append(ZeoliteParsed.leaf(label: "ZeoliteEscapedChar", content: "\\n")) .append(ZeoliteParsed.leaf(label: "ZeoliteDoubleQuote", content: "\"")))) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: " ")) .append(ZeoliteParsed.leaf(label: "ZeoliteBlockComment", content: "/*/ done*/")) .append(ZeoliteParsed.leaf(label: "ZeoliteWhitespace", content: "\n")) } define ParsingTester { $ReadOnlyExcept[]$ @value ZeoliteParseContext context new (context) { return delegate -> #self } checkParsesAs (originalData, expected) { TextStream input <- TextStream.new(originalData) DefaultOrder output <- defer \ StreamTokenizer:new(context: context, tokenizer: context.defaultTokenizer()) .tokenizeAll(input, (output <- Vector.new())) // Match output. \ output `Matches:tryWith` CheckSequence:matches(CheckSequence:using(expected)) // Serialize output. [Append & Build] builder <- String.builder() UnformattedFormatter formatter <- UnformattedFormatter.new() traverse (output.defaultOrder() -> ZeoliteParsed parsed) { \ builder.append(parsed.formatWith(formatter)) } // Append unparsed remainder. while (`present` input.current()) { \ input.forward() } // This will be included in the output of failing tests. \ BasicOutput.stderr() .append("Remaining content: \"") .append(CharType.escapeBreaks(input.preview())) .append("\"\n") \ builder.append(input.take()) // Check that all data is accounted for. \ builder.build() `Matches:tryWith` CheckValue:equals(originalData) } }