001: package org.python.core;
002:
003: /**
004: * A utility class for handling mixed positional and keyword arguments.
005: *
006: * A typical usage:
007: *
008: * <pre>
009: * public MatchObject search(PyObject[] args, String[] kws) {
010: * ArgParser ap = new ArgParser("search", args, kws,
011: * "pattern", "pos", "endpos");
012: * String string = ap.getString(0);
013: * int start = ap.getInt(1, 0);
014: * int end = ap.getInt(2, string.length());
015: * ...
016: * </pre>
017: */
018:
019: public class ArgParser {
020: // The name of the function. Used in exception messages
021: private String funcname;
022:
023: // The actual argument values.
024: private PyObject[] args;
025:
026: // The list of actual keyword names.
027: private String[] kws;
028:
029: // The list of allowed and expected keyword names.
030: private String[] params = null;
031:
032: // A marker.
033: private static Object required = new Object();
034:
035: private static String[] emptyKws = new String[0];
036:
037: // private PyBuiltinFunction.Info info;
038:
039: private ArgParser(String funcname, PyObject[] args, String[] kws) {
040: this .funcname = funcname;
041: this .args = args;
042: if (kws == null) {
043: kws = emptyKws;
044: }
045: this .kws = kws;
046: }
047:
048: /**
049: * Create an ArgParser with one method argument
050: *
051: * @param funcname Name of the method. Used in error messages.
052: * @param args The actual call arguments supplied in the call.
053: * @param kws The actual keyword names supplied in the call.
054: * @param p0 The expected argument in the method definition.
055: */
056: public ArgParser(String funcname, PyObject[] args, String[] kws,
057: String p0) {
058: this (funcname, args, kws);
059: this .params = new String[] { p0 };
060: check();
061: }
062:
063: /**
064: * Create an ArgParser with two method argument
065: *
066: * @param funcname Name of the method. Used in error messages.
067: * @param args The actual call arguments supplied in the call.
068: * @param kws The actual keyword names supplied in the call.
069: * @param p0 The first expected argument in the method definition.
070: * @param p1 The second expected argument in the method definition.
071: */
072: public ArgParser(String funcname, PyObject[] args, String[] kws,
073: String p0, String p1) {
074: this (funcname, args, kws);
075: this .params = new String[] { p0, p1 };
076: check();
077: }
078:
079: /**
080: * Create an ArgParser with three method argument
081: *
082: * @param funcname Name of the method. Used in error messages.
083: * @param args The actual call arguments supplied in the call.
084: * @param kws The actual keyword names supplied in the call.
085: * @param p0 The first expected argument in the method definition.
086: * @param p1 The second expected argument in the method definition.
087: * @param p2 The third expected argument in the method definition.
088: */
089: public ArgParser(String funcname, PyObject[] args, String[] kws,
090: String p0, String p1, String p2) {
091: this (funcname, args, kws);
092: this .params = new String[] { p0, p1, p2 };
093: check();
094: }
095:
096: /**
097: * Create an ArgParser with three method argument
098: *
099: * @param funcname Name of the method. Used in error messages.
100: * @param args The actual call arguments supplied in the call.
101: * @param kws The actual keyword names supplied in the call.
102: * @param paramnames The list of expected argument in the method definition.
103: */
104: public ArgParser(String funcname, PyObject[] args, String[] kws,
105: String[] paramnames) {
106: this (funcname, args, kws);
107: this .params = paramnames;
108: check();
109: }
110:
111: public ArgParser(String funcname, PyObject[] args, String[] kws,
112: String[] paramnames, int minargs) {
113: this (funcname, args, kws);
114: this .params = paramnames;
115: check();
116: if (!PyBuiltinFunction.DefaultInfo.check(args.length, minargs,
117: this .params.length)) {
118: throw PyBuiltinFunction.DefaultInfo.unexpectedCall(
119: args.length, false, funcname, minargs,
120: this .params.length);
121: }
122: }
123:
124: /**
125: * Return a required argument as a String.
126: *
127: * @param pos The position of the .. First argument is numbered 0.
128: */
129: public String getString(int pos) {
130: return (String) getArg(pos, String.class, "string");
131: }
132:
133: /**
134: * Return an optional argument as a String.
135: *
136: * @param pos The position of the argument. First argument is numbered 0.
137: */
138: public String getString(int pos, String def) {
139: return (String) getArg(pos, String.class, "string", def);
140: }
141:
142: /**
143: * Return a required argument as an int.
144: *
145: * @param pos The position of the argument. First argument is numbered 0.
146: */
147: public int getInt(int pos) {
148: return ((PyInteger) getRequiredArg(pos).__int__()).getValue();
149: }
150:
151: /**
152: * Return an optional argument as an int.
153: *
154: * @param pos The position of the argument. First argument is numbered 0.
155: */
156: public int getInt(int pos, int def) {
157: PyObject value = getOptionalArg(pos);
158: if (value == null) {
159: return def;
160: }
161: return ((PyInteger) value.__int__()).getValue();
162: }
163:
164: /**
165: * Return a required argument as a PyObject.
166: *
167: * @param pos The position of the argument. First argument is numbered 0.
168: */
169: public PyObject getPyObject(int pos) {
170: return getRequiredArg(pos);
171: }
172:
173: /**
174: * Return an optional argument as a PyObject.
175: *
176: * @param pos The position of the argument. First argument is numbered 0.
177: */
178: public PyObject getPyObject(int pos, PyObject def) {
179: PyObject value = getOptionalArg(pos);
180: if (value == null) {
181: value = def;
182: }
183: return value;
184: }
185:
186: /**
187: * Return the remaining arguments as a tuple.
188: *
189: * @param pos The position of the argument. First argument is numbered 0.
190: */
191: public PyObject getList(int pos) {
192: int kws_start = this .args.length - this .kws.length;
193: if (pos < kws_start) {
194: PyObject[] ret = new PyObject[kws_start - pos];
195: System.arraycopy(this .args, pos, ret, 0, kws_start - pos);
196: return new PyTuple(ret);
197: }
198: return Py.EmptyTuple;
199: }
200:
201: private void check() {
202: int nargs = this .args.length - this .kws.length;
203: l1: for (int i = 0; i < this .kws.length; i++) {
204: for (int j = 0; j < this .params.length; j++) {
205: if (this .kws[i].equals(this .params[j])) {
206: if (j < nargs) {
207: throw Py
208: .TypeError("keyword parameter '"
209: + this .params[j]
210: + "' was given by position and by name");
211: }
212: continue l1;
213: }
214: }
215: throw Py.TypeError("'" + this .kws[i]
216: + "' is an invalid keyword "
217: + "argument for this function");
218: }
219: }
220:
221: private PyObject getRequiredArg(int pos) {
222: PyObject ret = getOptionalArg(pos);
223: if (ret == null) {
224: throw Py.TypeError(this .funcname + ": The " + ordinal(pos)
225: + " argument is required");
226: }
227: return ret;
228: }
229:
230: private PyObject getOptionalArg(int pos) {
231: int kws_start = this .args.length - this .kws.length;
232: if (pos < kws_start) {
233: return this .args[pos];
234: }
235: for (int i = 0; i < this .kws.length; i++) {
236: if (this .kws[i].equals(this .params[pos])) {
237: return this .args[kws_start + i];
238: }
239: }
240: return null;
241: }
242:
243: private Object getArg(int pos, Class clss, String classname) {
244: return getArg(pos, clss, classname, required);
245: }
246:
247: private Object getArg(int pos, Class clss, String classname,
248: Object def) {
249: PyObject value = null;
250: if (def == required) {
251: value = getRequiredArg(pos);
252: } else {
253: value = getOptionalArg(pos);
254: if (value == null) {
255: return def;
256: }
257: }
258:
259: Object ret = value.__tojava__(clss);
260: if (ret == Py.NoConversion) {
261: throw Py.TypeError("argument " + (pos + 1) + ": expected "
262: + classname + ", " + Py.safeRepr(value) + " found");
263: }
264: return ret;
265: }
266:
267: private static String ordinal(int n) {
268: switch (n + 1) {
269: case 1:
270: return "1st";
271: case 2:
272: return "2nd";
273: case 3:
274: return "3rd";
275: default:
276: return Integer.toString(n + 1) + "th";
277: }
278: }
279: }
|