index.html 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>JSDoc: Home</title>
  6. <script src="scripts/prettify/prettify.js"> </script>
  7. <script src="scripts/prettify/lang-css.js"> </script>
  8. <!--[if lt IE 9]>
  9. <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
  10. <![endif]-->
  11. <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
  12. <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
  13. </head>
  14. <body>
  15. <div id="main">
  16. <h1 class="page-title">Home</h1>
  17. <h3> </h3>
  18. <section>
  19. <article><h1>Programming Skulpt</h1><p>If you are reading this document, chances are you have used Skulpt in some form or another, maybe on skulpt.org or some other website. Or maybe you have embedded Skulpt on your own website. But, Skulpt is not complete. Bits and pieces of the Python language are missing, and now one of them is causing you enough pain that you have decided that you want to extend Skulpt with that missing bit. Or maybe you are just interested in learning a bit more about Skulpt and now you have found this document. Congratulations, thanks, and welcome.</p>
  20. <h2>What is Skulpt?</h2><p>Skulpt is a system that compiles Python (of the 2.6-ish variety) into Javascript. But its not Javascript that you can paste in to your browser and run. Python and Javascript are very different languanges, their types are different, their scoping rules are different. Python is designed to be run on Linux, or Windows, or Mac OS X, not in the browser! So, to provide a True Python experience Skulpt must provide a runtime environment in which the compiled code executes. This runtime environment is provided by the skulpt.min.js and skulpt-stdlib.js files that you must include in your web page in order to make Skulpt work. </p>
  21. <p>To give you some idea of what is going on behind the scenes with skulpt lets look at what happens when our friend &quot;hello world&quot; is is compiled from Python to Skulpt. We will revisit this program later and go into more detail, so for now, don't get bogged down in the detail, just have a look to see how much is really happening</p>
  22. <p><strong>Python Version</strong></p>
  23. <pre class="prettyprint source"><code>print &quot;hello world&quot;</code></pre><p><strong>Javascript Translation</strong></p>
  24. <pre class="prettyprint source"><code>/* 1 */ var $scope0 = (function($modname) {
  25. /* 2 */ var $blk = 0,
  26. /* 3 */ $exc = [],
  27. /* 4 */ $gbl = {},
  28. /* 5 */ $loc = $gbl,
  29. /* 6 */ $err = undefined;
  30. /* 7 */ $gbl.__name__ = $modname;
  31. /* 8 */ Sk.globals = $gbl;
  32. /* 9 */ try {
  33. /* 10 */ while (true) {
  34. /* 11 */ try {
  35. /* 12 */ switch ($blk) {
  36. /* 13 */ case 0:
  37. /* 14 */ /* --- module entry --- */
  38. /* 15 */ //
  39. /* 16 */ // line 1:
  40. /* 17 */ // print &quot;hello world&quot;
  41. /* 18 */ // ^
  42. /* 19 */ //
  43. /* 20 */ Sk.currLineNo = 1;
  44. /* 21 */ Sk.currColNo = 0
  45. /* 22 */
  46. /* 23 */
  47. /* 24 */ Sk.currFilename = './simple.py';
  48. /* 25 */
  49. /* 26 */ var $str1 = new Sk.builtins['str']('hello world');
  50. /* 27 */ Sk.misceval.print_(new Sk.builtins['str']($str1).v);
  51. /* 28 */ Sk.misceval.print_(&quot;\n&quot;);
  52. /* 29 */ return $loc;
  53. /* 30 */ throw new Sk.builtin.SystemError('internal error: unterminated block');
  54. /* 31 */ }
  55. /* 32 */ } catch (err) {
  56. /* 33 */ if ($exc.length > 0) {
  57. /* 34 */ $err = err;
  58. /* 35 */ $blk = $exc.pop();
  59. /* 36 */ continue;
  60. /* 37 */ } else {
  61. /* 38 */ throw err;
  62. /* 39 */ }
  63. /* 40 */ }
  64. /* 41 */ }
  65. /* 42 */ } catch (err) {
  66. /* 43 */ if (err instanceof Sk.builtin.SystemExit && !Sk.throwSystemExit) {
  67. /* 44 */ Sk.misceval.print_(err.toString() + '\n');
  68. /* 45 */ return $loc;
  69. /* 46 */ } else {
  70. /* 47 */ throw err;
  71. /* 48 */ }
  72. /* 49 */ }
  73. /* 50 */ });</code></pre><p>So, 50 lines of Javascript for hello world eh? That sounds kind of crazy, but you have to recognize that the environment with global variables, local variables, error handling, etc all has to happen even for the simplest program to run. The parts of the program above that really print &quot;hello world&quot; are lines 26-29. If you have a look at them you will see that we have to construct a string object from the string literal and then pass that off to some print function.</p>
  74. <p>In the example above <code>Sk.builtin.str</code> and <code>Sk.misceval.print_</code> are part of the Skulpt runtime. It is usually the case that to extend Skulpt one of these runtime functions must be modified, or a new runtime function must be created and exposed so that it can be used in an ordinary Python program. The rest of this manual will take you through the essential parts of Skulpt so you can feel comfortable working on and extending the runtime environment. </p>
  75. <p>An important thing to keep in mind as you are trying to understand Skulpt is that it is heavily influenced by the implementation of CPython. So although Python and Javascript are both object oriented languages many parts of the skulpt implementation are quite procedural. For example using functions that take an object as their first parameter may seem strange as we should have just created a method on that object. But in order to follow the CPython implementation this decision was made early on.</p>
  76. <h2>The Source</h2><p>The <code>src</code> directory contains the javascript that implements skulpt as well
  77. as parts of the standard library. library modules are in src/lib. The
  78. source files could roughly be divided into two pieces. The compiler and
  79. the runtime. The compiler files are:
  80. <code>ast.js, parser.js, symtable.js, compile.js, and tokenize.js</code> The
  81. compiler part of skulpt reads python code and generates a Javascript
  82. program. If you want to change the syntax of Python these are the files
  83. to look at. The syntax used in skulpt is taken right from the Python
  84. 2.6.5 distribution.</p>
  85. <p>When you run the program in the browser the javascript part is 'evaled'
  86. by javascript. The runtime files roughly correspond to all of the major
  87. object types in Python plus builtins:</p>
  88. <ul>
  89. <li>abstract.js -- contains lots of abstract function defs</li>
  90. <li>biginteger.js -- implements Python's long integer type</li>
  91. <li>bool.js</li>
  92. <li>skulpt-stdlib.js -- builtin functions: range, min, max, etc. are
  93. defined here</li>
  94. <li>builtindict.js -- Provides a mapping from the standard Python name
  95. to the internal name in skulpt-stdlib.js</li>
  96. <li>dict.js</li>
  97. <li>enumerate.js</li>
  98. <li>env.js</li>
  99. <li>errors.js -- Exceptions are defined here</li>
  100. <li>file.js</li>
  101. <li>float.js</li>
  102. <li>function.js</li>
  103. <li>generator.js</li>
  104. <li>import.js</li>
  105. <li>int.js</li>
  106. <li>list.js</li>
  107. <li>long.js</li>
  108. <li>method.js</li>
  109. <li>module.js</li>
  110. <li>native.js</li>
  111. <li>number.js</li>
  112. <li>object.js -- most things &quot;inherit&quot; from object</li>
  113. <li>set.js</li>
  114. <li>slice.js</li>
  115. <li>str.js</li>
  116. <li>timsort.js</li>
  117. <li>tuple.js</li>
  118. <li>type.js</li>
  119. </ul>
  120. <h2>Types and Namespaces</h2><p>The <code>Sk</code> object contains all of the core Skulpt objects and
  121. functions. Its pretty easy to get from Sk.blah to its source.
  122. Usually you will see something like <code>Sk.builtin.foo</code> which indicates
  123. that you will likely find a corresponding file for foo in the src directory.
  124. Similarly <code>Sk.misceval.callsim</code> tells you that you should look
  125. in <code>misceval.js</code> for the callsim function.</p>
  126. <p>Perhaps one of the most important concepts to learn when starting to program Skulpt is that you
  127. are always moving back and forth between Python objects and Javascript objects. Much of your job
  128. as a skulpt hacker is to either create Python objects as part of a builtin or module function,
  129. or interact with objects that have been created by the users &quot;regular&quot; Python code. Knowing when
  130. you are working with what is critical. For example a Javascript string is not the same thing as a
  131. python string. A Python string is really an instance of <code>Sk.builtin.str</code> and a Javscript string is
  132. an instance of <code>string</code>. You can't compare the two directly, and you definitely cannot use them
  133. interchangeably.</p>
  134. <table>
  135. <thead>
  136. <tr>
  137. <th>Python</th>
  138. <th>Skulpt</th>
  139. <th>Javascript</th>
  140. </tr>
  141. </thead>
  142. <tbody>
  143. <tr>
  144. <td>int</td>
  145. <td>Sk.builtin.int</td>
  146. <td>number</td>
  147. </tr>
  148. <tr>
  149. <td>float</td>
  150. <td>Sk.builtin.float</td>
  151. <td>number </td>
  152. </tr>
  153. <tr>
  154. <td>long</td>
  155. <td>Sk.builtin.lng</td>
  156. <td>NA</td>
  157. </tr>
  158. <tr>
  159. <td>complex</td>
  160. <td>Sk.builtin.complex</td>
  161. <td>NA</td>
  162. </tr>
  163. <tr>
  164. <td>list</td>
  165. <td>Sk.builtin.list</td>
  166. <td>Array</td>
  167. </tr>
  168. <tr>
  169. <td>dict</td>
  170. <td>Sk.builtin.dict</td>
  171. <td>Object</td>
  172. </tr>
  173. <tr>
  174. <td>set</td>
  175. <td>Sk.builtin.set</td>
  176. <td>NA</td>
  177. </tr>
  178. <tr>
  179. <td>bool</td>
  180. <td>Sk.builtin.bool</td>
  181. <td>bool</td>
  182. </tr>
  183. <tr>
  184. <td>tuple</td>
  185. <td>Sk.builtin.tuple</td>
  186. <td>NA</td>
  187. </tr>
  188. </tbody>
  189. </table>
  190. <p>So how do I get the equivalent value? How do I work with these Python objects from Javascript?</p>
  191. <p>There are two key functions in Sk.ffi: <code>Sk.ffi.remapToJs</code> and <code>Sk.ffi.remapToPy</code> These utility functions are smart enough to remap most builtin data types back and forth. So if you have a Python string and want to compare it to a Javascript string literal you just need to do <code>Sk.ffi.remapToJs(pystring)</code> to get a Javscript string you can compare.</p>
  192. <p>If the Python object in question is a collection, remapToJs will work recursively and not only remap the top level object but also all of the contained objects.</p>
  193. <p>When would you want to convert from Javascript to Python? Very often, in your implementation you will calculate a value that you want to return. The returned value needs to be a valid Python type. So lets say you calculate the factorial of a number in a new function you are adding to math. Then the resulting Javascript number must be turned into a Python object using <code>Sk.ffi.remapToPy(myresult)</code>.</p>
  194. <p>In many places in the current codebase you will see the use of <code>somePythonObject.v</code> Where <code>v</code> is the actual
  195. javascript value hidden away inside the Python object. This is not the preferred way to obtain the mapping. Use
  196. the <code>Sk.ffi</code> API.</p>
  197. <p>Skulpt is divided into several namespaces, you have already seen a couple of them, so here is the list</p>
  198. <ul>
  199. <li>Sk.abstr -- To extend skulpt you should know these functions</li>
  200. <li>Sk.builtin -- This is a big namespace that roughly corresponds to the Python <code>__builtin__</code> namespace</li>
  201. <li>Sk.ffi -- This is the foreign function interface. Good for mapping back and forth from Python to Javascript</li>
  202. <li>Sk.misceval -- To extend skulpt you should know these functions</li>
  203. </ul>
  204. <h2>The Generated Code</h2><p>Perhaps one of the most instructive things you can do to understand
  205. Skulpt and how the pieces begin to fit together is to look at a simple
  206. Python program, and its translation to Javscript. So lets begin with
  207. Hello World.</p>
  208. <h3>Python Version</h3><pre class="prettyprint source"><code>print &quot;hello world&quot;</code></pre><h3>Javascript Translation</h3><pre class="prettyprint source"><code>/* 1 */ var $scope0 = (function($modname) {
  209. /* 2 */ var $blk = 0,
  210. /* 3 */ $exc = [],
  211. /* 4 */ $gbl = {},
  212. /* 5 */ $loc = $gbl,
  213. /* 6 */ $err = undefined;
  214. /* 7 */ $gbl.__name__ = $modname;
  215. /* 8 */ Sk.globals = $gbl;
  216. /* 9 */ try {
  217. /* 10 */ while (true) {
  218. /* 11 */ try {
  219. /* 12 */ switch ($blk) {
  220. /* 13 */ case 0:
  221. /* 14 */ /* --- module entry --- */
  222. /* 15 */ //
  223. /* 16 */ // line 1:
  224. /* 17 */ // print &quot;hello world&quot;
  225. /* 18 */ // ^
  226. /* 19 */ //
  227. /* 20 */ Sk.currLineNo = 1;
  228. /* 21 */ Sk.currColNo = 0
  229. /* 22 */
  230. /* 23 */
  231. /* 24 */ Sk.currFilename = './simple.py';
  232. /* 25 */
  233. /* 26 */ var $str1 = new Sk.builtins['str']('hello world');
  234. /* 27 */ Sk.misceval.print_(new Sk.builtins['str']($str1).v);
  235. /* 28 */ Sk.misceval.print_(&quot;\n&quot;);
  236. /* 29 */ return $loc;
  237. /* 30 */ throw new Sk.builtin.SystemError('internal error: unterminated block');
  238. /* 31 */ }
  239. /* 32 */ } catch (err) {
  240. /* 33 */ if ($exc.length > 0) {
  241. /* 34 */ $err = err;
  242. /* 35 */ $blk = $exc.pop();
  243. /* 36 */ continue;
  244. /* 37 */ } else {
  245. /* 38 */ throw err;
  246. /* 39 */ }
  247. /* 40 */ }
  248. /* 41 */ }
  249. /* 42 */ } catch (err) {
  250. /* 43 */ if (err instanceof Sk.builtin.SystemExit && !Sk.throwSystemExit) {
  251. /* 44 */ Sk.misceval.print_(err.toString() + '\n');
  252. /* 45 */ return $loc;
  253. /* 46 */ } else {
  254. /* 47 */ throw err;
  255. /* 48 */ }
  256. /* 49 */ }
  257. /* 50 */ });</code></pre><p>So, one line of python becomes 50 lines of Javscript. Luckily lots of
  258. this is boiler plate that is the same for every program. One important
  259. convention is that variables that start with a $ are variables that are
  260. generated by the compiler. So, in the above example $scope0, $blk,
  261. $str1, etc are all generated by the compiler not by the Python program.
  262. Each line of the python program gets a corresponding entry in the
  263. Sk.currLineNo so that runtime error messages or exceptions can reference
  264. the line that caused them.</p>
  265. <p>For now lets concentrate on the parts of the code that were generated
  266. specifically for our program. That would be lines 26-29 above.</p>
  267. <ul>
  268. <li>26: The compiler creates a variable to hold the string literal
  269. &quot;hello world&quot; A Python version of the string literal is created by
  270. calling the constructor <code>Sk.builtins['str']</code> passing the javascript
  271. string literal.</li>
  272. <li>27: The <code>Sk.misceval.print_</code> function is called. Here is an
  273. interesting part of the runtime. The code for Sk.misceval.print_ is
  274. below. The key line is <code>Sk.output(s.v)</code> <code>Sk.output</code> is configurable
  275. to be any function that the web developer might want to provide. For
  276. example you might write a function that takes a javascript string as
  277. a parameter and updates a pre element. Or you might simply write a
  278. function that calls alert. Notice that <code>print_</code> simply expects to
  279. get an object. It converts this object into a Python string object
  280. by once again calling the string constructor <code>Sk.builtin.str</code>. If
  281. you've been keeping close watch, this is actually the third time our
  282. string liter has undergone this transformation. Luckily the string
  283. constructor is smart enough to simply return its parameter if the
  284. parameter is already a Python string. You might logically ask why
  285. does the compiler emit a call on line 27 when the runtime function
  286. takes care of the same issue. Not sure, maybe this is an
  287. optimization.</li>
  288. </ul>
  289. <pre class="prettyprint source"><code>Sk.misceval.print_ = function(x) // this was function print(x) not sure why...
  290. {
  291. if (Sk.misceval.softspace_)
  292. {
  293. if (x !== &quot;\n&quot;) Sk.output(' ');
  294. Sk.misceval.softspace_ = false;
  295. }
  296. var s = new Sk.builtin.str(x);
  297. Sk.output(s.v);
  298. var isspace = function(c)
  299. {
  300. return c === '\n' || c === '\t' || c === '\r';
  301. };
  302. if (s.v.length === 0 || !isspace(s.v[s.v.length - 1]) || s.v[s.v.length - 1] === ' ')
  303. Sk.misceval.softspace_ = true;
  304. };</code></pre><ul>
  305. <li>28: print always results in a newline. So do it.</li>
  306. <li>29: done return. This gets us out of the while(true) loop.</li>
  307. </ul>
  308. <h2>Another Example Naming Conventions</h2><h3>Python</h3><pre class="prettyprint source"><code>x = 1
  309. y = 2
  310. z = x + y
  311. print z</code></pre><h3>Javascript</h3><pre class="prettyprint source"><code>/* 1 */ var $scope0 = (function($modname) {
  312. /* 2 */ var $blk = 0,
  313. /* 3 */ $exc = [],
  314. /* 4 */ $gbl = {},
  315. /* 5 */ $loc = $gbl,
  316. /* 6 */ $err = undefined;
  317. /* 7 */ $gbl.__name__ = $modname;
  318. /* 8 */ Sk.globals = $gbl;
  319. /* 9 */ try {
  320. /* 10 */ while (true) {
  321. /* 11 */ try {
  322. /* 12 */ switch ($blk) {
  323. /* 13 */ case 0:
  324. /* 14 */ /* --- module entry --- */
  325. /* 15 */ //
  326. /* 16 */ // line 1:
  327. /* 17 */ // x = 1
  328. /* 18 */ // ^
  329. /* 19 */ //
  330. /* 20 */ Sk.currLineNo = 1;
  331. /* 21 */ Sk.currColNo = 0
  332. /* 22 */
  333. /* 23 */
  334. /* 24 */ Sk.currFilename = './simple.py';
  335. /* 25 */
  336. /* 26 */ $loc.x = new Sk.builtin.nmber(1, 'int');
  337. /* 27 */ //
  338. /* 28 */ // line 2:
  339. /* 29 */ // y = 2
  340. /* 30 */ // ^
  341. /* 31 */ //
  342. /* 32 */ Sk.currLineNo = 2;
  343. /* 33 */ Sk.currColNo = 0
  344. /* 34 */
  345. /* 35 */
  346. /* 36 */ Sk.currFilename = './simple.py';
  347. /* 37 */
  348. /* 38 */ $loc.y = new Sk.builtin.nmber(2, 'int');
  349. /* 39 */ //
  350. /* 40 */ // line 3:
  351. /* 41 */ // z = x + y
  352. /* 42 */ // ^
  353. /* 43 */ //
  354. /* 44 */ Sk.currLineNo = 3;
  355. /* 45 */ Sk.currColNo = 0
  356. /* 46 */
  357. /* 47 */
  358. /* 48 */ Sk.currFilename = './simple.py';
  359. /* 49 */
  360. /* 50 */ var $loadname1 = $loc.x !== undefined ? $loc.x : Sk.misceval.loadname('x', $gbl);
  361. /* 51 */ var $loadname2 = $loc.y !== undefined ? $loc.y : Sk.misceval.loadname('y', $gbl);
  362. /* 52 */ var $binop3 = Sk.abstr.numberBinOp($loadname1, $loadname2, 'Add');
  363. /* 53 */ $loc.z = $binop3;
  364. /* 54 */ //
  365. /* 55 */ // line 4:
  366. /* 56 */ // print z
  367. /* 57 */ // ^
  368. /* 58 */ //
  369. /* 59 */ Sk.currLineNo = 4;
  370. /* 60 */ Sk.currColNo = 0
  371. /* 61 */
  372. /* 62 */
  373. /* 63 */ Sk.currFilename = './simple.py';
  374. /* 64 */
  375. /* 65 */ var $loadname4 = $loc.z !== undefined ? $loc.z : Sk.misceval.loadname('z', $gbl);
  376. /* 66 */ Sk.misceval.print_(new Sk.builtins['str']($loadname4).v);
  377. /* 67 */ Sk.misceval.print_(&quot;\n&quot;);
  378. /* 68 */ return $loc;
  379. /* 69 */ throw new Sk.builtin.SystemError('internal error: unterminated block');
  380. /* 70 */ }
  381. /* 71 */ } catch (err) {
  382. /* 72 */ if ($exc.length > 0) {
  383. /* 73 */ $err = err;
  384. /* 74 */ $blk = $exc.pop();
  385. /* 75 */ continue;
  386. /* 76 */ } else {
  387. /* 77 */ throw err;
  388. /* 78 */ }
  389. /* 79 */ }
  390. /* 80 */ }
  391. /* 81 */ } catch (err) {
  392. /* 82 */ if (err instanceof Sk.builtin.SystemExit && !Sk.throwSystemExit) {
  393. /* 83 */ Sk.misceval.print_(err.toString() + '\n');
  394. /* 84 */ return $loc;
  395. /* 85 */ } else {
  396. /* 86 */ throw err;
  397. /* 87 */ }
  398. /* 88 */ }
  399. /* 89 */ });</code></pre><p>So, here we create some local variables. x, y, do some math to create a
  400. third local variable z, and then print it. Line 26 illustrates creating
  401. a local variable <code>x</code> (stored as an attribute of $loc)
  402. <code>new Sk.builtin.nmber(1, 'int');</code> By now you can probably guess that
  403. <code>Sk.builtin.nmber</code> is a constructor that creates a Python number object
  404. that is of type int, and has the value of 1. The same thing happens for
  405. <code>y</code>.</p>
  406. <p>Next, on lines 40 -- 53 we see what happens in an assignment statement.
  407. first we load the values of x and y into temporary variables $loadname1
  408. and $loadname2. Why not just use $loc.x ?? Well, we need to use
  409. Python's scoping rules. If $loc.x is undefined then we should check the
  410. outer scope to see if it exists there. <code>Sk.misceval.loadname</code> If
  411. loadname does not find a name <code>x</code> or <code>y</code> it throws a NameError, and
  412. execution would abort. You can see where this works by changing the
  413. assignment statement to <code>z = x + t</code> to purposely cause the error. The
  414. compiler blindly first tries $loc.t and then again calls loadname,
  415. which in this case does abort with an error!</p>
  416. <p>On lines 52 and 53 we perform the addition using
  417. <code>Sk.abstr.numberBinOp($loadname1, $loadname2, 'Add');</code> Note the abstract
  418. (see abstract.js) nature of <code>numberBinOp</code> -- two parameters for the
  419. operands, and one parameter <code>'Add'</code> that indicates the operator. Finally
  420. the temporary result returned by numberBinOp is stored in $loc.z. Its
  421. important to note that $loc.z contains a Python number object. Down in
  422. the bowels of numberBinOp, the javascript numeric values for x and y are
  423. retrieved and result of adding two javascript numbers is converted to
  424. the appropriate type of Python object.</p>
  425. <h3>Function Calls, Conditionals, and Loops</h3><p>Oh my! so what is the deal with this while(true)/try/switch thing? To
  426. understand this we need a bit more complicated example, so lets look at
  427. a program that contains an if/else conditional. We'll see that we now
  428. have a much more interesting switch statement.</p>
  429. <p>Without showing all of the generated code, lets consider a simple python
  430. program like the one below. There will be two scope functions generated
  431. by the compiler for this example. $scope0 is for the main program where
  432. foo is defined and there is an if statement. The second $scope1 is for
  433. when the foo function is actually called. The $scope1 while/switch
  434. combo contains four cases: 0, 1, 2, and 3. You can imagine this python
  435. code consisting of four blocks. The first block starts at the beginning
  436. and goes through the evaluation of the if condition. The second block is
  437. the if true block of the if. The third block is the else block of the if
  438. statement, and the final block is the rest of the program after the
  439. if/else is all done. You can verify this for yourself by putting this
  440. program into a file <code>simple.py</code> and running <code>./skulpt.py run simple.py</code>
  441. If you examine the output you will see that the <code>$blk</code> variable is
  442. manipulated to control which <code>case</code> is executed the next time through
  443. the while loop. Very clever! If Javascript had <code>goto statements</code> this
  444. would probably look a lot different.</p>
  445. <pre class="prettyprint source"><code># &lt;--- $blk 0 starts
  446. def foo(bar):
  447. print bar
  448. x = 2
  449. if x % 2 == 0: # &lt;---- end of $blk 0
  450. foo(&quot;hello&quot;) # &lt;---- $blk 3
  451. else:
  452. foo(&quot;goodbye&quot;) # &lt;---- $blk 2
  453. # &lt;--- $blk 1 end of if</code></pre><p>When foo is called, it has its own scope $scope1 created and called using Sk.misceval.callsim.</p>
  454. <h2>How do I add Feature X or Fix bug Y</h2><p>Probably the biggest hurdle in working with skulpt is, &quot;where do I
  455. start?&quot; So, let me take you through a recent scenario, that is pretty
  456. illustrative of how I go about doing development on Skulpt.</p>
  457. <p>The question was &quot;how do I add keyword parameters (cmp, key, and
  458. reverse)&quot; to the builtin sorted function. This is pretty tricky as
  459. Javascript does not support keyword parameters so there is no real
  460. straightforward path. So start as follows:</p>
  461. <pre class="prettyprint source"><code>x = [1,2,3]
  462. print(sorted(x,reverse=True))</code></pre><p>Now run this using <code>skulpt.py run test.py</code> and you will get a compiled
  463. program. With a little bit of sleuthing you find:</p>
  464. <pre class="prettyprint source"><code>/* 35 */ // line 2:
  465. /* 36 */ // print(sorted(x,reverse=True))
  466. /* 37 */ // ^
  467. /* 38 */ //
  468. /* 39 */ Sk.currLineNo = 2;
  469. /* 40 */ Sk.currColNo = 0
  470. /* 41 */
  471. /* 42 */
  472. /* 43 */ Sk.currFilename = './sd.py';
  473. /* 44 */
  474. /* 45 */ var $loadname8 = $loc.sorted !== undefined ? $loc.sorted : Sk.misceval.loadname('sorted', $gbl);
  475. /* 46 */ var $loadname9 = $loc.x !== undefined ? $loc.x : Sk.misceval.loadname('x', $gbl);
  476. /* 47 */ var $call10 = Sk.misceval.call($loadname8, undefined, undefined, ['reverse', Sk.builtin.bool.true$], $loadname9);</code></pre><p>Where the important thing is to notice how the call is formatted after
  477. it is compiled. The fourth parameter to <code>Sk.misceval.call</code> is
  478. <code>['reverse', Sk.builtin.bool.true$]</code> Now if you check the source for
  479. misceval, you will see that these parameters are passed on to the apply
  480. function. In the apply function you will see that there is an assertion
  481. that the fourth parameter should be empty. Ok, here's our starting point
  482. to add in what's needed to actually process these key value parameters
  483. successfully.</p>
  484. <p>In the case of a bug fix, you would do a similar thing, except that the
  485. line where your get an exception is likely to be closer to helping you
  486. figure out your next steps.</p>
  487. <h1>HOW TO</h1><p>This section is for providing specific examples, or documentation on how
  488. to do a specific task. Suggestions for additional tasks are welcome!</p>
  489. <h2>Default Parameters</h2><p>How do I add a function with named parameters with default values?</p>
  490. <p>The key to this is that as the author of either a builtin function, or a
  491. method in a module, you need to add some meta data to the function
  492. definition. Here's an example of how we added the named parameters to
  493. the <code>sorted</code> function.</p>
  494. <pre class="prettyprint source"><code>Sk.builtin.sorted = function sorted(iterable, cmp, key, reverse) {
  495. /* body of sorted here */
  496. }
  497. Sk.builtin.sorted.co_varnames = ['cmp', 'key', 'reverse'];
  498. Sk.builtin.sorted.$defaults = [Sk.builtin.none, Sk.builtin.none, false];
  499. Sk.builtin.sorted.co_numargs = 4;</code></pre><h2>kwargs</h2><p>How do I add a function with <code>**kwargs</code>?</p>
  500. <p>Again the idea comes down to adding some meta-data after the function is
  501. defined. Here is an example of adding <code>**kwargs</code> to a method in a
  502. module:</p>
  503. <pre class="prettyprint source"><code>var plotk_f = function(kwa)
  504. {
  505. Sk.builtin.pyCheckArgs(&quot;plotk&quot;, arguments, 0, Infinity, true, false)
  506. args = new Sk.builtins['tuple'](Array.prototype.slice.call(arguments, 1)); /*vararg*/
  507. kwargs = new Sk.builtins['dict'](kwa);
  508. return new Sk.builtins['tuple']([args, kwargs]);
  509. };
  510. plotk_f['co_kwargs'] = true;
  511. mod.plotk = new Sk.builtin.func(plotk_f);</code></pre><h2>Adding a Module</h2><p>This section is from a blog post I made in 2011, slightly updated.</p>
  512. <p>So, here's the deal. skulpt relies on two javascript files the first is
  513. skulpt.min.js and skulpt-stdlib.js A very minimal installation only uses
  514. skulpt.min.js, whereas if you want to use any modules they are in
  515. skulpt-stdlib.js. Looking around the distribution you will not
  516. immediately find skulpt.min.js because you need to build it. You get a
  517. sculpt.js file by using the m script that comes with the distribution.
  518. running m --help will give you the full list of commands, but the two
  519. that you probably most care about are m dist and m docbi The dist
  520. command builds both skulpt.min.js and skulpt-stdlib.js docbi builds
  521. skulpt-stdlib.js and puts a new copy of it in the doc/static directory.
  522. Lets begin with a quick tour of the source tree:</p>
  523. <ul>
  524. <li>src - contains the implementation of the Python interpreter</li>
  525. <li>src/lib - has the module implementations of webgl and goog. This is
  526. where turtle will live and any other modules I implement along the
  527. way.</li>
  528. <li>doc - This directory contains a google app engine application and is
  529. what you see on skulpt.org There are a couple of important files to
  530. check out in here. One of them is doc/static/env/editor.js This is
  531. the code that ties together the interactive editor on the home page
  532. with the skulpt interpreter and the codemirror editor. If you know
  533. how to build a google app engine app then this directory makes
  534. sense. One thing about the home page is that it is not set up to use
  535. any of the modules. The modules are used in the more advanced ide,
  536. which you can find in doc/ide/static. I'm going to tell you how to
  537. add modules to the simpler editor later in this article.</li>
  538. <li>test - this directory contains a bunch of files for testing the
  539. implementation in a batch mode. These tests are run whenever you run
  540. m dist, or m test.</li>
  541. <li>dist - This directory gets created and populated when you run the m
  542. dist command. It contains the built and compressed versions of
  543. skulpt.min.js and skulpt-stdlib.js</li>
  544. </ul>
  545. <p>To illustrate how to make use of modules, here's an extended version of
  546. my earlier hello world style example.</p>
  547. <pre class="prettyprint source"><code>&lt;html>
  548. &lt;head>
  549. &lt;script src=&quot;skulpt.min.js&quot; type=&quot;text/javascript&quot;>&lt;/script>
  550. &lt;script src=&quot;skulpt-stdlib.js&quot; type=&quot;text/javascript&quot;>&lt;/script>
  551. &lt;/head>
  552. &lt;body>
  553. &lt;script type=&quot;text/javascript&quot;>
  554. function outf(text) {
  555. var mypre = document.getElementById(&quot;output&quot;);
  556. mypre.innerHTML = mypre.innerHTML + text;
  557. }
  558. function builtinRead(x)
  559. {
  560. if (Sk.builtinFiles === undefined || Sk.builtinFiles[&quot;files&quot;][x] === undefined)
  561. throw &quot;File not found: '&quot; + x + &quot;'&quot;;
  562. return Sk.builtinFiles[&quot;files&quot;][x];
  563. }
  564. function runit() {
  565. var prog = document.getElementById(&quot;yourcode&quot;).value;
  566. var mypre = document.getElementById(&quot;output&quot;);
  567. mypre.innerHTML = '';
  568. Sk.configure({output:outf,
  569. read: builtinRead
  570. });
  571. try {
  572. Sk.importMainWithBody(&quot;&lt;stdin>&quot;,false,prog);
  573. } catch (e) {
  574. alert(e);
  575. }
  576. }
  577. &lt;/script>
  578. &lt;h3>Try This&lt;/h3>
  579. &lt;form>
  580. &lt;textarea edit_id=&quot;eta_5&quot; id=&quot;yourcode&quot;>
  581. print &quot;Hello World&quot;
  582. &lt;/textarea>
  583. &lt;button onclick=&quot;runit()&quot; type=&quot;button&quot;>Run&lt;/button>
  584. &lt;/form>
  585. &lt;pre id=&quot;output&quot;>&lt;/pre>
  586. &lt;/body>
  587. &lt;/html></code></pre><p>There are some important differences between this version, and the
  588. version and the non-module version. First off, the call to Sk.configure
  589. contains another key value pair which sets up a specialized read
  590. function. This is the function that is responsible for returning your
  591. module out of the large array of files that are contained in the
  592. skulpt-stdlib.js file. You will see that all of the modules are
  593. contained in this one file, stored in a big JSON structure. The extra
  594. key value pair is: read: builtinRead</p>
  595. <p>The read function is just for loading modules and is called when you do
  596. an import statement of some kind. In this case the function accesses the
  597. variable builtinFiles which is created from the skulpt-stdlib.js file.
  598. The other difference, of course, is that you have to include
  599. skulpt-stdlib.js in your html file. Note that skulpt-stdlib.js must be
  600. included after skulpt.min.js</p>
  601. <p>Now as far as the module itself goes, the easiest thing to do is to
  602. start your module in the src/lib directory. This way it will
  603. automatically get built and included in skulpt-stdlib.js. If you don't
  604. put it there then you are going to have to modify the m script,
  605. specifically the docbi function in the m script to include your module.
  606. Suppose that you want to have a module called bnm.test Here's what you
  607. have to do. First, you need to make a bnm directory under lib. In this
  608. directory you will need to have either __init__.py or
  609. __init__.js or bnm.js to stand in for the bnm module. There doesn't
  610. need to be anything in the file as long as it exists. This is just like
  611. CPython by the way. Then to make a test module you can either make a
  612. test directory and put all your javascript code in __init__.js or
  613. you can simply create a test.js file in the bnm directory. Lets look at
  614. the test module.</p>
  615. <pre class="prettyprint source"><code>var $builtinmodule = function(name)
  616. {
  617. var mod = {};
  618. var myfact = function(n) {
  619. if(n &lt; 1) {
  620. return 1;
  621. } else {
  622. return n * myfact(n-1);
  623. }
  624. }
  625. mod.fact = new Sk.builtin.func(function(a) {
  626. return myfact(a);
  627. });
  628. mod.Stack = Sk.misceval.buildClass(mod, function($gbl, $loc) {
  629. $loc.__init__ = new Sk.builtin.func(function(self) {
  630. self.stack = [];
  631. });
  632. $loc.push = new Sk.builtin.func(function(self,x) {
  633. self.stack.push(x);
  634. });
  635. $loc.pop = new Sk.builtin.func(function(self) {
  636. return self.stack.pop();
  637. });
  638. },
  639. 'Stack', []);
  640. return mod;
  641. }</code></pre><p>All modules start out with the $var builtinmodule = statement. This
  642. test module exposes a single method to the outside world, called fact,
  643. There are a couple of key functions for building up a module. The
  644. Sk.builtin.func call for adding functions to your module, and the
  645. Sk.misceval.buildClass method. This test module defines a simple
  646. factorial function called fact, and a class called stack. Here's a
  647. simple Python program that exercises the module:</p>
  648. <pre class="prettyprint source"><code>import bnm.test
  649. print 'starting'
  650. print bnm.test.fact(10)
  651. x = bnm.test.Stack()
  652. x.push(1)
  653. x.push(2)
  654. print x.pop()
  655. print 'done'</code></pre><p>Its not obvious, but the buildClass method takes four parameters:
  656. globals, func, name, bases It seems that you always pass the mod object
  657. itself as the globals parameter, the func parameter is a function that
  658. represents the class object, the Name is the external name of the class,
  659. and bases presumably would be if the class is inheriting from another
  660. class.</p>
  661. <p>The Sk.builtin.func method creates a function. For module creation we
  662. typically only have to worry about the one parameter, func, which is the
  663. javascript implementation of our Python function. The method can also
  664. take a globals object and two closure objects. Look at the comments in
  665. function.js if you want more explanation of how the builtin.func method
  666. works.</p>
  667. <p>Well, I think this should be enough to get you going. Its worth
  668. repeating, if you made it this far, don't forget to call m docbi or m
  669. dist after you make changes in your module, its easy to get into the
  670. mode of thinking that the new javascript is automatically loaded. But
  671. skulpt-stdlib.js is not automatically rebuilt!</p>
  672. <h2>Importing/Using a module in another module</h2><p>While working on the namedtuple factory in the collections module I
  673. needed to add code to make sure that the fields named in the named tuple
  674. did not duplicate python keywords. while I was looking around for a list
  675. of keywords I discovered that there already was a list of keywords in
  676. the keyword module. Why not use that? A couple of problems:</p>
  677. <ul>
  678. <li><p>How do you import a module into another module? Especially under the
  679. condition where you are writing a module in javascript and the module
  680. you want to include is a python module?</p>
  681. </li>
  682. <li><p>How do you call a function that was imported from a python module?
  683. Here is the snippet that demonstrates</p>
  684. </li>
  685. </ul>
  686. <pre class="prettyprint source"><code>var keywds = Sk.importModule(&quot;keyword&quot;, false, false);
  687. mod.namedtuple = function (name, fields) {
  688. var nm = Sk.ffi.remapToJs(name);
  689. // fields could be a string or a tuple or list of strings
  690. var flds = Sk.ffi.remapToJs(fields);
  691. if (typeof(flds) === 'string') {
  692. flds = flds.split(/\s+/);
  693. }
  694. // use the keyword module function iskeyword
  695. for (i = 0; i &lt; flds.length; i++) {
  696. if (Sk.ffi.remapToJs(Sk.misceval.callsim(keywds.$d['iskeyword'],Sk.ffi.remapToPy(flds[i])))) {
  697. throw new Sk.builtin.ValueError(&quot;Type names and field names cannot be a keyword: &quot; + flds[i]);
  698. }
  699. }</code></pre><p>The importing part is easy: <code>Sk.importModule(name, dumpJS, canSuspend)</code></p>
  700. <p>The not-so-obvious part is the line:
  701. <code>Sk.ffi.remapToJs(Sk.misceval.callsim(keywds.$d['iskeyword'],Sk.ffi.remapToPy(flds[i])))</code></p>
  702. <p>Working inside out: We use <code>Sk.misceval.callsim</code> to call the python
  703. function <code>iskeyword</code> which we retrieve from the module's dictionary of
  704. methods <code>$d</code> Because we are calling a Python function we need to remap
  705. the parameter from a javascript string to a Python string object. Hence
  706. the <code>remapToPy</code> call in the parameter. Since <code>iskeyword</code> will return a
  707. Python bool object we need to remap that back to javscript for our if
  708. statement.</p>
  709. <p>You can use a similar strategy for creating an instance of a class:</p>
  710. <pre class="prettyprint source"><code>var io = Sk.importModule(&quot;io&quot;, false, false);
  711. var stdin = Sk.misceval.callsim(io.$d[&quot;TextIOWrapper&quot;]);</code></pre><p>Seems like a lot of work to check for a keyword in an array. But knowing
  712. how to do this for much more complicated methods in other modules will
  713. pay off.</p>
  714. <h2>Debugging</h2><p>How do I use the debugger in the browser to help me debug my code?</p>
  715. <p>Easy, just add the statement: <code>debugger;</code> to your code. Now if you have
  716. the javscript deveoper tools open in the browser you will have it.</p>
  717. <p>If you want to start the debugger from a python function that you have
  718. written you can also add a debugger statement</p>
  719. <p>If you want to enable debugging generally for use with <code>debugbrowser</code>
  720. follow these handy instructions:</p>
  721. <ul>
  722. <li>I make a new test using ./m nrt</li>
  723. <li>then add a debugger; to the start of the statement at
  724. <https://github.com/skulpt/skulpt/blob/master/src/import.js#L179>
  725. the line would like this:
  726. <code>finalcode += &quot;\ndebugger;&quot; + co.funcname + &quot;(&quot; + namestr + &quot;);&quot;;</code></li>
  727. <li>run <code>./skulpt.py debugbrowser</code> wait until all tests have run</li>
  728. <li>startup the developer tools cmd+alt+i on a mac or F12 on a PC in
  729. chrome that is</li>
  730. <li>run the test I added before and it stops right before you enter the
  731. compiled code!</li>
  732. </ul>
  733. <h2>Development Workflow</h2><ol>
  734. <li>Make a fork of the repository on github. DO NOT simply clone
  735. <http://github.com/bnmnetp/runestone>. Make a Fork. If you don't
  736. know how to make a fork consult the documentation here:<https://help.github.com/articles/fork-a-repo></li>
  737. <li>Make a simple myabs.py file that contains a few lines of python that
  738. exercise the abs function. Say it looks like this:</li>
  739. </ol>
  740. <pre class="prettyprint source"><code>print abs(-1.0)
  741. print abs(24)</code></pre><ol>
  742. <li>Now go edit the source. To implement abs you would edit the
  743. builtin.js file. Now abs is pretty easy to add, because you can just
  744. have our skulpt version of abs call Math.abs So here it is</li>
  745. </ol>
  746. <pre class="prettyprint source"><code>Sk.builtin.abs = function abs(x)
  747. {
  748. return Math.abs(x);
  749. };</code></pre><p>You are not done yet, because builtin functions also have to be declared
  750. in the builtindict.js object as follows:</p>
  751. <pre class="prettyprint source"><code>Sk.builtins = {
  752. 'range': Sk.builtin.range,
  753. 'len': Sk.builtin.len,
  754. 'min': Sk.builtin.min,
  755. 'max': Sk.builtin.max,
  756. 'sum': Sk.builtin.sum,
  757. 'abs': Sk.builtin.abs,
  758. ...
  759. }</code></pre><p>Now you can test your modifications from the command line by running:</p>
  760. <pre class="prettyprint source"><code>./skulpt.py run myabs.py
  761. -----
  762. print abs(-1.0)
  763. print abs(24)
  764. -----
  765. /* 1 */ var $scope0 = (function($modname) {
  766. /* 2 */ var $blk = 0,
  767. /* 3 */ $exc = [],
  768. /* 4 */ $gbl = {},
  769. /* 5 */ $loc = $gbl;
  770. /* 6 */ $gbl.__name__ = $modname;
  771. /* 7 */ while (true) {
  772. /* 8 */ try {
  773. /* 9 */ switch ($blk) {
  774. /* 10 */ case 0:
  775. /* 11 */ /* --- module entry --- */
  776. /* 12 */ //
  777. /* 13 */ // line 1:
  778. /* 14 */ // print abs(-1.0)
  779. /* 15 */ // ^
  780. /* 16 */ //
  781. /* 17 */ Sk.currLineNo = 1;
  782. /* 18 */ Sk.currColNo = 0
  783. /* 19 */
  784. /* 20 */
  785. /* 21 */ Sk.currFilename = './myabs.py';
  786. /* 22 */
  787. /* 23 */ var $loadname1 = $loc.abs !== undefined ? $loc.abs : Sk.misceval.loadname('abs', $gbl);
  788. /* 24 */ var $call2 = Sk.misceval.callsim($loadname1, Sk.numberFromStr('-1.0'));
  789. /* 25 */ Sk.misceval.print_(new Sk.builtins['str']($call2).v);
  790. /* 26 */ Sk.misceval.print_(&quot;\n&quot;);
  791. /* 27 */ //
  792. /* 28 */ // line 2:
  793. /* 29 */ // print abs(24)
  794. /* 30 */ // ^
  795. /* 31 */ //
  796. /* 32 */ Sk.currLineNo = 2;
  797. /* 33 */ Sk.currColNo = 0
  798. /* 34 */
  799. /* 35 */
  800. /* 36 */ Sk.currFilename = './myabs.py';
  801. /* 37 */
  802. /* 38 */ var $loadname3 = $loc.abs !== undefined ? $loc.abs : Sk.misceval.loadname('abs', $gbl);
  803. /* 39 */ var $call4 = Sk.misceval.callsim($loadname3, Sk.numberFromStr('24'));
  804. /* 40 */ Sk.misceval.print_(new Sk.builtins['str']($call4).v);
  805. /* 41 */ Sk.misceval.print_(&quot;\n&quot;);
  806. /* 42 */ return $loc;
  807. /* 43 */ goog.asserts.fail('unterminated block');
  808. /* 44 */ }
  809. /* 45 */ } catch (err) {
  810. /* 46 */ if ($exc.length > 0) {
  811. /* 47 */ $blk = $exc.pop();
  812. /* 48 */ continue;
  813. /* 49 */ } else {
  814. /* 50 */ throw err;
  815. /* 51 */ }
  816. /* 52 */ }
  817. /* 53 */ }
  818. /* 54 */ });
  819. 1
  820. 24</code></pre><p>This is all incredibly useful information.</p>
  821. <p>First it demonstrates that your addition actually worked. You can see
  822. the output at the bottom. Second, you can see how skulpt 'compiled' your
  823. python program into its intermediate Javascript form. While this may not
  824. be all that helpful in this particular case it can be very very helpful
  825. in figuring out what skulpt is actually doing. Now you should run all of
  826. the unit tests to make sure you have broken anything else accidentally.
  827. This is really easy:</p>
  828. <pre class="prettyprint source"><code>./skulpt.py test</code></pre><p>If any tests fail it will be obvious that they did, and you'll have to
  829. do some investigation to figure out why. At the time of this writing you
  830. should see:</p>
  831. <pre class="prettyprint source"><code>run: 343/343 (+1 disabled)
  832. closure: skipped</code></pre><p>Once you are satisfied that your extension is working fine. You should
  833. add a test case to test/run see: New Tests for instructions. This way we
  834. will have a permanent test in the bank of test cases in order to check
  835. for any future regressions.</p>
  836. <p>Finally make a pull request on github to have your new feature
  837. integrated into the master copy. I probably will not accept your pull
  838. request if you haven't done step 4.</p>
  839. <p>Outside of your editor, your browser, and your wits, the main
  840. development tool for skulpt is the skulpt.py command (also linked to m
  841. for historical compatibility).</p>
  842. <pre class="prettyprint source"><code>./skulpt.py --help</code></pre><blockquote>
  843. <p>Usage:</p>
  844. <blockquote>
  845. <p>skulpt.py \<command\> [\<options\>] [script.py]</p>
  846. </blockquote>
  847. <p>Commands:</p>
  848. <blockquote>
  849. <p>run Run a Python file using Skulpt test Run all test cases dist
  850. Build core and library distribution files docbi Build library
  851. distribution file only and copy to doc/static</p>
  852. <p>regenparser Regenerate parser tests regenasttests Regen abstract
  853. symbol table tests regenruntests Regenerate runtime unit tests
  854. regensymtabtests Regenerate symbol table tests regentests Regenerate
  855. all of the above</p>
  856. <p>help Display help information about Skulpt host Start a simple HTTP
  857. server for testing upload Run appcfg.py to upload doc to live GAE
  858. site doctest Run the GAE development server for doc testing nrt
  859. Generate a file for a new test case runopt Run a Python file
  860. optimized browser Run all tests in the browser shell Run a Python
  861. program but keep a shell open (like python -i) vfs Build a virtual
  862. file system to support Skulpt read tests</p>
  863. <p>debugbrowser Debug in the browser -- open your javascript console</p>
  864. </blockquote>
  865. <p>Options:</p>
  866. <blockquote>
  867. <p>-q, --quiet Only output important information -s, --silent Do not
  868. output anything, besides errors -u, --uncompressed Makes
  869. uncompressed core distribution file for debugging -v, --verbose Make
  870. output more verbose [default] --version Returns the version string
  871. in Bower configuration file.</p>
  872. </blockquote>
  873. <p>Options:
  874. : --version show program's version number and exit -h, --help show
  875. this help message and exit -q, --quiet -s, --silent -u,
  876. --uncompressed -v, --verbose Make output more verbose [default]</p>
  877. <h3>run</h3></blockquote>
  878. <p>The command <code>./skulpt.py run foo.py</code> compiles and runs a Python program
  879. generating output similar to the examples shown in the previous section.
  880. This is very common for development. For example if you find a bug, that
  881. you can express in a small Python program you can start by running the
  882. program from the command line and inspecting the generated code. Usually
  883. this will give you a pretty good idea where the bug might be.</p>
  884. <h3>test</h3><p>Run all the unit tests.</p>
  885. <h3>dist</h3><p>Build the distribution files for skulpt:</p>
  886. <ul>
  887. <li>skulpt.min.js -- This is a minified version of the core interpreter
  888. files.</li>
  889. <li>skulpt-stdlib.js -- This is an unminified version of library
  890. functions. This file may contain javascript that implements a
  891. module, such as turtle or math, or it may contain pure python.</li>
  892. </ul>
  893. <h3>Building on windows</h3><p>Running <code>.\skulpt.cmd dist</code> on windows requires some extra work, because
  894. the tests check against the text output, things with line-endings tend
  895. to get icky.</p>
  896. <p>We want to make use we checkout skulpt with <code>LF</code> line endings, which is
  897. not default on windows. You have to configure git and reset your working
  898. directory. Like this:</p>
  899. <pre class="prettyprint source"><code>> git config core.autocrlf input
  900. > git update-index --refresh
  901. > git rm --cached -r .
  902. > git reset --hard</code></pre><h2>Getting stack traces from an exception</h2><p>Sk.builtin.Exception objects have a property called 'traceback'. This
  903. property contains an Array of objects with 'filename', 'lineno' and
  904. (optionally) 'colno' properties, each representing a stack frame. The
  905. array is ordered from innermost to outermost frame.</p>
  906. <p>If an object that is not an instance of Sk.builtin.Exception is thrown
  907. from within a Skulpt function (typically as part of an external piece of
  908. Javascript), it is wrapped in an Sk.builtin.ExternalError. The original
  909. object thrown is stringified (so the exception can be manipulated in
  910. Python), but a reference to the original is also saved in the
  911. ExternalError's 'nativeError' property so it can be inspected from
  912. Javascript.</p></article>
  913. </section>
  914. </div>
  915. <nav>
  916. <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="Sk.abstr.iter-seqIter.html">seqIter</a></li><li><a href="Sk.builtin.bool.html">bool</a></li><li><a href="Sk.builtin.float_.html">float_</a></li><li><a href="Sk.builtin.func.html">func</a></li><li><a href="Sk.builtin.int_.html">int_</a></li><li><a href="Sk.builtin.none.html">none</a></li><li><a href="Sk.builtin.NotImplemented.html">NotImplemented</a></li><li><a href="Sk.builtin.numtype.html">numtype</a></li><li><a href="Sk.builtin.object.html">object</a></li><li><a href="Sk.builtin.seqtype.html">seqtype</a></li><li><a href="Sk.misceval.Suspension.html">Suspension</a></li></ul><h3>Namespaces</h3><ul><li><a href="Sk.html">Sk</a></li><li><a href="Sk.abstr.html">abstr</a></li><li><a href="Sk.builtin.html">builtin</a></li><li><a href="Sk.ffi.html">ffi</a></li><li><a href="Sk.misceval.html">misceval</a></li></ul>
  917. </nav>
  918. <br class="clear">
  919. <footer>
  920. Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0</a> on Thu Aug 13 2015 08:14:27 GMT-0500 (CDT)
  921. </footer>
  922. <script> prettyPrint(); </script>
  923. <script src="scripts/linenumber.js"> </script>
  924. </body>
  925. </html>