From 8004c7b2688abbff1c602f299cdedffab3784f38 Mon Sep 17 00:00:00 2001 From: Eirik Meland Date: Fri, 16 Aug 2024 14:59:34 +0200 Subject: [PATCH] =?UTF-8?q?tatt=20bort=20l=C3=B8sning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/test/scala/arktekk/ParserSuite.scala | 3 + .../test/scala/arktekk/json/JsonParser.scala | 116 +------- .../scala/arktekk/oppgave1/Backtracking.scala | 19 +- .../arktekk/oppgave1/ParsersWithCapture.scala | 17 +- .../arktekk/oppgave1/SimpleParsers.scala | 37 +-- .../arktekk/oppgave2/PointerParser.scala | 34 +-- .../scala/arktekk/oppgave3/tomlParser.scala | 248 +----------------- 7 files changed, 42 insertions(+), 432 deletions(-) diff --git a/oppgaver/src/test/scala/arktekk/ParserSuite.scala b/oppgaver/src/test/scala/arktekk/ParserSuite.scala index 5fa0a9f..fdf48c9 100644 --- a/oppgaver/src/test/scala/arktekk/ParserSuite.scala +++ b/oppgaver/src/test/scala/arktekk/ParserSuite.scala @@ -5,6 +5,9 @@ import org.scalatest.funsuite.AnyFunSuite trait ParserSuite extends AnyFunSuite { + inline def implement_me: Parser[Unit] = ??? + inline def implement_me[A]: Parser[A] = ??? + inline def assertParses[A](parser: Parser[A], inputs: (String, A)*) = { inputs.foreach { (input, expectedResult) => val result = parser.parseAll(input) diff --git a/oppgaver/src/test/scala/arktekk/json/JsonParser.scala b/oppgaver/src/test/scala/arktekk/json/JsonParser.scala index 27ddedd..6d83ebd 100644 --- a/oppgaver/src/test/scala/arktekk/json/JsonParser.scala +++ b/oppgaver/src/test/scala/arktekk/json/JsonParser.scala @@ -1,119 +1,5 @@ package arktekk.json -import cats.data.NonEmptyList -import cats.parse.{Parser, Rfc5234} import arktekk.ParserSuite -import scala.util.Try - -class JsonParser extends ParserSuite { - - enum JsonValue { - case JsonNull - case JsonBoolean(value: Boolean) - case JsonNumber(value: BigDecimal) - case JsonString(value: String) - case JsonArray(values: List[JsonValue]) - case JsonObject(pairs: List[(String, JsonValue)]) - } - import JsonValue.* - - val ows = (Rfc5234.wsp | Rfc5234.crlf).rep0.void - val comma = Parser.char(',').surroundedBy(ows).withContext("comma") - val colon = Parser.char(':').surroundedBy(ows) - val openBracket = Parser.char('[').surroundedBy(ows) - val closeBracket = Parser.char(']').surroundedBy(ows).withContext("closeBracket") - val openBrace = Parser.char('{').surroundedBy(ows) - val closeBrace = Parser.char('}').surroundedBy(ows).withContext("closeBrace") - - val jsonNull: Parser[JsonValue] = Parser.string("null").as(JsonNull).withContext("null") - val jsonBoolean: Parser[JsonValue] = - (Parser - .string("false") - .as(JsonBoolean(false)) | Parser.string("true").as(JsonBoolean(true))).withContext("boolean") - val jsonNumber: Parser[JsonValue] = - cats.parse.Numbers.jsonNumber.mapFilter(s => Try(JsonNumber(BigDecimal(s))).toOption) - - val jsonStringParser: Parser[String] = cats.parse.strings.Json.delimited.parser - - val jsonString: Parser[JsonValue] = jsonStringParser.map(JsonString.apply) - - val jsonScalar: Parser[JsonValue] = jsonNull | jsonBoolean | jsonNumber | jsonString - - val jsonRecur: Parser[JsonValue] = Parser.defer { - val jsonValue = (jsonRecur | jsonScalar).surroundedBy(ows) - val jsonArray: Parser[JsonValue] = { - (openBracket ~ closeBracket).as(JsonArray(List.empty)).backtrack | - jsonValue - .repSep(comma) - .between(openBracket, closeBracket) - .map(nel => JsonArray(nel.toList)) - } - - val jsonObject: Parser[JsonValue] = { - (openBrace ~ closeBrace).as(JsonObject(List.empty)).backtrack | - ((jsonStringParser <* colon) ~ jsonValue) - .repSep(comma) - .between(openBrace, closeBrace) - .map((pairs: NonEmptyList[(String, JsonValue)]) => JsonObject(pairs.toList)) - } - - jsonArray | jsonObject - } - - val jsonValue: Parser[JsonValue] = jsonScalar | jsonRecur - - test("null") { - assertParses(jsonValue, "null" -> JsonNull) - } - - test("true/false") { - val validInputs = List( - "false" -> JsonBoolean(false), - "true" -> JsonBoolean(true) - ) - - assertParses(jsonValue, validInputs*) - } - - test("jsonNumber") { - val validInputs = List( - "123" -> JsonNumber(BigDecimal("123")), - "123.123" -> JsonNumber(123.123) - ) - - assertParses(jsonValue, validInputs*) - } - - test("jsonString") { - val validInputs = List( - "\"foo\"" -> JsonString("foo"), - "\"æøå\"" -> JsonString("æøå") - ) - assertParses(jsonValue, validInputs*) - } - - test("jsonArray") { - val validInputs = List( - " [ ] " -> JsonArray(List.empty), - "[ 1, 20 ]" -> JsonArray(List(JsonNumber(1), JsonNumber(20))) - ) - - assertParses(jsonValue, validInputs*) - } - - test("jsonObject") { - val validInputs = List( - "{ }" -> JsonObject(List.empty), - """{"test": 1}""" -> JsonObject(List("test" -> JsonNumber(BigDecimal(1)))), - """{"foo": "bar","fizz":[1,2,3,"fizz"]}""" -> JsonObject( - List( - ("foo", JsonString("bar")), - ("fizz", JsonArray(List(JsonNumber(1), JsonNumber(2), JsonNumber(3), JsonString("fizz")))) - ) - ) - ) - - assertParses(jsonValue, validInputs*) - } -} +class JsonParser extends ParserSuite {} diff --git a/oppgaver/src/test/scala/arktekk/oppgave1/Backtracking.scala b/oppgaver/src/test/scala/arktekk/oppgave1/Backtracking.scala index 4d2a27b..f63532f 100644 --- a/oppgaver/src/test/scala/arktekk/oppgave1/Backtracking.scala +++ b/oppgaver/src/test/scala/arktekk/oppgave1/Backtracking.scala @@ -1,7 +1,7 @@ package arktekk.oppgave1 import arktekk.ParserSuite -import cats.parse.{Parser, Rfc5234} +import cats.parse.Parser class Backtracking extends ParserSuite { @@ -17,12 +17,7 @@ class Backtracking extends ParserSuite { ".55" -> Tall.Flyttall(0.55) ) - val heltall = Rfc5234.digit.rep.string.map(s => Tall.Heltall(s.toInt)).withContext("heltall") - val flyttall = (Rfc5234.digit.rep0.with1 ~ Parser.char('.') ~ Rfc5234.digit.rep).string - .map(s => Tall.Flyttall(s.toDouble)) - .withContext("flyttall") - - val p = flyttall.backtrack | heltall + val p: Parser[Tall] = implement_me assertParses(p, validInputs*) } @@ -42,15 +37,7 @@ class Backtracking extends ParserSuite { "19m" -> Lengde.Meter(19) ) - val heltall: Parser[Int] = Rfc5234.digit.rep.string.mapFilter(_.toIntOption) - - val millimeter: Parser[Lengde] = - (heltall <* Parser.string("mm")).map(Lengde.Millimeter.apply).withContext("millimeter") - val centimeter: Parser[Lengde] = - (heltall <* Parser.string("cm")).map(Lengde.Centimeter.apply).withContext("centimeter") - val meter: Parser[Lengde] = (heltall <* Parser.string("m")).map(Lengde.Meter.apply).withContext("meter") - - val p = millimeter.backtrack | centimeter.backtrack | meter + val p: Parser[Lengde] = implement_me assertParses(p, validInputs*) } diff --git a/oppgaver/src/test/scala/arktekk/oppgave1/ParsersWithCapture.scala b/oppgaver/src/test/scala/arktekk/oppgave1/ParsersWithCapture.scala index 703d1f6..ba082c6 100644 --- a/oppgaver/src/test/scala/arktekk/oppgave1/ParsersWithCapture.scala +++ b/oppgaver/src/test/scala/arktekk/oppgave1/ParsersWithCapture.scala @@ -1,7 +1,7 @@ package arktekk.oppgave1 -import cats.parse.{Parser, Rfc5234} import arktekk.ParserSuite +import cats.parse.Parser class ParsersWithCapture extends ParserSuite { @@ -13,7 +13,7 @@ class ParsersWithCapture extends ParserSuite { " a " -> "a" ) - val p: Parser[String] = Parser.char('a').string.surroundedBy(Rfc5234.wsp.rep0) + val p: Parser[String] = implement_me assertParses(p, validInputs*) } @@ -25,7 +25,18 @@ class ParsersWithCapture extends ParserSuite { "æøåÆØÅ" -> "æøåÆØÅ" ) - val p = Parser.charIn(0x00.toChar to 0x10ffff.toChar).rep.string + val p: Parser[String] = implement_me + + assertParses(p, validInputs*) + } + + test("boolean") { + val validInputs = List( + "true" -> true, + "false" -> false + ) + + val p: Parser[Boolean] = implement_me assertParses(p, validInputs*) } diff --git a/oppgaver/src/test/scala/arktekk/oppgave1/SimpleParsers.scala b/oppgaver/src/test/scala/arktekk/oppgave1/SimpleParsers.scala index 89da067..cdc1e31 100644 --- a/oppgaver/src/test/scala/arktekk/oppgave1/SimpleParsers.scala +++ b/oppgaver/src/test/scala/arktekk/oppgave1/SimpleParsers.scala @@ -1,27 +1,27 @@ package arktekk.oppgave1 -import cats.parse.{Parser, Rfc5234} import arktekk.ParserSuite +import cats.parse.Parser class SimpleParsers extends ParserSuite { test("parse \"a\"") { val input = "a" - val p = Parser.char('a') + val p = implement_me assertParsesValid(p, input) } test("parse \"ab\"") { val input = "ab" - val p = Parser.char('a') ~ Parser.char('b') + val p = implement_me assertParsesValid(p, input) } test("parse \"aba\"") { val input = "aba" - val p = Parser.char('a') ~ Parser.char('b') ~ Parser.char('a') + val p = implement_me assertParsesValid(p, input) } @@ -30,7 +30,7 @@ class SimpleParsers extends ParserSuite { val validInputs = List("aaba", "aba", "aaaabaaa") val invalidInputs = List("baaa", "aabbaa") - val p = Parser.char('a').rep ~ Parser.char('b') ~ Parser.char('a').rep + val p = implement_me assertParsesValid(p, validInputs*) assertParsesInvalid(p, invalidInputs*) @@ -39,7 +39,8 @@ class SimpleParsers extends ParserSuite { test("parse \"aa\" og \"aaa\", men ikke \"a\" eller \"aaaa\"") { val validInputs = List("aa", "aaa") val invalidInputs = List("a", "aaaa") - val p = Parser.char('a').rep(2, 3) + + val p = implement_me assertParsesValid(p, validInputs*) assertParsesInvalid(p, invalidInputs*) @@ -49,10 +50,7 @@ class SimpleParsers extends ParserSuite { val validInputs = List("(a, a, a)", "(a, a)", "(a, a)") val invalidInputs = List("()", "(a)", "(a, aa)", "(a,a)") - val p = - Parser.char('(') ~ - Parser.char('a').repSep(2, Parser.string(", ")) ~ - Parser.char(')') + val p = implement_me assertParsesValid(p, validInputs*) assertParsesInvalid(p, invalidInputs*) @@ -61,7 +59,7 @@ class SimpleParsers extends ParserSuite { test("parse \"a\" med vilkårlig mange spaces før og/eller etter") { val validInputs = List("a", " a", " a", " a ") - val p = Parser.char('a').surroundedBy(Rfc5234.wsp.rep0) + val p = implement_me assertParsesValid(p, validInputs*) } @@ -70,7 +68,7 @@ class SimpleParsers extends ParserSuite { val validInput = "nananananananananana Batman" val invalidInputs = List("nanana Batman", "nananananananananananananananananananana Batman") - val p = Parser.string("na").rep(10, 10) ~ Rfc5234.wsp ~ Parser.string("Batman") + val p = implement_me assertParsesValid(p, validInput) assertParsesInvalid(p, invalidInputs*) @@ -80,7 +78,7 @@ class SimpleParsers extends ParserSuite { val validInputs = List("123", "234", "1", "0") val invalidInputs = List("-1", "0xff", "a", "12c") - val p = Parser.charsWhile(_.isDigit) + val p = implement_me assertParsesValid(p, validInputs*) assertParsesInvalid(p, invalidInputs*) @@ -89,19 +87,8 @@ class SimpleParsers extends ParserSuite { test("DNA") { val validInputs = List("ACGT", "AAA", "TT", "ATGG", "CCAATG") - val p = Parser.charIn("ACGT").rep + val p = implement_me assertParsesValid(p, validInputs*) } - - test("boolean") { - val validInputs = List( - "true" -> true, - "false" -> false - ) - - val p: Parser[Boolean] = Parser.string("true").as(true) | Parser.string("false").as(false) - - assertParses(p, validInputs*) - } } diff --git a/oppgaver/src/test/scala/arktekk/oppgave2/PointerParser.scala b/oppgaver/src/test/scala/arktekk/oppgave2/PointerParser.scala index 9e6288a..d9ffb5a 100644 --- a/oppgaver/src/test/scala/arktekk/oppgave2/PointerParser.scala +++ b/oppgaver/src/test/scala/arktekk/oppgave2/PointerParser.scala @@ -1,37 +1,15 @@ package arktekk.oppgave2 -import cats.data.NonEmptyList import cats.parse.* object PointerParser { - val unescaped = Parser.charIn(0x00.toChar to 0x2e.toChar) | Parser.charIn(0x30.toChar to 0x7d.toChar) | Parser.charIn( - 0x7f.toChar to 0x10ffff.toChar - ) - val escaped = Parser.string("~0") | Parser.string("~1") - val zero = Parser.char('0').as(Ref.Index(0)) + // json-pointer = *( "/" reference-token ) + // reference-token = *( unescaped / escaped ) + // unescaped = %x00-2E / %x30-7D / %x7F-10FFFF ; %x2F ('/') and %x7E ('~') are excluded from 'unescaped' + // escaped = "~" ( "0" / "1" ) ; representing '~' and '/', respectively - val endOfList = Parser.char('-').as(Ref.EndOfList) - - val digitWithOutZero = Parser.charIn('1' to '9') - val digit = Parser.charIn('0' to '9') - val numericIndex = (digitWithOutZero ~ digit.rep0).string.map(x => Ref.Index(x.toInt)) - - val sep = Parser.char('/') - val emptyProp = sep.as(Ref.Property("")) - - val index: Parser[Ref & ArrayRef] = zero | endOfList | numericIndex - val property: Parser[Ref] = - (unescaped | escaped).rep.string.map(Ref.Property(_)) | emptyProp - - val root = Parser.end.as(Path.Root) - - val refs = (emptyProp ~ (index | property).repSep0(sep.?) ~ emptyProp.?).map { case ((empty, list), maybeEnd) => - if list.isEmpty then Path.Refs(NonEmptyList.of(empty)) - else Path.Refs(NonEmptyList.fromListUnsafe(list ++ maybeEnd.toList)) - } - - val parser: Parser0[Path] = - root | refs + // skal være val + def parser: Parser0[Path] = ??? def parse(input: String): Either[Parser.Error, Path] = parser.parseAll(input) diff --git a/oppgaver/src/test/scala/arktekk/oppgave3/tomlParser.scala b/oppgaver/src/test/scala/arktekk/oppgave3/tomlParser.scala index 9767865..43d210f 100644 --- a/oppgaver/src/test/scala/arktekk/oppgave3/tomlParser.scala +++ b/oppgaver/src/test/scala/arktekk/oppgave3/tomlParser.scala @@ -1,250 +1,8 @@ package arktekk.oppgave3 -import cats.data.NonEmptyList -import cats.parse.{Parser0, Rfc5234, Parser as P} +import cats.parse.Parser0 // https://github.com/toml-lang/toml/blob/1.0.0/toml.abnf -val DIGIT: P[Char] = Rfc5234.digit -val HEXDIG: P[Char] = Rfc5234.hexdig -val LF = Rfc5234.lf -val CRLF = Rfc5234.crlf -val ALPHA = Rfc5234.alpha - -// ;; Whitespace -// -// wschar = %x20 ; Space -// wschar =/ %x09 ; Horizontal tab -val wschar: P[Char] = P.charIn(' ', '\t') - -// ws = *wschar -val ws: Parser0[List[Char]] = wschar.rep0 - -// ;; Newline -// -// newline = %x0A ; LF -// newline =/ %x0D.0A ; CRLF -val newline: P[Unit] = LF | CRLF - -// ;; Comment -// -// comment-start-symbol = %x23 ; # -val comment_start_symbol: P[Unit] = P.char('#') - -// non-ascii = %x80-D7FF / %xE000-10FFFF -// non-eol = %x09 / %x20-7F / non-ascii -// -// comment = comment-start-symbol *non-eol -val comment: P[Unit] = (comment_start_symbol ~ P.charsWhile0(_ != '\n')).void - -// ;; Integer -// minus = %x2D ; - -val minus = P.char('-') - -// plus = %x2B ; + -val plus = P.char('+') - -// underscore = %x5F ; _ -val underscore = P.char('_') - -// digit1-9 = %x31-39 ; 1-9 -val digit1_9 = P.charIn('1' to '9') - -// digit0-7 = %x30-37 ; 0-7 -val digit0_7 = P.charIn('0' to '7') - -// digit0-1 = %x30-31 ; 0-1 -val digit0_1 = P.charIn('0', '1') - -// hex-prefix = %x30.78 ; 0x -val hex_prefix: P[Unit] = P.string("0x") - -// oct-prefix = %x30.6F ; 0o -val oct_prefix: P[Unit] = P.string("0o") - -// bin-prefix = %x30.62 ; 0b -val bin_prefix: P[Unit] = P.string("0b") - -// unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) -val unsigned_dec_int: P[String] = ((digit1_9 ~ (DIGIT | (underscore ~ DIGIT)).rep0) | DIGIT).string - -// hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) -val hex_int: P[String] = hex_prefix *> (HEXDIG ~ (HEXDIG | (underscore ~ HEXDIG)).rep0).string - .map(s => java.lang.Long.parseLong(s.replaceAll("_", ""), 16).toString) - -// oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) -val oct_int: P[String] = oct_prefix *> (digit0_7 ~ (digit0_7 | (underscore ~ digit0_7)).rep0).string - .map(s => java.lang.Long.parseLong(s.replaceAll("_", ""), 8).toString) - -// bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) -val bin_int: P[String] = bin_prefix *> (digit0_1 ~ (digit0_1 | (underscore ~ digit0_1)).rep0).string - .map(s => java.lang.Long.parseLong(s.replaceAll("_", ""), 2).toString) - -// dec-int = [ minus / plus ] unsigned-dec-int -val dec_int: P[String] = ((minus | plus).?.with1 ~ unsigned_dec_int).string - .map(s => s.replaceAll("_", "").replaceAll("\\+", "")) - -// integer = dec-int / hex-int / oct-int / bin-int -val integer: P[TomlInteger] = (hex_int | oct_int | bin_int | dec_int) - .map { s => - val i = s.toLong - if i == 0L then TomlInteger("0") - else TomlInteger(s) - } - -// zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT ) -val zero_prefixable_int: P[(Char, Any)] = DIGIT ~ (DIGIT | (underscore *> DIGIT)).rep0 - -// -// decimal-point = %x2E ; . -val decimal_point: P[Unit] = P.char('.') - -// ;; Boolean -// false = %x66.61.6C.73.65 ; false -// true = %x74.72.75.65 ; true -// boolean = true / false -val boolean: P[TomlBoolean] = P.string("true").as(TomlBoolean("true")) | P.string("false").as(TomlBoolean("false")) - -// ;; Date and Time (as defined in RFC 3339) -// -//date-fullyear = 4DIGIT -val date_fullyear = DIGIT.rep(4, 4) - -//date-month = 2DIGIT ; 01-12 -val date_month = DIGIT.rep(2, 2).string.flatMap { s => - val i = s.toInt - if i >= 1 && i <= 12 then P.pure(s) - else P.Fail -} - -//date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year -val date_mday = DIGIT.rep(2, 2).string.flatMap { s => - val i = s.toInt - if i >= 1 && i <= 31 then P.pure(s) - else P.Fail -} - -//time-delim = "T" / %x20 ; T, t, or space -val time_delim = P.ignoreCaseCharIn("T ") - -//time-hour = 2DIGIT ; 00-23 -val time_hour: P[String] = DIGIT.rep(2, 2).string.flatMap { s => - val i = s.toInt - - if i >= 0 && i <= 23 then P.pure(s) - else P.Fail -} - -//time-minute = 2DIGIT ; 00-59 -val time_minute: P[String] = (P.charIn('0' to '5') ~ DIGIT).string.flatMap { s => - val i = s.toInt - - if (i >= 0 && i < 60) P.pure(s) - else P.fail -} - -//time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules -val time_second: P[String] = DIGIT.rep(2, 2).string.flatMap { s => - val i = s.toInt - if i >= 0 && i <= 59 then P.pure(s) - else P.Fail -} - -//time-secfrac = "." 1*DIGIT -val time_secfrac: P[String] = P.char('.') *> DIGIT.rep.string.map(_.padTo(3, '0')) - -//time-numoffset = ( "+" / "-" ) time-hour ":" time-minute -val time_numoffset: P[String] = (P.charIn("+-") ~ time_hour ~ P.char(':') ~ time_minute).string - -//time-offset = "Z" / time-numoffset -val time_offset: P[String] = P.ignoreCaseCharIn('Z').as("Z") | time_numoffset - -// -//partial-time = time-hour ":" time-minute ":" time-second [ time-secfrac ] -val partial_time: P[String] = - ((time_hour <* P.char(':')) - ~ time_minute - ~ (P.char(':') *> (time_second ~ time_secfrac.?)).?) - .map { case ((hour, minute), maybeSec) => - val seconds: String = - maybeSec match { - case Some((sec, Some(secFrac))) => sec + "." + secFrac - case Some((sec, None)) => sec - case None => "00" - } - - hour + ":" + minute + ":" + seconds - } - -//full-date = date-fullyear "-" date-month "-" date-mday -val full_date = date_fullyear ~ P.char('-') ~ date_month ~ P.char('-') ~ date_mday - -//full-time = partial-time time-offset -val full_time: P[String] = (partial_time ~ time_offset).map { case (partial, offset) => partial + offset } - -//;; Offset Date-Time -// -//offset-date-time = full-date time-delim full-time -val offset_date_time: P[TomlDateTime] = ((full_date.string <* time_delim) ~ full_time).map { case (date, time) => - TomlDateTime(s"${date}T${time}") -} -// -//;; Local Date-Time -// -//local-date-time = full-date time-delim partial-time -val local_date_time: P[TomlDateTimeLocal] = ((full_date.string <* time_delim) ~ partial_time).map { case (date, time) => - TomlDateTimeLocal(s"${date}T$time") -} - -//;; Local Date -// -//local-date = full-date -val local_date: P[TomlDateLocal] = full_date.string.map(TomlDateLocal.apply) -// -//;; Local Time -// -//local-time = partial-time -val local_time: P[TomlTimeLocal] = partial_time.map(TomlTimeLocal.apply) - -//date-time = offset-date-time / local-date-time / local-date / local-time -val date_time = - offset_date_time.backtrack | local_date_time.backtrack | local_date.backtrack | local_time - -// ;; Key-Value pairs -// val = string / boolean / array / inline-table / date-time / float / integer -val value: P[TomlVal] = boolean | date_time.backtrack | integer - -// keyval-sep = ws %x3D ws ; = -val keyval_sep: P[Unit] = (ws.with1 ~ P.char('=') ~ ws).void - -// dot-sep = ws %x2E ws ; . Period -// -// dotted-key = simple-key 1*( dot-sep simple-key ) -// quoted-key = basic-string / literal-string -// unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ -val unquoted_key: P[String] = (ALPHA | DIGIT | minus | underscore).rep.string - -// simple-key = quoted-key / unquoted-key -val simple_key: P[String] = unquoted_key - -// key = simple-key / dotted-key -val key: P[String] = simple_key - -// keyval = key keyval-sep val -val keyval: P[TomlKeyVal] = (key ~ (keyval_sep *> value)) - .map((key, value) => TomlKeyVal(key, value)) - -// expression = ws [ comment ] -// expression =/ ws keyval ws [ comment ] -// expression =/ ws table ws [ comment ] -val expression: P[TomlKeyVal] = - ws.with1 *> keyval - -// toml = expression *( newline expression ) -val toml: Parser0[TomlDocument] = { - val emptyline: P[Unit] = ((ws ~ comment.?).with1 ~ newline).void - val expressions: P[NonEmptyList[TomlKeyVal]] = expression.repSep(emptyline.rep) - - (emptyline.rep0 *> expressions <* emptyline.rep0) - .map(es => TomlDocument(es.toList)) -} +// skal være val +def toml: Parser0[TomlDocument] = ???