source: text-formbuilder/trunk/lib/Text/FormBuilder/grammar @ 74

Last change on this file since 74 was 74, checked in by peichman, 19 years ago

deprecated the !field directive
updated docs for generated code

File size: 7.2 KB
RevLine 
[66]1{
2    #$::RD_TRACE = 1;
[21]3    my (
4        $context,      # line or group
[29]5        @sections,     # master data structure
6        $section_head,
7        $section_id,
8        @lines,        # lines in each section
[21]9        $title,
10        $author,
11        $description,
12        %lists,
13        %patterns,
[39]14        %subs,         # validation subs
[21]15        @group,        # current group
16        %groups,       # stored groups of fields
17        $type,
18        @options,
[24]19        $required,
[21]20        $list_var,
21        $size,
[56]22        $maxlength,
[21]23        $rows,
24        $cols,
25    );
26    $context = 'line';
27}
[1]28
[50]29form_spec: (list_def | description_def | validate_def | group_def | note | line)(s)
[1]30    {
[29]31        # grab the last section, if there is any
32        if (@lines) {
33            push @sections,
34                {
35                    id   => $section_id,
36                    head => $section_head,
37                    lines => [ @lines ],
38                };
39        }
40       
41        $section_id = $item{identifier};
42        $section_head = $item[3];
43        @lines = ();
[1]44        $return = {
45            title    => $title,
46            author   => $author,
[14]47            description => $description,
[28]48            lists    => \%lists,
49            patterns => \%patterns,
[39]50            subs     => \%subs,
[28]51            groups   => \%groups,
[29]52            sections => \@sections,
[1]53        }
54    }
55
[16]56list_def: '!list' var_name (static_list | dynamic_list)
57    { $lists{$item{var_name}} = [ @options ]; @options = () }
[1]58
[66]59static_list: '{' /\s*/ option(s /\s*,\s*/) /,?/ /\s*/ '}'
[10]60
61dynamic_list: '&' <perl_codeblock>
62    {
[64]63        warn "[Text::FormBuilder] Dynamic lists have been removed from the formspec grammar";
[10]64    }
65
[57]66description_def: '!description' block
[64]67    {
68        warn "[Text::FormBuilder] Description redefined at input text line $thisline\n" if defined $description;
69        $description = $item{block};
[14]70    }
71
[39]72validate_def: '!validate' var_name <perl_codeblock>
[42]73    { $subs{$item{var_name}} = eval "sub $item[3]" }
[39]74
[21]75group_def: '!group' { $context = 'group' } var_name '{' field_line(s) '}' { $context = 'line' }
76    {
77        #warn "$item{var_name} group; context $context\n"
78        $groups{$item{var_name}} = [ @group ];
79        @group = ();
80    }
[1]81
[64]82note: '!note' block  { push @lines, [ 'note', $item{block} ]; }
[50]83
[64]84
85#TODO: allow \ escape for [] {} in these blocks
86
[57]87# curly-brace delimited block, that can contain properly
[64]88# nested curly braces, along with any other characters
89# inner blocks return with the '{...}' so that nested
90# blocks get the braces treated as literals
91block: '{' <skip:''> block_content(s) '}' { join('', @{ $item[3] }) }
92inner_block: '{' <skip:''> block_content(s) '}'  { '{' . join('', @{ $item[3] }) . '}' }
93block_content: /[^\{\}]+?/ | inner_block
[50]94
[64]95# square brace delimited block, that can contain properly
96# nested square brackets, along with any other characters
97# inner bracket blocks return with the '[...]' so that nested
98# blocks get the braces treated as literals
99bracket_block: '[' <skip:''> bracket_block_content(s) ']' { join('', @{ $item[3] }) }
100inner_bracket_block: '[' <skip:''> bracket_block_content(s) ']' { '[' . join('', @{ $item[3] }) . ']'; }
101bracket_block_content: /[^\[\]]+?/ | inner_bracket_block
[57]102
103
[64]104# field lines are the subset of lines that are allowed in a !group directive
[21]105field_line: <skip:'[ \t]*'> ( field | comment | blank ) "\n"
[64]106
[63]107line: <skip:'[ \t]*'> ( title | author | pattern_def | section_head | heading | group_field | field_group | unknown_directive | field | comment | blank ) "\n"
[21]108
[1]109title: '!title' /.*/
[28]110    {
[57]111        warn "[Text::FormBuilder] Title redefined at input text line $thisline\n" if defined $title;
[28]112        $title = $item[2];
113    }
[1]114
115author: '!author' /.*/
[28]116    {
[57]117        warn "[Text::FormBuilder] Author redefined at input text line $thisline\n" if defined $author;
[28]118        $author = $item[2];
119    }
[1]120
[16]121pattern_def: '!pattern' var_name pattern
122    { $patterns{$item{var_name}} = $item{pattern} }
[1]123
124pattern: /.*/
125
[29]126section_head: '!section' identifier /.*/
127    {
128        #warn "starting section $item{identifier}\n";
129        #warn "  with heading $item[3]\n" if $item[3];
130       
131        if (@lines) {
132            push @sections,
133                {
134                    id   => $section_id,
135                    head => $section_head,
136                    lines => [ @lines ],
137                };
138        }
139       
140        $section_id = $item{identifier};
141        $section_head = $item[3];
142        @lines = ();
143    }
144
[28]145heading: '!head' /.*/    { push @lines, [ 'head', $item[2] ] }
[11]146
[21]147group_field: '!field' group_name name label(?)
[74]148    {
149        warn "[Text::FormBuilder] The !field directive has been DEPRECATED (input file line $thisline). Please use the name:GROUP style";
[28]150        push @lines, [ 'group', { name => $item{name}, label => $item{'label(?)'}[0], group => $item{group_name} } ];
[21]151    }
152
153group_name: /%[A-Z_]+/
154
[73]155field_group: name label(?) hint(?) group_type comment(?)
156    {
[74]157        #warn "[$thisline] comment = $item{'hint(?)'}[0]\n" if $item{'hint(?)'}[0];
[63]158        #warn "[$thisline] field $item{name} is $item{group_type}\n";
[73]159        push @lines, [ 'group', {
160            name    => $item{name},
161            label   => $item{'label(?)'}[0],
162            comment => $item{'hint(?)'}[0],
163            group   => $item{group_type},
164        } ];
[63]165    }
166
167group_type: ':' var_name
168
[64]169# this is the real heart of the thing
[66]170field: name field_size(?) growable(?) label(?) hint(?) type(?) other(?) default(?) option_list(?) validate(?) comment(?)
[1]171    {
172        my $field = {
173            name     => $item{name},
[66]174            growable => $item{'growable(?)'}[0],
[1]175            label    => $item{'label(?)'}[0],
176            comment  => $item{'hint(?)'}[0],
177            type     => $item{'type(?)'}[0],
[66]178            other    => $item{'other(?)'}[0],
[1]179            value    => $item{'default(?)'}[0],
[63]180            list     => $list_var,
181            validate => $item{'validate(?)'}[0],
[68]182            required => $required,
[1]183        };
184       
185        $$field{options} = [ @options ] if @options;
186       
187        $$field{rows} = $rows if defined $rows;
188        $$field{cols} = $cols if defined $cols;
189        $$field{size} = $size if defined $size;
[56]190        $$field{maxlength} = $maxlength if defined $maxlength;
[1]191       
[28]192        #warn "[$thisline] field $item{name}; context $context\n";
[21]193        if ($context eq 'group') {
194            push @group, $field;
195        } else {
196            push @lines, [ 'field', $field ];
197        }
[1]198       
199        $type = undef;
[68]200        $required = undef;
[1]201        $list_var = undef;
202        $size = undef;
203        $rows = undef;
204        $cols = undef;
[56]205        $maxlength = undef;
[1]206        @options = ();
[63]207       
[62]208        $field;
[1]209    }
210   
211name: identifier
212
[16]213var_name: /[A-Z_]+/
214
[1]215field_size: '[' ( row_col | size ) ']'
216
[56]217size: /\d+/ bang(?)
218    { $maxlength = $item[1] if $item[2][0]; $size = $item[1] }
[1]219
[56]220bang: '!'
221
[1]222row_col: /\d+/ /,\s*/ /\d+/
223    { $rows = $item[1]; $cols = $item[3] }
224
[66]225growable: '*' limit(?) { $item{'limit(?)'}[0] || 1 }
[61]226
[66]227limit: /\d+/
228
[22]229label: '|' (simple_multiword | quoted_string) { $item[2] }
[1]230
[64]231hint: bracket_block
[1]232
[63]233type: ':' builtin_field
[1]234
[55]235builtin_field: /textarea|text|password|file|checkbox|radio|select|hidden|static/
236
[66]237other: '+' 'other' { 1 }
[55]238
[22]239default: '=' (simple_multiword | quoted_string) { $item[2] }
[1]240
[22]241# for simple multiword values not involving punctuation
[68]242simple_multiword: <skip:''> /\w[\w\t ]*/ { $item[2] }
[22]243
244# my attempt at a single-quoted, non-interpolating string
245# where the backslash can escape literal single quotes
246quoted_string: <skip:''> "'" /(\\'|[^'])*/ "'"
247    { $item[3] =~ s/\\'/'/g; $item[3] }
248
[1]249option_list: options | list_var
250   
[66]251options: '{' option(s /,/) '}'
[1]252
253list_var: /@[A-Z_]+/ { $list_var = $item[1] }
254
[66]255option: (simple_multiword | quoted_string) display_text(?)
[23]256    { push @options, { $item[1] => $item{'display_text(?)'}[0] } }
[1]257
258value: identifier
259
[64]260display_text: bracket_block
[1]261
[59]262
[64]263validate: '//' (optional_pattern | required_pattern)
[59]264
[64]265optional_pattern: var_name '?'  { $required = 0; $item[1] }
[1]266
[64]267required_pattern: var_name { $required = 1; $item[1] }
[24]268
[1]269comment: '#' /.*/
270blank:
271
272identifier: /\w+/
[16]273
274# skip unknown directives with a warning
275unknown_directive: /\!\S*/ /.*/
276    { warn "[Text::Formbuilder] Skipping unknown directive '$item[1]' at input text line $thisline\n"; }
Note: See TracBrowser for help on using the repository browser.