Index: trunk/lib/Text/FormBuilder/grammar
===================================================================
--- trunk/lib/Text/FormBuilder/grammar	(revision 97)
+++ trunk/lib/Text/FormBuilder/grammar	(revision 1)
@@ -1,212 +1,45 @@
-# line directives
-# block directives
-# field lines
-# comments
+{ my ($title, $author, %lists, %patterns, @fields, $type, @options, $list_var, $size, $rows, $cols); }
 
-{
-    #$::RD_TRACE = 1;
-    my (
-	@sections,     # master data structure
-	$section_head,
-	$section_id,
-	@lines,        # lines in each section
-	%lists,
-	%patterns,
-	%subs,         # validation subs
-	@group,        # current group
-	%groups,       # stored groups of fields
-	$type,
-	@options,
-	$required,
-	$multiple,
-	$list_var,
-	$size,
-	$maxlength,
-	$rows,
-	$cols,
-	@submit,
-    );
-    my $context = 'line';	# start in line context by default
-    my %formspec;
-    
-    # TODO: helper sub?
-    sub alert ($) {
-	warn '[' . (split(/::/, (caller(1))[3]))[-1] . '] ' . shift() . "\n";
-    }
-}
-
-form_spec:
+form_spec: (list_def | line)(s) 
     {
-	# clear out old data, so we don't end up with old data in new objects
-	@lines    = ();
-	@sections = ();
-	%formspec = ();
-    }
-    (list_def | description_def | group_def | note | fb_params | unknown_block_directive | line)(s)
-    {
-	# grab the last section, if there is any
-	if (@lines) {
-	    push @sections,
-		{
-		    id   => $section_id,
-		    head => $section_head,
-		    lines => [ @lines ],
-		};
-	}
-	
-	# make copies instead of taking references, again so we
-	# don't end up with connections between objects
 	$return = {
-	    fb_params   => $formspec{fb_params},
-	    title       => $formspec{title},
-	    author      => $formspec{author},
-	    description => $formspec{description},
-	    lists       => { %lists },
-	    patterns    => { %patterns },
-	    subs        => { %subs },
-	    groups      => { %groups },
-	    sections    => [ @sections ],
-	    ( @submit ? (submit => @submit == 1 ? $submit[0] : [ @submit ]) : () ),
-	    reset       => $formspec{reset},
+	    title    => $title,
+	    author   => $author,
+	    lists    => \%lists, 
+	    patterns => \%patterns, 
+	    fields   => \@fields,
 	}
     }
 
-list_def: '!list' var_name (static_list | dynamic_list)
-    { $lists{$item{var_name}} = [ @options ]; @options = () }
+list_def: '!list' list_name '{' option(s /,\s*/) /,?/ '}'
+    { $lists{$item{list_name}} = [ @options ]; @options = () }
 
-static_list: '{' /\s*/ option(s /\s*,\s*/) /,?/ /\s*/ '}'
+list_name: /[A-Z_]+/
 
-dynamic_list: '&' <perl_codeblock>
-    { warn "[Text::FormBuilder] Dynamic lists have been removed from the formspec grammar"; }
-
-description_def: '!description' block
-    {
-	warn "[Text::FormBuilder] Description redefined at input text line $thisline\n" if defined $formspec{description};
-	$formspec{description} = $item{block};
-    }
-
-group_def: '!group' { $context = 'group' } var_name '{' field_line(s) '}' { $context = 'line' }
-    { 
-	#warn "$item{var_name} group; context $context\n"
-	$groups{$item{var_name}} = [ @group ];
-	@group = ();
-    }
-
-note: '!note' block  { push @lines, [ 'note', $item{block} ]; }
-
-
-# curly-brace delimited block, that can contain properly
-# nested curly braces, along with any other characters
-# inner blocks return with the '{...}' so that nested
-# blocks get the braces treated as literals
-block: '{' <skip:''> block_content(s) '}' { join('', @{ $item[3] }) }
-inner_block: '{' <skip:''> block_content(s) '}'  { '{' . join('', @{ $item[3] }) . '}' }
-block_content: /[^\{\}]+?/ | inner_block
-
-# square brace delimited block, that can contain properly
-# nested square brackets, along with any other characters
-# inner bracket blocks return with the '[...]' so that nested
-# blocks get the braces treated as literals
-bracket_block: '[' <skip:''> bracket_block_content(s) ']' { join('', @{ $item[3] }) }
-inner_bracket_block: '[' <skip:''> bracket_block_content(s) ']' { '[' . join('', @{ $item[3] }) . ']'; }
-bracket_block_content: /[^\[\]]+?/ | inner_bracket_block
-
-
-# field lines are the subset of lines that are allowed in a !group directive
-field_line: <skip:'[ \t]*'> ( field | comment | blank ) "\n"
-
-line: <skip:'[ \t]*'> ( title | author | pattern_def | section_head | heading | submit | reset | group_field | field_group | unknown_directive | field | comment | blank ) /\n+/
+line: <skip:'[ \t]*'> ( title | author | pattern_def | field | comment | blank ) "\n"
 
 title: '!title' /.*/
