Three-object parsing and 'collapsing' two actions into one

So as far as I understand it, normal i7 parsing is limited to verbs with a direct object and an indirect object.

I’m currently working on a game with an Obra Dinn-style investigation mechanic; this game has two custom commands for the player to record their conjectures (I’m making up fake examples here as I don’t want to talk about the actual game’s actual story yet):

  • CONCLUDE Captain Alvarez disappeared in Segovia
  • CONCLUDE Captain Alvarez disappeared in 1846

These are two distinct actions, called ‘murder-weapon-assigning it to’ and ‘murder-location’-assigning it to’.

However, I think you can see where this is going; players will expect to be able to do CONCLUDE Captain Alvarez disappeared in 1846 in Segovia. I’m aware of an old solution to third-object parsing, but I wonder if there’s a simpler way to achieve this, or if there’s particular pitfalls I should be aware of when messing around with the additional grammar tokens. I also don’t really understand i6 or the i6 standard library, so I’d love to have a pure i7 way to address this.

Also, as you can tell, in this case the action doesn’t apply purely to things – it uses numbers and a custom value type (the person is an actual person and not text understood as a topic, which would be a different way to implement this kind of play). So there’s that complication there.

Unfortunately this sort of parsing is something Inform (both 6 and 7) fundamentally doesn’t like. The parser machinery is built from its very foundations around the assumption that there are at most two parameters to any action, and I7 additionally assumes that at most one of those parameters is a non-object (numbers, kinds of value, etc).

This means the only pure-I7 way to address this is in “after reading a command” rules, which I heartily recommend against, because the result will be very fragile and prone to malfunctioning. Bringing in a bit of I6 can do it all right, though—in fact, parsing an extra non-object value can be done a lot more elegantly than parsing an extra object!

The only hard part is getting hold of the routine name of the GPR for a custom non-object value, which I know sounds like nonsense but will hopefully bring the other I6-in-I7 hackers out of the woodwork to help. @otistdog @Zed ?

(The goal would be to replicate the “third noun” code linked above but calling a different kov’s parsing routine; like in that case, the result will be stashed in a global, then transferred to an action variable.)

A thought I’m having, would it be possible to create a custom (complicated) grammar token that can act as two values in one ‘indirect object’? So that the third command is then phrased as CONCLUDE [any person] DISAPPEARED IN [demise-description], where demise-description matches the general form of [a number] in [a location] and produces one value/reference that can be passed to the action (this third action then is just carried out by trying the two distinct actions).

1 Like

@Draconis is correct in his general assessment, however, in your case there might be a workaround which can be done in “a pure I7 way.” It’s either ugly or elegant – take your pick. It would also mean instructing the player to a non-standard syntax.

If you are willing to allow this:

>Captain Alvarez, disappeared in 1846 in Segovia

as your command syntax, then you should be able to get it to work.

Below is a partial implementation to see if that’s a road you want to go down. It takes advantage of the fact that every action actually already has three nouns, if you include the actor. Since one of your extra nouns is a person, I’ve leveraged that. Essentially, the command parses as asking a person to try assigning the murder details, which then get stored in properties of that person (although you can store that info however you like). As of now it only deals with the cases of when both items are assigned, but as you can see from the report rule, I put in allowances for when one piece of data isn’t. I initially tried to make that work using rules for supplying missing noun/second noun, but ran into a hiccup. You might need separate actions for those. Also, in this implementation, the accused have to be in the room with you. That means you’d have to deal with scoping issues as well going forward, but that shouldn’t be difficult. Take a look and see what you think.

Lab is a room. 

A murder-place is a kind of thing. Undefined, Segovia, and Orlando are murder-places.
A person has a murder-place. 
A person has a number called the murder-number.

Limbo is a room. Al, Sam, and Joe are people in the Lab [Limbo].

Murder-data-assigning it to is an action applying to one visible thing and one number.
Persuasion rule while asking someone to try murder-data-assigning something to: rule succeeds.

Understand "disappeared in [any murder-place] in [a number]" as murder-data-assigning it to.
Understand "disappeared in [a number] in [any murder-place]" as murder-data-assigning it to (with nouns reversed).
[Understand "disappeared in [any murder-place]" as murder-data-assigning it to.]
[Understand "disappeared in [a number]" as murder-data-assigning it to.]

[Rule for supplying a missing second noun while someone trying murder-data-assigning something to:
	now the number understood is 0.]	

Check Murder-data-assigning it to (this is the can't investigate self rule):
	if the actor is the player:
		say "[We] [are] not here to investigate [ourselves].".
		
Carry out someone murder-data-assigning something to:
	now the murder-place of the actor is the noun;
	now the murder-number of the actor is the number understood.
	
Report someone murder-data-assigning something to:
	say "Conclusion: [The actor] disappeared [if the murder-place of the actor is not undefined]in [murder-place of the actor][end if][if the murder-number of the actor is not 0] in [murder-number of the actor][end if].".
	
test me with "disappeared in orlando in 1970 / al, disappeared in segovia in 1846 /  Sam, disappeared in 1980 in Orlando / Joe, disappeared in Segovia in 2025".

Edit: every action doesn’t have three nouns, just the “two-noun” ones – if you include the actor.

4 Likes

Hmm… if that works, could you maybe use After reading a command to insert a comma in certain circumstances?

Draconis covered the way that the I7 compiler can’t handle the idea of a three-parameter action. It turns a blind eye to I6-implemented GPR tokens, which is why the third noun workaround that Sequitur cited can function.

My only thought for a pure I7 approach is along the lines of what Sequitur already proposed: hardcoding parameters into grammar lines. That sounds worse to me than accepting some I6 GPR tokens into the mix, especially if there are different kinds of conclusion domains, since that would imply that “disappearance” is essentially a fourth parameter. Will the approach outlined by Sequitur even work? I thought that the I7 compiler won’t accept multi-parameter topics, either.

I outlined something for rileypb to use once that might be helpful here. See Parsing multiples of a kind - #10 by otistdog for a pattern that doesn’t require much understanding of I6 to use for making GPRs specific to various kinds.

EDIT: @Sequitur, the main pitfall to worry about is that a standard I7 token to parse any enumerated kind of value tends to overwrite the last one, e.g. parsing [number] will overwrite a previously-parsed [color understood]. All of the [<KOV> understood] substitutions point to the same underlying global variable. (Unless that’s something that has been changed for 10?)

How many different things might go in the disappeared slot ?

In this case this is a fixed part of the command that can’t change. The parts that vary are the year (1846 in the example) and the location (Segovia).

This basically works. But it uses something worse than I6.

regular expressions.

 

A disappearance-location is a kind of value.
Segovia is a disappearance-location.

when-concluding it in is an action applying to one visible thing and one number.
understand "conclude that/-- [any person] disappeared in [number]" as when-concluding it in.

where-concluding it in is an action applying to one visible things and one disappearance-location.
understand "conclude that/-- [any person] disappeared in [any disappearance-location]" as where-concluding it in.

carry out when-concluding: say "[Noun] disappeared in [number understood]!".

carry out where-concluding: say "[Noun] disappeared in [disappearance-location understood]!".

disappearance-year is a number that varies.

after where-concluding when disappearance-year is not zero:
  try when-concluding the noun in disappearance-year.

after reading a command:
  let pc be the substituted form of ("[the player's command]" in lower case);
  let remainder be "";
  if pc matches the regular expression "(.+?)(,|\.|\s+then\s+)(.*)" begin;
    now pc is text matching subexpression 1;
    now remainder is substituted form of "[text matching subexpression 2][text matching subexpression 3]";
  end if;
  if pc matches the regular expression "conclude\s+(that\s+)?(<^,\.>+?)\s+disappeared\s+in\s+(<^,\.>+?)\s+in(<^,\.>+)" begin;
    let the subject be the text matching subexpression 2;
    let d1 be the text matching subexpression 3;
    let d2 be the text matching subexpression 4;
    if d1 matches the regular expression "^\d+$" begin;
      change the text of the player's command to d1;
      if the player's command matches "[number]", now disappearance-year is the number understood;
      now d1 is d2;
    else if d2 matches the regular expression "^\d+$" begin;
      change the text of the player's command to d2;
      if the player's command matches "[number]", now disappearance-year is the number understood;
    end if;
    change the text of the player's command to "conclude [subject] disappeared in [d1] [remainder]";
  else;
    now disappearance-year is zero;
  end if;

Lab is a room.
Captain Alvarez is a person.

test me with "conclude captain alvarez disappeared in segovia /
conclude captain alvarez disappeared in 1846 /
conclude captain alvarez disappeared in 1846 in segovia /
conclude captain alvarez disappeared in segovia in 1846".

I put some effort into ensuring it would still work with multiple commands on one line, but with only very limited success. Things will work if there are additional commands after conclude [...] but not if conclude follows other commands.

Getting keyboard input is the reading a command activity’s fallback when no for reading a command rule applies (the situation by default). So no matter how many commands a user may enter, the after reading a command rulebook is followed just the once, immediately after input is entered. If the parser finds multiple commands, whatever’s beyond the first command gets stowed while it deals with the first command, but when it goes back to consider the remainder, it tackles them raw, without any post-processing by after a command.

(Also, I hope there aren’t going to be any people or disappearance-locations whose names include “then”.)

“Before processing a command” can handle this part, at least.

I couldn’t resist running with this. I threw dealing with multiple commands under the bus. And disappearance-location is unavoidably a kind of thing.

Lab is a room.
Captain Alvarez is a person.

test me with "conclude captain alvarez disappeared in segovia /
conclude captain alvarez disappeared in 1846 /
conclude captain alvarez disappeared in 1846 in segovia /
conclude captain alvarez disappeared in segovia in 1846".

A disappearance-location is a kind of thing.
Segovia is a disappearance-location.

when-concluding it in is an action applying to one visible thing and one number.
understand "conclude that/-- [any person] disappeared in [number]" as when-concluding it in.

where-concluding it in is an action applying to two visible things.
understand "conclude that/-- [any person] disappeared in [any disappearance-location]" as where-concluding it in.

carry out when-concluding: say "[Noun] disappeared in [number understood]!".

carry out where-concluding: say "[Noun] disappeared in [Second noun]!".

multi-concluding it in is an action applying to one visible thing and one number.
understand "multiconc [any disappearance-location] in [number]" as multi-concluding it in.
understand "multiconc [number] in [any disappearance-location]" as multi-concluding it in (with nouns reversed).

carry out someone multi-concluding: say "[The person asked] disappeared in [the noun] in [the number understood]!"

after reading a command:
  let pc be the substituted form of ("[the player's command]" in lower case);
  if pc matches the regular expression "conclude\s+(that\s+)?(<^,\.>+?)\s+disappeared\s+in\s+(<^,\.>+?)\s+in(<^,\.>+)" begin;
    let the subject be the text matching subexpression 2;
    let d1 be the text matching subexpression 3;
    let d2 be the text matching subexpression 4;
    change the text of the player's command to "[subject], multiconc [d1] in [d2]";
  end if;

After deciding the scope of the player when the player's command includes "multiconc":
  repeat with p running through people begin;
    place p in scope;
  end repeat;

Persuasion for asking someone to try multi-concluding: rule succeeds.

In short, conclude captain alvarez disappeared in segovia in 1846 gets rewritten as captain alvarez, multiconc segovia in 1846 where multiconc corresponds to an action expected to be carried out by someone who isn’t the player.

I love the lack of fuss regarding the order of the place and year I could get away with here: the grammar does it all!

understand "multiconc [any disappearance-location] in [number]" as multi-concluding it in.
understand "multiconc [number] in [any disappearance-location]" as multi-concluding it in (with nouns reversed).
1 Like