Coverage Report - org.webmacro.directive.DirectiveDescriptor
 
Classes in this File Line Coverage Branch Coverage Complexity
DirectiveDescriptor
92%
39/42
82%
34/41
6.5
 
 1  
 /*
 2  
  * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
 3  
  *
 4  
  * Redistribution and use in source and binary forms, with or without
 5  
  * modification, are permitted under the terms of either of the following
 6  
  * Open Source licenses:
 7  
  *
 8  
  * The GNU General Public License, version 2, or any later version, as
 9  
  * published by the Free Software Foundation
 10  
  * (http://www.fsf.org/copyleft/gpl.html);
 11  
  *
 12  
  *  or
 13  
  *
 14  
  * The Semiotek Public License (http://webmacro.org/LICENSE.)
 15  
  *
 16  
  * This software is provided "as is", with NO WARRANTY, not even the
 17  
  * implied warranties of fitness to purpose, or merchantability. You
 18  
  * assume all risks and liabilities associated with its use.
 19  
  *
 20  
  * See www.webmacro.org for more information on the WebMacro project.
 21  
  */
 22  
 
 23  
 package org.webmacro.directive;
 24  
 
 25  
 import org.webmacro.directive.Directive.ArgDescriptor;
 26  
 import org.webmacro.directive.Directive.Subdirective;
 27  
 
 28  
 /**
 29  
  * Each directive needs a DirectiveDescriptor to describe how it
 30  
  * should be parsed and built by the parser.  The directive descriptor
 31  
  * identifies the directive's name, the class of the underlying concrete
 32  
  * directive object, a list of directive argument descriptors, and a list
 33  
  * of subdirective descriptors.
 34  
  *
 35  
  * If the directive does not specify the class, the directive provider will
 36  
  * fill it in automatically.
 37  
  *
 38  
  * The args field is an array of Directive.ArgDescriptor objects.  There
 39  
  * are static nested classes within Directive for each type of argument
 40  
  * -- Condition, LValue, RValue, Keyword, Punctuation, Block, LiteralBlock,
 41  
  * and special argument descriptors for OptionalGroup and OptionalChoice.
 42  
  * These allow the directive writer to specify
 43  
  * a flexible syntax for directive arguments.
 44  
  * Each directive can have a set of subdirectives, and each subdirective
 45  
  * can have its own argument list.  Subdirectives can be required, optional,
 46  
  * or optional-repeating (multiple subdirectives of the same kind, like
 47  
  * #elseif.)  There are constructors for Subdirective in the Directive module
 48  
  * as well.
 49  
  * 
 50  
  * @author Brian Goetz
 51  
  */
 52  
 public final class DirectiveDescriptor
 53  
 {
 54  
 
 55  
     public String name;
 56  
     public Class dirClass;
 57  
     public ArgDescriptor[] args;
 58  
     public Subdirective[] subdirectives;
 59  
 
 60  156
     public boolean valid = false,
 61  
     hasBreakingSubdirectives = false;
 62  
 
 63  
     public DirectiveDescriptor (String name,
 64  
                                 Class dirClass,
 65  
                                 ArgDescriptor[] args,
 66  
                                 Subdirective[] subdirectives)
 67  156
     {
 68  156
         this.name = name;
 69  156
         this.dirClass = dirClass;
 70  156
         this.args = args;
 71  156
         this.subdirectives = subdirectives;
 72  
 
 73  156
         completeArgs(this.args);
 74  156
         valid = validateArgs(this.args);
 75  
 
 76  156
         if (subdirectives != null)
 77  
         {
 78  24
             for (int i = 0; i < this.subdirectives.length; i++)
 79  
             {
 80  16
                 completeArgs(this.subdirectives[i].args);
 81  16
                 valid &= validateArgs(this.subdirectives[i].args);
 82  16
                 if (this.subdirectives[i].isBreaking)
 83  16
                     hasBreakingSubdirectives = true;
 84  
             }
 85  
         }
 86  156
     }
 87  
 
 88  
     /**
 89  
      * Determines the index of the next argument following a given argument.
 90  
      * May return an index > args.length.
 91  
      */
 92  
     private static int nextArg (ArgDescriptor[] args, int i)
 93  
     {
 94  1524
         if (args[i].type == Directive.ArgType_GROUP
 95  
                 || args[i].type == Directive.ArgType_CHOICE)
 96  
         {
 97  370
             int k = i + 1;
 98  1006
             for (int j = 0; j < args[i].subordinateArgs; j++)
 99  636
                 k = nextArg(args, k);
 100  370
             return k;
 101  
         }
 102  
         else
 103  1154
             return i + 1;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Set the nextArg, children[] fields as necessary.
 108  
      */
 109  
     private static void completeArgs (ArgDescriptor[] args)
 110  
     {
 111  
         int j, k;
 112  
 
 113  1060
         for (int i = 0; i < args.length; i++)
 114  888
             args[i].nextArg = nextArg(args, i);
 115  
 
 116  1060
         for (int i = 0; i < args.length; i++)
 117  
         {
 118  888
             switch (args[i].type)
 119  
             {
 120  
                 case Directive.ArgType_GROUP:
 121  
                 case Directive.ArgType_CHOICE:
 122  208
                     args[i].children = new int[args[i].subordinateArgs];
 123  610
                     for (j = 0, k = i + 1; j < args[i].subordinateArgs; j++)
 124  
                     {
 125  402
                         args[i].children[j] = k;
 126  402
                         k = args[k].nextArg;
 127  
                     }
 128  
                     break;
 129  
 
 130  
                 default:
 131  
                     break;
 132  
             }
 133  
         }
 134  172
     }
 135  
 
 136  
     /**
 137  
      * Make sure that the structure of the arguments list is valid.
 138  
      * This means that
 139  
      *   GROUP arguments begin with a keyword, not optional
 140  
      *   Each of the children of a CHOICE argument is an OPTIONAL GROUP
 141  
      */
 142  
     private static boolean validateArgs (ArgDescriptor[] args)
 143  
     {
 144  172
         boolean valid = true;
 145  1060
         for (int i = 0; i < args.length; i++)
 146  
         {
 147  888
             if (args[i].type == Directive.ArgType_GROUP)
 148  
             {
 149  192
                 if (args[i].subordinateArgs == 0)
 150  0
                     valid = false;
 151  192
                 else if ((args[args[i].children[0]].type != Directive.ArgType_KEYWORD
 152  
                         && args[args[i].children[0]].type != Directive.ArgType_ASSIGN)
 153  
                         || args[args[i].children[0]].optional)
 154  0
                     valid = false;
 155  
             }
 156  696
             else if (args[i].type == Directive.ArgType_CHOICE)
 157  
             {
 158  72
                 for (int j = 0; j < args[i].subordinateArgs; j++)
 159  
                 {
 160  56
                     if (args[args[i].children[j]].type != Directive.ArgType_GROUP
 161  
                             || !args[args[i].children[j]].optional)
 162  0
                         valid = false;
 163  
                 }
 164  
             }
 165  
         }
 166  
 
 167  172
         return valid;
 168  
     }
 169  
 }