-    {
-	warn "[Text::FormBuilder] Title redefined at input text line $thisline\n" if defined $formspec{title};
-	$formspec{title} = $item[2];
-    }
+    { warn "[Text::Formbuilder] Title redefined at input text line $thisline\n" if defined $title;
+    $title = $item[2] }
 
 author: '!author' /.*/
-    {
-	warn "[Text::FormBuilder] Author redefined at input text line $thisline\n" if defined $formspec{author};
-	$formspec{author} = $item[2];
-    }
+    { $author = $item[2] }
 
-pattern_def: '!pattern' var_name pattern
-    { $patterns{$item{var_name}} = $item{pattern} }
+pattern_def: '!pattern' pattern_name pattern
+    { $patterns{$item{pattern_name}} = $item{pattern} }
 
+pattern_name: /[A-Z_]+/
 pattern: /.*/
 
-section_head: '!section' identifier /.*/
+field: name field_size(?) label(?) hint(?) type(?) default(?) option_list(?) validate(?)
     {
-	#warn "starting section $item{identifier}\n";
-	#warn "  with heading $item[3]\n" if $item[3];
-	
-	if (@lines) {
-	    push @sections,
-		{
-		    id   => $section_id,
-		    head => $section_head,
-		    lines => [ @lines ],
-		};
-	}
-	
-	$section_id = $item{identifier};
-	$section_head = $item[3];
-	@lines = ();
-    }
-
-heading: '!head' /.*/    { push @lines, [ 'head', $item[2] ] }
-
-submit: '!submit' string(s /\s*,\s*/)
-    {
-	#warn scalar(@{ $item[2] }) . ' submit button(s)';
-	push @submit, @{ $item[2] };
-    }
-
-reset: '!reset' string
-    {
-	warn "[Text::FormBuilder] Reset button redefined at input text line $thisline\n" if defined $formspec{reset};
-	$formspec{reset} = $item{string};
-    }
-
-group_field: '!field' group_name name label(?)
-    {
-	warn "WARNING line $thisline: The '!field' directive has been DEPRECATED. Use the 'name:GROUP' style instead.\n";
-	push @lines, [ 'group', { name => $item{name}, label => $item{'label(?)'}[0], group => $item{group_name} } ];
-    }
-
-group_name: /%[A-Z_]+/
-
-# parameters that get passed to the FB constructor; these are serialized in YAML
-fb_params: '!fb' block
-    { $formspec{fb_params} .= $item{block}; }
-
-field_group: name label(?) hint(?) group_type comment(?)
-    {
-	#warn "[$thisline] comment = $item{'hint(?)'}[0]\n" if $item{'hint(?)'}[0];
-	#warn "[$thisline] field $item{name} is $item{group_type}\n";
-	push @lines, [ 'group', {
-	    name    => $item{name},
-	    label   => $item{'label(?)'}[0],
-	    comment => $item{'hint(?)'}[0],
-	    group   => $item{group_type},
-	} ];
-    }
-
-group_type: ':' var_name
-
-# this is the real heart of the thing
-field: name field_size(?) growable(?) label(?) hint(?) type(?) multi(?) other(?) default(?) option_list(?) validate(?) comment(?)
-    {	
 	my $field = {
 	    name     => $item{name},
-	    growable => $item{'growable(?)'}[0],
 	    label    => $item{'label(?)'}[0],
 	    comment  => $item{'hint(?)'}[0],
-	    multiple => $item{'multi(?)'}[0],
 	    type     => $item{'type(?)'}[0],
-	    other    => $item{'other(?)'}[0],
 	    value    => $item{'default(?)'}[0],
-	    list     => $list_var,
-	    validate => $item{'validate(?)'}[0],
-	    required => $required,
+            list     => $list_var,
+            validate => $item{'validate(?)'}[0],
 	};
 	
@@ -216,89 +49,48 @@
 	$$field{cols} = $cols if defined $cols;
 	$$field{size} = $size if defined $size;
-	$$field{maxlength} = $maxlength if defined $maxlength;
 	
-	#warn "[$thisline] field $item{name}; context $context\n";
-	if ($context eq 'group') {
-	    push @group, $field;
-	} else {
-	    push @lines, [ 'field', $field ];
-	}
+	push @fields, $field;
 	
 	$type = undef;
-	$required = undef;
-	$multiple = undef;
 	$list_var = undef;
 	$size = undef;
 	$rows = undef;
 	$cols = undef;
-	$maxlength = undef;
 	@options = ();
-	
-	#warn "$$field{name}: $field";
-	
-	$field;
+        
     }
     
 name: identifier
 
-var_name: /[A-Z_]+/
-
 field_size: '[' ( row_col | size ) ']'
 
-size: /\d+/ bang(?)
-    { $maxlength = $item[1] if $item[2][0]; $size = $item[1] }
-
-bang: '!'
+size: /\d+/
+    { $size = $item[1] }
 
 row_col: /\d+/ /,\s*/ /\d+/
     { $rows = $item[1]; $cols = $item[3] }
 
-growable: '*' limit(?) { $item{'limit(?)'}[0] || 1 }
+label: '|' /[^:\[\{\/]+/i
 
-limit: /\d+/
+hint: '[' /[^\]]+/ ']'    { $item[2] }
 
-label: '|' string { $item[2] }
+type: ':' /textarea|text|password|file|checkbox|radio|select|hidden|static/
 
-hint: bracket_block
-
-type: ':' builtin_field
-
-builtin_field: /textarea|text|password|file|checkbox|radio|select|hidden|static/
-
-multi: '*' { 1 }
-
-other: '+' 'other' { 1 }
-
-default: '=' string { $item[2] }
-
-string: simple_multiword | quoted_string
-
-# for simple multiword values not involving punctuation
-simple_multiword: /\w/ <skip:''> /[\w\t ]*/ { $item[1] . $item[3] }
-
-# my attempt at a single-quoted, non-interpolating string
-# where the backslash can escape literal single quotes
-quoted_string: "'" <skip:''> /(\\'|[^'])*/ "'"
-    { $item[3] =~ s/\\'/'/g; $item[3] }
+default: '=' /[^\@\{\s]+/
 
 option_list: options | list_var
     
-options: '{' option(s /\s*,\s*/) '}'
+options: '{' option(s /,\s*/) '}'
 
 list_var: /@[A-Z_]+/ { $list_var = $item[1] }
 
-option: string display_text(?)
-    { push @options, { $item[1] => $item{'display_text(?)'}[0] } }
+option: value display_text(?)
+    { push @options, { $item{value} => $item{'display_text(?)'}[0] } }
 
 value: identifier
 
-display_text: bracket_block
+display_text: '[' /[^\]]+/i ']'    { $item[2] }
 
-
-validate: '//' (optional_pattern | required_pattern)
-
-optional_pattern: var_name '?'	{ $required = 0; $item[1] }
-
-required_pattern: var_name { $required = 1; $item[1] }
+validate: '//' value
 
 comment: '#' /.*/
@@ -306,9 +98,2 @@
 
 identifier: /\w+/
-
-# skip unknown directives with a warning
-unknown_directive: /\!\S*/ /.*/
-    { warn "[Text::Formbuilder] Skipping unknown directive '$item[1]' at input text line $thisline\n"; }
-
-unknown_block_directive: /\!\S*/ var_name(?) block
-    { warn "[Text::Formbuilder] Skipping unknown block directive '$item[1]' at input text line $thisline\n"; }
