📄 rule.java
字号:
return token;
}
}
/**
* Return a trace of the recently seen tokens, for use
* in error reporting
*/
public String recentTokens() {
StringBuffer trace = new StringBuffer();
for (int i = priorTokens.size()-1; i >= 0; i--) {
trace.append(priorTokens.get(i));
trace.append(" ");
}
return trace.toString();
}
/**
* Peek ahead one token.
*/
String peekToken() {
if (lookahead == null) {
lookahead = nextToken();
}
return lookahead;
}
/**
* Push back a previously fetched token. Only depth 1 supported.
*/
void pushback(String token) {
lookahead = token;
}
/**
* Returns true if token is an skippable separator
*/
boolean isSeparator(String token) {
if (token.length() == 1) {
char c = token.charAt(0);
return (c == ',' || Character.isWhitespace(c));
}
return false;
}
/**
* Returns true if token is a syntax element ()[]
*/
boolean isSyntax(String token) {
if (token.length() == 1) {
char c = token.charAt(0);
return (c == '(' || c == ')' || c == '[' || c == ']');
}
return false;
}
/**
* Find the variable index for the given variable name
* and return a Node_RuleVariable with that index.
*/
Node_RuleVariable getNodeVar(String name) {
Node_RuleVariable node = (Node_RuleVariable)varMap.get(name);
if (node == null) {
node = new Node_RuleVariable(name, varMap.size());
varMap.put(name, node);
}
return node;
}
/**
* Translate a token to a node.
*/
Node parseNode(String token) {
if (token.startsWith("?")) {
return getNodeVar(token);
// Dropped support for anon wildcards until the implementation is better resolved
} else if (token.equals("*") || token.equals("_")) {
throw new ParserException("Wildcard variables no longer supported", this);
//// return Node_RuleVariable.ANY;
// return Node_RuleVariable.WILD;
} else if (token.indexOf(':') != -1) {
String exp = prefixMapping.expandPrefix(token); // Local map first
exp = PrintUtil.expandQname(exp); // Retain global map for backward compatibility
if (exp == token) {
// No expansion was possible
String prefix = token.substring(0, token.indexOf(':'));
if (prefix.equals("http") || prefix.equals("urn")
|| prefix.equals("ftp") || prefix.equals("mailto")) {
// assume it is all OK and fall through
} else {
// Likely to be a typo in a qname or failure to register
throw new ParserException("Unrecognized qname prefix (" + prefix + ") in rule", this);
}
}
return Node.createURI(exp);
} else if (peekToken().equals("(")) {
Functor f = new Functor(token, parseNodeList(), BuiltinRegistry.theRegistry);
return Functor.makeFunctorNode( f );
} else if (token.equals("'") || token.equals("\"")) {
// A plain literal
String lit = nextToken();
// Skip the trailing quote
nextToken();
// Check for an explicit datatype
if (peekToken().startsWith("^^")) {
String dtURI = nextToken().substring(2);
if (dtURI.indexOf(':') != -1) {
// Thanks to Steve Cranefield for pointing out the need for prefix expansion here
String exp = prefixMapping.expandPrefix(dtURI); // Local map first
exp = PrintUtil.expandQname(exp); // Retain global map for backward compatibility
if (exp == dtURI) {
// No expansion was possible
String prefix = dtURI.substring(0, dtURI.indexOf(':'));
if (prefix.equals("http") || prefix.equals("urn")
|| prefix.equals("ftp") || prefix.equals("mailto")) {
// assume it is all OK and fall through
} else {
// Likely to be a typo in a qname or failure to register
throw new ParserException("Unrecognized qname prefix (" + prefix + ") in rule", this);
}
} else {
dtURI = exp;
}
}
RDFDatatype dt = TypeMapper.getInstance().getSafeTypeByName(dtURI);
return Node.createLiteral(lit, "", dt);
} else {
return Node.createLiteral(lit, "", false);
}
} else if ( Character.isDigit(token.charAt(0)) ||
(token.charAt(0) == '-' && token.length() > 1 && Character.isDigit(token.charAt(1))) ) {
// A number literal
return parseNumber(token);
} else {
// A uri
return Node.createURI(token);
}
}
/**
* Turn a possible numeric token into typed literal else a plain literal
* @return the constructed literal node
*/
Node parseNumber(String lit) {
if ( Character.isDigit(lit.charAt(0)) ||
(lit.charAt(0) == '-' && lit.length() > 1 && Character.isDigit(lit.charAt(1))) ) {
if (lit.indexOf(".") != -1) {
// Float?
if (XSDDatatype.XSDfloat.isValid(lit)) {
return Node.createLiteral(lit, "", XSDDatatype.XSDfloat);
}
} else {
// Int?
if (XSDDatatype.XSDint.isValid(lit)) {
return Node.createLiteral(lit, "", XSDDatatype.XSDint);
}
}
}
// Default is a plain literal
return Node.createLiteral(lit, "", false);
}
/**
* Parse a list of nodes delimited by parentheses
*/
List parseNodeList() {
String token = nextToken();
if (!token.equals("(")) {
throw new ParserException("Expected '(' at start of clause, found " + token, this);
}
token = nextToken();
List nodeList = new ArrayList();
while (!isSyntax(token)) {
nodeList.add(parseNode(token));
token = nextToken();
}
if (!token.equals(")")) {
throw new ParserException("Expected ')' at end of clause, found " + token, this);
}
return nodeList;
}
/**
* Parse a clause, could be a triple pattern, a rule or a functor
*/
Object parseClause() {
String token = peekToken();
if (token.equals("(")) {
List nodes = parseNodeList();
if (nodes.size() != 3) {
throw new ParserException("Triple with " + nodes.size() + " nodes!", this);
}
if (Functor.isFunctor((Node)nodes.get(0))) {
throw new ParserException("Functors not allowed in subject position of pattern", this);
}
if (Functor.isFunctor((Node)nodes.get(1))) {
throw new ParserException("Functors not allowed in predicate position of pattern", this);
}
return new TriplePattern((Node)nodes.get(0), (Node)nodes.get(1), (Node)nodes.get(2));
} else if (token.equals("[")) {
nextToken();
return doParseRule(true);
} else {
String name = nextToken();
List args = parseNodeList();
Functor clause = new Functor(name, args, BuiltinRegistry.theRegistry);
if (clause.getImplementor() == null) {
// Not a fatal error becase later processing can add this
// implementation to the registry
logger.warn("Rule references unimplemented functor: " + name);
}
return clause;
}
}
/**
* Parse a rule, terminated by a "]" or "." character.
*/
public Rule parseRule() {
return doParseRule(false);
}
/**
* Parse a rule, terminated by a "]" or "." character.
* @param retainVarMap set to true to ccause the existing varMap to be left in place, which
* is required for nested rules.
*/
private Rule doParseRule(boolean retainVarMap) {
try {
// Skip initial '[' if present
if (peekToken().equals("[")) {
nextToken();
}
// Check for optional name
String name = null;
String token = peekToken();
if (token.endsWith(":")) {
name = token.substring(0, token.length()-1);
nextToken();
}
// Start rule parsing with empty variable table
if (!retainVarMap) varMap = new HashMap();
// Body
List body = new ArrayList();
token = peekToken();
while ( !(token.equals("->") || token.equals("<-")) ) {
body.add(parseClause());
token = peekToken();
}
boolean backwardRule = token.equals("<-");
List head = new ArrayList();
token = nextToken(); // skip -> token
token = peekToken();
while ( !(token.equals(".") || token.equals("]")) ) {
head.add(parseClause());
token = peekToken();
}
nextToken(); // consume the terminating token
Rule r = null;
if (backwardRule) {
r = new Rule(name, body, head);
} else {
r = new Rule(name, head, body);
}
r.numVars = varMap.keySet().size();
r.isBackward = backwardRule;
return r;
} catch (NoSuchElementException e) {
throw new ParserException("Malformed rule", this);
}
}
}
/** Equality override */
public boolean equals(Object o) {
// Pass 1 - just check basic shape
if (! (o instanceof Rule) ) return false;
Rule other = (Rule) o;
if (other.head.length != head.length) return false;
if (other.body.length != body.length) return false;
// Pass 2 - check clause by clause matching
for (int i = 0; i < body.length; i++) {
if (! ((ClauseEntry)body[i]).sameAs((ClauseEntry)other.body[i]) ) return false;
}
for (int i = 0; i < head.length; i++) {
if (! ((ClauseEntry)head[i]).sameAs((ClauseEntry)other.head[i]) ) return false;
}
return true;
}
/** hash function override */
public int hashCode() {
int hash = 0;
for (int i = 0; i < body.length; i++) {
hash = (hash << 1) ^ body[i].hashCode();
}
for (int i = 0; i < head.length; i++) {
hash = (hash << 1) ^ head[i].hashCode();
}
return hash;
}
/**
* Compare clause entries, taking into account variable indices.
* The equality function ignores differences between variables.
*/
public boolean sameAs(Object o) {
return equals(o);
}
//=======================================================================
// Other supporting inner classes
/**
* Inner class. Exception raised if there is a problem
* during rule parsing.
*/
public static class ParserException extends JenaException {
/** constructor */
public ParserException(String message, Parser parser) {
super(constructMessage(message, parser));
}
/**
* Extract context trace from prior tokens stack
*/
private static String constructMessage(String baseMessage, Parser parser) {
StringBuffer message = new StringBuffer();
message.append(baseMessage);
message.append("\nAt '");
message.append(parser.recentTokens());
message.append("'");
return message.toString();
}
}
}
/*
(c) Copyright 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development Company, LP
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -