@@ -45,6 +45,17 @@ object Lexicon {
4545
4646 implicit def astNodeToSem (node : ParseNode ): Sem = Form (node)
4747
48+ /** Type checks that the given Seq has only elements of the expected case class (using .getClass()).
49+ * Sadly necessary because of type erasure ...
50+ * The .getClass().toString() approach requires an exact class name match, so this will only work for case classes, not traits.
51+ * TODO(AN): Come up with a more general approach that would work for inherited traits as well? */
52+ def validatingSeq [T , U ](seq : Seq [T ], expectedClassName : String )(out : U ): U = {
53+ if (! seq.forall(_.getClass().toString() == " class wordbots.Semantics$" + expectedClassName)) {
54+ Fail (s " Seq parameter failed type check " )
55+ }
56+ out
57+ }
58+
4859 val lexicon : ParserDict [CcgCat ] = ParserDict [CcgCat ]() +
4960 (Seq (" a" , " an" ) -> Seq (
5061 (N / N , identity),
@@ -331,15 +342,15 @@ object Lexicon {
331342 (" gain" .s -> Seq ( // "[All robots] gain ..."
332343 ((S \ NP )/ NP , λ {aa : AttributeAmount => λ {t : TargetObject => ModifyAttribute (t, aa.attr, Plus (aa.amount))}}), // " ... X attack"
333344 ((S / N )\ NP , λ {t : TargetObject => λ {attrs : Seq [AttributeAmount ] => // "... X attack and Y speed"
334- MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Plus (a.amount))))}}),
345+ validatingSeq(attrs, " AttributeAmount " ) { MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Plus (a.amount))))} }}),
335346 ((S / NP )\ NP , λ {p : TargetPlayer => λ {e : Energy => ModifyEnergy (p, Plus (e.amount))}}), // Y gains X energy.
336347 (((S \ NP )/ N )/ Num , λ {num : Number => λ {a : Attribute => λ {t : TargetObject => ModifyAttribute (t, a, Plus (num))}}}) // Y gains X (attribute).
337348 )) +
338349 (" get" .s -> (((S / N )/ Num )\ NP , λ {t : TargetObject => λ {i : Scalar => λ {a : Attribute => SetAttribute (t, a, i)}}})) + // "All robots get X attack"))
339350 ((" get" .s ++ " gain" .s) -> Seq ( // "[All robots] get/gain ..."
340351 ((S / NP )\ NP , λ {t : TargetObject => λ {op : AttributeOperation => ModifyAttribute (t, op.attr, op.op)}}), // "... +X attack"
341352 ((S / NP )\ NP , λ {t : TargetObject => λ {ops : Seq [AttributeOperation ] => // "... +X attack and +Y speed"
342- MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))}}),
353+ validatingSeq(ops, " AttributeOperation " ) { MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))} }}),
343354 ((S / S )\ NP , λ {t : TargetObject => λ {a : Ability => GiveAbility (t, a)}}), // "... [ability]"
344355 ((S / S )\ NP , λ {t : TargetObject => λ {a : (AttributeOperation , Ability ) => // "... +X attack and [ability]"
345356 MultipleActions (Seq (SaveTarget (t), ModifyAttribute (SavedTargetObject , a._1.attr, a._1.op), GiveAbility (SavedTargetObject , a._2)))}}),
@@ -352,9 +363,9 @@ object Lexicon {
352363 (((S / PP )/ N )/ Num , λ {i : Scalar => λ {a : Attribute => λ {t : TargetObject => ModifyAttribute (t, a, Plus (i))}}}), // "Give X attack [to a robot]"
353364 (((S / PP )/ N )/ Adj , λ {o : Operation => λ {a : Attribute => λ {t : TargetObject => ModifyAttribute (t, a, o)}}}), // "Give +X attack [to a robot]"
354365 ((S / N )/ NP , λ {t : TargetObject => λ {attrs : Seq [AttributeAmount ] => // "... X attack and Y speed"
355- MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Plus (a.amount))))}}),
366+ validatingSeq(attrs, " AttributeAmount " ) { MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Plus (a.amount))))} }}),
356367 ((S / NP )/ NP , λ {t : TargetObject => λ {ops : Seq [AttributeOperation ] => // "... +X attack and +Y speed"
357- MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))}}),
368+ validatingSeq(ops, " AttributeOperation " ) { MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))} }}),
358369 ((S / S )/ NP , λ {t : TargetObject => λ {a : Ability => GiveAbility (t, a)}}), // "... [ability]"
359370 ((S / S )/ NP , λ {t : TargetObject => λ {a : (AttributeOperation , Ability ) => // "... +X attack and [ability]"
360371 MultipleActions (Seq (SaveTarget (t), ModifyAttribute (SavedTargetObject , a._1.attr, a._1.op), GiveAbility (SavedTargetObject , a._2)))}})
@@ -378,7 +389,7 @@ object Lexicon {
378389 )) +
379390 (Seq (" has" , " have" ) -> Seq (
380391 (S / NP , λ {ac : AttributeComparison => ac}),
381- (S / NP , λ {cs : Seq [AttributeComparison ] => cs }), // multiple conditions
392+ (S / NP , λ {cs : Seq [AttributeComparison ] => validatingSeq(cs, " AttributeComparison " ) { cs } }), // multiple conditions
382393 ((S \ NP )/ S , λ {a : Ability => λ {t : TargetObject => HasAbility (t, a)}}),
383394 ((S \ NP )/ N , λ {a : AttributeAmount => λ {t : TargetObject => AttributeAdjustment (t, a.attr, Constant (a.amount))}}), // "... X attack"
384395 ((S / NP )\ NP , λ {t : TargetObject => λ {op : AttributeOperation => AttributeAdjustment (t, op.attr, op.op)}}), // "... +X attack"
@@ -434,7 +445,7 @@ object Lexicon {
434445 ((S / NP )\ NP , λ {p : TargetPlayer => λ {e : Energy => ModifyEnergy (p, Minus (e.amount))}}), // Y loses X energy.
435446 ((S \ NP )/ NP , λ {aa : AttributeAmount => λ {t : TargetObject => ModifyAttribute (t, aa.attr, Minus (aa.amount))}}), // " ... X attack"
436447 ((S / N )\ NP , λ {t : TargetObject => λ {attrs : Seq [AttributeAmount ] => // "... X attack and Y speed"
437- MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Minus (a.amount))))}}),
448+ validatingSeq(attrs, " AttributeAmount " ) { MultipleActions (Seq (SaveTarget (t)) ++ attrs.map(a => ModifyAttribute (SavedTargetObject , a.attr, Minus (a.amount))))} }}),
438449 (((S \ NP )/ N )/ Num , λ {num : Number => λ {a : Attribute => λ {t : TargetObject => ModifyAttribute (t, a, Minus (num))}}}) // Y loses X (attribute).
439450 )) +
440451 (" more" -> Seq (
@@ -476,7 +487,8 @@ object Lexicon {
476487 ((" object" .s :+ " objects '" ) -> (N , AllObjects : Sem )) +
477488 (" odd" -> (NP / N , λ {attr : Attribute => AttributeComparison (attr, IsOdd )})) +
478489 (" of" -> Seq (
479- ((S / NP )\ V , λ {ops : Seq [AttributeOperation ] => λ {t : TargetObject => MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))}}),
490+ ((S / NP )\ V , λ {ops : Seq [AttributeOperation ] => λ {t : TargetObject =>
491+ validatingSeq(ops, " AttributeOperation" ) { MultipleActions (Seq (SaveTarget (t)) ++ ops.map(op => ModifyAttribute (SavedTargetObject , op.attr, op.op)))}}}),
480492 ((NP / NP )\ Num , λ {num : Number => λ {o : ObjectCollection => ChooseO (o, num)}}) // e.g. "X of your opponent's robots"
481493 )) +
482494 (" other" -> Seq (
@@ -517,7 +529,7 @@ object Lexicon {
517529 (" remove all abilities" -> (S / PP , λ {t : TargetObject => RemoveAllAbilities (t)})) +
518530 (" replace" -> Seq (
519531 ((S / PP )/ NP , λ {r : TextReplacement => λ {t : TargetCard => RewriteText (t, Map (r.from.text -> r.to.text))}}),
520- ((S / PP )/ NP , λ {rs : Seq [TextReplacement ] => λ {t : TargetCard => RewriteText (t, rs.map(r => (r.from.text -> r.to.text)).toMap)}})
532+ ((S / PP )/ NP , λ {rs : Seq [TextReplacement ] => λ {t : TargetCard => validatingSeq(rs, " TextReplacement " ) { RewriteText (t, rs.map(r => (r.from.text -> r.to.text)).toMap)} }})
521533 )) +
522534 (" restore" -> Seq (
523535 ((S / PP )/ N , λ {a : Attribute => λ {t : TargetObjectOrPlayer => RestoreAttribute (t, a, None )}}), // e.g. "Restore health to X"
@@ -541,7 +553,7 @@ object Lexicon {
541553 (NP / PP , λ {d : DiscardPile => CardsInDiscardPile (d.player, Robot )}),
542554 ((NP / PP )/ Adj , λ {condition : CardCondition => λ {hand : Hand => CardsInHand (hand.player, Robot , Seq (condition))}}),
543555 ((NP / PP )/ Adj , λ {condition : CardCondition => λ {d : DiscardPile => CardsInDiscardPile (d.player, Robot , Seq (condition))}}),
544- (NP \ Adj , λ {attrs : Seq [AttributeAmount ] => GeneratedCard (Robot , attrs)}) // e.g. "a 3/1/2 robot"
556+ (NP \ Adj , λ {attrs : Seq [AttributeAmount ] => validatingSeq(attrs, " AttributeAmount " ) { GeneratedCard (Robot , attrs)} }) // e.g. "a 3/1/2 robot"
545557 )) +
546558 (" robot on the board" -> (N , Robot : Sem )) + // e.g. "If you control a robot on the board with 3 or more health, ..."
547559 (" rounded down" -> (Adv , RoundedDown : Sem )) +
@@ -651,11 +663,11 @@ object Lexicon {
651663 ((" win" .s ++ Seq (" win the game" , " wins the game" )) -> ((S \ NP , λ {p : TargetPlayer => WinGame (p)}))) +
652664 (" with" -> Seq ( // "with" = "that" + "has"
653665 (Adj / NP , identity),
654- (ReverseConj , λ {a : ParseNode => λ {b : ParseNode => Seq (a, b)}}),
666+ (ReverseConj , λ {a : ParseNode => λ {b : ParseNode => Seq (a, b)}}), // i.e. "[Swap the positions of] a robot WITH your kernel"
655667 ((NP \ N )/ NP , λ {s : AttributeComparison => λ {o : ObjectType => ObjectsMatchingConditions (o, Seq (s))}}),
656- ((NP \ N )/ NP , λ {s : Seq [AttributeComparison ] => λ {o : ObjectType => ObjectsMatchingConditions (o, s) }}),
668+ ((NP \ N )/ NP , λ {cs : Seq [AttributeComparison ] => λ {o : ObjectType => validatingSeq(cs, " AttributeComparison " ) { ObjectsMatchingConditions (o, cs) } }}),
657669 ((NP \ N )/ N , λ {attr : AttributeAmount => λ { o : ObjectType => GeneratedCard (o, Seq (attr))}}), // (generated card with 1 attribute, useful only for structures)
658- ((NP \ N )/ N , λ {attrs : Seq [AttributeAmount ] => λ {o : ObjectType => GeneratedCard (o, attrs)}}),
670+ ((NP \ N )/ N , λ {attrs : Seq [AttributeAmount ] => λ {o : ObjectType => validatingSeq(attrs, " AttributeAmount " ) { GeneratedCard (o, attrs)} }}),
659671 ((NP \ S )/ S , λ {toText : Text => λ {fromText : Text => TextReplacement (fromText, toText)}}) // i.e. "Replace \"<from>\" with \"<to>\" on ..."
660672 )) +
661673 (" within" -> Seq (
0 commit comments