Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decide whether Affix Table feature is included in V1 #16

Open
maetl opened this issue Oct 4, 2022 · 1 comment
Open

Decide whether Affix Table feature is included in V1 #16

maetl opened this issue Oct 4, 2022 · 1 comment

Comments

@maetl
Copy link
Contributor

maetl commented Oct 4, 2022

This algorithm was implemented thanks to support from RubyNZ. It is an incredibly powerful feature for string rewriting and can reduce large amounts of boilerplate and complexity in grammars if used coherently, but the tradeoff is that it is a lot more difficult to understand than some of the other core features, and there are potentially logic edge cases to deal with.

The technical concept of the feature is to add new syntax that allows higher order application of a rewrite rule to the output of a standard grammar production. The rewrite rules are encoded in an affix table which can also use wildcard patterns to match on any string, but only in an affix position (so not implementing a full regular language). Affix tables can be bidirectional, so lookups/rewrites from key to value can be done from left to right or from right to left.

Test specification showing how this works atomically:

  describe 'wildcard match' do
    let(:affix_table) do
      Calyx::Production::AffixTable.parse({
        "%y" => "%ies",
        "%s" => "%ses",
        "%" => "%s"
      }, registry)
    end

    specify 'lookup from key to value' do
      expect(affix_table.value_for('ferry')).to eq('ferries')
      expect(affix_table.value_for('bus')).to eq('buses')
      expect(affix_table.value_for('car')).to eq('cars')
    end

    specify 'lookup from value to key' do
      expect(affix_table.key_for('ferries')).to eq('ferry')
      expect(affix_table.key_for('buses')).to eq('bus')
      expect(affix_table.key_for('cars')).to eq('car')
    end
  end

The proposed syntax for bidirectional lookups is to use the > and < characters to visually indicate the direction of mapping.

const grammar = calyx.grammar({
  "plural": "the plural of {vehicle} is {vehicle>countable}",
  "singular": "the singular of {vehicle} is {vehicle<countable}",
  "countable": {
      "%y": "%ies",
      "%s": "%ses",
      "%": "%s"
})

grammar.generate({start: "{singular}", vehicle: "train"})
grammar.generate({start: "{singular}", vehicle: "bus"})
grammar.generate({start: "{singular}", vehicle: "ferry"})

grammar.generate({start: "{plural}", vehicle: "trains"})
grammar.generate({start: "{plural}", vehicle: "buses"})
grammar.generate({start: "{plural}", vehicle: "ferries"})

This is pretty cool. But neither the string rewrite wildcard or the bidirectional mapping feels very intuitive.

@maetl
Copy link
Contributor Author

maetl commented Oct 5, 2022

Another syntax option is to use a single unary application operator with bidirectional mapping handled by flipping the lhs and rhs tokens.

Instead of:

vehicle>countable
vehicle<countable

Do this:

vehicle|countable
countable|vehicle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant