public Map parse(final LispValue arguments) {
final Map ret = new HashMap();
int state = 0; // 0 = regular, 1 = optional, 2 = rest, 3 = key
final Set keyArgsLeft = new HashSet(keyArguments.keySet());
final Set optArgsLeft = new HashSet(optionalArguments);
LispValue vals = lisp.NIL;
Iterator next = normalArguments.iterator();
LispValue rests = null;
boolean tempAllow = allowOtherKeys;
if(!tempAllow) {
for(final Iterator iter = arguments.iterator();iter.hasNext();) {
if((((LispValue)iter.next()).eql(allowOtherKeysKey)) == lisp.T && iter.next() != lisp.NIL) {
tempAllow = true;
break;
}
}
}
for(final Iterator iter = arguments.iterator();iter.hasNext();) {
final LispValue val = (LispValue)iter.next();
if(tempAllow && (val.eql(allowOtherKeysKey) == lisp.T)) {
iter.next();
continue;
}
while(next != null && !next.hasNext()) {
state++;
switch(state) {
case 1:
next = optionalArguments.iterator();
break;
case 2:
if(restArgument != null) {
rests = lisp.NIL;
}
next = null;
break;
default:
next = null;
break;
}
}
switch(state) {
case 0:
final NormalArgument arg = (NormalArgument)next.next();
ret.put(arg.getVar(),val);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),val),vals);
break;
case 1:
final OptionalArgument oarg = (OptionalArgument)next.next();
ret.put(oarg.getVar(),val);
vals = lisp.makeCons(lisp.makeList(oarg.getVar(),val),vals);
optArgsLeft.remove(oarg);
if(oarg.getSupplied() != null) {
ret.put(oarg.getSupplied(),lisp.T);
vals = lisp.makeCons(lisp.makeList(oarg.getSupplied(),lisp.T),vals);
}
break;
default:
if(keyArguments.size() > 0 || tempAllow) {
final KeyArgument key = (KeyArgument)keyArguments.get(val);
if(null != key || tempAllow) {
keyArgsLeft.remove(val);
final LispValue theVal = (LispValue)iter.next();
if(null != rests) {
rests = rests.append(lisp.makeCons(val,lisp.makeCons(theVal,lisp.NIL)));
}
if(null != key) {
ret.put(key.getVar(),theVal);
vals = lisp.makeCons(lisp.makeList(key.getVar(),theVal),vals);
if(key.getSupplied() != null) {
ret.put(key.getSupplied(),lisp.T);
vals = lisp.makeCons(lisp.makeList(key.getSupplied(),lisp.T),vals);
}
}
} else {
throw new IllegalArgumentException("Bad key argument: " + val); //TODO: fix good exception here
}
} else if(null != rests) {
rests = rests.append(lisp.makeCons(val,lisp.NIL));
} else {
throw new IllegalArgumentException("Bad arguments"); //TODO: fix good exception here
}
break;
}
}
if(state == 0 && !optionalArguments.isEmpty()) {
next = optionalArguments.iterator();
}
for(;next != null && next.hasNext();) {
final OptionalArgument arg = (OptionalArgument)next.next();
if(arg.getInitForm() != null) {
final LispValue val = lisp.eval(arg.getInitForm(),lisp.makeList(vals));
ret.put(arg.getVar(),val);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),val),vals);
} else {
ret.put(arg.getVar(),lisp.NIL);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),lisp.NIL),vals);
}
if(arg.getSupplied() != null) {
ret.put(arg.getSupplied(),lisp.NIL);
vals = lisp.makeCons(lisp.makeList(arg.getSupplied(),lisp.NIL),vals);
}
}
for(final Iterator iter = keyArgsLeft.iterator();iter.hasNext();) {
final LispValue sym = (LispValue)iter.next();
final KeyArgument arg = (KeyArgument)keyArguments.get(sym);
if(arg.getInitForm() != null) {
final LispValue val = lisp.eval(arg.getInitForm(),lisp.makeList(vals));
ret.put(arg.getVar(),val);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),val),vals);
} else {
ret.put(arg.getVar(),lisp.NIL);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),lisp.NIL),vals);
}
if(arg.getSupplied() != null) {
ret.put(arg.getSupplied(),lisp.NIL);
vals = lisp.makeCons(lisp.makeList(arg.getSupplied(),lisp.NIL),vals);
}
}
if(restArgument != null) {
if(rests != null) {
ret.put(restArgument.getVar(),rests);
vals = lisp.makeCons(lisp.makeList(restArgument.getVar(),rests),vals);
} else {
ret.put(restArgument.getVar(),lisp.NIL);
vals = lisp.makeCons(lisp.makeList(restArgument.getVar(),lisp.NIL),vals);
}
}
for(final Iterator iter = auxArguments.iterator();iter.hasNext();) {
final AuxArgument arg = (AuxArgument)iter.next();
final LispValue val = lisp.eval(arg.getInitForm(),lisp.makeList(vals));
ret.put(arg.getVar(),val);
vals = lisp.makeCons(lisp.makeList(arg.getVar(),val),vals);
}
return ret;
}