package org.nutz.ioc.java;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.LinkedArray;
import org.nutz.lang.util.LinkedCharArray;
public class ChainParsing {
private char[] cs;
private int i;
private ChainNode first;
private ChainNode last;
/**
* 如果不为 null,那么 addNode 将全加到这里
*/
private LinkedArray<LinkedArray<ChainNode>> argss;
/**
* 控制 parse 函数,合适退出
*/
private LinkedCharArray ends;
/**
* parse 函数所使用的字符缓冲区
*/
private StringBuilder sb;
public ChainParsing(String s) {
ends = new LinkedCharArray(10);
sb = new StringBuilder();
argss = new LinkedArray<LinkedArray<ChainNode>>(5);
cs = s.toCharArray();
parse();
}
private void parse() {
for (; i < cs.length; i++) {
char c = cs[i];
if (c == ',') {
checkIfNeedAddNode();
}
// 属性
else if (null != first && c == '.') {
String fn = clearStringBuffer();
if (!Strings.isBlank(fn)) {
addNode(new FieldNode(fn));
}
}
// String
else if (c == '\'' || c == '"') {
clearStringBuffer();
for (i++; i < cs.length; i++) {
char n = cs[i];
if (n == c)
break;
sb.append(n);
}
addNode(new StringNode(clearStringBuffer()));
}
// @Ioc | @Context | @Name
else if (c == '@') {
String name = readToDot().toUpperCase();
if ("IOC".equals(name)) {
addNode(new IocSelfNode());
} else if ("CONTEXT".equals(name)) {
addNode(new IocContextNode());
} else if ("NAME".equals(name)) {
addNode(new IocObjectNameNode());
}
continue;
}
// $xxx
else if (c == '$') {
String name = readToDot();
addNode(new IocObjectNode(name));
continue;
}
// (...) in func
else if (c == '(') {
String funcName = Strings.trim(clearStringBuffer());
argss.push(new LinkedArray<ChainNode>(ChainNode.class, 5));
ends.push(')');
i++;
parse();
ends.popLast();
ChainNode[] args = argss.popLast().toArray();
int pos = funcName.lastIndexOf('.');
// 嗯... 看来是静态方法调用 ...
if (pos > 0) {
String className = funcName.substring(0, pos);
funcName = funcName.substring(pos + 1);
addNode(new StaticFunctionNode(className, funcName, args));
}
// 前面节点如果为 (...),那么 . 会被计入
else if (pos == 0) {
addNode(new ObjectFunctionNode(funcName.substring(1), args));
}
// 简直就是一个方法调用
else {
addNode(new ObjectFunctionNode(funcName, args));
}
clearStringBuffer();
}
// If funcs, it will will quit when encounter the ')'
else if (ends.size() > 0 && c == ends.last()) {
checkIfNeedAddNode();
return;
}
// xxx.xxx.xxx
else {
sb.append(c);
}
}
checkIfNeedAddNode();
}
private void checkIfNeedAddNode() {
// Finished Parsing, check the buffer
if (!Strings.isBlank(sb)) {
String s = Strings.trim(clearStringBuffer());
// null
if (s.equalsIgnoreCase("null")) {
addNode(new NullNode());
}
// boolean
else if (s.matches("^(true|false)$")) {
addNode(new BooleanNode(s));
}
// number
else if (s.matches("^([-]?[0-9]+)?([.][0-9]+)?([fL]?)$")) {
addNode(new NumberNode(s));
}
// the chain is empty
else if (null == last) {
int pos = s.lastIndexOf('.');
if (pos < 0)
throw Lang.makeThrow("Don't know how to invoke '%s'", s);
String className = s.substring(0, pos);
String funcName = s.substring(pos + 1);
addNode(new StaticFunctionNode(className,
funcName,
new ChainNode[0]));
}
// some node had been built
else {
addNode(new FieldNode(s));
}
}
}
private String readToDot() {
for (i++; i < cs.length; i++) {
char c = cs[i];
if (c == '.' || c == ',')
break;
sb.append(c);
}
return clearStringBuffer();
}
private String clearStringBuffer() {
String re = Strings.trim(sb);
sb = new StringBuilder();
return re;
}
private void addNode(ChainNode node) {
// For arguments
if (argss.size() > 0) {
argss.last().push(node);
}
// First time
else if (last == null) {
first = node;
last = node;
}
// Normal ...
else {
last.setNext(node);
last = node;
}
}
public ChainNode getNode() {
return first;
}
}