Permalink
Browse files

work in progress on rule definition syntax

  • Loading branch information...
dwarring committed Jul 18, 2016
1 parent 3131045 commit 83849de26862dfa59e5424d9b88c6234a48ea918
View
@@ -1,3 +1,12 @@
0.4.0
- Added rule declarations.
It's now possible to define rules for sharing between properties. For example
<voice-family> := male | female | child
- Choices are now left-associative
for example: 'font-family' [ <generic-family> | <family-name> ]#
will resolve as a generic-family in preference to a family name
0.3.2 Starting adding property checks:
- If a property has edges, there should be exactly four
- All children of an edge property, should also be edges
View
@@ -1,6 +1,6 @@
{ "perl" : "6.c",
"name" : "CSS::Specification",
"version" : "0.3.2",
"version" : "0.4.0",
"description" : "CSS Property definition grammar and tools",
"depends" : [ "CSS::Grammar" ],
"source-url" : "git://github.com/p6-css/perl6-CSS-Specification.git",
View
@@ -17,7 +17,9 @@
'speak-punctuation' code | none | inherit none yes aural
'speech-rate' <number> | x-slow | slow | medium | fast | x-fast | faster | slower | inherit medium yes aural
'stress' <number> | inherit 50 yes aural
'voice-family' [<specific-voice> | <generic-voice> ]# | inherit depends on user agent yes aural
'voice-family' [<generic-voice> | <specific-voice> ]# | inherit depends on user agent yes aural
<generic-voice> := male | female | child
<specific-voice> := <identifier> | <string>
'volume' <number> | <percentage> | silent | x-soft | soft | medium | loud | x-loud | inherit medium yes refer to inherited value aural
# snick in a non-aural 'boxed' property
'border-color' [ <color> | transparent ]{1,4} | inherit see individual properties no visual
View
@@ -7,7 +7,7 @@
use CSS::Grammar::CSS3;
grammar CSS::Specification:ver<000.04> {
rule TOP { <property-spec> * }
rule TOP { [<def=.property-spec> | <def=.rule-spec>] * }
rule property-spec {
:my @*PROP-NAMES = [];
@@ -17,6 +17,9 @@ grammar CSS::Specification:ver<000.04> {
[ \t <-[ \t ]>*? # applies to
\t [<inherit=.yes>|<inherit=.no>]? ]?
}
rule rule-spec {
\t? <rule> ':=' <spec>
}
rule spec { :my $*CHOICE; <terms> }
# possibly tab delimited. Assume one spec per line.
token ws {<!ww>' '*}
@@ -36,6 +39,7 @@ grammar CSS::Specification:ver<000.04> {
token id-quoted { <.quote> <id> <.quote> }
rule keyw { <id> }
rule digits { \d+ }
rule rule { '<'~'>' <id> }
rule terms { <term=.term-options>+ }
rule term-options { <term=.term-combo> +% '|' }
@@ -59,7 +63,7 @@ grammar CSS::Specification:ver<000.04> {
rule value:sym<keyw-quant> { <keyw><occurs> }
rule value:sym<num-quant> { <digits><occurs> }
rule value:sym<group> { '[' ~ ']' <terms> }
rule value:sym<rule> { '<'~'>' <id> }
rule value:sym<rule> { <rule> }
rule value:sym<op> { < , / = > }
rule value:sym<prop-ref> { <property-ref> }
@@ -6,15 +6,14 @@ class CSS::Specification::Actions {
# rules or actions.
has %.prop-refs is rw;
has %.props is rw;
has %.rules is rw;
has %.child-props is rw;
method TOP($/) { make $<property-spec>>>.ast };
# condensation eg: 'border-top-style' ... 'border-left-style'
# ==> pfx='border' props=<top right bottom left> sfx='-style'
method TOP($/) { make $<def>>>.ast };
method property-spec($/) {
my @props = @($<prop-names>.ast);
%.props{$_}++ for @props;
my $spec = $<spec>.ast;
@@ -32,6 +31,20 @@ class CSS::Specification::Actions {
make %prop-def;
}
method rule-spec($/) {
my $rule = $<rule>.ast,
my $perl6 = $<spec>.ast;
my $synopsis = ~$<spec>;
%.props{$rule}++;
my %rule-def = (
:$rule, :$synopsis, :$perl6
);
make %rule-def;
}
method yes($/) { make True }
method no($/) { make False }
@@ -45,14 +58,14 @@ class CSS::Specification::Actions {
method prop-names($/) {
my @prop-names = $<id>>>.ast;
%.props{$_}++ for @prop-names;
make @prop-names;
}
method id($/) { make ~$/ }
method id-quoted($/) { make $<id>.ast }
method keyw($/) { make $<id>.subst(/\-/, '\-'):g }
method digits($/) { make $/.Int }
method rule($/) { make $<id>.ast }
method terms($/) {
make @<term>>>.ast.join(' ');
@@ -62,7 +75,7 @@ class CSS::Specification::Actions {
my @choices = @<term>>>.ast;
make @choices > 1
?? [~] '[ ', @choices.join(' | '), ' ]'
?? [~] '[ ', @choices.join(' || '), ' ]'
!! @choices[0];
}
@@ -151,7 +164,7 @@ class CSS::Specification::Actions {
}
method value:sym<rule>($/) {
my $val = ~$<id>.ast;
my $val = ~$<rule>.ast;
%.prop-refs{ $val }++;
make [~] '<', $val, '>'
}
@@ -12,7 +12,7 @@ module CSS::Specification::Build {
multi sub generate('grammar', Str $grammar-name, Str :$input-path?) {
my $actions = CSS::Specification::Actions.new;
my @defs = load-props($input-path, $actions);
my @defs = load-defs($input-path, $actions);
say "use v6;";
say "# -- DO NOT EDIT --";
@@ -29,7 +29,7 @@ module CSS::Specification::Build {
multi sub generate('actions', Str $class-name, Str :$input-path?) {
my $actions = CSS::Specification::Actions.new;
my @defs = load-props($input-path, $actions);
my @defs = load-defs($input-path, $actions);
say "use v6;";
say "# -- DO NOT EDIT --";
@@ -47,7 +47,7 @@ module CSS::Specification::Build {
multi sub generate('interface', Str $role-name, Str :$input-path?) {
my $actions = CSS::Specification::Actions.new;
my @defs = load-props($input-path, $actions);
my @defs = load-defs($input-path, $actions);
say "use v6;";
say "# -- DO NOT EDIT --";
@@ -56,8 +56,9 @@ module CSS::Specification::Build {
say "role {$role-name} \{";
my %prop-refs = $actions.prop-refs;
my %prop-names = $actions.props;
generate-perl6-interface(@defs, %prop-refs, %prop-names);
my %props = $actions.props;
my %rules = $actions.rules;
generate-perl6-interface(@defs, %prop-refs, %props, %rules);
say '}';
}
@@ -120,29 +121,29 @@ module CSS::Specification::Build {
our sub summary(Str :$input-path? ) {
my $actions = CSS::Specification::Actions.new;
my @defs = load-props($input-path, $actions);
my @defs = load-defs($input-path, $actions);
my @summary;
my %properties;
for @defs -> $def {
my @props = @( $def<props> );
my $perl6 = $def<perl6>;
my $synopsis = $def<synopsis>;
my $box = $perl6 ~~ / '**1..4' $/;
with $def<props> -> @props {
my $perl6 = $def<perl6>;
my $synopsis = $def<synopsis>;
my $box = $perl6 ~~ / '**1..4' $/;
for @props -> $name {
my %details = :$name, :$synopsis;
%details<default> = $_
with $def<default>;
%details<inherit> = $_
with $def<inherit>;
%details<box> = True
if $box;
%properties{$name} = %details;
@summary.push: %details;
for @props -> $name {
my %details = :$name, :$synopsis;
%details<default> = $_
with $def<default>;
%details<inherit> = $_
with $def<inherit>;
%details<box> = True
if $box;
%properties{$name} = %details;
@summary.push: %details;
}
}
}
find-edges(%properties, $actions.child-props);
@@ -151,55 +152,63 @@ module CSS::Specification::Build {
return @summary;
}
sub load-props ($properties-spec, $actions?) {
sub load-defs ($properties-spec, $actions?) {
my $fh = $properties-spec
?? open $properties-spec, :r
!! $*IN;
my @props;
my @defs;
for $fh.lines -> $prop-spec {
# handle full line comments
next if $prop-spec ~~ /^'#'/ || $prop-spec eq '';
# '| inherit' and '| initial' are implied anyway; get rid of them
my $spec = $prop-spec.subst(/\s* '|' \s* [inherit|initial]/, ''):g;
my $/ = CSS::Specification.subparse($spec, :rule('property-spec'), :actions($actions) );
my $/ = CSS::Specification.subparse($spec, :actions($actions) );
die "unable to parse: $spec"
unless $/;
my $prop-defn = $/.ast;
@props.push: $prop-defn;
my $defs = $/.ast;
@defs.append: @$defs;
}
return @props;
return @defs;
}
sub generate-perl6-rules(@defs) {
for @defs -> $def {
my @props = @( $def<props> );
my $perl6 = $def<perl6>;
my $synopsis = $def<synopsis>;
# boxed repeating property. repeat the expr
my $box = $perl6 ~~ / '**1..4' $/
?? ', :box'
!! '';
my $repeats = '';
if $box {
$perl6 ~~ s/ '**1..4' $//;
$repeats = '**1..4';
}
with $def<props> -> @props {
my $perl6 = $def<perl6>;
my $synopsis = $def<synopsis>;
# boxed repeating property. repeat the expr
my $box = $perl6 ~~ / '**1..4' $/
?? ', :box'
!! '';
my $repeats = '';
if $box {
$perl6 ~~ s/ '**1..4' $//;
$repeats = '**1..4';
}
for @props -> $prop {
my $match = $prop.subst(/\-/, '\-'):g;
for @props -> $prop {
my $match = $prop.subst(/\-/, '\-'):g;
say "";
say " #| $prop: $synopsis";
say " rule decl:sym<{$prop}> \{:i ($match) ':' <val( rx\{ <expr=.expr-{$prop}>$repeats \}, &?ROUTINE.WHY)> \}";
say " rule expr-$prop \{:i $perl6 \}";
}
}
else {
my $rule = $def<rule>;
my $perl6 = $def<perl6>;
my $synopsis = $def<synopsis>;
say "";
say " #| $prop: $synopsis";
say " rule decl:sym<{$prop}> \{:i ($match) ':' <val( rx\{ <expr=.expr-{$prop}>$repeats \}, &?ROUTINE.WHY)> \}";
say " rule expr-$prop \{:i $perl6 \}";
say " #| $rule: $synopsis";
say " rule $rule \{:i $perl6 \}";
}
}
}
@@ -208,23 +217,30 @@ module CSS::Specification::Build {
for @defs -> $def {
my @props = @( $def<props> );
my $synopsis = $def<synopsis>;
for @props -> $prop {
with $def<props> -> @props {
for @props -> $prop {
say " method expr-{$prop}(\$/) \{ make \$.list(\$/) \}"
if %references{'expr-' ~ $prop}:exists;
say " method expr-{$prop}(\$/) \{ make \$.list(\$/) \}"
if %references{'expr-' ~ $prop}:exists;
}
}
else {
my $rule = $def<rule>;
say " method $rule\(\$/\) \{ make \$.node(\$/).pairs[0] \}"
}
}
}
#= generate an interface class for all unresolved terms.
sub generate-perl6-interface(@defs, %references, %prop-names) {
sub generate-perl6-interface(@defs, %references, %prop-names, %rule-names) {
my %unresolved = %references;
%unresolved{'expr-' ~ $_}:delete
for %prop-names.keys;
%unresolved{$_}:delete
for %rule-names.keys;
for %unresolved.keys.sort -> $sym {
say " method {$sym}(\$/) \{ ... \}";
View
@@ -14,10 +14,10 @@ for (
ast => '[ thin & <keyw> ]?',
},
'spec' => {input => '35 | 7 | 42?',
ast => '[ [ 35 | 7 ] & <number> | [ 42 & <number> ]? ]',
ast => '[ [ 35 | 7 ] & <number> || [ 42 & <number> ]? ]',
},
'spec' => {input => "<rule-ref> [, [ 'css21-prop-ref' | <'css3-prop-ref'> ] ]*",
ast => "<rule-ref> [ <op(',')> [ [ <expr-css21-prop-ref> | <expr-css3-prop-ref> ] ] ]*",
ast => "<rule-ref> [ <op(',')> [ [ <expr-css21-prop-ref> || <expr-css3-prop-ref> ] ] ]*",
},
'spec' => {input => '<length>{4}',
ast => '<length>**4',
@@ -35,7 +35,7 @@ for (
'property-spec' => {input => "'content'\tnormal | none | [ <string> | <uri> | <counter> | attr(<identifier>) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit normal :before and :after pseudo-elements no",
ast => {:props['content'],
:default<normal>,
:perl6('[ [ normal | none ] & <keyw> | [ [ <string> | <uri> | <counter> | <attr> | [ open\\-quote | close\\-quote | no\\-open\\-quote | no\\-close\\-quote ] & <keyw> ] ]+ | inherit & <keyw> ]'),
:perl6('[ [ normal | none ] & <keyw> || [ [ <string> || <uri> || <counter> || <attr> || [ open\\-quote | close\\-quote | no\\-open\\-quote | no\\-close\\-quote ] & <keyw> ] ]+ || inherit & <keyw> ]'),
:synopsis('normal | none | [ <string> | <uri> | <counter> | attr(<identifier>) | open-quote | close-quote | no-open-quote | no-close-quote ]+ | inherit'),
:inherit(False),
},
View
@@ -11,7 +11,4 @@ class CSS::Aural::Actions
does CSS::Aural::Spec::Interface {
method proforma:sym<inherit>($/) { make {'keyw' => ~$<sym>} }
method generic-voice($/) { make $<keyw>.ast }
method specific-voice($/) { make $<voice>.ast }
}
View
@@ -11,8 +11,4 @@ grammar CSS::Aural::Grammar
does CSS::Aural::Spec::Interface {
rule proforma:sym<inherit> { <sym> }
rule expr-voice-family {:i [ [ <generic-voice> || <specific-voice> ] ] +% ',' }
rule generic-voice {:i [ male | female | child ] & <keyw> }
rule specific-voice {:i <voice=.identifier> | <voice=.string> }
}
@@ -5,4 +5,6 @@ use v6;
class CSS::Aural::Spec::Actions {
method expr-cue-after($/) { make $.list($/) }
method expr-cue-before($/) { make $.list($/) }
method generic-voice($/) { make $.node($/).pairs[0] }
method specific-voice($/) { make $.node($/).pairs[0] }
}
Oops, something went wrong.

0 comments on commit 83849de

Please sign in to comment.