diff --git a/core/src/main/scala-3/Parser.scala b/core/src/main/scala-3/Parser.scala index ae0dbec..7b2ed60 100644 --- a/core/src/main/scala-3/Parser.scala +++ b/core/src/main/scala-3/Parser.scala @@ -74,32 +74,22 @@ object Parser { a } - def optionlessSeq[A](option: Option[Seq[A]]): Seq[A] = option match { - case None => Seq[A]() - case Some(x) => x - } - - /** Higher-order optional parser. - * - * Takes a parser p, and parses it optionally, defaulting the parsed value to - * the passed default. - * - * @todo: - * Figure out dark implicit magic to figure out magically that the default - * is "T()". - * - * @tparam T - * The optionally parsed type. - * @param p - * The parser to use optionally - * @param default - * The default value to use if the parser fails. - * @return - * A parser optionally parsing p, defaulting to default. - */ - inline def Optional[$: P, T](p: => P[T], default: T): P[T] = P( - p.?.map(_.getOrElse(default)) - ) + extension [T](inline p: P[T]) + + /** Make the parser optional, parsing defaults if otherwise failing. + * + * @todo: + * Figure out dark implicit magic to figure out magically that the + * default default is "T()". + * + * @param default + * The default value to use if the parser fails. + * @return + * An optional parser, defaulting to default. + */ + inline def orElse[$: P](default: T): P[T] = P( + p.?.map(_.getOrElse(default)) + ) /*≡==--==≡≡≡==--=≡≡*\ || SCOPE || @@ -374,7 +364,7 @@ object Parser { def FloatLiteral[$: P] = P( CharIn("\\-\\+").? ~~ (Digit.repX(1) ~~ "." ~~ Digit.repX(1)).! ~~ (CharIn("eE") - ~~ (CharIn("\\-\\+").? ~~ Digit.repX(1)).!).?.map(_.getOrElse("0")) + ~~ (CharIn("\\-\\+").? ~~ Digit.repX(1)).!).orElse("0") ).map(parseFloatNum(_)) // substituted [0-9]* with [0-9]+ def notExcluded[$: P] = P( @@ -713,9 +703,7 @@ class Parser(val context: MLContext, val args: Args = Args()) P(OperationPat.rep(at_least_this_many).map(_.to(ListType))) def OperationPat[$: P]: P[Operation] = P( - OpResultList.?./.map( - optionlessSeq - ).flatMap(Op(_)) ~/ TrailingLocation.? + OpResultList.orElse(Seq()).flatMap(Op(_)) ~/ TrailingLocation.? ) def Op[$: P](resNames: Seq[String]) = P( @@ -732,11 +720,11 @@ class Parser(val context: MLContext, val args: Args = Args()) }) def GenericOperation[$: P](resNames: Seq[String]) = P( - StringLiteral ~/ "(" ~ ValueUseList.?.map(optionlessSeq) ~ ")" - ~/ SuccessorList.?.map(optionlessSeq) - ~/ Optional(DictionaryProperties, DictType.empty) - ~/ RegionList.?.map(optionlessSeq) - ~/ Optional(DictionaryAttribute, DictType.empty) ~/ ":" ~/ FunctionType + StringLiteral ~/ "(" ~ ValueUseList.orElse(Seq()) ~ ")" + ~/ SuccessorList.orElse(Seq()) + ~/ DictionaryProperties.orElse(DictType.empty) + ~/ RegionList.orElse(Seq()) + ~/ (DictionaryAttribute).orElse(DictType.empty) ~/ ":" ~/ FunctionType ).map( ( ( @@ -802,7 +790,7 @@ class Parser(val context: MLContext, val args: Args = Args()) P(BlockLabel ~ Operations(0)).map(createBlock) def BlockLabel[$: P] = P( - BlockId ~ BlockArgList.?.map(optionlessSeq) ~ ":" + BlockId ~ BlockArgList.orElse(Seq()) ~ ":" ) /*≡==--==≡≡≡≡≡==--=≡≡*\ @@ -874,10 +862,10 @@ class Parser(val context: MLContext, val args: Args = Args()) def ValueIdAndType[$: P] = P(ValueId ~ ":" ~ Type) def ValueIdAndTypeList[$: P] = - P(ValueIdAndType.rep(sep = ",")) + P(ValueIdAndType.rep(sep = ",")).orElse(Seq()) def BlockArgList[$: P] = - P("(" ~ ValueIdAndTypeList.? ~ ")").map(optionlessSeq) + P("(" ~ ValueIdAndTypeList ~ ")") // [x] dictionary-properties ::= `<` dictionary-attribute `>` // [x] dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}` @@ -910,7 +898,7 @@ class Parser(val context: MLContext, val args: Args = Args()) * present. */ inline def OptionalProperties[$: P]() = - Optional(DictionaryProperties, DictType.empty) + (DictionaryProperties).orElse(DictType.empty) /** Parses an optional attributes dictionary from the input. * @@ -919,7 +907,7 @@ class Parser(val context: MLContext, val args: Args = Args()) * present. */ inline def OptionalAttributes[$: P] = - Optional(DictionaryAttribute, DictType.empty) + (DictionaryAttribute).orElse(DictType.empty) /** Parses an optional attributes dictionary from the input, preceded by the * `attributes` keyword. @@ -928,7 +916,7 @@ class Parser(val context: MLContext, val args: Args = Args()) * An optional dictionary of attributes - empty if no keyword is present. */ inline def OptionalKeywordAttributes[$: P] = - Optional("attributes" ~ DictionaryAttribute, DictType.empty) + ("attributes" ~ DictionaryAttribute).orElse(DictType.empty) /*≡==--==≡≡≡≡==--=≡≡*\ || PARSE FUNCTION || diff --git a/core/src/main/scala-3/builtin/AttrParser.scala b/core/src/main/scala-3/builtin/AttrParser.scala index 5d1f80c..527cca8 100644 --- a/core/src/main/scala-3/builtin/AttrParser.scala +++ b/core/src/main/scala-3/builtin/AttrParser.scala @@ -184,14 +184,13 @@ class AttrParser(val ctx: MLContext) { // dense-array-attribute ::= `array` `<` (integer-type | float-type) (`:` tensor-literal)? `>` def DenseArrayAttributeP[$: P]: P[DenseArrayAttr] = P( - "array<" ~ (((IntegerTypeP) ~ (":" ~ IntDataP.rep(sep = ",")).?.map( - _.getOrElse(Seq()) + "array<" ~ (((IntegerTypeP) ~ (":" ~ IntDataP.rep(sep = ",")).orElse( + Seq() )).map((typ: IntegerType, x: Seq[IntData]) => DenseArrayAttr(typ, x.map(IntegerAttr(_, typ))) - ) | ((FloatTypeP) ~ (":" ~ FloatDataP.rep(sep = ",")).?.map( - _.getOrElse(Seq()) - )).map((typ: FloatType, x: Seq[FloatData]) => - DenseArrayAttr(typ, x.map(FloatAttr(_, typ))) + ) | ((FloatTypeP) ~ (":" ~ FloatDataP.rep(sep = ",")).orElse(Seq())).map( + (typ: FloatType, x: Seq[FloatData]) => + DenseArrayAttr(typ, x.map(FloatAttr(_, typ))) )) ~ ">" ) diff --git a/dialects/src/main/scala-3/lingodb/RelAlgOps.scala b/dialects/src/main/scala-3/lingodb/RelAlgOps.scala index 03c2f36..fba46c0 100644 --- a/dialects/src/main/scala-3/lingodb/RelAlgOps.scala +++ b/dialects/src/main/scala-3/lingodb/RelAlgOps.scala @@ -8,7 +8,7 @@ import scair.Parser import scair.Parser.BareId import scair.Parser.E import scair.Parser.ValueId -import scair.Parser.optionlessSeq +import scair.Parser.orElse import scair.Parser.whitespace import scair.dialects.LingoDB.SubOperatorOps.* import scair.dialects.LingoDB.TupleStream.* @@ -136,13 +136,13 @@ case class SortSpecificationAttr( private def DialectRegion[$: P](parser: Parser) = P( E({ parser.enterLocalRegion }) - ~ (parser.BlockArgList.?.map(optionlessSeq).map( - (x: Seq[(String, Attribute)]) => { + ~ (parser.BlockArgList + .orElse(Seq()) + .map((x: Seq[(String, Attribute)]) => { val b = new Block(ListType.empty, ListType.from(x.map(_._2))) parser.currentScope.defineValues(x.map(_._1) zip b.arguments) b - } - ) + }) ~ "{" ~ parser.Operations(1) ~ "}").map((b: Block, y: ListType[Operation]) => { b.operations ++= y @@ -244,8 +244,8 @@ object SelectionOp extends OperationObject { override def parse[$: P]( parser: Parser ): P[Operation] = P( - ValueId ~ DialectRegion(parser) - ~ "attributes" ~ parser.OptionalAttributes + ValueId ~ DialectRegion(parser) ~ + parser.OptionalKeywordAttributes ) .map( ( @@ -325,10 +325,7 @@ object MapOp extends OperationObject { ~ "computes" ~ ":" ~ "[" ~ ColumnDefAttr.parse(parser).rep.map(ArrayAttribute(_)) ~ "]" ~ DialectRegion(parser) - ~ Parser.Optional( - "attributes" ~ parser.DictionaryAttribute, - DictType.empty - ) + ~ parser.OptionalKeywordAttributes ).map( ( x: String, @@ -430,10 +427,7 @@ object AggregationOp extends OperationObject { .rep(sep = ",") .map(ArrayAttribute(_)) ~ "]" ~ DialectRegion(parser) - ~ Parser.Optional( - "attributes" ~ parser.DictionaryAttribute, - DictType.empty - ) + ~ parser.OptionalKeywordAttributes ).map( ( x: String, diff --git a/dialects/src/main/scala-3/lingodb/TupleStream.scala b/dialects/src/main/scala-3/lingodb/TupleStream.scala index 56de6ca..0435007 100644 --- a/dialects/src/main/scala-3/lingodb/TupleStream.scala +++ b/dialects/src/main/scala-3/lingodb/TupleStream.scala @@ -4,6 +4,7 @@ import fastparse.* import scair.AttrParser import scair.Parser import scair.Parser.ValueId +import scair.Parser.orElse import scair.Parser.whitespace import scair.dialects.builtin.* import scair.ir.* @@ -142,7 +143,7 @@ object ReturnOp extends OperationObject { ): P[Operation] = P( parser.OptionalAttributes ~ (ValueId.rep(sep = ",") ~ ":" ~ - parser.Type.rep(sep = ",")).?.map(makeResults) + parser.Type.rep(sep = ",")).orElse((Seq(), Seq())) ).map((x: DictType[String, Attribute], y: (Seq[String], Seq[Attribute])) => parser.generateOperation( opName = name,