Domanda

the following works just fine for what I'm trying to do, but it's obviously very repetitive. It should match the following examples:

  • #id.class1.class2 attr="asdsa"
  • .class1.class2 attr="asdsad"
  • attr="asds"

It's tempting to use

id:idShortcut? classes:classShortcut* attrs:fullAttribute* 

But I don't want it to match if all three components are absent. How do I specify a rule of 3 optional components, but at least one must be present?

attributes = id:idShortcut classes:classShortcut* attrs:fullAttribute* 
{ 
  var ret = [['id', id]];
  for(var i = 0; i < classes.length; ++i ) {
    ret.push(['class', classes[i]]);
  }

  for(var i = 0; i < attrs.length; ++i ) {
    ret.push(attrs[i]);
  }

  return ret;
}
/ classes:classShortcut+ attrs:fullAttribute* { 

  // TODO: how to dry this with the above?

  var ret = [];
  for(var i = 0; i < classes.length; ++i ) {
    ret.push(['class', classes[i]]);
  }

  for(var i = 0; i < attrs.length; ++i ) {
    ret.push(attrs[i]);
  }

  return ret;
}
/ attrs:fullAttribute+ { 
  var ret = [];
  for(var i = 0; i < attrs.length; ++i ) {
    ret.push(attrs[i]);
  }
  return ret;
}
È stato utile?

Soluzione 2

OK, not sure why this was even a struggle for me, but this refactored nicely as follows (and could probably be improved beyond that:

attributes 
  = a:( attributesAtLeastID
    / attributesAtLeastClass
    / attributesAtFullAttr ) 
{
  var id = a[0];
  var classes = a[1];
  var attrs = a[2];
  var ret = [];

  if(id) { ret.push(['id', id]); }

  for(var i = 0; i < classes.length; ++i ) {
    ret.push(['class', classes[i]]);
  }

  for(var i = 0; i < attrs.length; ++i ) {
    ret.push(attrs[i]);
  }
}

attributesAtLeastID = id:idShortcut classes:classShortcut* attrs:fullAttribute* { return [id, classes, attrs]; }
attributesAtLeastClass = classes:classShortcut+ attrs:fullAttribute* { return [null, classes, attrs]; }
attributesAtFullAttr = attrs:fullAttribute+ { return [null, [], attrs]; }

Altri suggerimenti

This is what And predicates are useful for

Attributes only matches if either id is not undefined, or classes is not an empty array, or attrs is not an empty array.

attributes = 
    id:idShortcut? classes:classShortcut* attrs:fullAttribute* &{return id !== undefined || classes.length > 0 || attrs.length > 0;} 
    {
        var ret = [];
        if (id) {
            ret.push(['id', id]);
        }
        for (var x=0; x < classes.length;x++) {
            ret.push(['class', classes[x]);
        }
        for (var y=0; y < attrs.length;y++) {
            ret.push([attrs[y]);
        }
        return ret;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top