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 }