Mercurial > pymonkey
comparison src/utils.cpp @ 117:ac8ca0ee7760
Moved all .cpp/.h files into 'src' dir and test suite into 'tests' dir.
author | Atul Varma <varmaa@toolness.com> |
---|---|
date | Mon, 17 Aug 2009 22:08:33 -0700 |
parents | utils.cpp@3570ab12747b |
children | 856ca7a139e4 |
comparison
equal
deleted
inserted
replaced
116:06269ca0b36c | 117:ac8ca0ee7760 |
---|---|
1 /* ***** BEGIN LICENSE BLOCK ***** | |
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | |
3 * | |
4 * The contents of this file are subject to the Mozilla Public License Version | |
5 * 1.1 (the "License"); you may not use this file except in compliance with | |
6 * the License. You may obtain a copy of the License at | |
7 * http://www.mozilla.org/MPL/ | |
8 * | |
9 * Software distributed under the License is distributed on an "AS IS" basis, | |
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
11 * for the specific language governing rights and limitations under the | |
12 * License. | |
13 * | |
14 * The Original Code is Pymonkey. | |
15 * | |
16 * The Initial Developer of the Original Code is Mozilla. | |
17 * Portions created by the Initial Developer are Copyright (C) 2007 | |
18 * the Initial Developer. All Rights Reserved. | |
19 * | |
20 * Contributor(s): | |
21 * Atul Varma <atul@mozilla.com> | |
22 * | |
23 * Alternatively, the contents of this file may be used under the terms of | |
24 * either the GNU General Public License Version 2 or later (the "GPL"), or | |
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | |
26 * in which case the provisions of the GPL or the LGPL are applicable instead | |
27 * of those above. If you wish to allow use of your version of this file only | |
28 * under the terms of either the GPL or the LGPL, and not to allow others to | |
29 * use your version of this file under the terms of the MPL, indicate your | |
30 * decision by deleting the provisions above and replace them with the notice | |
31 * and other provisions required by the GPL or the LGPL. If you do not delete | |
32 * the provisions above, a recipient may use your version of this file under | |
33 * the terms of any one of the MPL, the GPL or the LGPL. | |
34 * | |
35 * ***** END LICENSE BLOCK ***** */ | |
36 | |
37 #include "utils.h" | |
38 #include "undefined.h" | |
39 #include "object.h" | |
40 | |
41 PyObject *PYM_error; | |
42 | |
43 static int | |
44 PYM_doubleToJsval(PYM_JSContextObject *context, | |
45 double number, | |
46 jsval *rval) | |
47 { | |
48 jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number); | |
49 if (numberAsJsdouble == NULL) { | |
50 PyErr_SetString(PYM_error, "JS_NewDouble() failed"); | |
51 return -1; | |
52 } | |
53 *rval = DOUBLE_TO_JSVAL(numberAsJsdouble); | |
54 return 0; | |
55 } | |
56 | |
57 int | |
58 PYM_pyObjectToJsval(PYM_JSContextObject *context, | |
59 PyObject *object, | |
60 jsval *rval) | |
61 { | |
62 if (PyString_Check(object) || PyUnicode_Check(object)) { | |
63 PyObject *unicode; | |
64 if (PyString_Check(object)) { | |
65 unicode = PyUnicode_FromObject(object); | |
66 if (unicode == NULL) | |
67 return -1; | |
68 } else { | |
69 unicode = object; | |
70 Py_INCREF(unicode); | |
71 } | |
72 | |
73 PyObject *string = PyUnicode_AsUTF16String(unicode); | |
74 Py_DECREF(unicode); | |
75 if (string == NULL) | |
76 return -1; | |
77 | |
78 char *buffer = PyString_AS_STRING(string); | |
79 Py_ssize_t size = PyString_GET_SIZE(string); | |
80 | |
81 // Note that we're manipulating buffer and size here to get rid of | |
82 // the BOM. | |
83 JSString *jsString = JS_NewUCStringCopyN(context->cx, | |
84 (const jschar *) (buffer + 2), | |
85 (size / 2) - 1); | |
86 Py_DECREF(string); | |
87 if (jsString == NULL) { | |
88 PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed"); | |
89 return -1; | |
90 } | |
91 | |
92 *rval = STRING_TO_JSVAL(jsString); | |
93 return 0; | |
94 } | |
95 | |
96 if (PyInt_Check(object)) { | |
97 long number = PyInt_AS_LONG(object); | |
98 if (INT_FITS_IN_JSVAL(number)) { | |
99 *rval = INT_TO_JSVAL(number); | |
100 return 0; | |
101 } else | |
102 return PYM_doubleToJsval(context, number, rval); | |
103 } | |
104 | |
105 if (PyFloat_Check(object)) | |
106 return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval); | |
107 | |
108 if (PyObject_TypeCheck(object, &PYM_JSObjectType)) { | |
109 PYM_JSObject *jsObject = (PYM_JSObject *) object; | |
110 JSRuntime *rt = JS_GetRuntime(context->cx); | |
111 if (rt != jsObject->runtime->rt) { | |
112 PyErr_SetString(PyExc_ValueError, | |
113 "JS object and JS context are from different " | |
114 "JS runtimes"); | |
115 return -1; | |
116 } | |
117 *rval = OBJECT_TO_JSVAL(jsObject->obj); | |
118 return 0; | |
119 } | |
120 | |
121 if (object == Py_True) { | |
122 *rval = JSVAL_TRUE; | |
123 return 0; | |
124 } | |
125 | |
126 if (object == Py_False) { | |
127 *rval = JSVAL_FALSE; | |
128 return 0; | |
129 } | |
130 | |
131 if (object == Py_None) { | |
132 *rval = JSVAL_NULL; | |
133 return 0; | |
134 } | |
135 | |
136 // TODO: Support more types. | |
137 PyErr_SetString(PyExc_NotImplementedError, | |
138 "Data type conversion not implemented."); | |
139 return -1; | |
140 } | |
141 | |
142 PyObject * | |
143 PYM_jsvalToPyObject(PYM_JSContextObject *context, | |
144 jsval value) { | |
145 if (JSVAL_IS_INT(value)) | |
146 return PyInt_FromLong(JSVAL_TO_INT(value)); | |
147 | |
148 if (JSVAL_IS_DOUBLE(value)) { | |
149 jsdouble *doubleRef = JSVAL_TO_DOUBLE(value); | |
150 return PyFloat_FromDouble(*doubleRef); | |
151 } | |
152 | |
153 if (value == JSVAL_FALSE) | |
154 Py_RETURN_FALSE; | |
155 | |
156 if (value == JSVAL_TRUE) | |
157 Py_RETURN_TRUE; | |
158 | |
159 if (JSVAL_IS_NULL(value)) | |
160 Py_RETURN_NONE; | |
161 | |
162 if (JSVAL_IS_VOID(value)) | |
163 Py_RETURN_UNDEFINED; | |
164 | |
165 if (JSVAL_IS_STRING(value)) { | |
166 // Strings in JS are funky: think of them as 16-bit versions of | |
167 // Python 2.x's 'str' type. Whether or not they're valid UTF-16 | |
168 // is entirely up to the client code. | |
169 | |
170 // TODO: Instead of ignoring errors, consider actually treating | |
171 // the string as a raw character buffer. | |
172 JSString *str = JSVAL_TO_STRING(value); | |
173 const char *chars = (const char *) JS_GetStringChars(str); | |
174 size_t length = JS_GetStringLength(str); | |
175 | |
176 // We're multiplying length by two since Python wants the number | |
177 // of bytes, not the number of 16-bit characters. | |
178 return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL); | |
179 } | |
180 | |
181 if (JSVAL_IS_OBJECT(value)) | |
182 return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value), | |
183 NULL); | |
184 | |
185 // TODO: Support more types. | |
186 PyErr_SetString(PyExc_NotImplementedError, | |
187 "Data type conversion not implemented."); | |
188 return NULL; | |
189 } | |
190 | |
191 void | |
192 PYM_pythonExceptionToJs(PYM_JSContextObject *context) | |
193 { | |
194 PyObject *type; | |
195 PyObject *value; | |
196 PyObject *traceback; | |
197 | |
198 PyErr_Fetch(&type, &value, &traceback); | |
199 | |
200 if (type == PYM_error && value && | |
201 PyObject_HasAttrString(value, "message")) { | |
202 jsval val; | |
203 PyObject *message = PyObject_GetAttrString(value, "message"); | |
204 if (message && PYM_pyObjectToJsval(context, message, &val) == 0) { | |
205 JS_SetPendingException(context->cx, val); | |
206 } else | |
207 JS_ReportError(context->cx, | |
208 "Python exception occurred, but exception " | |
209 "couldn't be converted"); | |
210 Py_XDECREF(message); | |
211 } else { | |
212 if (value) { | |
213 JSObject *exception = PYM_JS_newObject(context->cx, value); | |
214 if (exception) | |
215 JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception)); | |
216 else | |
217 JS_ReportOutOfMemory(context->cx); | |
218 } else | |
219 JS_ReportError(context->cx, "Python exception occurred"); | |
220 } | |
221 | |
222 Py_XDECREF(type); | |
223 Py_XDECREF(value); | |
224 Py_XDECREF(traceback); | |
225 } | |
226 | |
227 void | |
228 PYM_jsExceptionToPython(PYM_JSContextObject *context) | |
229 { | |
230 if (!JS_IsExceptionPending(context->cx) && | |
231 PyErr_Occurred()) | |
232 return; | |
233 | |
234 jsval val; | |
235 if (JS_GetPendingException(context->cx, &val)) { | |
236 PyObject *obj = PYM_jsvalToPyObject(context, val); | |
237 if (obj) { | |
238 PyErr_SetObject(PYM_error, obj); | |
239 Py_DECREF(obj); | |
240 } else { | |
241 PyErr_Clear(); | |
242 | |
243 JSString *str = NULL; | |
244 | |
245 Py_BEGIN_ALLOW_THREADS; | |
246 str = JS_ValueToString(context->cx, val); | |
247 Py_END_ALLOW_THREADS; | |
248 | |
249 if (str != NULL) { | |
250 const char *chars = JS_GetStringBytes(str); | |
251 PyErr_SetString(PYM_error, chars); | |
252 } else | |
253 PyErr_SetString(PYM_error, "JS exception occurred"); | |
254 } | |
255 } else | |
256 PyErr_SetString(PYM_error, "JS_GetPendingException() failed"); | |
257 } |