/**
* Copyright (c) 2011 Cloudsmith Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Cloudsmith
*
*/
package org.cloudsmith.geppetto.pp.dsl.validation;
import java.util.regex.Pattern;
import com.google.inject.Inject;
import com.google.inject.Singleton;
/**
* Helper patterns for puppet
* (hint: http://www.regexplanet.com/simple/index.html for interactive testing of java regex).
*
*/
// terminal NAME : ('0'..'9' | 'a'..'z') EXT_WORD_CHAR* ;
// terminal CLASS_NAME : (('a'..'z') EXT_WORD_CHAR*)? ('::' ('a'..'z') EXT_WORD_CHAR*)+;
// terminal CLASS_REF: ('::'? ('A'..'Z') EXT_WORD_CHAR*)+ ;
//
// terminal fragment EXT_WORD_CHAR : WORD_CHAR | '-' ;
// terminal fragment EXT_WORD_CHAR_NUM : EXT_WORD_CHAR | '-' | '.'; // to allow decimals 0.0E-2 as a name, hex is already ok 0x0aef
// terminal fragment WORD_CHAR : ('0'..'9')|('a'..'z')|('A'..'Z')|'_';
@Singleton
public class PPPatternHelper {
protected final Pattern namePattern;
protected final Pattern classRefPattern;
protected final Pattern classNamePattern;
protected final Pattern regexpPattern;
protected final Pattern variablePattern;
protected final Pattern sqStringPattern;
protected final Pattern unrecognizedSQEscapes;
protected final Pattern recognizedSQEscapes;
protected final Pattern unrecognizedDQEscapes;
protected final Pattern recognizedDQEscapes;
protected final Pattern decimalVarPattern;
/**
* Intended as Ruby %r{[\w-]} equivalence
*/
private static final String EXT_WORD_CHAR = "[0-9a-zA-Z_\\.-]";
/**
* Intended as Ruby %r{-[\w]} equivalence
*/
private static final String WORD_CHAR = "[0-9a-zA-Z_-]";
/**
* No '-' allowed in variables.
*/
private static final String VAR_CHAR = "[0-9a-zA-Z_]";
@Inject
public PPPatternHelper() {
namePattern = Pattern.compile("[0-9a-z]" + EXT_WORD_CHAR + "*");
classRefPattern = Pattern.compile("((::)?[A-Z]" + WORD_CHAR + "*)+");
classNamePattern = Pattern.compile("([a-z]" + WORD_CHAR + "*)?(::[a-z]" + WORD_CHAR + "*)*");
// regexp may not:
// be empty - '//'
// start with a * - '/*...'
// contain newline character
regexpPattern = Pattern.compile("/([^/\\n\\*\\\\]|(\\\\[^\\n]))([^/\\n\\\\]|(\\\\[^\\n]))*/[a-z]*");
variablePattern = Pattern.compile("\\$(::)?(" + VAR_CHAR + "+::)*" + VAR_CHAR + "+");
// sq string may not contain unescaped single quote
sqStringPattern = Pattern.compile("([^'\\\\]|\\\\.)*");
unrecognizedSQEscapes = Pattern.compile("\\\\[^stn '\"\\\\\\r\\n]");
recognizedSQEscapes = Pattern.compile("\\\\[\\\\nrst'\" ]");
unrecognizedDQEscapes = Pattern.compile("\\\\[^stn '\"\\\\\\r\\n\\$]");
recognizedDQEscapes = Pattern.compile("\\\\[\\\\nrst'\" \\$]");
decimalVarPattern = Pattern.compile("\\$?([0]|([1-9][0-9]*))");
}
/**
* For DQ string
*
* @return
*/
public Pattern getRecognizedDQEscapePattern() {
return recognizedDQEscapes;
}
/**
* For SQ string
*
* @return
*/
public Pattern getRecognizedSQEscapePattern() {
return recognizedSQEscapes;
}
/**
* Finds unrecognized escapes if recognized escapes have been removed from the input first.
* For DQ string.
*
* @return
*/
public Pattern getUnrecognizedDQEscapesPattern() {
return unrecognizedDQEscapes;
}
/**
* Finds unrecognized escapes if recognized escapes have been removed from the input first.
* For SQ string.
*
* @return
*/
public Pattern getUnrecognizedSQEscapesPattern() {
return unrecognizedSQEscapes;
}
public boolean isCLASSNAME(String s) {
if(s == null || s.length() == 0)
return false;
return classNamePattern.matcher(s).matches() && !s.contains(":::");
}
public boolean isCLASSREF(String s) {
if(s == null || s.length() == 0)
return false;
return classRefPattern.matcher(s).matches() && !s.contains(":::");
}
public boolean isDECIMALVAR(String s) {
if(s == null || s.length() == 0)
return false;
return decimalVarPattern.matcher(s).matches();
}
public boolean isNAME(String s) {
if(s == null || s.length() == 0)
return false;
return namePattern.matcher(s).matches() && !s.contains(":::");
}
public boolean isREGEXP(String s) {
if(s == null || s.length() == 0)
return false;
return regexpPattern.matcher(s).matches();
}
/**
* Checks the content *between* ' ' (i.e. do not include the quotes in the given input).
*
* @param s
* @return
*/
public boolean isSQSTRING(String s) {
if(s == null || s.length() == 0)
return true; // ok if empty
// return sqStringPattern.matcher(s).matches();
boolean escaped = false;
for(int i = 0; i < s.length(); i++) {
switch(s.charAt(i)) {
case '\\':
escaped = !escaped;
break;
case '\'':
if(!escaped)
return false;
escaped = false;
break;
default:
escaped = false;
}
}
return true;
}
public boolean isVARIABLE(String s) {
if(s == null || s.length() == 0)
return false;
return variablePattern.matcher(s).matches();
}
}