From: Bjoern H. <der...@gm...> - 2003-07-27 03:34:50
|
Hi Robin, I wrote a hackerish parser for the property value definitions used in the CSS and SVG specifications. For example for the font property in CSS 2.1 [ [ <'font-style'> || <'font-variant'> || <'font-weight'> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'> ] | caption | icon | menu | message-box | small-caption | status-bar | inherit which would parse to a hash reference like (XML::Simple::XMLout rootname => 'val'): <val typ="Disjunction" min="1" max="1"> <val typ="Sequence" min="1" max="1"> <val typ="Conjunction" min="0" max="1"> <val min="1" val="<'font-style'>" max="1" /> <val min="1" val="<'font-variant'>" max="1" /> <val min="1" val="<'font-weight'>" max="1" /> </val> <val min="1" val="<'font-size'>" max="1" /> <val typ="Sequence" min="0" max="1"> <val min="1" val="/" max="1" /> <val min="1" val="<'line-height'>" max="1" /> </val> <val min="1" val="<'font-family'>" max="1" /> </val> <val min="1" val="caption" max="1" /> <val min="1" val="icon" max="1" /> <val min="1" val="menu" max="1" /> <val min="1" val="message-box" max="1" /> <val min="1" val="small-caption" max="1" /> <val min="1" val="status-bar" max="1" /> <val min="1" val="inherit" max="1" /> </val> This enables a secondary module with more knowledge of properties to resolve this definition to <val typ="Disjunction" min="1" max="1"> <val typ="Sequence" min="1" max="1"> <val typ="Conjunction" min="0" max="1"> <val typ="Disjunction" min="1" max="1"> <val min="1" val="normal" max="1" /> <val min="1" val="italic" max="1" /> <val min="1" val="oblique" max="1" /> </val> <val typ="Disjunction" min="1" max="1"> <val min="1" val="normal" max="1" /> <val min="1" val="small-caps" max="1" /> </val> <val typ="Disjunction" min="1" max="1"> <val min="1" val="normal" max="1" /> <val min="1" val="bold" max="1" /> <val min="1" val="bolder" max="1" /> <val min="1" val="lighter" max="1" /> <val min="1" val="100" max="1" /> <val min="1" val="200" max="1" /> <val min="1" val="300" max="1" /> <val min="1" val="400" max="1" /> <val min="1" val="500" max="1" /> <val min="1" val="600" max="1" /> <val min="1" val="700" max="1" /> <val min="1" val="800" max="1" /> <val min="1" val="900" max="1" /> </val> </val> <val typ="Disjunction" min="1" max="1"> <val min="1" val="xx-small" max="1" /> <val min="1" val="x-small" max="1" /> <val min="1" val="small" max="1" /> <val min="1" val="medium" max="1" /> <val min="1" val="large" max="1" /> <val min="1" val="x-large" max="1" /> <val min="1" val="xx-large" max="1" /> <val min="1" val="larger" max="1" /> <val min="1" val="smaller" max="1" /> <val min="1" val="<length>" max="1" /> <val min="1" val="<percentage>" max="1" /> </val> <val typ="Sequence" min="0" max="1"> <val min="1" val="/" max="1" /> <val typ="Disjunction" min="1" max="1"> <val min="1" val="normal" max="1" /> <val min="1" val="<integer>" max="1" /> <val min="1" val="<real>" max="1" /> <val min="1" val="<length>" max="1" /> <val min="1" val="<percentage>" max="1" /> </val> </val> <val typ="Disjunction" min="1" max="1"> <val typ="Sequence" min="1" max="1"> <val typ="Disjunction" min="1" max="1"> <val min="1" val="<identifier>" max="-1" /> <val min="1" val="<string>" max="1" /> <val min="1" val="serif" max="1" /> <val min="1" val="sans-serif" max="1" /> <val min="1" val="cursive" max="1" /> <val min="1" val="fantasy" max="1" /> <val min="1" val="monospace" max="1" /> </val> <val typ="Disjunction" min="0" max="-1"> <val typ="Sequence" min="1" max="1"> <val min="1" val="," max="1" /> <val typ="Disjunction" min="1" max="1"> <val min="1" val="<identifier>" max="-1" /> <val min="1" val="<string>" max="1" /> </val> </val> <val min="1" val="serif" max="1" /> <val min="1" val="sans-serif" max="1" /> <val min="1" val="cursive" max="1" /> <val min="1" val="fantasy" max="1" /> <val min="1" val="monospace" max="1" /> </val> </val> </val> </val> <val min="1" val="caption" max="1" /> <val min="1" val="icon" max="1" /> <val min="1" val="menu" max="1" /> <val min="1" val="message-box" max="1" /> <val min="1" val="small-caption" max="1" /> <val min="1" val="status-bar" max="1" /> <val min="1" val="inherit" max="1" /> </val> (Yes, font is complex :-) (Note that <length> is not yet expanded. That's however probably mandatory if there are differences between CSS/SVG versions, profiles, etc.) I wrote a module that performs this operation but it is not an alpha yet. There are also issues with the value definitions, for example 'font-size' does not allow negative values while 'left' does but both refer only to <length> in their definitions. The final goal is to write a CSS::Validator module that takes such a syntax tree and validates the LexicalValueList provided by CSS::SAC for a property against it. That's quite easy as the values are supposed to represent single LexicalUnits and all a validator has to do would be to check $lu->is_type(INTEGER) for example. What I've got so far is able to tell you a > b + c ~ d e { font: inherit; -- valid font: invalid; -- invalid font: normal small-caps 3em/3 Verdana, sans-serif; -- valid color: red; -- valid unknown: foo; -- unknown } The major benefit of this approach is that the validator can easily be extended for new or custom profiles without writing any code. Users would for example be able to write a profile for a specific browser and have a SAC filter that excludes all unsupported properties or for a validator that warns about their use. Or they could validate proprietary extensions like the -moz-* or mso-* properties. That much about long term goals... For the parser, could you suggest a name? I've called it My::CSS::ValueDefParser but I am sure there is room for improvement. It should also make sense when used in combination with a module that resolves the property references like <'font-size'> and macros like <absolute-length> with more knowledge of a given CSS profile. May I add it to the CVS repository? Anything to note about the best location for it or anything else? As I've said, it's quite hackerish and slow (based on Parse::RecDescent by the way) but it does what it is supposed to. PS: Any progress wrt Sourceforge CVS access? If not, it would be nice to have what you got so far, it could then commit it to CVS. regards. |