001    package com.thaiopensource.relaxng.impl;
002    
003    import org.relaxng.datatype.Datatype;
004    import org.relaxng.datatype.ValidationContext;
005    
006    class DataDerivFunction extends AbstractPatternFunction {
007      private final ValidatorPatternBuilder builder;
008      private final ValidationContext vc;
009      private final String str;
010    
011      DataDerivFunction(String str, ValidationContext vc, ValidatorPatternBuilder builder) {
012        this.str = str;
013        this.vc = vc;
014        this.builder = builder;
015      }
016    
017      static boolean isBlank(String str) {
018        int len = str.length();
019        for (int i = 0; i < len; i++) {
020          switch (str.charAt(i)) {
021          case '\r':
022          case '\n':
023          case ' ':
024          case '\t':
025            break;
026          default:
027            return false;
028          }
029        }
030        return true;
031      }
032    
033      public Object caseText(TextPattern p) {
034        return p;
035      }
036    
037      public Object caseList(ListPattern p) {
038        int len = str.length();
039        int tokenStart = -1;
040        PatternMemo memo = builder.getPatternMemo(p.getOperand());
041        for (int i = 0; i < len; i++) {
042          switch (str.charAt(i)) {
043          case '\r':
044          case '\n':
045          case ' ':
046          case '\t':
047            if (tokenStart >= 0) {
048              memo = tokenDeriv(memo, tokenStart, i);
049              tokenStart = -1;
050            }
051            break;
052          default:
053            if (tokenStart < 0)
054              tokenStart = i;
055            break;
056          }
057        }
058        if (tokenStart >= 0)
059          memo = tokenDeriv(memo, tokenStart, len);
060        if (memo.getPattern().isNullable())
061          return builder.makeEmpty();
062        else
063          return builder.makeNotAllowed();
064      }
065    
066      private PatternMemo tokenDeriv(PatternMemo p, int i, int j) {
067        return p.dataDeriv(str.substring(i, j), vc);
068      }
069    
070      public Object caseValue(ValuePattern p) {
071        Datatype dt = p.getDatatype();
072        Object value = dt.createValue(str, vc);
073        if (value != null && dt.sameValue(p.getValue(), value))
074          return builder.makeEmpty();
075        else
076          return builder.makeNotAllowed();
077      }
078    
079      public Object caseData(DataPattern p) {
080        if (p.allowsAnyString())
081          return builder.makeEmpty();
082        if (p.getDatatype().isValid(str, vc))
083          return builder.makeEmpty();
084        else
085          return builder.makeNotAllowed();
086      }
087    
088      public Object caseDataExcept(DataExceptPattern p) {
089        Pattern tem = (Pattern)caseData(p);
090        if (tem.isNullable() && memoApply(p.getExcept()).isNullable())
091          return builder.makeNotAllowed();
092        return tem;
093      }
094    
095      public Object caseAfter(AfterPattern p) {
096        Pattern p1 = p.getOperand1();
097        if (memoApply(p1).isNullable() || (p1.isNullable() && isBlank(str)))
098          return p.getOperand2();
099        return builder.makeNotAllowed();
100      }
101    
102      public Object caseChoice(ChoicePattern p) {
103        return builder.makeChoice(memoApply(p.getOperand1()),
104                                  memoApply(p.getOperand2()));
105      }
106      
107      public Object caseGroup(GroupPattern p) {
108        final Pattern p1 = p.getOperand1();
109        final Pattern p2 = p.getOperand2();
110        Pattern tem = builder.makeGroup(memoApply(p1), p2);
111        if (!p1.isNullable())
112          return tem;
113        return builder.makeChoice(tem, memoApply(p2));
114      }
115    
116      public Object caseInterleave(InterleavePattern p) {
117        final Pattern p1 = p.getOperand1();
118        final Pattern p2 = p.getOperand2();
119        return builder.makeChoice(builder.makeInterleave(memoApply(p1), p2),
120                                  builder.makeInterleave(p1, memoApply(p2)));
121      }
122    
123      public Object caseOneOrMore(OneOrMorePattern p) {
124        return builder.makeGroup(memoApply(p.getOperand()),
125                                 builder.makeOptional(p));
126      }
127    
128      public Object caseOther(Pattern p) {
129        return builder.makeNotAllowed();
130      }
131    
132      private Pattern memoApply(Pattern p) {
133         return builder.getPatternMemo(p).dataDeriv(str, vc).getPattern();
134       }
135    }