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 }