1
0
Pārlūkot izejas kodu

Merge remote-tracking branch 'gokr/master'

Nicolas Petton 13 gadi atpakaļ
vecāks
revīzija
9398d20880

+ 90 - 0
ide.html

@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<!-- saved from url=(0025)http://jtalk-project.org/ -->
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+    <title>Jtalk Smalltalk</title>
+    
+    <meta name="author" content="Nicolas Petton">
+    <link rel="stylesheet" type="text/css" href="./ide/style.css">
+    <link rel="stylesheet" type="text/css" href="./ide/syntax.css">
+    <script type="text/javascript" src="./js/jquery-1.4.4.min.js"></script>
+    <script type="text/javascript" src="./js/jquery-ui-1.8.9.custom.min.js"></script>
+    <script type="text/javascript" src="./js/jquery.textarea.js"></script>
+    <script type="text/javascript" src="./js/boot.js"></script>
+    <script type="text/javascript" src="./js/Kernel.js"></script>
+    <script type="text/javascript" src="./js/Canvas.js"></script>
+    <script type="text/javascript" src="./js/JQuery.js"></script>
+    <script type="text/javascript" src="./js/Parser.js"></script>
+    <script type="text/javascript" src="./js/Compiler.js"></script>
+    <script type="text/javascript" src="./js/IDE.js"></script>
+    <script type="text/javascript" src="./js/SUnit.js"></script>
+    <script type="text/javascript" src="./js/Examples.js"></script>
+    <script type="text/javascript" src="./js/init.js"></script>
+    <link rel="stylesheet" type="text/css" href="./css/jtalk.css">
+    <link rel="stylesheet" type="text/css" href="./css/sunit.css">
+  </head>
+  <body>
+    <script type="text/javascript">
+      jQuery(window).scroll(function() {
+      	if(jQuery(window).scrollTop() > 210) {
+		jQuery('#menu')
+      			.css('position', 'fixed')
+			.css('top', '0px')
+	} else {
+      		jQuery('#menu')
+			.css('position', 'absolute')
+      			.css('top', '210px')
+      	}
+      });
+    </script>
+
+    <a href="http://github.com/NicolasPetton/jtalk"><img style="position: absolute; top: 0; lef
+t: 0; border: 0;" src="./ide/fork_me.png" alt="Fork me on GitHub"></a>
+
+    <div id="wrapper">
+      <div id="header">
+	<div class="main">
+	  <img alt="Jtalk, the Smalltalk for web developers" src="./ide/text_header.png">
+	</div>
+      </div>
+      
+      <div id="menu">
+	<div class="main">
+	  <ul>
+	    <li><a href="http://jtalk-project.org/index.html">Overview</a></li> · 
+	    <li><a href="http://jtalk-project.org/index.html#download">Download</a></li> · 
+	    <li><a id="doc_link" href="http://jtalk-project.org/documentation.html">Documentation</a></li> ·
+	    <li><a target="_blank" href="https://github.com/NicolasPetton/jtalk">Source</a></li> 
+	  </ul>
+	</div>
+      </div>
+
+      <div id="content">
+	<div class="main">
+	  <div class="box first">
+  <div class="content">
+    <h1><img alt="Jtalk is an implementation of the Smalltalk language that runs on the JavaScript runtime." src="./ide/title_container1.png"></h1>
+    <div class="left">
+      <p>Jtalk is an implementation of the  <a href="http://en.wikipedia.org/wiki/Smalltalk">Smalltalk</a> language that runs on top of the <a href="http://en.wikipedia.org/wiki/Javascript">JavaScript</a> runtime. It is designed to make client-side development faster and easier.</p>
+      <p>Jtalk is written in itself, including the parser and compiler. Jtalk compiles into efficient JavaScript, mapping one-to-one with the equivalent JavaScript. There is no interpretation at runtime.</p>
+      <p>Try a <button onclick="smalltalk.Browser._open()"> Class browser</button> right now!</p>
+    </div>
+    <div class="right"><img src="./ide/screen2.png"></div>
+    <div class="clear"></div>
+  </div>
+</div>
+
+	</div>
+      </div>
+    
+    <div id="footer">
+      <div class="main">
+	<p>Copyright © 2011 <a href="http://www.nicolas-petton.fr/">Nicolas Petton</a>. The content of this website in licensed under <a href="http://creativecommons.org/licenses/by-nc/3.0/">CC-BY-NC 3.0</a>.</p>
+	<p>Jtalk is an opensource project sponsored by <a href="http://www.objectfusion.fr/">objectfusion</a>.</p>
+	<p>The design of this website was provided by <a href="mailto:neomie.thirion@gmail.com">Noémie Thirion</a>.</p>
+      </div> 
+    </div>
+    
+  
+
+
+</div></body></html>

BIN
ide/fork_me.png


BIN
ide/screen2.png


+ 456 - 0
ide/style.css

@@ -0,0 +1,456 @@
+/* CSS Reset */
+
+html,body {
+	margin: 0;
+	padding: 0;
+	font: 16px/1.6em Georgia,Times,Serif;
+}
+
+/* Layout */
+
+.clear {clear:both}
+
+.main {
+    margin: 0 auto;
+    width: 960px;
+}
+
+#header {
+	background: transparent url("../images/background_header.png") top center repeat-x;
+	height: 210px;
+}
+
+#header .main {
+    background: url("../images/balloon_header.png") no-repeat scroll right bottom;
+    height: 210px;
+    width: 973px;
+}
+
+#menu {
+    background: #d0def1;
+    border-top: 1px solid #aaa;
+    border-bottom: 1px solid #aaa;
+    position: absolute;
+    width: 100%;
+    height: 36px;
+    top: 210px;
+    font-family: arial,helvetica,sans;
+    z-index: 1;
+}
+
+#menu ul {
+    padding: 5px 0;
+    margin: 0;
+}
+
+#menu li {
+	display: inline;
+	padding: 1px;
+}
+
+#menu a {
+	color: #515a6a;
+	text-decoration: none;
+	padding: 10px 15px;
+}
+
+#menu a:hover {
+	color: #072d5a;
+	text-decoration: underline;
+}
+
+#menu .selected a,
+#menu a:hover {
+	color: #072d5a;
+	text-decoration: none;
+}
+
+#menu #dropdown {
+    float: left;
+    margin-left: 220px;
+    background: #d0def1;
+    border: 1px solid #aaa;
+    border-top: 0 none;
+    width: auto; 
+    display: none;
+}
+
+#menu #dropdown li {
+    display: block;
+    padding: 5px 0;
+}
+	
+#content .main {
+	width: 980px;
+	margin: 0 auto;
+}
+
+.box {
+    padding: 30px;
+    margin: 40px 0;
+    color: #777;
+    box-shadow: 0 0 8px #aaa;
+    -moz-box-shadow: 0 0 8px #aaa;
+    -webkit-box-shadow: 0 0 8px #aaa;
+    border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    background: #fff url('../images/background_box.png') bottom left repeat-x;
+}
+
+.box a {
+    color: #5b9ff2;
+    text-decoration: none; 
+}
+
+.box a:hover {
+    text-decoration: underline;
+}
+
+.box h2 {
+	font: 26px Georgia, Times, serif;
+	color: #242424;
+	margin: -30px;
+	margin-bottom: 0px;
+	padding: 15px;
+	background: #eee;
+	border-bottom: 1px solid #ccc;
+	border-top-left-radius: 10px;
+	border-top-right-radius: 10px;
+	-webkit-border-top-left-radius: 10px;
+	-webkit-border-top-right-radius: 10px;
+	-moz-border-radius-topleft: 10px;
+	-moz-border-radius-topright: 10px;
+}
+
+.box.first {
+    padding-top: 0;
+    margin-top: 70px;
+}
+
+.box.first, .box.last {
+    background-image: none;
+}
+
+.box.first h1 {
+	padding-bottom: 15px;
+}
+
+.box.first .content .right img {
+	margin-right: -30px
+}
+
+.box .content .right {
+	float: right;
+}
+
+.box .content .left {
+	float: left;
+	width: 420px;
+}
+
+.doc .content {
+	width: 620px;
+}
+
+.box h1 {
+    text-align: center;
+    margin-top: 0;
+    padding-top: 0;
+}
+
+.doc h3 a {
+    color: #ccc;
+}
+
+.doc h3 a:hover {
+    color: #0088CC;
+}
+
+.box .content p, h3 {
+	font: 16px Georgia, Times, Serif;
+	line-height: 1.6em;
+	padding: 10px 0;
+	margin: 0;
+}
+
+.box .content h3 {
+	font-size: 20px;
+	padding-bottom: 2px;
+	padding-top: 30px;
+	color: #272727;
+}
+
+.box .content h4 {
+	font: 18px Georgia, Times, serif;
+	color: #272727;
+	padding-top: 1em;
+	margin-top: 10px;
+	margin-bottom: 5px;
+}
+
+.box .content pre {
+	border: 1px solid #ccc;
+	background-color: #f5f5f5;
+	border-radius: 10px;
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	padding: 1em;
+	line-height: 1.5em;
+	font-size: 14px;
+	color: #333;
+}
+
+.box .content code {
+	font-size: 14px;
+	color: #333;
+	margin: 0;
+	padding: 0 3px;
+	border: 1px solid #bbb;
+	background: #f1f1f1;
+}
+
+.box .content pre code {
+    background: transparent;
+    border: 0 none;
+    color: #333;
+}
+
+.box .content pre .prompt {
+    color: #aaa;
+}
+
+.box .content pre .kbd {
+    font-weight: bold;
+}
+
+.box .content pre .kbd.var {
+    font-weight: normal;
+    font-style: italic;
+}
+
+.box .content .tip {
+	border: 1px solid #565656;
+	border-radius: 10px;
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	padding: 1em;
+}
+
+.box .top img {
+	margin: 30px 0 0 70px;
+}
+
+.box.last .content .left {
+    width: 560px;
+}
+
+.box.last .content .left {
+    margin-left: -30px;
+    margin-bottom: -32px
+}
+
+.box.doc {
+    margin-top: 70px;
+    position: relative;
+    width: 630px;
+}
+
+.box .content .warning,
+.box .content .information {
+    position: absolute;
+    right: -250px;
+    margin-top: 20px;
+    width: 200px;
+    font-size: 14px;
+    color: #222;
+    font-family: arial,helevetica,sans;
+    padding: 10px;
+    opacity: 0.7;
+    -moz-transition: opacity 0.3s;
+    -webkit-transition: opacity 0.3s;
+    -o-transition: opacity 0.3s;
+}
+
+.box .content .warning:hover,
+.box .content .information:hover {
+    opacity: 1;
+}
+
+.box .content .information:before,
+.box .content .warning:before {
+    font-family: Georgia, sans-serif;
+    font-size: 28px;
+    font-style: italic;
+    position: absolute;
+    right: 0;
+    top: -21px;
+    opacity: 0.5;
+}
+
+.box .content .information:before {
+    content: "Info";
+    color: #a6b1f3;
+}
+
+.box .content .warning:before {
+    content: "Warning";
+    color: #e869e7;
+}
+
+.box .content .information {
+    background-color: #e4e8ff;
+}    
+
+.box .content .warning {
+    background-color: #f8ccf8;
+}
+
+.box .content .code {
+	background: #565656;
+	border-radius: 10px;
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+	padding: 7px;
+}
+
+.box .content .code p {
+	color: white;
+}
+
+.box.first .content .left h2 {
+	font: 30px regular Georgia, Times, serif;
+	color: #272727;
+	margin-top: 10px;
+}
+
+.box.first .content .left ul {
+	padding-left: 10px;
+}
+
+.box.last .content .right {
+    width: 300px;
+}
+
+.doc .box.first .content .right {
+	float: right;
+	width: 230px;
+	margin-top: 20px;
+	padding: 10px;
+	background-color: #ececec;
+	border: 1px solid #e1e1e1;
+	border-radius: 10px;
+	-moz-border-radius: 10px;
+	-webkit-border-radius: 10px;
+}
+
+.doc .box.first .content .right ol, 
+.doc .box.first .content .right ol a {
+	font: 18px Georgia, Time, serif;
+	color: #03388a;
+}
+
+.doc .box.first .content .right ol {
+	padding: 0 0 7px 35px;
+}
+
+.doc .box.first .content .right ol li{
+	padding: 7px 0 7px 0; 
+}
+
+.doc .box.first .content .right ul a {
+	font: 15px Helvetica, Arial, sans;
+	color: black;
+}
+
+.doc .box.first .content .right ul li {
+	list-style-type: none;
+	padding: 2px 0 2px 0;
+}
+
+.trysmalltalk {
+    text-align: right;
+    padding: 10px;
+}
+
+.trysmalltalk textarea {
+    width: 850px;
+    height: 300px;
+    padding: 20px;
+    background-color: #eaeaea;
+    border: 1px solid #d3d3d3;
+    border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+    font: 16px monaco, courier, monospace;
+    color: 434343;
+    line-height: 1.6em;
+}
+
+.trysmalltalk button {
+    margin: 20px 0 0 5px;
+    padding: 4px;
+    background: #75aef5;
+    border: 1px solid #7caeed;
+    border-radius: 8px;
+    -moz-border-radius: 8px;
+    -webkit-border-radius: 8px;
+    color: white;
+    cursor: pointer;
+}
+
+.trysmalltalk .print-it {
+	background: #bebebe;
+	border: 1px solid #b2b2b2;
+}
+
+.trysmalltalk button:hover {
+	background: #3180e1;
+	border: 1px solid #518cd6; 
+}
+
+#counters {
+    border: 2px dashed;
+    text-align: center;
+    padding: 10px;
+    margin: 10px;
+    background: #ffffcc;
+    font-family: arial,helvetica,sans;
+}
+
+#counters h1 {
+    margin: 10px;
+    color: #333;
+}
+
+
+.trysmalltalk .print-it:hover {
+	background: #898989;
+	border: 1px solid #919293; 
+}
+
+#footer {
+	height: 160px;
+	margin: 0 auto;
+}
+
+#footer .main {
+    	border-top: 1px dashed #bbb;
+	padding-top: 10px;
+}
+
+#footer p {
+	text-align: center;
+	line-height: 1em;
+	color: #aaa;
+}
+
+#footer a {
+	color: #3faae1;
+	text-decoration: none;
+}
+
+#footer a:hover {
+	text-decoration: underline;
+}
+

+ 61 - 0
ide/syntax.css

@@ -0,0 +1,61 @@
+.highlight { background: #ffffff; }
+.highlight .c { color: #999988; font-style: italic } /* Comment */
+.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.highlight .k { font-weight: bold } /* Keyword */
+.highlight .o { font-weight: bold } /* Operator */
+.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */
+.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
+.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */
+.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
+.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
+.highlight .ge { font-style: italic } /* Generic.Emph */
+.highlight .gr { color: #aa0000 } /* Generic.Error */
+.highlight .gh { color: #999999 } /* Generic.Heading */
+.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
+.highlight .go { color: #888888 } /* Generic.Output */
+.highlight .gp { color: #555555 } /* Generic.Prompt */
+.highlight .gs { font-weight: bold } /* Generic.Strong */
+.highlight .gu { color: #aaaaaa } /* Generic.Subheading */
+.highlight .gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc { font-weight: bold } /* Keyword.Constant */
+.highlight .kd { font-weight: bold } /* Keyword.Declaration */
+.highlight .kp { font-weight: bold } /* Keyword.Pseudo */
+.highlight .kr { font-weight: bold } /* Keyword.Reserved */
+.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */
+.highlight .m { color: #009999 } /* Literal.Number */
+.highlight .s { color: #d14 } /* Literal.String */
+.highlight .na { color: #008080 } /* Name.Attribute */
+.highlight .nb { color: #0086B3 } /* Name.Builtin */
+.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */
+.highlight .no { color: #008080 } /* Name.Constant */
+.highlight .ni { color: #800080 } /* Name.Entity */
+.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */
+.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */
+.highlight .nn { color: #555555 } /* Name.Namespace */
+.highlight .nt { color: #000080 } /* Name.Tag */
+.highlight .nv { color: #008080 } /* Name.Variable */
+.highlight .ow { font-weight: bold } /* Operator.Word */
+.highlight .w { color: #bbbbbb } /* Text.Whitespace */
+.highlight .mf { color: #009999 } /* Literal.Number.Float */
+.highlight .mh { color: #009999 } /* Literal.Number.Hex */
+.highlight .mi { color: #009999 } /* Literal.Number.Integer */
+.highlight .mo { color: #009999 } /* Literal.Number.Oct */
+.highlight .sb { color: #d14 } /* Literal.String.Backtick */
+.highlight .sc { color: #d14 } /* Literal.String.Char */
+.highlight .sd { color: #d14 } /* Literal.String.Doc */
+.highlight .s2 { color: #d14 } /* Literal.String.Double */
+.highlight .se { color: #d14 } /* Literal.String.Escape */
+.highlight .sh { color: #d14 } /* Literal.String.Heredoc */
+.highlight .si { color: #d14 } /* Literal.String.Interpol */
+.highlight .sx { color: #d14 } /* Literal.String.Other */
+.highlight .sr { color: #009926 } /* Literal.String.Regex */
+.highlight .s1 { color: #d14 } /* Literal.String.Single */
+.highlight .ss { color: #990073 } /* Literal.String.Symbol */
+.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */
+.highlight .vc { color: #008080 } /* Name.Variable.Class */
+.highlight .vg { color: #008080 } /* Name.Variable.Global */
+.highlight .vi { color: #008080 } /* Name.Variable.Instance */
+.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */
+

BIN
ide/text_header.png


BIN
ide/title_container1.png


BIN
images/background_box.png


BIN
images/background_header.png


BIN
images/balloon_header.png


+ 2 - 2
js/Canvas.js

@@ -269,7 +269,7 @@ self['@root']=smalltalk.send(smalltalk.TagBrush, "_fromString_canvas_", ["div",
 return self;},
 return self;},
 source: unescape('initialize%0A%20%20%20%20super%20initialize.%0A%20%20%20%20root%20%3A%3D%20TagBrush%20fromString%3A%20%27div%27%20canvas%3A%20self%0A'),
 source: unescape('initialize%0A%20%20%20%20super%20initialize.%0A%20%20%20%20root%20%3A%3D%20TagBrush%20fromString%3A%20%27div%27%20canvas%3A%20self%0A'),
 messageSends: ["initialize", "fromString:canvas:"],
 messageSends: ["initialize", "fromString:canvas:"],
-referencedClasses: [smalltalk.TagBrush]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.HTMLCanvas);
 smalltalk.HTMLCanvas);
 
 
@@ -299,7 +299,7 @@ return smalltalk.send(smalltalk.TagBrush, "_fromString_canvas_", [aString, self]
 return self;},
 return self;},
 source: unescape('newTag%3A%20aString%0A%20%20%20%20%5ETagBrush%20fromString%3A%20aString%20canvas%3A%20self%0A'),
 source: unescape('newTag%3A%20aString%0A%20%20%20%20%5ETagBrush%20fromString%3A%20aString%20canvas%3A%20self%0A'),
 messageSends: ["fromString:canvas:"],
 messageSends: ["fromString:canvas:"],
-referencedClasses: [smalltalk.TagBrush]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.HTMLCanvas);
 smalltalk.HTMLCanvas);
 
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 10 - 10
js/Compiler.js


+ 1 - 1
js/Examples.js

@@ -277,7 +277,7 @@ self['@movingPiece']=smalltalk.send(smalltalk.TetrisPiece, "_atRandom", []);
 return self;},
 return self;},
 source: unescape('newPiece%0A%09movingPiece%20%3A%3D%20TetrisPiece%20atRandom'),
 source: unescape('newPiece%0A%09movingPiece%20%3A%3D%20TetrisPiece%20atRandom'),
 messageSends: ["atRandom"],
 messageSends: ["atRandom"],
-referencedClasses: [smalltalk.TetrisPiece]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Tetris);
 smalltalk.Tetris);
 
 

+ 33 - 20
js/IDE.js

@@ -518,13 +518,13 @@ var self=this;
 try{var lines=nil;
 try{var lines=nil;
 var startLine=nil;
 var startLine=nil;
 var endLine=nil;
 var endLine=nil;
-lines=smalltalk.send(smalltalk.send(smalltalk.send(self['@textarea'], "_asJQuery", []), "_val", []), "_tokenize_", [smalltalk.send(smalltalk.String, "_cr", [])]);
+lines=smalltalk.send(smalltalk.send(smalltalk.send(self['@textarea'], "_asJQuery", []), "_val", []), "_tokenize_", [smalltalk.send(smalltalk.String, "_lf", [])]);
 startLine=endLine=(0);
 startLine=endLine=(0);
 smalltalk.send(lines, "_do_", [(function(each){endLine=smalltalk.send(startLine, "__plus", [smalltalk.send(each, "_size", [])]);startLine=smalltalk.send(endLine, "__plus", [(1)]);return smalltalk.send(smalltalk.send(endLine, "__gt_eq", [smalltalk.send(self, "_selectionStart", [])]), "_ifTrue_", [(function(){smalltalk.send(self, "_selectionEnd_", [endLine]);return (function(){throw({name: 'stReturn', selector: '_currentLine', fn: function(){return each}})})();})]);})]);
 smalltalk.send(lines, "_do_", [(function(each){endLine=smalltalk.send(startLine, "__plus", [smalltalk.send(each, "_size", [])]);startLine=smalltalk.send(endLine, "__plus", [(1)]);return smalltalk.send(smalltalk.send(endLine, "__gt_eq", [smalltalk.send(self, "_selectionStart", [])]), "_ifTrue_", [(function(){smalltalk.send(self, "_selectionEnd_", [endLine]);return (function(){throw({name: 'stReturn', selector: '_currentLine', fn: function(){return each}})})();})]);})]);
 return self;
 return self;
 } catch(e) {if(e.name === 'stReturn' && e.selector === '_currentLine'){return e.fn()} throw(e)}},
 } catch(e) {if(e.name === 'stReturn' && e.selector === '_currentLine'){return e.fn()} throw(e)}},
-source: unescape('currentLine%0A%20%20%20%20%7C%20lines%20startLine%20endLine%7C%0A%20%20%20%20lines%20%3A%3D%20textarea%20asJQuery%20val%20tokenize%3A%20String%20cr.%0A%20%20%20%20startLine%20%3A%3D%20endLine%20%3A%3D%200.%0A%20%20%20%20lines%20do%3A%20%5B%3Aeach%20%7C%0A%09endLine%20%3A%3D%20startLine%20+%20each%20size.%0A%09startLine%20%3A%3D%20endLine%20+%201.%0A%09endLine%20%3E%3D%20self%20selectionStart%20ifTrue%3A%20%5B%0A%09%20%20%20%20self%20selectionEnd%3A%20endLine.%0A%09%20%20%20%20%5Eeach%5D%5D%0A'),
-messageSends: ["tokenize:", "val", "asJQuery", "cr", "do:", unescape("+"), "size", "ifTrue:", unescape("%3E%3D"), "selectionStart", "selectionEnd:"],
+source: unescape('currentLine%0A%20%20%20%20%7C%20lines%20startLine%20endLine%7C%0A%20%20%20%20lines%20%3A%3D%20textarea%20asJQuery%20val%20tokenize%3A%20String%20lf.%0A%20%20%20%20startLine%20%3A%3D%20endLine%20%3A%3D%200.%0A%20%20%20%20lines%20do%3A%20%5B%3Aeach%20%7C%0A%09endLine%20%3A%3D%20startLine%20+%20each%20size.%0A%09startLine%20%3A%3D%20endLine%20+%201.%0A%09endLine%20%3E%3D%20self%20selectionStart%20ifTrue%3A%20%5B%0A%09%20%20%20%20self%20selectionEnd%3A%20endLine.%0A%09%20%20%20%20%5Eeach%5D%5D%0A'),
+messageSends: ["tokenize:", "val", "asJQuery", "lf", "do:", unescape("+"), "size", "ifTrue:", unescape("%3E%3D"), "selectionStart", "selectionEnd:"],
 referencedClasses: [smalltalk.String]
 referencedClasses: [smalltalk.String]
 }),
 }),
 smalltalk.Workspace);
 smalltalk.Workspace);
@@ -961,14 +961,12 @@ category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 try{var klass=nil;
 try{var klass=nil;
-var protocols=nil;
-protocols=smalltalk.send(smalltalk.Array, "_new", []);
-smalltalk.send(self['@selectedClass'], "_ifNotNil_", [(function(){smalltalk.send(smalltalk.send(self['@selectedTab'], "__eq", ["comment"]), "_ifTrue_", [(function(){return (function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return []}})})();})]);klass=smalltalk.send(smalltalk.send(self['@selectedTab'], "__eq", ["instance"]), "_ifTrue_ifFalse_", [(function(){return self['@selectedClass'];}), (function(){return smalltalk.send(self['@selectedClass'], "_class", []);})]);smalltalk.send(smalltalk.send(smalltalk.send(klass, "_methodDictionary", []), "_isEmpty", []), "_ifTrue_", [(function(){return smalltalk.send(protocols, "_add_", ["not yet classified"]);})]);return smalltalk.send(smalltalk.send(klass, "_methodDictionary", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(protocols, "_includes_", [smalltalk.send(each, "_category", [])]), "_ifFalse_", [(function(){return smalltalk.send(protocols, "_add_", [smalltalk.send(each, "_category", [])]);})]);})]);})]);
-(function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return smalltalk.send(protocols, "_sort", [])}})})();
+smalltalk.send(self['@selectedClass'], "_ifNotNil_", [(function(){smalltalk.send(smalltalk.send(self['@selectedTab'], "__eq", ["comment"]), "_ifTrue_", [(function(){return (function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return []}})})();})]);klass=smalltalk.send(smalltalk.send(self['@selectedTab'], "__eq", ["instance"]), "_ifTrue_ifFalse_", [(function(){return self['@selectedClass'];}), (function(){return smalltalk.send(self['@selectedClass'], "_class", []);})]);smalltalk.send(smalltalk.send(smalltalk.send(klass, "_methodDictionary", []), "_isEmpty", []), "_ifTrue_", [(function(){return (function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return smalltalk.send(smalltalk.Array, "_with_", ["not yet classified"])}})})();})]);return (function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return smalltalk.send(klass, "_protocols", [])}})})();})]);
+(function(){throw({name: 'stReturn', selector: '_protocols', fn: function(){return smalltalk.send(smalltalk.Array, "_new", [])}})})();
 return self;
 return self;
 } catch(e) {if(e.name === 'stReturn' && e.selector === '_protocols'){return e.fn()} throw(e)}},
 } catch(e) {if(e.name === 'stReturn' && e.selector === '_protocols'){return e.fn()} throw(e)}},
-source: unescape('protocols%0A%20%20%20%20%7C%20klass%20protocols%20%7C%0A%20%20%20%20protocols%20%3A%3D%20Array%20new.%0A%20%20%20%20selectedClass%20ifNotNil%3A%20%5B%0A%09selectedTab%20%3D%20%23comment%20ifTrue%3A%20%5B%5E%23%28%29%5D.%0A%09klass%20%3A%3D%20selectedTab%20%3D%20%23instance%0A%09%20%20%20%20ifTrue%3A%20%5BselectedClass%5D%0A%09%20%20%20%20ifFalse%3A%20%5BselectedClass%20class%5D.%0A%09klass%20methodDictionary%20isEmpty%20ifTrue%3A%20%5B%0A%09%20%20%20%20protocols%20add%3A%20%27not%20yet%20classified%27%5D.%0A%09klass%20methodDictionary%20do%3A%20%5B%3Aeach%20%7C%0A%09%20%20%20%20%28protocols%20includes%3A%20each%20category%29%20ifFalse%3A%20%5B%0A%09%09protocols%20add%3A%20each%20category%5D%5D%5D.%0A%20%20%20%20%5Eprotocols%20sort%0A'),
-messageSends: ["new", "ifNotNil:", "ifTrue:", unescape("%3D"), "ifTrue:ifFalse:", "class", "isEmpty", "methodDictionary", "add:", "do:", "ifFalse:", "includes:", "category", "sort"],
+source: unescape('protocols%0A%20%20%20%20%7C%20klass%20%7C%0A%20%20%20%20selectedClass%20ifNotNil%3A%20%5B%0A%09selectedTab%20%3D%20%23comment%20ifTrue%3A%20%5B%5E%23%28%29%5D.%0A%09klass%20%3A%3D%20selectedTab%20%3D%20%23instance%0A%09%20%20%20%20ifTrue%3A%20%5BselectedClass%5D%0A%09%20%20%20%20ifFalse%3A%20%5BselectedClass%20class%5D.%0A%09klass%20methodDictionary%20isEmpty%20ifTrue%3A%20%5B%0A%09%20%20%20%20%5EArray%20with%3A%20%27not%20yet%20classified%27%5D.%0A%09%5Eklass%20protocols%5D.%0A%20%20%20%20%5EArray%20new'),
+messageSends: ["ifNotNil:", "ifTrue:", unescape("%3D"), "ifTrue:ifFalse:", "class", "isEmpty", "methodDictionary", "with:", "protocols", "new"],
 referencedClasses: [smalltalk.Array]
 referencedClasses: [smalltalk.Array]
 }),
 }),
 smalltalk.Browser);
 smalltalk.Browser);
@@ -1063,11 +1061,11 @@ fn: function (){
 var self=this;
 var self=this;
 var stream=nil;
 var stream=nil;
 stream=smalltalk.send("", "_writeStream", []);
 stream=smalltalk.send("", "_writeStream", []);
-smalltalk.send(self['@selectedClass'], "_ifNotNil_", [(function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(self['@selectedClass'], "_superclass", []), "_asString", [])]);smalltalk.send($rec, "_nextPutAll_", [unescape("%20subclass%3A%20%23")]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(self['@selectedClass'], "_name", [])]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.String, "_cr", []), "__comma", [smalltalk.send(smalltalk.String, "_tab", [])])]);return smalltalk.send($rec, "_nextPutAll_", [unescape("instanceVariableNames%3A%20%27")]);})(stream);smalltalk.send(smalltalk.send(self['@selectedClass'], "_instanceVariableNames", []), "_do_separatedBy_", [(function(each){return smalltalk.send(stream, "_nextPutAll_", [each]);}), (function(){return smalltalk.send(stream, "_nextPutAll_", [" "]);})]);return (function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(unescape("%27"), "__comma", [smalltalk.send(smalltalk.String, "_cr", [])]), "__comma", [smalltalk.send(smalltalk.String, "_tab", [])])]);smalltalk.send($rec, "_nextPutAll_", [unescape("category%3A%20%27")]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(self['@selectedClass'], "_category", [])]);return smalltalk.send($rec, "_nextPutAll_", [unescape("%27")]);})(stream);})]);
+smalltalk.send(self['@selectedClass'], "_ifNotNil_", [(function(){(function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(self['@selectedClass'], "_superclass", []), "_asString", [])]);smalltalk.send($rec, "_nextPutAll_", [unescape("%20subclass%3A%20%23")]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(self['@selectedClass'], "_name", [])]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(smalltalk.String, "_lf", []), "__comma", [smalltalk.send(smalltalk.String, "_tab", [])])]);return smalltalk.send($rec, "_nextPutAll_", [unescape("instanceVariableNames%3A%20%27")]);})(stream);smalltalk.send(smalltalk.send(self['@selectedClass'], "_instanceVariableNames", []), "_do_separatedBy_", [(function(each){return smalltalk.send(stream, "_nextPutAll_", [each]);}), (function(){return smalltalk.send(stream, "_nextPutAll_", [" "]);})]);return (function($rec){smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(smalltalk.send(unescape("%27"), "__comma", [smalltalk.send(smalltalk.String, "_lf", [])]), "__comma", [smalltalk.send(smalltalk.String, "_tab", [])])]);smalltalk.send($rec, "_nextPutAll_", [unescape("category%3A%20%27")]);smalltalk.send($rec, "_nextPutAll_", [smalltalk.send(self['@selectedClass'], "_category", [])]);return smalltalk.send($rec, "_nextPutAll_", [unescape("%27")]);})(stream);})]);
 return smalltalk.send(stream, "_contents", []);
 return smalltalk.send(stream, "_contents", []);
 return self;},
 return self;},
-source: unescape('classDeclarationSource%0A%20%20%20%20%7C%20stream%20%7C%0A%20%20%20%20stream%20%3A%3D%20%27%27%20writeStream.%0A%20%20%20%20selectedClass%20ifNotNil%3A%20%5B%0A%09stream%20%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20superclass%20asString%3B%0A%09%20%20%20%20nextPutAll%3A%20%27%20subclass%3A%20%23%27%3B%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20name%3B%0A%09%20%20%20%20nextPutAll%3A%20String%20cr%2C%20String%20tab%3B%0A%09%20%20%20%20nextPutAll%3A%20%27instanceVariableNames%3A%20%27%27%27.%0A%09selectedClass%20instanceVariableNames%20%0A%09%20%20%20%20do%3A%20%5B%3Aeach%20%7C%20stream%20nextPutAll%3A%20each%5D%20%0A%09%20%20%20%20separatedBy%3A%20%5Bstream%20nextPutAll%3A%20%27%20%27%5D.%0A%09stream%0A%09%20%20%20%20nextPutAll%3A%20%27%27%27%27%2C%20String%20cr%2C%20String%20tab%3B%0A%09%20%20%20%20nextPutAll%3A%20%27category%3A%20%27%27%27%3B%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20category%3B%0A%09%20%20%20%20nextPutAll%3A%20%27%27%27%27%5D.%0A%20%20%20%20%5Estream%20contents%0A'),
-messageSends: ["writeStream", "ifNotNil:", "nextPutAll:", "asString", "superclass", "name", unescape("%2C"), "cr", "tab", "do:separatedBy:", "instanceVariableNames", "category", "contents"],
+source: unescape('classDeclarationSource%0A%20%20%20%20%7C%20stream%20%7C%0A%20%20%20%20stream%20%3A%3D%20%27%27%20writeStream.%0A%20%20%20%20selectedClass%20ifNotNil%3A%20%5B%0A%09stream%20%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20superclass%20asString%3B%0A%09%20%20%20%20nextPutAll%3A%20%27%20subclass%3A%20%23%27%3B%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20name%3B%0A%09%20%20%20%20nextPutAll%3A%20String%20lf%2C%20String%20tab%3B%0A%09%20%20%20%20nextPutAll%3A%20%27instanceVariableNames%3A%20%27%27%27.%0A%09selectedClass%20instanceVariableNames%20%0A%09%20%20%20%20do%3A%20%5B%3Aeach%20%7C%20stream%20nextPutAll%3A%20each%5D%20%0A%09%20%20%20%20separatedBy%3A%20%5Bstream%20nextPutAll%3A%20%27%20%27%5D.%0A%09stream%0A%09%20%20%20%20nextPutAll%3A%20%27%27%27%27%2C%20String%20lf%2C%20String%20tab%3B%0A%09%20%20%20%20nextPutAll%3A%20%27category%3A%20%27%27%27%3B%0A%09%20%20%20%20nextPutAll%3A%20selectedClass%20category%3B%0A%09%20%20%20%20nextPutAll%3A%20%27%27%27%27%5D.%0A%20%20%20%20%5Estream%20contents%0A'),
+messageSends: ["writeStream", "ifNotNil:", "nextPutAll:", "asString", "superclass", "name", unescape("%2C"), "lf", "tab", "do:separatedBy:", "instanceVariableNames", "category", "contents"],
 referencedClasses: [smalltalk.String]
 referencedClasses: [smalltalk.String]
 }),
 }),
 smalltalk.Browser);
 smalltalk.Browser);
@@ -1299,11 +1297,11 @@ selector: 'commitCategory',
 category: 'actions',
 category: 'actions',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
-smalltalk.send(self['@selectedCategory'], "_ifNotNil_", [(function(){return (function($rec){smalltalk.send($rec, "_at_put_", ["type", "PUT"]);smalltalk.send($rec, "_at_put_", ["data", smalltalk.send(smalltalk.send(smalltalk.Exporter, "_new", []), "_exportCategory_", [self['@selectedCategory']])]);smalltalk.send($rec, "_at_put_", ["error", (function(){return smalltalk.send(self, "_alert_", [unescape("Commit%20failed%21")]);})]);return smalltalk.send($rec, "_send", []);})(smalltalk.send(smalltalk.Ajax, "_url_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "_commitPath", []), "__comma", [unescape("/")]), "__comma", [self['@selectedCategory']]), "__comma", [".js"])]));})]);
+smalltalk.send(self['@selectedCategory'], "_ifNotNil_", [(function(){(function($rec){smalltalk.send($rec, "_at_put_", ["type", "PUT"]);smalltalk.send($rec, "_at_put_", ["data", smalltalk.send(smalltalk.send(smalltalk.Exporter, "_new", []), "_exportCategory_", [self['@selectedCategory']])]);smalltalk.send($rec, "_at_put_", ["error", (function(){return smalltalk.send(self, "_alert_", [unescape("Commit%20failed%21")]);})]);return smalltalk.send($rec, "_send", []);})(smalltalk.send(smalltalk.Ajax, "_url_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "_commitPathJs", []), "__comma", [unescape("/")]), "__comma", [self['@selectedCategory']]), "__comma", [".js"])]));return (function($rec){smalltalk.send($rec, "_at_put_", ["type", "PUT"]);smalltalk.send($rec, "_at_put_", ["data", smalltalk.send(smalltalk.send(smalltalk.ChunkExporter, "_new", []), "_exportCategory_", [self['@selectedCategory']])]);smalltalk.send($rec, "_at_put_", ["error", (function(){return smalltalk.send(self, "_alert_", [unescape("Commit%20failed%21")]);})]);return smalltalk.send($rec, "_send", []);})(smalltalk.send(smalltalk.Ajax, "_url_", [smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(self, "_class", []), "_commitPathSt", []), "__comma", [unescape("/")]), "__comma", [self['@selectedCategory']]), "__comma", [".st"])]));})]);
 return self;},
 return self;},
-source: unescape('commitCategory%0A%20%20%20%20selectedCategory%20ifNotNil%3A%20%5B%0A%09%28Ajax%20url%3A%20self%20class%20commitPath%2C%20%27/%27%2C%20selectedCategory%2C%20%27.js%27%29%0A%09%20%20%20%20at%3A%20%27type%27%20put%3A%20%27PUT%27%3B%0A%09%20%20%20%20at%3A%20%27data%27%20put%3A%20%28Exporter%20new%20exportCategory%3A%20selectedCategory%29%3B%0A%09%20%20%20%20at%3A%20%27error%27%20put%3A%20%5Bself%20alert%3A%20%27Commit%20failed%21%27%5D%3B%0A%09%20%20%20%20send%5D%0A'),
-messageSends: ["ifNotNil:", "at:put:", "exportCategory:", "new", "alert:", "send", "url:", unescape("%2C"), "commitPath", "class"],
-referencedClasses: [smalltalk.Exporter,smalltalk.Ajax]
+source: unescape('commitCategory%0A%20%20%20%20selectedCategory%20ifNotNil%3A%20%5B%0A%09%28Ajax%20url%3A%20self%20class%20commitPathJs%2C%20%27/%27%2C%20selectedCategory%2C%20%27.js%27%29%0A%09%20%20%20%20at%3A%20%27type%27%20put%3A%20%27PUT%27%3B%0A%09%20%20%20%20at%3A%20%27data%27%20put%3A%20%28Exporter%20new%20exportCategory%3A%20selectedCategory%29%3B%0A%09%20%20%20%20at%3A%20%27error%27%20put%3A%20%5Bself%20alert%3A%20%27Commit%20failed%21%27%5D%3B%0A%09%20%20%20%20send.%0A%09%28Ajax%20url%3A%20self%20class%20commitPathSt%2C%20%27/%27%2C%20selectedCategory%2C%20%27.st%27%29%0A%09%20%20%20%20at%3A%20%27type%27%20put%3A%20%27PUT%27%3B%0A%09%20%20%20%20at%3A%20%27data%27%20put%3A%20%28ChunkExporter%20new%20exportCategory%3A%20selectedCategory%29%3B%0A%09%20%20%20%20at%3A%20%27error%27%20put%3A%20%5Bself%20alert%3A%20%27Commit%20failed%21%27%5D%3B%0A%09%20%20%20%20send%5D%0A'),
+messageSends: ["ifNotNil:", "at:put:", "exportCategory:", "new", "alert:", "send", "url:", unescape("%2C"), "commitPathJs", "class", "commitPathSt"],
+referencedClasses: [smalltalk.Exporter,smalltalk.Ajax,smalltalk.ChunkExporter]
 }),
 }),
 smalltalk.Browser);
 smalltalk.Browser);
 
 
@@ -1713,7 +1711,7 @@ smalltalk.send(smalltalk.ReferencesBrowser, "_search_", [smalltalk.send(self['@s
 return self;},
 return self;},
 source: unescape('searchClassReferences%0A%09ReferencesBrowser%20search%3A%20selectedClass%20name'),
 source: unescape('searchClassReferences%0A%09ReferencesBrowser%20search%3A%20selectedClass%20name'),
 messageSends: ["search:", "name"],
 messageSends: ["search:", "name"],
-referencedClasses: [smalltalk.ReferencesBrowser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Browser);
 smalltalk.Browser);
 
 
@@ -1749,15 +1747,30 @@ referencedClasses: []
 smalltalk.Browser.klass);
 smalltalk.Browser.klass);
 
 
 smalltalk.addMethod(
 smalltalk.addMethod(
-'_commitPath',
+'_commitPathJs',
 smalltalk.method({
 smalltalk.method({
-selector: 'commitPath',
+selector: 'commitPathJs',
 category: 'accessing',
 category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
 return "js";
 return "js";
 return self;},
 return self;},
-source: unescape('commitPath%0A%09%5E%27js%27'),
+source: unescape('commitPathJs%0A%09%5E%27js%27'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Browser.klass);
+
+smalltalk.addMethod(
+'_commitPathSt',
+smalltalk.method({
+selector: 'commitPathSt',
+category: 'accessing',
+fn: function (){
+var self=this;
+return "st";
+return self;},
+source: unescape('commitPathSt%0A%09%5E%27st%27'),
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),

+ 0 - 0
js/JQuery.js


+ 100 - 22
js/Kernel.js

@@ -176,7 +176,7 @@ return smalltalk.send(smalltalk.Association, "_key_value_", [self, anObject]);
 return self;},
 return self;},
 source: unescape('-%3E%20anObject%0A%09%5EAssociation%20key%3A%20self%20value%3A%20anObject%0A'),
 source: unescape('-%3E%20anObject%0A%09%5EAssociation%20key%3A%20self%20value%3A%20anObject%0A'),
 messageSends: ["key:value:"],
 messageSends: ["key:value:"],
-referencedClasses: [smalltalk.Association]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Object);
 smalltalk.Object);
 
 
@@ -655,7 +655,7 @@ var self=this;
 return self;},
 return self;},
 source: unescape('doesNotUnderstand%3A%20aMessage%0A%09MessageNotUnderstood%20new%0A%09%09receiver%3A%20self%3B%0A%09%09message%3A%20aMessage%3B%0A%09%09signal'),
 source: unescape('doesNotUnderstand%3A%20aMessage%0A%09MessageNotUnderstood%20new%0A%09%09receiver%3A%20self%3B%0A%09%09message%3A%20aMessage%3B%0A%09%09signal'),
 messageSends: ["receiver:", "message:", "signal", "new"],
 messageSends: ["receiver:", "message:", "signal", "new"],
-referencedClasses: [smalltalk.MessageNotUnderstood]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Object);
 smalltalk.Object);
 
 
@@ -960,7 +960,7 @@ return (function($rec){smalltalk.send($rec, "_class_category_", [self, aString])
 return self;},
 return self;},
 source: unescape('methodsFor%3A%20aString%0A%09%5EClassCategoryReader%20new%0A%09%20%20%20%20class%3A%20self%20category%3A%20aString%3B%0A%09%20%20%20%20yourself%0A'),
 source: unescape('methodsFor%3A%20aString%0A%09%5EClassCategoryReader%20new%0A%09%20%20%20%20class%3A%20self%20category%3A%20aString%3B%0A%09%20%20%20%20yourself%0A'),
 messageSends: ["class:category:", "yourself", "new"],
 messageSends: ["class:category:", "yourself", "new"],
-referencedClasses: [smalltalk.ClassCategoryReader]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Behavior);
 smalltalk.Behavior);
 
 
@@ -1037,7 +1037,7 @@ return (function($rec){smalltalk.send($rec, "_class_", [self]);return smalltalk.
 return self;},
 return self;},
 source: unescape('commentStamp%0A%20%20%20%20%5EClassCommentReader%20new%0A%09class%3A%20self%3B%0A%09yourself%0A'),
 source: unescape('commentStamp%0A%20%20%20%20%5EClassCommentReader%20new%0A%09class%3A%20self%3B%0A%09yourself%0A'),
 messageSends: ["class:", "yourself", "new"],
 messageSends: ["class:", "yourself", "new"],
-referencedClasses: [smalltalk.ClassCommentReader]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Behavior);
 smalltalk.Behavior);
 
 
@@ -1072,6 +1072,24 @@ referencedClasses: []
 }),
 }),
 smalltalk.Behavior);
 smalltalk.Behavior);
 
 
+smalltalk.addMethod(
+'_protocols',
+smalltalk.method({
+selector: 'protocols',
+category: 'accessing',
+fn: function (){
+var self=this;
+var protocols=nil;
+protocols=smalltalk.send(smalltalk.Array, "_new", []);
+smalltalk.send(smalltalk.send(self, "_methodDictionary", []), "_do_", [(function(each){return smalltalk.send(smalltalk.send(protocols, "_includes_", [smalltalk.send(each, "_category", [])]), "_ifFalse_", [(function(){return smalltalk.send(protocols, "_add_", [smalltalk.send(each, "_category", [])]);})]);})]);
+return smalltalk.send(protocols, "_sort", []);
+return self;},
+source: unescape('protocols%0A%20%20%20%20%7C%20protocols%20%7C%0A%20%20%20%20protocols%20%3A%3D%20Array%20new.%0A%20%20%20%20self%20methodDictionary%20do%3A%20%5B%3Aeach%20%7C%0A%09%20%20%20%20%28protocols%20includes%3A%20each%20category%29%20ifFalse%3A%20%5B%0A%09%09protocols%20add%3A%20each%20category%5D%5D.%0A%20%20%20%20%5Eprotocols%20sort'),
+messageSends: ["new", "do:", "methodDictionary", "ifFalse:", "includes:", "category", "add:", "sort"],
+referencedClasses: [smalltalk.Array]
+}),
+smalltalk.Behavior);
+
 
 
 
 
 smalltalk.addClass('Class', smalltalk.Behavior, [], 'Kernel');
 smalltalk.addClass('Class', smalltalk.Behavior, [], 'Kernel');
@@ -1131,7 +1149,7 @@ return smalltalk.send(smalltalk.send(smalltalk.ClassBuilder, "_new", []), "_supe
 return self;},
 return self;},
 source: unescape('subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A%09%5EClassBuilder%20new%0A%09%20%20%20%20superclass%3A%20self%20subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A'),
 source: unescape('subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A%09%5EClassBuilder%20new%0A%09%20%20%20%20superclass%3A%20self%20subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A'),
 messageSends: ["superclass:subclass:instanceVariableNames:category:", "new"],
 messageSends: ["superclass:subclass:instanceVariableNames:category:", "new"],
-referencedClasses: [smalltalk.ClassBuilder]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Class);
 smalltalk.Class);
 
 
@@ -1213,7 +1231,7 @@ smalltalk.send(smalltalk.send(smalltalk.ClassBuilder, "_new", []), "_class_insta
 return self;},
 return self;},
 source: unescape('instanceVariableNames%3A%20aCollection%0A%09ClassBuilder%20new%0A%09%20%20%20%20class%3A%20self%20instanceVariableNames%3A%20aCollection%0A'),
 source: unescape('instanceVariableNames%3A%20aCollection%0A%09ClassBuilder%20new%0A%09%20%20%20%20class%3A%20self%20instanceVariableNames%3A%20aCollection%0A'),
 messageSends: ["class:instanceVariableNames:", "new"],
 messageSends: ["class:instanceVariableNames:", "new"],
-referencedClasses: [smalltalk.ClassBuilder]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Metaclass);
 smalltalk.Metaclass);
 
 
@@ -1743,7 +1761,7 @@ return smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.send(smalltalk.sen
 return self;},
 return self;},
 source: unescape('atRandom%0A%20%20%20%20%5E%28Random%20new%20next%20*%20self%29%20truncated%20+%201%0A'),
 source: unescape('atRandom%0A%20%20%20%20%5E%28Random%20new%20next%20*%20self%29%20truncated%20+%201%0A'),
 messageSends: [unescape("+"), "truncated", unescape("*"), "next", "new"],
 messageSends: [unescape("+"), "truncated", unescape("*"), "next", "new"],
-referencedClasses: [smalltalk.Random]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Number);
 smalltalk.Number);
 
 
@@ -1758,7 +1776,7 @@ return smalltalk.send(smalltalk.Point, "_x_y_", [self, aNumber]);
 return self;},
 return self;},
 source: unescape('@%20aNumber%0A%09%5EPoint%20x%3A%20self%20y%3A%20aNumber'),
 source: unescape('@%20aNumber%0A%09%5EPoint%20x%3A%20self%20y%3A%20aNumber'),
 messageSends: ["x:y:"],
 messageSends: ["x:y:"],
-referencedClasses: [smalltalk.Point]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Number);
 smalltalk.Number);
 
 
@@ -1773,7 +1791,7 @@ return smalltalk.send(smalltalk.Point, "_x_y_", [self, self]);
 return self;},
 return self;},
 source: unescape('asPoint%0A%09%5EPoint%20x%3A%20self%20y%3A%20self'),
 source: unescape('asPoint%0A%09%5EPoint%20x%3A%20self%20y%3A%20self'),
 messageSends: ["x:y:"],
 messageSends: ["x:y:"],
-referencedClasses: [smalltalk.Point]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Number);
 smalltalk.Number);
 
 
@@ -2845,7 +2863,7 @@ return smalltalk.send(smalltalk.send(smalltalk.ClassBuilder, "_new", []), "_supe
 return self;},
 return self;},
 source: unescape('subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A%09%5EClassBuilder%20new%0A%09%20%20%20%20superclass%3A%20self%20subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A'),
 source: unescape('subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A%09%5EClassBuilder%20new%0A%09%20%20%20%20superclass%3A%20self%20subclass%3A%20aString%20instanceVariableNames%3A%20aString2%20category%3A%20aString3%0A'),
 messageSends: ["superclass:subclass:instanceVariableNames:category:", "new"],
 messageSends: ["superclass:subclass:instanceVariableNames:category:", "new"],
-referencedClasses: [smalltalk.ClassBuilder]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.UndefinedObject);
 smalltalk.UndefinedObject);
 
 
@@ -3402,7 +3420,7 @@ return smalltalk.Stream;
 return self;},
 return self;},
 source: unescape('streamClass%0A%09%20%20%20%20%5EStream%0A'),
 source: unescape('streamClass%0A%09%20%20%20%20%5EStream%0A'),
 messageSends: [],
 messageSends: [],
-referencedClasses: [smalltalk.Stream]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.Collection.klass);
 smalltalk.Collection.klass);
 
 
@@ -4043,7 +4061,7 @@ return smalltalk.send(smalltalk.send(smalltalk.PPStringParser, "_new", []), "_st
 return self;},
 return self;},
 source: unescape('asParser%0A%20%20%20%20%09%5EPPStringParser%20new%20string%3A%20self%0A'),
 source: unescape('asParser%0A%20%20%20%20%09%5EPPStringParser%20new%20string%3A%20self%0A'),
 messageSends: ["string:", "new"],
 messageSends: ["string:", "new"],
-referencedClasses: [smalltalk.PPStringParser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.String);
 smalltalk.String);
 
 
@@ -4058,7 +4076,7 @@ return smalltalk.send(smalltalk.PPChoiceParser, "_withAll_", [smalltalk.send(sma
 return self;},
 return self;},
 source: unescape('asChoiceParser%0A%20%20%20%20%09%5EPPChoiceParser%20withAll%3A%20%28self%20asArray%20collect%3A%20%5B%3Aeach%20%7C%20each%20asParser%5D%29%0A'),
 source: unescape('asChoiceParser%0A%20%20%20%20%09%5EPPChoiceParser%20withAll%3A%20%28self%20asArray%20collect%3A%20%5B%3Aeach%20%7C%20each%20asParser%5D%29%0A'),
 messageSends: ["withAll:", "collect:", "asArray", "asParser"],
 messageSends: ["withAll:", "collect:", "asArray", "asParser"],
-referencedClasses: [smalltalk.PPChoiceParser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.String);
 smalltalk.String);
 
 
@@ -4073,7 +4091,7 @@ return smalltalk.send(smalltalk.send(smalltalk.PPCharacterParser, "_new", []), "
 return self;},
 return self;},
 source: unescape('asCharacterParser%0A%20%20%20%20%09%5EPPCharacterParser%20new%20string%3A%20self%0A'),
 source: unescape('asCharacterParser%0A%20%20%20%20%09%5EPPCharacterParser%20new%20string%3A%20self%0A'),
 messageSends: ["string:", "new"],
 messageSends: ["string:", "new"],
-referencedClasses: [smalltalk.PPCharacterParser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.String);
 smalltalk.String);
 
 
@@ -4239,7 +4257,7 @@ return smalltalk.StringStream;
 return self;},
 return self;},
 source: unescape('streamClass%0A%09%20%20%20%20%5EStringStream%0A'),
 source: unescape('streamClass%0A%09%20%20%20%20%5EStringStream%0A'),
 messageSends: [],
 messageSends: [],
-referencedClasses: [smalltalk.StringStream]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.String.klass);
 smalltalk.String.klass);
 
 
@@ -4265,9 +4283,9 @@ selector: 'cr',
 category: 'accessing',
 category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
-return '\n';;
+return '\r';;
 return self;},
 return self;},
-source: unescape('cr%0A%09%7B%27return%20%27%27%5Cn%27%27%3B%27%7D'),
+source: unescape('cr%0A%09%7B%27return%20%27%27%5Cr%27%27%3B%27%7D'),
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -4280,9 +4298,9 @@ selector: 'lf',
 category: 'accessing',
 category: 'accessing',
 fn: function (){
 fn: function (){
 var self=this;
 var self=this;
-return '\r';;
+return '\n';;
 return self;},
 return self;},
-source: unescape('lf%0A%09%7B%27return%20%27%27%5Cr%27%27%3B%27%7D%0A'),
+source: unescape('lf%0A%09%7B%27return%20%27%27%5Cn%27%27%3B%27%7D%0A'),
 messageSends: [],
 messageSends: [],
 referencedClasses: []
 referencedClasses: []
 }),
 }),
@@ -4318,6 +4336,21 @@ referencedClasses: []
 }),
 }),
 smalltalk.String.klass);
 smalltalk.String.klass);
 
 
+smalltalk.addMethod(
+'_crlf',
+smalltalk.method({
+selector: 'crlf',
+category: 'accessing',
+fn: function (){
+var self=this;
+return '\r\n';;
+return self;},
+source: unescape('crlf%0A%09%7B%27return%20%27%27%5Cr%5Cn%27%27%3B%27%7D%0A'),
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.String.klass);
+
 
 
 smalltalk.addClass('Array', smalltalk.SequenceableCollection, [], 'Kernel');
 smalltalk.addClass('Array', smalltalk.SequenceableCollection, [], 'Kernel');
 smalltalk.addMethod(
 smalltalk.addMethod(
@@ -5364,7 +5397,7 @@ self['@chunkParser']=smalltalk.send(smalltalk.ChunkParser, "_new", []);
 return self;},
 return self;},
 source: unescape('initialize%0A%09super%20initialize.%0A%09chunkParser%20%3A%3D%20ChunkParser%20new.%0A'),
 source: unescape('initialize%0A%09super%20initialize.%0A%09chunkParser%20%3A%3D%20ChunkParser%20new.%0A'),
 messageSends: ["initialize", "new"],
 messageSends: ["initialize", "new"],
-referencedClasses: [smalltalk.ChunkParser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.ClassCategoryReader);
 smalltalk.ClassCategoryReader);
 
 
@@ -5415,7 +5448,7 @@ smalltalk.send(self['@class'], "_addCompiledMethod_", [method]);
 return self;},
 return self;},
 source: unescape('compileMethod%3A%20aString%0A%09%7C%20method%20%7C%0A%09method%20%3A%3D%20Compiler%20new%20load%3A%20aString%20forClass%3A%20class.%0A%09method%20category%3A%20category.%0A%09class%20addCompiledMethod%3A%20method%0A'),
 source: unescape('compileMethod%3A%20aString%0A%09%7C%20method%20%7C%0A%09method%20%3A%3D%20Compiler%20new%20load%3A%20aString%20forClass%3A%20class.%0A%09method%20category%3A%20category.%0A%09class%20addCompiledMethod%3A%20method%0A'),
 messageSends: ["load:forClass:", "new", "category:", "addCompiledMethod:"],
 messageSends: ["load:forClass:", "new", "category:", "addCompiledMethod:"],
-referencedClasses: [smalltalk.Compiler]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.ClassCategoryReader);
 smalltalk.ClassCategoryReader);
 
 
@@ -5842,6 +5875,51 @@ referencedClasses: []
 }),
 }),
 smalltalk.StringStream);
 smalltalk.StringStream);
 
 
+smalltalk.addMethod(
+'_cr',
+smalltalk.method({
+selector: 'cr',
+category: 'writing',
+fn: function (){
+var self=this;
+return smalltalk.send(self, "_nextPutAll_", [smalltalk.send(smalltalk.String, "_cr", [])]);
+return self;},
+source: unescape('cr%0A%09%5Eself%20nextPutAll%3A%20String%20cr'),
+messageSends: ["nextPutAll:", "cr"],
+referencedClasses: [smalltalk.String]
+}),
+smalltalk.StringStream);
+
+smalltalk.addMethod(
+'_crlf',
+smalltalk.method({
+selector: 'crlf',
+category: 'writing',
+fn: function (){
+var self=this;
+return smalltalk.send(self, "_nextPutAll_", [smalltalk.send(smalltalk.String, "_crlf", [])]);
+return self;},
+source: unescape('crlf%0A%09%5Eself%20nextPutAll%3A%20String%20crlf'),
+messageSends: ["nextPutAll:", "crlf"],
+referencedClasses: [smalltalk.String]
+}),
+smalltalk.StringStream);
+
+smalltalk.addMethod(
+'_lf',
+smalltalk.method({
+selector: 'lf',
+category: 'writing',
+fn: function (){
+var self=this;
+return smalltalk.send(self, "_nextPutAll_", [smalltalk.send(smalltalk.String, "_lf", [])]);
+return self;},
+source: unescape('lf%0A%09%5Eself%20nextPutAll%3A%20String%20lf'),
+messageSends: ["nextPutAll:", "lf"],
+referencedClasses: [smalltalk.String]
+}),
+smalltalk.StringStream);
+
 
 
 
 
 smalltalk.addClass('ClassCommentReader', smalltalk.Object, ['class', 'chunkParser'], 'Kernel');
 smalltalk.addClass('ClassCommentReader', smalltalk.Object, ['class', 'chunkParser'], 'Kernel');
@@ -5889,7 +5967,7 @@ self['@chunkParser']=smalltalk.send(smalltalk.ChunkParser, "_new", []);
 return self;},
 return self;},
 source: unescape('initialize%0A%09super%20initialize.%0A%09chunkParser%20%3A%3D%20ChunkParser%20new.%0A'),
 source: unescape('initialize%0A%09super%20initialize.%0A%09chunkParser%20%3A%3D%20ChunkParser%20new.%0A'),
 messageSends: ["initialize", "new"],
 messageSends: ["initialize", "new"],
-referencedClasses: [smalltalk.ChunkParser]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.ClassCommentReader);
 smalltalk.ClassCommentReader);
 
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 15 - 15
js/Parser.js


+ 4 - 4
js/SUnit.js

@@ -130,7 +130,7 @@ var self=this;
 return self;},
 return self;},
 source: unescape('signalFailure%3A%20aString%0A%09TestFailure%20new%0A%09%09messageText%3A%20aString%3B%0A%09%09signal'),
 source: unescape('signalFailure%3A%20aString%0A%09TestFailure%20new%0A%09%09messageText%3A%20aString%3B%0A%09%09signal'),
 messageSends: ["messageText:", "signal", "new"],
 messageSends: ["messageText:", "signal", "new"],
-referencedClasses: [smalltalk.TestFailure]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.TestCase);
 smalltalk.TestCase);
 
 
@@ -162,7 +162,7 @@ smalltalk.send(smalltalk.send(self, "_methods", []), "_do_", [(function(each){sm
 return self;},
 return self;},
 source: unescape('performTestFor%3A%20aResult%0A%09self%20methods%20do%3A%20%5B%3Aeach%20%7C%20%0A%09%09%5B%5Bself%20perform%3A%20each%5D%0A%09%09%09on%3A%20TestFailure%20do%3A%20%5B%3Aex%20%7C%20aResult%20addFailure%3A%20self%20class%20name%2C%20%27%3E%3E%27%2C%20each%5D%5D%0A%09%09%09on%3A%20Error%20do%3A%20%5B%3Aex%20%7C%20aResult%20addError%3A%20self%20class%20name%2C%20%27%3E%3E%27%2C%20each%5D.%0A%09%09aResult%20increaseRuns%5D'),
 source: unescape('performTestFor%3A%20aResult%0A%09self%20methods%20do%3A%20%5B%3Aeach%20%7C%20%0A%09%09%5B%5Bself%20perform%3A%20each%5D%0A%09%09%09on%3A%20TestFailure%20do%3A%20%5B%3Aex%20%7C%20aResult%20addFailure%3A%20self%20class%20name%2C%20%27%3E%3E%27%2C%20each%5D%5D%0A%09%09%09on%3A%20Error%20do%3A%20%5B%3Aex%20%7C%20aResult%20addError%3A%20self%20class%20name%2C%20%27%3E%3E%27%2C%20each%5D.%0A%09%09aResult%20increaseRuns%5D'),
 messageSends: ["do:", "methods", "on:do:", "perform:", "addFailure:", unescape("%2C"), "name", "class", "addError:", "increaseRuns"],
 messageSends: ["do:", "methods", "on:do:", "perform:", "addFailure:", unescape("%2C"), "name", "class", "addError:", "increaseRuns"],
-referencedClasses: [smalltalk.TestFailure,smalltalk.Error]
+referencedClasses: [smalltalk.nil,smalltalk.Error]
 }),
 }),
 smalltalk.TestCase);
 smalltalk.TestCase);
 
 
@@ -595,7 +595,7 @@ smalltalk.send(aCollection, "_do_", [(function(each){return smalltalk.send((func
 return self;},
 return self;},
 source: unescape('run%3A%20aCollection%0A%09result%20%3A%3D%20TestResult%20new.%0A%09self%20%0A%09%09updateStatusDiv%3B%0A%09%09updateMethodsList.%0A%09self%20progressBar%20updatePercent%3A%200.%0A%09result%20total%3A%20%28aCollection%20inject%3A%200%20into%3A%20%5B%3Aacc%20%3Aeach%20%7C%20acc%20+%20each%20methods%20size%5D%29.%0A%09aCollection%20do%3A%20%5B%3Aeach%20%7C%20%0A%09%09%5Beach%20runCaseFor%3A%20result.%0A%09%09self%20progressBar%20updatePercent%3A%20result%20runs%20/%20result%20total%20*%20100.%0A%09%09self%20updateStatusDiv.%0A%09%09self%20updateMethodsList%5D%20valueWithTimeout%3A%20100%5D.'),
 source: unescape('run%3A%20aCollection%0A%09result%20%3A%3D%20TestResult%20new.%0A%09self%20%0A%09%09updateStatusDiv%3B%0A%09%09updateMethodsList.%0A%09self%20progressBar%20updatePercent%3A%200.%0A%09result%20total%3A%20%28aCollection%20inject%3A%200%20into%3A%20%5B%3Aacc%20%3Aeach%20%7C%20acc%20+%20each%20methods%20size%5D%29.%0A%09aCollection%20do%3A%20%5B%3Aeach%20%7C%20%0A%09%09%5Beach%20runCaseFor%3A%20result.%0A%09%09self%20progressBar%20updatePercent%3A%20result%20runs%20/%20result%20total%20*%20100.%0A%09%09self%20updateStatusDiv.%0A%09%09self%20updateMethodsList%5D%20valueWithTimeout%3A%20100%5D.'),
 messageSends: ["new", "updateStatusDiv", "updateMethodsList", "updatePercent:", "progressBar", "total:", "inject:into:", unescape("+"), "size", "methods", "do:", "valueWithTimeout:", "runCaseFor:", unescape("*"), unescape("/"), "runs", "total"],
 messageSends: ["new", "updateStatusDiv", "updateMethodsList", "updatePercent:", "progressBar", "total:", "inject:into:", unescape("+"), "size", "methods", "do:", "valueWithTimeout:", "runCaseFor:", unescape("*"), unescape("/"), "runs", "total"],
-referencedClasses: [smalltalk.TestResult]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.TestRunner);
 smalltalk.TestRunner);
 
 
@@ -690,7 +690,7 @@ self['@result']=smalltalk.send(smalltalk.TestResult, "_new", []);
 return self;},
 return self;},
 source: unescape('initialize%0A%09super%20initialize.%0A%09result%20%3A%3D%20TestResult%20new'),
 source: unescape('initialize%0A%09super%20initialize.%0A%09result%20%3A%3D%20TestResult%20new'),
 messageSends: ["initialize", "new"],
 messageSends: ["initialize", "new"],
-referencedClasses: [smalltalk.TestResult]
+referencedClasses: [smalltalk.nil]
 }),
 }),
 smalltalk.TestRunner);
 smalltalk.TestRunner);
 
 

+ 0 - 0
js/boot.js


+ 0 - 0
js/init.js


+ 0 - 0
js/jquery-1.4.4.min.js


+ 0 - 0
js/jquery-ui-1.8.9.custom.min.js


+ 0 - 0
js/jquery.textarea.js


+ 0 - 0
js/jtalk.deploy.js


+ 0 - 0
js/jtalk.js


+ 215 - 66
st/canvas.st → st/Canvas.st

@@ -1,15 +1,103 @@
+Object subclass: #CanvasRenderingContext
+	instanceVariableNames: ''
+	category: 'Canvas'!
+
+!CanvasRenderingContext methodsFor: 'drawing arcs'!
+
+arcTo: aPoint radius: aNumber startAngle: aNumber2 endAngle: aNumber3 anticlockwise: aBoolean
+	{'self.arc(aPoint._x(), aPoint._y(), aNumber, aNumber2, aNumber3, aBoolean)'} 
+!
+
+arcTo: aPoint radius: aNumber
+	self arcTo: aPoint radius: aNumber startAngle: 0 endAngle: Number pi * 2 anticlockwise: false
+! !
+
+!CanvasRenderingContext methodsFor: 'drawing paths'!
+
+fillStyle: aString
+	{'self.fillStyle = String(aString)'}
+!
+
+beginPath
+	{'self.beginPath()'}
+!
+
+closePath
+	{'self.closePath()'}
+!
+
+fill
+	{'self.fill()'}
+!
+
+stroke
+	{'self.stroke()'}
+!
+
+moveTo: aPoint
+	{'self.moveTo(aPoint._x(), aPoint._y())'}
+!
+
+lineTo: aPoint
+	{'self.lineTo(aPoint._x(), aPoint._y())'}
+!
+
+strokeStyle: aString
+	{'self.strokeStyle = String(aString)'}
+!
+
+lineWidth: aNumber
+	{'self.lineWidth = aNumber'}
+! !
+
+!CanvasRenderingContext methodsFor: 'drawing rectangles'!
+
+fillRectFrom: aPoint to: anotherPoint
+	{'self.fillRect(aPoint._x(), aPoint._y(), anotherPoint._x(), anotherPoint._y())'}
+!
+
+strokeRectFrom: aPoint to: anotherPoint
+	{'self.strokeRect(aPoint._x(), aPoint._y(), anotherPoint._x(), anotherPoint._y())'}
+!
+
+clearRectFrom: aPoint to: anotherPoint
+	{'self.fillRect(aPoint._x(), aPoint._y(), anotherPoint._x(), anotherPoint._y())'}
+! !
+
+!CanvasRenderingContext class methodsFor: 'instance creation'!
+
+tagBrush: aTagBrush
+	{'return aTagBrush._element().getContext(''2d'')'}
+! !
+
 Object subclass: #HTMLCanvas
 Object subclass: #HTMLCanvas
 	instanceVariableNames: 'root'
 	instanceVariableNames: 'root'
 	category: 'Canvas'!
 	category: 'Canvas'!
 
 
+!HTMLCanvas methodsFor: '*JQuery'!
+
+appendToJQuery: aJQuery
+    aJQuery appendElement: root element
+
+! !
+
 !HTMLCanvas methodsFor: 'accessing'!
 !HTMLCanvas methodsFor: 'accessing'!
 
 
 root: aTagBrush
 root: aTagBrush
     root := aTagBrush
     root := aTagBrush
+
 !
 !
 
 
 root
 root
     ^root
     ^root
+
+! !
+
+!HTMLCanvas methodsFor: 'adding'!
+
+with: anObject
+    ^self root with: anObject
+
 ! !
 ! !
 
 
 !HTMLCanvas methodsFor: 'initialization'!
 !HTMLCanvas methodsFor: 'initialization'!
@@ -17,138 +105,155 @@ root
 initialize
 initialize
     super initialize.
     super initialize.
     root := TagBrush fromString: 'div' canvas: self
     root := TagBrush fromString: 'div' canvas: self
-! !
 
 
-!HTMLCanvas methodsFor: 'adding'!
-
-with: anObject
-    ^self root with: anObject
 ! !
 ! !
 
 
 !HTMLCanvas methodsFor: 'tags'!
 !HTMLCanvas methodsFor: 'tags'!
 
 
 newTag: aString
 newTag: aString
     ^TagBrush fromString: aString canvas: self
     ^TagBrush fromString: aString canvas: self
+
 !
 !
 
 
 tag: aString
 tag: aString
     ^root addBrush: (self newTag: aString)
     ^root addBrush: (self newTag: aString)
+
 !
 !
 
 
 h1
 h1
     ^self tag: 'h1'
     ^self tag: 'h1'
+
 !
 !
 
 
 h2
 h2
     ^self tag: 'h2'
     ^self tag: 'h2'
+
 !
 !
 
 
 h3
 h3
     ^self tag: 'h3'
     ^self tag: 'h3'
+
 !
 !
 
 
 h4
 h4
     ^self tag: 'h4'
     ^self tag: 'h4'
+
 !
 !
 
 
 h5
 h5
     ^self tag: 'h5'
     ^self tag: 'h5'
+
 !
 !
 
 
 h6
 h6
     ^self tag: 'h6'
     ^self tag: 'h6'
+
 !
 !
 
 
 p
 p
     ^self tag: 'p'
     ^self tag: 'p'
+
 !
 !
 
 
 div
 div
     ^self tag: 'div'
     ^self tag: 'div'
+
 !
 !
 
 
 span
 span
     ^self tag: 'span'
     ^self tag: 'span'
+
 !
 !
 
 
 img
 img
     ^self tag: 'img'
     ^self tag: 'img'
+
 !
 !
 
 
 ul
 ul
     ^self tag: 'ul'
     ^self tag: 'ul'
+
 !
 !
 
 
 ol
 ol
     ^self tag: 'ol'
     ^self tag: 'ol'
+
 !
 !
 
 
 li
 li
     ^self tag: 'li'
     ^self tag: 'li'
+
 !
 !
 
 
 table
 table
     ^self tag: 'table'
     ^self tag: 'table'
+
 !
 !
 
 
 tr
 tr
     ^self tag: 'tr'
     ^self tag: 'tr'
+
 !
 !
 
 
 td 
 td 
     ^self tag: 'td'
     ^self tag: 'td'
+
 !
 !
 
 
 th
 th
     ^self tag: 'th'
     ^self tag: 'th'
+
 !
 !
 
 
 form
 form
     ^self tag: 'form'
     ^self tag: 'form'
+
 !
 !
 
 
 input
 input
     ^self tag: 'input'
     ^self tag: 'input'
+
 !
 !
 
 
 button
 button
     ^self tag: 'button'
     ^self tag: 'button'
+
 !
 !
 
 
 select
 select
     ^self tag: 'select'
     ^self tag: 'select'
+
 !
 !
 
 
 option
 option
     ^self tag: 'option'
     ^self tag: 'option'
+
 !
 !
 
 
 textarea
 textarea
     ^self tag: 'textarea'
     ^self tag: 'textarea'
+
 !
 !
 
 
 a
 a
     ^self tag: 'a'
     ^self tag: 'a'
-! !
 
 
+!
 
 
-!HTMLCanvas methodsFor: '*JQuery'!
+canvas
+	^self tag: 'canvas'
 
 
-appendToJQuery: aJQuery
-    aJQuery appendElement: root element
 ! !
 ! !
 
 
-
 Object subclass: #TagBrush
 Object subclass: #TagBrush
-	instanceVariableNames: 'element'
+	instanceVariableNames: 'canvas, element'
 	category: 'Canvas'!
 	category: 'Canvas'!
 
 
-!TagBrush class methodsFor: 'instance creation'!
+!TagBrush methodsFor: 'accessing'!
+
+element
+    ^element
 
 
-fromString: aString canvas: aCanvas
-    ^self new
-	initializeFromString: aString canvas: aCanvas;
-	yourself
 ! !
 ! !
 
 
 !TagBrush methodsFor: 'adding'!
 !TagBrush methodsFor: 'adding'!
@@ -156,23 +261,28 @@ fromString: aString canvas: aCanvas
 contents: anObject
 contents: anObject
     self asJQuery empty.
     self asJQuery empty.
     self append: anObject
     self append: anObject
+
 !
 !
 
 
 addBrush: aTagBrush
 addBrush: aTagBrush
     self appendChild: aTagBrush element.
     self appendChild: aTagBrush element.
     ^aTagBrush
     ^aTagBrush
+
 !
 !
 
 
 with: anObject
 with: anObject
     self append: anObject
     self append: anObject
+
 !
 !
 
 
 append: anObject
 append: anObject
     anObject appendToBrush: self
     anObject appendToBrush: self
+
 !
 !
 
 
 appendToBrush: aTagBrush
 appendToBrush: aTagBrush
     aTagBrush addBrush: self
     aTagBrush addBrush: self
+
 !
 !
 
 
 appendBlock: aBlock
 appendBlock: aBlock
@@ -181,114 +291,138 @@ appendBlock: aBlock
     canvas root: self.
     canvas root: self.
     aBlock value: canvas.
     aBlock value: canvas.
     canvas root: root
     canvas root: root
+
 !
 !
 
 
 appendChild: anElement
 appendChild: anElement
     {'self[''@element''].appendChild(anElement)'}
     {'self[''@element''].appendChild(anElement)'}
+
 !
 !
 
 
 appendString: aString
 appendString: aString
     self appendChild: (self createTextNodeFor: aString)
     self appendChild: (self createTextNodeFor: aString)
+
 ! !
 ! !
 
 
 !TagBrush methodsFor: 'attributes'!
 !TagBrush methodsFor: 'attributes'!
 
 
 at: aString put: aValue
 at: aString put: aValue
     {'self[''@element''].setAttribute(aString, aValue)'}
     {'self[''@element''].setAttribute(aString, aValue)'}
+
 !
 !
 
 
 removeAt: aString
 removeAt: aString
     {'self[''@element''].removeAttribute(aString)'}
     {'self[''@element''].removeAttribute(aString)'}
+
 !
 !
 
 
 class: aString
 class: aString
     self at: 'class' put: aString
     self at: 'class' put: aString
+
 !
 !
 
 
 id: aString
 id: aString
     self at: 'id' put: aString
     self at: 'id' put: aString
+
 !
 !
 
 
 src: aString
 src: aString
     self  at: 'src' put: aString
     self  at: 'src' put: aString
+
 !
 !
 
 
 href: aString
 href: aString
     self at: 'href' put: aString
     self at: 'href' put: aString
+
 !
 !
 
 
 title: aString
 title: aString
     self at: 'title' put: aString
     self at: 'title' put: aString
+
 !
 !
 
 
 style: aString
 style: aString
     self at: 'style' put: aString
     self at: 'style' put: aString
-! !
-
-!TagBrush methodsFor: 'initialization'!
 
 
-initializeFromString: aString canvas: aCanvas
-    element := self createElementFor: aString.
-    canvas := aCanvas
-! !
-
-!TagBrush methodsFor: 'accessing'!
-
-element
-    ^element
 ! !
 ! !
 
 
 !TagBrush methodsFor: 'converting'!
 !TagBrush methodsFor: 'converting'!
 
 
 asJQuery
 asJQuery
-    ^{'return smalltalk.JQuery._from_(jQuery(self[''@element'']))'}
+	{'return smalltalk.JQuery._from_(jQuery(self[''@element'']))'}
+
 !
 !
 
 
 asJQueryDo: aBlock
 asJQueryDo: aBlock
     aBlock value: self asJQuery
     aBlock value: self asJQuery
+
 ! !
 ! !
 
 
 !TagBrush methodsFor: 'events'!
 !TagBrush methodsFor: 'events'!
 
 
 onKeyDown: aBlock
 onKeyDown: aBlock
     self asJQuery on: 'keydown' do: aBlock
     self asJQuery on: 'keydown' do: aBlock
+
 !
 !
 
 
 onKeyPress: aBlock
 onKeyPress: aBlock
     self asJQuery on: 'keypress' do: aBlock
     self asJQuery on: 'keypress' do: aBlock
+
 !
 !
 
 
 onKeyUp: aBlock
 onKeyUp: aBlock
     self asJQuery on: 'keyup' do: aBlock
     self asJQuery on: 'keyup' do: aBlock
+
 !
 !
 
 
 onFocus: aBlock
 onFocus: aBlock
     self asJQuery on: 'focus' do: aBlock
     self asJQuery on: 'focus' do: aBlock
+
 !
 !
 
 
 onBlur: aBlock
 onBlur: aBlock
     self asJQuery on: 'blur' do: aBlock
     self asJQuery on: 'blur' do: aBlock
+
 !
 !
 
 
 onChange: aBlock
 onChange: aBlock
     self asJQuery on: 'change' do: aBlock
     self asJQuery on: 'change' do: aBlock
+
 !
 !
 
 
 onClick: aBlock
 onClick: aBlock
     self asJQuery on: 'click' do: aBlock
     self asJQuery on: 'click' do: aBlock
+
+! !
+
+!TagBrush methodsFor: 'initialization'!
+
+initializeFromString: aString canvas: aCanvas
+    element := self createElementFor: aString.
+    canvas := aCanvas
+
 ! !
 ! !
 
 
 !TagBrush methodsFor: 'private'!
 !TagBrush methodsFor: 'private'!
 
 
 createElementFor: aString
 createElementFor: aString
-    ^{'return document.createElement(String(aString))'}
+	{'return document.createElement(String(aString))'}
+
 !
 !
 
 
 createTextNodeFor: aString
 createTextNodeFor: aString
-    ^{'return document.createTextNode(String(aString))'}
+	{'return document.createTextNode(String(aString))'}
+
 ! !
 ! !
 
 
+!TagBrush class methodsFor: 'instance creation'!
 
 
+fromString: aString canvas: aCanvas
+    ^self new
+	initializeFromString: aString canvas: aCanvas;
+	yourself
+
+! !
 
 
 Object subclass: #Widget
 Object subclass: #Widget
 	instanceVariableNames: 'root'
 	instanceVariableNames: 'root'
@@ -298,35 +432,29 @@ Object subclass: #Widget
 
 
 root
 root
     ^root
     ^root
-! !
-
-!Widget methodsFor: 'adding'!
 
 
-appendToBrush: aTagBrush
-    self appendToJQuery: aTagBrush asJQuery
-!
-
-appendToJQuery: aJQuery
-    self render.
-    aJQuery append: self root asJQuery
 ! !
 ! !
 
 
 !Widget methodsFor: 'actions'!
 !Widget methodsFor: 'actions'!
 
 
 alert: aString
 alert: aString
     {'alert(aString)'}
     {'alert(aString)'}
+
 !
 !
 
 
 confirm: aString
 confirm: aString
-    ^{'return window.confirm(aString)'}
+    {'return window.confirm(aString)'}
+
 !
 !
 
 
 prompt: aString
 prompt: aString
     ^self prompt: aString default: ''
     ^self prompt: aString default: ''
+
 !
 !
 
 
 prompt: aString default: anotherString
 prompt: aString default: anotherString
-    ^{'return window.prompt(aString, anotherString)'}
+    {'return window.prompt(aString, anotherString)'}
+
 !
 !
 
 
 update
 update
@@ -335,6 +463,20 @@ update
     canvas root: self root.
     canvas root: self root.
     self root asJQuery empty.
     self root asJQuery empty.
     self renderOn: canvas
     self renderOn: canvas
+
+! !
+
+!Widget methodsFor: 'adding'!
+
+appendToBrush: aTagBrush
+    self appendToJQuery: aTagBrush asJQuery
+
+!
+
+appendToJQuery: aJQuery
+    self render.
+    aJQuery append: self root asJQuery
+
 ! !
 ! !
 
 
 !Widget methodsFor: 'rendering'!
 !Widget methodsFor: 'rendering'!
@@ -344,43 +486,50 @@ render
     canvas := HTMLCanvas new.
     canvas := HTMLCanvas new.
     root := canvas root.
     root := canvas root.
     self renderOn: canvas
     self renderOn: canvas
+
 !
 !
 
 
 renderOn: html
 renderOn: html
     self
     self
+
 ! !
 ! !
 
 
-Widget subclass: #Counter
-	instanceVariableNames: 'count'
+TagBrush subclass: #CanvasBrush
+	instanceVariableNames: ''
 	category: 'Canvas'!
 	category: 'Canvas'!
 
 
-!Counter methodsFor: 'initialization'!
+!CanvasBrush methodsFor: 'initialization'!
 
 
-initialize
-    super initialize.
-    count := 0
+initializeWithCanvas: aCanvas
+	canvas := aCanvas
 ! !
 ! !
 
 
-!Counter methodsFor: 'rendering'!
+!CanvasBrush methodsFor: 'private'!
 
 
-renderOn: html
-    html h1 with: count asString.
-    html button
-	with: '++';
-	onClick: [self increase].
-    html button
-	with: '--';
-	onClick: [self decrease]
+createElement
+	{'return document.createElement(''canvas'')'}
 ! !
 ! !
 
 
-!Counter methodsFor: 'actions'!
+!CanvasBrush class methodsFor: 'instance creation'!
+
+canvas: aCanvas
+	^self new
+		initializeWithCanvas: aCanvas;
+		yourself
+! !
+
+
+
+appendToBrush: aTagBrush
+    aTagBrush append: self asString
 
 
-increase
-    count := count + 1.
-    self update
 !
 !
 
 
-decrease
-    count := count - 1.
-    self update
-! !
+appendToBrush: aTagBrush
+    aTagBrush appendBlock: self
+!
+
+appendToBrush: aTagBrush
+    aTagBrush appendString: self
+
+!

+ 325 - 195
st/compiler.st → st/Compiler.st

@@ -2,109 +2,109 @@ Object subclass: #Node
 	instanceVariableNames: 'nodes'
 	instanceVariableNames: 'nodes'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !Node methodsFor: 'accessing'!
 !Node methodsFor: 'accessing'!
 
 
+nodes
+	^nodes ifNil: [nodes := Array new]
+
+!
+
 addNode: aNode
 addNode: aNode
 	self nodes add: aNode
 	self nodes add: aNode
-!
 
 
-nodes
-	^nodes ifNil: [nodes := Array new]
 ! !
 ! !
 
 
 !Node methodsFor: 'building'!
 !Node methodsFor: 'building'!
 
 
 nodes: aCollection
 nodes: aCollection
 	nodes := aCollection
 	nodes := aCollection
+
 ! !
 ! !
 
 
 !Node methodsFor: 'visiting'!
 !Node methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitNode: self
 	aVisitor visitNode: self
-! !
 
 
+! !
 
 
 Node subclass: #MethodNode
 Node subclass: #MethodNode
-	instanceVariableNames: 'selector arguments source'
+	instanceVariableNames: 'selector, arguments, source'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !MethodNode methodsFor: 'accessing'!
 !MethodNode methodsFor: 'accessing'!
 
 
+selector
+	^selector
+
+!
+
+selector: aString
+	selector := aString
+
+!
+
 arguments
 arguments
 	^arguments ifNil: [#()]
 	^arguments ifNil: [#()]
+
 !
 !
 
 
 arguments: aCollection
 arguments: aCollection
 	arguments := aCollection
 	arguments := aCollection
-!
-
-selector
-	^selector
-!
 
 
-selector: aString
-	selector := aString
 !
 !
 
 
 source
 source
 	^source
 	^source
+
 !
 !
 
 
 source: aString
 source: aString
 	source := aString
 	source := aString
+
 ! !
 ! !
 
 
 !MethodNode methodsFor: 'visiting'!
 !MethodNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitMethodNode: self
 	aVisitor visitMethodNode: self
-! !
 
 
+! !
 
 
 Node subclass: #SendNode
 Node subclass: #SendNode
-	instanceVariableNames: 'selector arguments receiver'
+	instanceVariableNames: 'selector, arguments, receiver'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !SendNode methodsFor: 'accessing'!
 !SendNode methodsFor: 'accessing'!
 
 
+selector
+	^selector
+
+!
+
+selector: aString
+	selector := aString
+
+!
+
 arguments
 arguments
 	^arguments ifNil: [arguments := #()]
 	^arguments ifNil: [arguments := #()]
+
 !
 !
 
 
 arguments: aCollection
 arguments: aCollection
 	arguments := aCollection
 	arguments := aCollection
-!
 
 
-cascadeNodeWithMessages: aCollection
-	| first |
-	first := SendNode new
-	    selector: self selector;
-	    arguments: self arguments;
-	    yourself.
-	^CascadeNode new
-	    receiver: self receiver;
-	    nodes: (Array with: first), aCollection;
-	    yourself
 !
 !
 
 
 receiver
 receiver
 	^receiver
 	^receiver
+
 !
 !
 
 
 receiver: aNode
 receiver: aNode
 	receiver := aNode
 	receiver := aNode
-!
 
 
-selector
-	^selector
-!
-
-selector: aString
-	selector := aString
 !
 !
 
 
 valueForReceiver: anObject
 valueForReceiver: anObject
@@ -115,102 +115,122 @@ valueForReceiver: anObject
 	    selector: self selector;
 	    selector: self selector;
 	    arguments: self arguments;
 	    arguments: self arguments;
 	    yourself
 	    yourself
+
+!
+
+cascadeNodeWithMessages: aCollection
+	| first |
+	first := SendNode new
+	    selector: self selector;
+	    arguments: self arguments;
+	    yourself.
+	^CascadeNode new
+	    receiver: self receiver;
+	    nodes: (Array with: first), aCollection;
+	    yourself
+
 ! !
 ! !
 
 
 !SendNode methodsFor: 'visiting'!
 !SendNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitSendNode: self
 	aVisitor visitSendNode: self
-! !
 
 
+! !
 
 
 Node subclass: #CascadeNode
 Node subclass: #CascadeNode
 	instanceVariableNames: 'receiver'
 	instanceVariableNames: 'receiver'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !CascadeNode methodsFor: 'accessing'!
 !CascadeNode methodsFor: 'accessing'!
 
 
 receiver
 receiver
 	^receiver
 	^receiver
+
 !
 !
 
 
 receiver: aNode
 receiver: aNode
 	receiver := aNode
 	receiver := aNode
+
 ! !
 ! !
 
 
 !CascadeNode methodsFor: 'visiting'!
 !CascadeNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitCascadeNode: self
 	aVisitor visitCascadeNode: self
-! !
 
 
+! !
 
 
 Node subclass: #AssignmentNode
 Node subclass: #AssignmentNode
-	instanceVariableNames: 'left right'
+	instanceVariableNames: 'left, right'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !AssignmentNode methodsFor: 'accessing'!
 !AssignmentNode methodsFor: 'accessing'!
 
 
 left
 left
 	^left
 	^left
+
 !
 !
 
 
 left: aNode
 left: aNode
 	left := aNode
 	left := aNode
+
 !
 !
 
 
 right
 right
 	^right
 	^right
+
 !
 !
 
 
 right: aNode
 right: aNode
 	right := aNode
 	right := aNode
+
 ! !
 ! !
 
 
 !AssignmentNode methodsFor: 'visiting'!
 !AssignmentNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitAssignmentNode: self
 	aVisitor visitAssignmentNode: self
-! !
 
 
+! !
 
 
 Node subclass: #BlockNode
 Node subclass: #BlockNode
 	instanceVariableNames: 'parameters'
 	instanceVariableNames: 'parameters'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !BlockNode methodsFor: 'accessing'!
 !BlockNode methodsFor: 'accessing'!
 
 
 parameters
 parameters
 	^parameters ifNil: [parameters := Array new]
 	^parameters ifNil: [parameters := Array new]
+
 !
 !
 
 
 parameters: aCollection
 parameters: aCollection
 	parameters := aCollection
 	parameters := aCollection
+
 ! !
 ! !
 
 
 !BlockNode methodsFor: 'visiting'!
 !BlockNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitBlockNode: self
 	aVisitor visitBlockNode: self
-! !
 
 
+! !
 
 
 Node subclass: #SequenceNode
 Node subclass: #SequenceNode
 	instanceVariableNames: 'temps'
 	instanceVariableNames: 'temps'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !SequenceNode methodsFor: 'accessing'!
 !SequenceNode methodsFor: 'accessing'!
 
 
 temps
 temps
 	^temps ifNil: [#()]
 	^temps ifNil: [#()]
+
 !
 !
 
 
 temps: aCollection
 temps: aCollection
 	temps := aCollection
 	temps := aCollection
+
 ! !
 ! !
 
 
 !SequenceNode methodsFor: 'testing'!
 !SequenceNode methodsFor: 'testing'!
@@ -220,205 +240,244 @@ asBlockSequenceNode
 	    nodes: self nodes;
 	    nodes: self nodes;
 	    temps: self temps;
 	    temps: self temps;
 	    yourself
 	    yourself
+
 ! !
 ! !
 
 
 !SequenceNode methodsFor: 'visiting'!
 !SequenceNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitSequenceNode: self
 	aVisitor visitSequenceNode: self
-! !
 
 
+! !
 
 
 SequenceNode subclass: #BlockSequenceNode
 SequenceNode subclass: #BlockSequenceNode
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !BlockSequenceNode methodsFor: 'visiting'!
 !BlockSequenceNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitBlockSequenceNode: self
 	aVisitor visitBlockSequenceNode: self
-! !
 
 
+! !
 
 
 Node subclass: #ReturnNode
 Node subclass: #ReturnNode
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !ReturnNode methodsFor: 'visiting'!
 !ReturnNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitReturnNode: self
 	aVisitor visitReturnNode: self
-! !
 
 
+! !
 
 
 Node subclass: #ValueNode
 Node subclass: #ValueNode
 	instanceVariableNames: 'value'
 	instanceVariableNames: 'value'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !ValueNode methodsFor: 'accessing'!
 !ValueNode methodsFor: 'accessing'!
 
 
 value
 value
 	^value
 	^value
+
 !
 !
 
 
 value: anObject
 value: anObject
 	value := anObject
 	value := anObject
+
 ! !
 ! !
 
 
 !ValueNode methodsFor: 'visiting'!
 !ValueNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitValueNode: self
 	aVisitor visitValueNode: self
-! !
 
 
+! !
 
 
 ValueNode subclass: #VariableNode
 ValueNode subclass: #VariableNode
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !VariableNode methodsFor: 'visiting'!
 !VariableNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitVariableNode: self
 	aVisitor visitVariableNode: self
-! !
 
 
+! !
 
 
 VariableNode subclass: #ClassReferenceNode
 VariableNode subclass: #ClassReferenceNode
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !ClassReferenceNode methodsFor: 'visiting'!
 !ClassReferenceNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitClassReferenceNode: self
 	aVisitor visitClassReferenceNode: self
-! !
 
 
+! !
 
 
 Node subclass: #JSStatementNode
 Node subclass: #JSStatementNode
 	instanceVariableNames: 'source'
 	instanceVariableNames: 'source'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !JSStatementNode methodsFor: 'accessing'!
 !JSStatementNode methodsFor: 'accessing'!
 
 
 source
 source
 	^source ifNil: ['']
 	^source ifNil: ['']
+
 !
 !
 
 
 source: aString
 source: aString
 	source := aString
 	source := aString
+
 ! !
 ! !
 
 
 !JSStatementNode methodsFor: 'visiting'!
 !JSStatementNode methodsFor: 'visiting'!
 
 
 accept: aVisitor
 accept: aVisitor
 	aVisitor visitJSStatementNode: self
 	aVisitor visitJSStatementNode: self
-! !
 
 
+! !
 
 
 Object subclass: #NodeVisitor
 Object subclass: #NodeVisitor
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !NodeVisitor methodsFor: 'visiting'!
 !NodeVisitor methodsFor: 'visiting'!
 
 
 visit: aNode
 visit: aNode
 	aNode accept: self
 	aNode accept: self
+
 !
 !
 
 
-visitAssignmentNode: aNode
-	self visitNode: aNode
+visitNode: aNode
+
 !
 !
 
 
-visitBlockNode: aNode
+visitMethodNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
-!
 
 
-visitBlockSequenceNode: aNode
-	self visitSequenceNode: aNode
 !
 !
 
 
-visitCascadeNode: aNode
+visitSequenceNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
-!
 
 
-visitClassReferenceNode: aNode
-	self 
-	    nextPutAll: 'smalltalk.';
-	    nextPutAll: aNode value
 !
 !
 
 
-visitJSStatementNode: aNode
-	self 
-	    nextPutAll: 'function(){';
-	    nextPutAll: aNode source;
-	    nextPutAll: '})()'
+visitBlockSequenceNode: aNode
+	self visitSequenceNode: aNode
+
 !
 !
 
 
-visitMethodNode: aNode
+visitBlockNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
-!
 
 
-visitNode: aNode
 !
 !
 
 
 visitReturnNode: aNode
 visitReturnNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
+
 !
 !
 
 
 visitSendNode: aNode
 visitSendNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
+
 !
 !
 
 
-visitSequenceNode: aNode
+visitCascadeNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
+
 !
 !
 
 
 visitValueNode: aNode
 visitValueNode: aNode
 	self visitNode: aNode
 	self visitNode: aNode
+
 !
 !
 
 
 visitVariableNode: aNode
 visitVariableNode: aNode
-! !
 
 
+!
+
+visitAssignmentNode: aNode
+	self visitNode: aNode
+
+!
+
+visitClassReferenceNode: aNode
+	self 
+	    nextPutAll: 'smalltalk.';
+	    nextPutAll: aNode value
+
+!
+
+visitJSStatementNode: aNode
+	self 
+	    nextPutAll: 'function(){';
+	    nextPutAll: aNode source;
+	    nextPutAll: '})()'
+
+! !
 
 
 NodeVisitor subclass: #Compiler
 NodeVisitor subclass: #Compiler
-	instanceVariableNames: 'stream nestedBlocks earlyReturn currentClass currentSelector'
+	instanceVariableNames: 'stream, nestedBlocks, earlyReturn, currentClass, currentSelector, unknownVariables, tempVariables, messageSends, referencedClasses'
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
-
 !Compiler methodsFor: 'accessing'!
 !Compiler methodsFor: 'accessing'!
 
 
+parser
+	^SmalltalkParser new
+
+!
+
 currentClass
 currentClass
 	^currentClass
 	^currentClass
+
 !
 !
 
 
 currentClass: aClass
 currentClass: aClass
 	currentClass := aClass
 	currentClass := aClass
+
 !
 !
 
 
-parser
-	^SmalltalkParser new
+unknownVariables
+	^unknownVariables copy
+!
+
+pseudoVariables
+	^#('self' 'super' 'true' 'false' 'nil' 'thisContext')
+!
+
+tempVariables
+	^tempVariables copy
+!
+
+knownVariables
+	^self pseudoVariables 
+		addAll: self tempVariables;
+		yourself
+!
+
+classNameFor: aClass
+	^aClass isMetaclass
+	    ifTrue: [aClass instanceClass name, '.klass']
+	    ifFalse: [
+		aClass isNil
+		    ifTrue: ['nil']
+		    ifFalse: [aClass name]]
 ! !
 ! !
 
 
 !Compiler methodsFor: 'compiling'!
 !Compiler methodsFor: 'compiling'!
 
 
-parse: aString
-    ^self parser parse: aString readStream
-!
+loadExpression: aString
+	DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
+	^DoIt new doIt
 
 
-parseExpression: aString
-    ^self parse: 'doIt ^[', aString, '] value'
 !
 !
 
 
-compile: aString
-	^self compileNode: (self parse: aString)
+load: aString forClass: aClass
+	^self eval: (self compile: aString forClass: aClass)
+
 !
 !
 
 
 compile: aString forClass: aClass
 compile: aString forClass: aClass
@@ -429,55 +488,138 @@ compile: aString forClass: aClass
 compileExpression: aString
 compileExpression: aString
 	self currentClass: DoIt.
 	self currentClass: DoIt.
 	^self compileNode: (self parseExpression: aString)
 	^self compileNode: (self parseExpression: aString)
+
+!
+
+eval: aString
+	{'return eval(aString)'}
+!
+
+compile: aString
+	^self compileNode: (self parse: aString)
+
 !
 !
 
 
 compileNode: aNode
 compileNode: aNode
 	stream := '' writeStream.
 	stream := '' writeStream.
 	self visit: aNode.
 	self visit: aNode.
 	^stream contents
 	^stream contents
+
 !
 !
 
 
-eval: aString
-	^{'return eval(aString);'}
+parse: aString
+    ^self parser parse: aString readStream
+
 !
 !
 
 
-load: aString forClass: aClass
-	^self eval: (self compile: aString forClass: aClass)
+parseExpression: aString
+    ^self parse: 'doIt ^[', aString, '] value'
+
 !
 !
 
 
-loadExpression: aString
-	DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).
-	^DoIt new doIt
+recompile: aClass
+	aClass methodDictionary do: [:each || method |
+		method := self load: each source forClass: aClass.
+		method category: each category.
+		aClass addCompiledMethod: method].
+	aClass isMetaclass ifFalse: [self recompile: aClass class]
+!
+
+recompileAll
+	Smalltalk current classes do: [:each |
+		self recompile: each]
 ! !
 ! !
 
 
 !Compiler methodsFor: 'initialization'!
 !Compiler methodsFor: 'initialization'!
 
 
 initialize
 initialize
 	super initialize.
 	super initialize.
-	stream := '' writeStream
+	stream := '' writeStream.
+	unknownVariables := #().
+	tempVariables := #().
+	messageSends := #().
+	classReferenced := #()
+
 ! !
 ! !
 
 
 !Compiler methodsFor: 'visiting'!
 !Compiler methodsFor: 'visiting'!
 
 
 visit: aNode
 visit: aNode
 	aNode accept: self
 	aNode accept: self
+
 !
 !
 
 
-visitAssignmentNode: aNode
-	self visit: aNode left.
-	stream nextPutAll: '='.
-	self visit: aNode right
+visitMethodNode: aNode
+	| str currentSelector |
+	currentSelector := aNode selector asSelector.
+	nestedBlocks := 0.
+	earlyReturn := false.
+	messageSends := #().
+	referencedClasses := #().
+	unknownVariables := #().
+	tempVariables := #().
+	stream 
+	    nextPutAll: 'smalltalk.method({'; lf;
+	    nextPutAll: 'selector: "', aNode selector, '",'; lf.
+	Smalltalk current debugMode ifTrue: [
+	    stream nextPutAll: 'source: unescape("', aNode source escaped, '"),';lf].
+	stream nextPutAll: 'fn: function('.
+	aNode arguments 
+	    do: [:each | 
+		tempVariables add: each.
+		stream nextPutAll: each]
+	    separatedBy: [stream nextPutAll: ', '].
+	stream 
+	    nextPutAll: '){'; lf;
+	    nextPutAll: 'var self=this;'; lf.
+	str := stream.
+	stream := '' writeStream.
+	aNode nodes do: [:each |
+	    self visit: each].
+	earlyReturn ifTrue: [
+	    str nextPutAll: 'try{'].
+	str nextPutAll: stream contents.
+	stream := str.
+	stream 
+	    lf; 
+	    nextPutAll: 'return self;'.
+	earlyReturn ifTrue: [
+	    stream lf; nextPutAll: '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
+	stream nextPutAll: '}'.
+	Smalltalk current debugMode ifTrue: [
+		stream 
+			nextPutAll: ',', String lf, 'messageSends: ';
+			nextPutAll: messageSends asJavascript, ','; lf;
+			nextPutAll: 'referencedClasses: ['.
+		referencedClasses 
+			do: [:each | stream nextPutAll: each]
+			separatedBy: [stream nextPutAll: ','].
+		stream nextPutAll: ']'].
+	stream nextPutAll: '})'
 !
 !
 
 
 visitBlockNode: aNode
 visitBlockNode: aNode
 	stream nextPutAll: '(function('.
 	stream nextPutAll: '(function('.
 	aNode parameters 
 	aNode parameters 
 	    do: [:each |
 	    do: [:each |
+		tempVariables add: each.
 		stream nextPutAll: each]
 		stream nextPutAll: each]
 	    separatedBy: [stream nextPutAll: ', '].
 	    separatedBy: [stream nextPutAll: ', '].
 	stream nextPutAll: '){'.
 	stream nextPutAll: '){'.
 	aNode nodes do: [:each | self visit: each].
 	aNode nodes do: [:each | self visit: each].
 	stream nextPutAll: '})'
 	stream nextPutAll: '})'
+
+!
+
+visitSequenceNode: aNode
+	aNode temps do: [:each |
+	    tempVariables add: each.
+	    stream nextPutAll: 'var ', each, '=nil;'; lf].
+	aNode nodes do: [:each |
+	    self visit: each.
+	    stream nextPutAll: ';']
+	    separatedBy: [stream lf]
+
 !
 !
 
 
 visitBlockSequenceNode: aNode
 visitBlockSequenceNode: aNode
@@ -488,8 +630,8 @@ visitBlockSequenceNode: aNode
 		stream nextPutAll: 'return nil;']
 		stream nextPutAll: 'return nil;']
 	    ifFalse: [
 	    ifFalse: [
 		aNode temps do: [:each |
 		aNode temps do: [:each |
-		    stream nextPutAll: 'var ', each, '=nil;'.
-		    stream nextPutAll: String cr].
+		    tempVariables add: each.
+		    stream nextPutAll: 'var ', each, '=nil;'; lf].
 		index := 0.
 		index := 0.
 		aNode nodes do: [:each |
 		aNode nodes do: [:each |
 		    index := index + 1.
 		    index := index + 1.
@@ -498,68 +640,7 @@ visitBlockSequenceNode: aNode
 		    self visit: each.
 		    self visit: each.
 		    stream nextPutAll: ';']].
 		    stream nextPutAll: ';']].
 	nestedBlocks := nestedBlocks - 1
 	nestedBlocks := nestedBlocks - 1
-!
-
-visitCascadeNode: aNode
-	| index |
-	index := 0.
-	stream nextPutAll: '(function($rec){'.
-	aNode nodes do: [:each |
-	    index := index + 1.
-	    index = aNode nodes size ifTrue: [
-		stream nextPutAll: 'return '].
-	    each receiver: (VariableNode new value: '$rec').
-	    self visit: each.
-	    stream nextPutAll: ';'].
-	stream nextPutAll: '})('.
-	self visit: aNode receiver.
-	stream nextPutAll: ')'
-!
-
-visitClassReferenceNode: aNode
-	stream
-	    nextPutAll: 'smalltalk.';
-	    nextPutAll: aNode value
-!
 
 
-visitJSStatementNode: aNode
-	stream nextPutAll: '(function(){'.
-	stream nextPutAll: (aNode source value replace: '''''' with: '''').
-	stream nextPutAll: '})()'
-!
-
-visitMethodNode: aNode
-	| str currentSelector |
-	currentSelector := aNode selector asSelector.
-	nestedBlocks := 0.
-	earlyReturn := false.
-	stream 
-	    nextPutAll: 'smalltalk.method({', String cr;
-	    nextPutAll: 'selector: "', aNode selector, '",', String cr;
-	    nextPutAll: 'source: unescape("', aNode source escaped, '"),', String cr;
-	    nextPutAll: 'fn: function('.
-	aNode arguments 
-	    do: [:each | stream nextPutAll: each]
-	    separatedBy: [stream nextPutAll: ', '].
-	stream 
-	    nextPutAll: '){', String cr;
-	    nextPutAll: 'var self=this;', String cr.
-	str := stream.
-	stream := '' writeStream.
-	aNode nodes do: [:each |
-	    self visit: each].
-	earlyReturn ifTrue: [
-	    str nextPutAll: 'try{'].
-	str nextPutAll: stream contents.
-	stream := str.
-	stream 
-	    nextPutAll: String cr; 
-	    nextPutAll: 'return self;'.
-	earlyReturn ifTrue: [
-	    stream nextPutAll: String cr, '} catch(e) {if(e.name === ''stReturn'' && e.selector === ', currentSelector printString, '){return e.fn()} throw(e)}'].
-	stream 
-	    nextPutAll: '}', String cr;
-	    nextPutAll: '})'
 !
 !
 
 
 visitReturnNode: aNode
 visitReturnNode: aNode
@@ -580,53 +661,102 @@ visitReturnNode: aNode
 !
 !
 
 
 visitSendNode: aNode
 visitSendNode: aNode
-	| str |
+	| str receiver superSend |
 	str := stream.
 	str := stream.
+	(messageSends includes: aNode selector) ifFalse: [
+		messageSends add: aNode selector].
 	stream := '' writeStream.
 	stream := '' writeStream.
 	self visit: aNode receiver.
 	self visit: aNode receiver.
-	stream contents = 'super' 
-	    ifTrue: [
-		stream := str.
-		stream 
-		    nextPutAll: 'self.klass.superclass.fn.prototype[''';
-		    nextPutAll: aNode selector asSelector;
-		    nextPutAll: '''].apply(self, ['.
-		aNode arguments 
-		    do: [:each | self visit: each]
-		    separatedBy: [stream nextPutAll: ','].
-		stream nextPutAll: '])']
-	    ifFalse: [
-		str nextPutAll: stream contents.
-		stream := str.
-		stream nextPutAll: '.', aNode selector asSelector, '('.
-		aNode arguments 
-		    do: [:each | self visit: each]
-		    separatedBy: [stream nextPutAll: ','].
-		stream nextPutAll: ')']
+	superSend := stream contents = 'super'.
+	receiver := superSend ifTrue: ['self'] ifFalse: [stream contents].
+	str nextPutAll: 'smalltalk.send('.
+	str nextPutAll: receiver.
+	stream := str.
+	stream nextPutAll: ', "', aNode selector asSelector, '", ['.
+	aNode arguments 
+	    do: [:each | self visit: each]
+	    separatedBy: [stream nextPutAll: ', '].
+	stream nextPutAll: ']'.
+	superSend ifTrue: [
+		stream nextPutAll: ', smalltalk.', (self classNameFor: self currentClass superclass)].
+	stream nextPutAll: ')'
 !
 !
 
 
-visitSequenceNode: aNode
-	aNode temps do: [:each |
-	    stream nextPutAll: 'var ', each, '=nil;'.
-	    stream nextPutAll: String cr].
+visitCascadeNode: aNode
+	| index |
+	index := 0.
+	(tempVariables includes: '$rec') ifFalse: [
+		tempVariables add: '$rec'].
+	stream nextPutAll: '(function($rec){'.
 	aNode nodes do: [:each |
 	aNode nodes do: [:each |
+	    index := index + 1.
+	    index = aNode nodes size ifTrue: [
+		stream nextPutAll: 'return '].
+	    each receiver: (VariableNode new value: '$rec').
 	    self visit: each.
 	    self visit: each.
-	    stream nextPutAll: ';']
-	    separatedBy: [stream nextPutAll: String cr]
+	    stream nextPutAll: ';'].
+	stream nextPutAll: '})('.
+	self visit: aNode receiver.
+	stream nextPutAll: ')'
+
 !
 !
 
 
 visitValueNode: aNode
 visitValueNode: aNode
 	stream nextPutAll: aNode value asJavascript
 	stream nextPutAll: aNode value asJavascript
+
+!
+
+visitAssignmentNode: aNode
+	self visit: aNode left.
+	stream nextPutAll: '='.
+	self visit: aNode right
+
+!
+
+visitClassReferenceNode: aNode
+	| klass |
+	klass := 'smalltalk.', aNode value.
+	(Smalltalk current at: aNode value) isClass ifTrue: [
+		(referencedClasses includes: klass)
+			ifFalse: [referencedClasses add: klass]].
+	stream nextPutAll: klass
 !
 !
 
 
 visitVariableNode: aNode
 visitVariableNode: aNode
-	(self currentClass instVarNames includes: aNode value) 
-	    ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
-	    ifFalse: [stream nextPutAll: aNode value]
+	(self currentClass instanceVariableNames includes: aNode value) 
+		ifTrue: [stream nextPutAll: 'self[''@', aNode value, ''']']
+		ifFalse: [
+			(self knownVariables includes: aNode value) ifFalse: [
+				unknownVariables add: aNode value].
+			stream nextPutAll: aNode value]
+
+!
+
+visitJSStatementNode: aNode
+	stream nextPutAll: (aNode source value replace: '''''' with: '''')
 ! !
 ! !
 
 
+!Compiler class methodsFor: 'compiling'!
+
+recompile: aClass
+	aClass methodDictionary do: [:each || method |
+		method := self new load: each source forClass: aClass.
+		method category: each category.
+		aClass addCompiledMethod: method].
+	aClass isMetaclass ifFalse: [self recompile: aClass class]
+!
+
+recompileAll
+	Smalltalk current classes do: [:each |
+		self recompile: each]
+! !
 
 
 Object subclass: #DoIt
 Object subclass: #DoIt
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Compiler'!
 	category: 'Compiler'!
 
 
+!DoIt methodsFor: ''!
+
+doIt ^[ChunkExporter new exportCategory: 'Parser' ] value
+! !
+

+ 361 - 0
st/Examples.st

@@ -0,0 +1,361 @@
+Widget subclass: #Counter
+	instanceVariableNames: 'count, header'
+	category: 'Examples'!
+
+!Counter methodsFor: 'actions'!
+
+increase
+    count := count + 1.
+    header contents: [:html | html with: count asString]
+!
+
+decrease
+    count := count - 1.
+    header contents: [:html | html with: count asString]
+! !
+
+!Counter methodsFor: 'initialization'!
+
+initialize
+    super initialize.
+    count := 0
+
+! !
+
+!Counter methodsFor: 'rendering'!
+
+renderOn: html
+    header := html h1 
+	with: count asString;
+	yourself.
+    html button
+	with: '++';
+	onClick: [self increase].
+    html button
+	with: '--';
+	onClick: [self decrease]
+
+! !
+
+Widget subclass: #Tetris
+	instanceVariableNames: 'renderingContext, timer, speed, score, rows, movingPiece'
+	category: 'Examples'!
+
+!Tetris methodsFor: 'accessing'!
+
+width
+	^self class width
+!
+
+height
+	^self class height
+!
+
+squares
+	^self class squares
+!
+
+gluePiece: aPiece
+	aPiece glueOn: self
+	
+!
+
+rows
+	"An array of rows. Each row is a collection of points."
+	^rows
+!
+
+addRow: aCollection
+	self rows add: aCollection
+! !
+
+!Tetris methodsFor: 'actions'!
+
+startNewGame
+	self newGame.
+	timer ifNotNil: [timer clearInterval].
+	timer := [self nextStep] valueWithInterval: speed
+!
+
+nextStep
+	movingPiece ifNil: [self newPiece].
+	(movingPiece canMoveIn: self)
+		ifTrue: [movingPiece position: movingPiece position + (0@1)]
+		ifFalse: [self newPiece].
+	self redraw
+	
+!
+
+redraw
+	renderingContext clearRectFrom: 0@ self width to: 0@ self height.
+	self 
+		drawMap;
+		drawPiece
+!
+
+drawMap
+	renderingContext 
+		fillStyle: '#fafafa';
+		fillRectFrom: 0@0 to: self width@self height.
+	renderingContext 
+		lineWidth: 0.5;
+		strokeStyle: '#999'.
+	0 to: self class squares x do: [:each | | x |
+		x := each * self class squareSize.
+		self drawLineFrom: x@0 to: x@self height].
+	0 to: self class squares y do: [:each | | y |
+		y := each * self class squareSize.
+		self drawLineFrom: 0@y to: self width@y].
+!
+
+drawLineFrom: aPoint to: anotherPoint
+	renderingContext 
+		beginPath;
+		moveTo: aPoint;
+		lineTo: anotherPoint;
+		stroke
+!
+
+newGame
+	rows := #().
+	movingPiece := nil.
+	speed := 200.
+	score := 0
+!
+
+newPiece
+	movingPiece := TetrisPiece atRandom
+!
+
+drawRows
+	self rows do: [:each |].
+	movingPiece ifNotNil: [movingPiece drawOn: renderingContext]
+!
+
+drawPiece
+	movingPiece ifNotNil: [
+		movingPiece drawOn: renderingContext]
+! !
+
+!Tetris methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	self newGame
+! !
+
+!Tetris methodsFor: 'rendering'!
+
+renderOn: html
+	html div
+		class: 'tetris';
+		with: [
+			html h3 with: 'Tetris'.
+			self renderCanvasOn: html.
+			self renderButtonsOn: html]
+!
+
+renderCanvasOn: html
+	| canvas |
+	canvas := html canvas.
+	canvas at: 'width' put: self width asString.
+	canvas at: 'height' put: self height asString.
+	renderingContext := CanvasRenderingContext tagBrush: canvas.
+	self redraw
+!
+
+renderButtonsOn: html
+	html div 
+		class: 'tetris_buttons';
+		with: [
+			html button
+				with: 'New game';
+				onClick: [self startNewGame].
+			html button
+				with: 'play/pause';
+				onClick: [self update]]
+! !
+
+!Tetris class methodsFor: 'accessing'!
+
+squareSize
+	^22
+!
+
+width
+	^self squareSize * (self squares x)
+!
+
+height
+	^self squareSize * (self squares y)
+!
+
+squares
+	^10@15
+! !
+
+Widget subclass: #TetrisPiece
+	instanceVariableNames: 'rotation, position'
+	category: 'Examples'!
+
+!TetrisPiece methodsFor: 'accessing'!
+
+rotation
+	^rotation ifNil: [rotation := 1]
+!
+
+rotation: aNumber
+	rotation := aNumber
+!
+
+position
+	^position ifNil: [(Tetris squares x / 2) -1 @ 0]
+!
+
+position: aPoint
+	^position := aPoint
+!
+
+bounds
+	self subclassResponsibility
+!
+
+color
+	^'#afa'
+!
+
+height
+	^2
+! !
+
+!TetrisPiece methodsFor: 'drawing'!
+
+drawOn: aRenderingContext
+	aRenderingContext fillStyle: self color.
+	self bounds do: [:each |
+		aRenderingContext 
+			fillRectFrom: each + self position* Tetris squareSize to: 1@1 * Tetris squareSize;
+			strokeStyle: '#999';
+			lineWidth: 2;
+			strokeRectFrom: each + self position* Tetris squareSize to: 1@1 * Tetris squareSize]
+! !
+
+!TetrisPiece methodsFor: 'testing'!
+
+canMove
+	^self position y < (Tetris squares y - self height)
+!
+
+canMoveIn: aTetris
+	^self position y < (aTetris squares y - self height)
+! !
+
+!TetrisPiece class methodsFor: 'instance creation'!
+
+atRandom
+	^(self subclasses at: self subclasses size atRandom) new
+! !
+
+TetrisPiece subclass: #TetrisPieceO
+	instanceVariableNames: ''
+	category: 'Examples'!
+
+!TetrisPieceO methodsFor: 'accessing'!
+
+bounds
+	^Array new
+		add: 0@0;
+		add: 0@1;
+		add: 1@0;
+		add: 1@1;
+		yourself
+! !
+
+TetrisPiece subclass: #TetrisPieceL
+	instanceVariableNames: ''
+	category: 'Examples'!
+
+!TetrisPieceL methodsFor: 'accessing'!
+
+bounds
+	^Array new
+		add: 0@0;
+		add: 0@1;
+		add: 0@2;
+		add: 1@2;
+		yourself
+!
+
+color
+	^'#ffa'
+!
+
+height
+	^3
+! !
+
+TetrisPiece subclass: #TetrisPieceJ
+	instanceVariableNames: ''
+	category: 'Examples'!
+
+!TetrisPieceJ methodsFor: 'accessing'!
+
+color
+	^'#aaf'
+!
+
+bounds
+	^Array new
+		add: 1@0;
+		add: 1@1;
+		add: 1@2;
+		add: 0@2;
+		yourself
+!
+
+height
+	^3
+! !
+
+TetrisPiece subclass: #TetrisPieceI
+	instanceVariableNames: ''
+	category: 'Examples'!
+
+!TetrisPieceI methodsFor: 'accessing'!
+
+color
+	^'#faa'
+!
+
+bounds
+	^Array new
+		add: 0@0;
+		add: 0@1;
+		add: 0@2;
+		add: 0@3;
+		yourself
+!
+
+height
+	^4
+! !
+
+TetrisPiece subclass: #TetrisPieceT
+	instanceVariableNames: ''
+	category: 'Examples'!
+
+!TetrisPieceT methodsFor: 'accessing'!
+
+bounds
+	^Array new
+		add: 0@0;
+		add: 1@0;
+		add: 2@0;
+		add: 1@1;
+		yourself
+!
+
+color
+	^'#aaf'
+! !
+

+ 713 - 162
st/ide.st → st/IDE.st

@@ -1,72 +1,34 @@
 Widget subclass: #TabManager
 Widget subclass: #TabManager
-	instanceVariableNames: 'selectedTab tabs opened'
+	instanceVariableNames: 'selectedTab, tabs, opened'
 	category: 'IDE'!
 	category: 'IDE'!
 
 
-TabManager class instanceVariableNames: 'current'!
-
-!TabManager class methodsFor: 'instance creation'!
-
-current
-    ^current ifNil: [current := super new]
-!
-
-new
-    self shouldNotImplement
-! !
-
-!TabManager methodsFor: 'initialization'!
-
-initialize
-    super initialize.
-    opened := true.
-    'body' asJQuery 
-	append: self;
-	append: [:html | html div id: 'jtalk'];
-	addClass: 'jtalkBody'.
-    self 
-	addTab: Transcript current;
-	addTab: Workspace new.
-    self selectTab: self tabs last.
-    self 
-	onResize: [self updateBodyMargin; updatePosition];
-	onWindowResize: [self updatePosition]
-! !
-
 !TabManager methodsFor: 'accessing'!
 !TabManager methodsFor: 'accessing'!
 
 
 tabs
 tabs
     ^tabs ifNil: [tabs := Array new]
     ^tabs ifNil: [tabs := Array new]
-! !
-
-!TabManager methodsFor: 'adding/Removing'!
 
 
-addTab: aWidget
-    self tabs add: aWidget.
-    '#jtalk' asJQuery append: aWidget.
-    aWidget root asJQuery hide
-!
-
-removeTab: aWidget
-    self tabs remove: aWidget.
-    self update
 ! !
 ! !
 
 
 !TabManager methodsFor: 'actions'!
 !TabManager methodsFor: 'actions'!
 
 
 updateBodyMargin
 updateBodyMargin
     self setBodyMargin: '#jtalk' asJQuery height + 27
     self setBodyMargin: '#jtalk' asJQuery height + 27
+
 !
 !
 
 
 updatePosition
 updatePosition
     {'jQuery(''#jtalk'').css(''top'', '''''').css(''bottom'', ''27px'');'}
     {'jQuery(''#jtalk'').css(''top'', '''''').css(''bottom'', ''27px'');'}
+
 !
 !
 
 
 removeBodyMargin
 removeBodyMargin
     self setBodyMargin: 0
     self setBodyMargin: 0
+
 !
 !
 
 
 setBodyMargin: anInteger
 setBodyMargin: anInteger
     '.jtalkBody' asJQuery cssAt: 'margin-bottom' put: anInteger asString, 'px'
     '.jtalkBody' asJQuery cssAt: 'margin-bottom' put: anInteger asString, 'px'
+
 !
 !
 
 
 onResize: aBlock
 onResize: aBlock
@@ -75,10 +37,12 @@ onResize: aBlock
 	resize: aBlock,
 	resize: aBlock,
 	minHeight: 230
 	minHeight: 230
 });'}
 });'}
+
 !
 !
 
 
 onWindowResize: aBlock
 onWindowResize: aBlock
     {'jQuery(window).resize(aBlock)'}
     {'jQuery(window).resize(aBlock)'}
+
 !
 !
 
 
 open
 open
@@ -89,6 +53,7 @@ open
 	self updateBodyMargin.
 	self updateBodyMargin.
 	selectedTab root asJQuery show.
 	selectedTab root asJQuery show.
 	opened := true]
 	opened := true]
+
 !
 !
 
 
 close
 close
@@ -98,10 +63,12 @@ close
 	self removeBodyMargin.
 	self removeBodyMargin.
 	'body' asJQuery removeClass: 'jtalkBody'.
 	'body' asJQuery removeClass: 'jtalkBody'.
 	opened := false]
 	opened := false]
+
 !
 !
 
 
 newBrowserTab
 newBrowserTab
     Browser open
     Browser open
+
 !
 !
 
 
 selectTab: aWidget
 selectTab: aWidget
@@ -111,6 +78,7 @@ selectTab: aWidget
 	each root asJQuery hide].
 	each root asJQuery hide].
     aWidget root asJQuery show.
     aWidget root asJQuery show.
     self update
     self update
+
 !
 !
 
 
 closeTab: aWidget
 closeTab: aWidget
@@ -118,6 +86,41 @@ closeTab: aWidget
     self selectTab: self tabs last.
     self selectTab: self tabs last.
     aWidget root asJQuery remove.
     aWidget root asJQuery remove.
     self update
     self update
+
+! !
+
+!TabManager methodsFor: 'adding/Removing'!
+
+addTab: aWidget
+    self tabs add: aWidget.
+    '#jtalk' asJQuery append: aWidget.
+    aWidget root asJQuery hide
+
+!
+
+removeTab: aWidget
+    self tabs remove: aWidget.
+    self update
+
+! !
+
+!TabManager methodsFor: 'initialization'!
+
+initialize
+    super initialize.
+    opened := true.
+    'body' asJQuery 
+	append: self;
+	append: [:html | html div id: 'jtalk'];
+	addClass: 'jtalkBody'.
+    self 
+	addTab: Transcript current;
+	addTab: Workspace new.
+    self selectTab: self tabs last.
+    self 
+	onResize: [self updateBodyMargin; updatePosition];
+	onWindowResize: [self updatePosition]
+
 ! !
 ! !
 
 
 !TabManager methodsFor: 'rendering'!
 !TabManager methodsFor: 'rendering'!
@@ -136,6 +139,7 @@ renderOn: html
 		class: 'newtab';
 		class: 'newtab';
 		with: ' + ';
 		with: ' + ';
 		onClick: [self newBrowserTab]]
 		onClick: [self newBrowserTab]]
+
 !
 !
 
 
 renderTabFor: aWidget on: html
 renderTabFor: aWidget on: html
@@ -152,23 +156,32 @@ renderTabFor: aWidget on: html
 		class: 'close';
 		class: 'close';
 		with: 'x';
 		with: 'x';
 		onClick: [self closeTab: aWidget]]]
 		onClick: [self closeTab: aWidget]]]
+
 ! !
 ! !
 
 
+TabManager class instanceVariableNames: 'current'!
 
 
-Widget subclass: #TabWidget
-	instanceVariableNames: ''
-	category: 'IDE'!
+!TabManager class methodsFor: 'instance creation'!
 
 
-!TabWidget class methodsFor: 'instance creation'!
+current
+    ^current ifNil: [current := super new]
+
+!
+
+new
+    self shouldNotImplement
 
 
-open
-    ^self new open
 ! !
 ! !
 
 
+Widget subclass: #TabWidget
+	instanceVariableNames: ''
+	category: 'IDE'!
+
 !TabWidget methodsFor: 'accessing'!
 !TabWidget methodsFor: 'accessing'!
 
 
 label
 label
     self subclassResponsibility
     self subclassResponsibility
+
 ! !
 ! !
 
 
 !TabWidget methodsFor: 'actions'!
 !TabWidget methodsFor: 'actions'!
@@ -177,12 +190,7 @@ open
     TabManager current
     TabManager current
 	addTab: self;
 	addTab: self;
 	selectTab: self
 	selectTab: self
-! !
 
 
-!TabWidget methodsFor: 'testing'!
-
-canBeClosed
-    ^false
 ! !
 ! !
 
 
 !TabWidget methodsFor: 'rendering'!
 !TabWidget methodsFor: 'rendering'!
@@ -197,15 +205,30 @@ renderOn: html
 	    html div
 	    html div
 		class: 'jt_buttons';
 		class: 'jt_buttons';
 		with: [self renderButtonsOn: html]]
 		with: [self renderButtonsOn: html]]
+
 !
 !
 
 
 renderBoxOn: html
 renderBoxOn: html
+
 !
 !
 
 
 renderButtonsOn: html
 renderButtonsOn: html
+
 ! !
 ! !
 
 
+!TabWidget methodsFor: 'testing'!
+
+canBeClosed
+    ^false
 
 
+! !
+
+!TabWidget class methodsFor: 'instance creation'!
+
+open
+    ^self new open
+
+! !
 
 
 TabWidget subclass: #Workspace
 TabWidget subclass: #Workspace
 	instanceVariableNames: 'textarea'
 	instanceVariableNames: 'textarea'
@@ -215,31 +238,37 @@ TabWidget subclass: #Workspace
 
 
 label
 label
     ^'[Workspace]'
     ^'[Workspace]'
+
 !
 !
 
 
 selection
 selection
-    ^{'return document.selection'}
+    {'return document.selection'}
+
 !
 !
 
 
 selectionStart
 selectionStart
-    ^{'return jQuery(''.jt_workspace'')[0].selectionStart'}
+    {'return jQuery(''.jt_workspace'')[0].selectionStart'}
+
 !
 !
 
 
 selectionEnd
 selectionEnd
-    ^{'return jQuery(''.jt_workspace'')[0].selectionEnd'}
+    {'return jQuery(''.jt_workspace'')[0].selectionEnd'}
+
 !
 !
 
 
 selectionStart: anInteger
 selectionStart: anInteger
     {'jQuery(''.jt_workspace'')[0].selectionStart = anInteger'}
     {'jQuery(''.jt_workspace'')[0].selectionStart = anInteger'}
+
 !
 !
 
 
 selectionEnd: anInteger
 selectionEnd: anInteger
     {'jQuery(''.jt_workspace'')[0].selectionEnd = anInteger'}
     {'jQuery(''.jt_workspace'')[0].selectionEnd = anInteger'}
+
 !
 !
 
 
 currentLine
 currentLine
     | lines startLine endLine|
     | lines startLine endLine|
-    lines := textarea asJQuery val tokenize: String cr.
+    lines := textarea asJQuery val tokenize: String lf.
     startLine := endLine := 0.
     startLine := endLine := 0.
     lines do: [:each |
     lines do: [:each |
 	endLine := startLine + each size.
 	endLine := startLine + each size.
@@ -247,39 +276,50 @@ currentLine
 	endLine >= self selectionStart ifTrue: [
 	endLine >= self selectionStart ifTrue: [
 	    self selectionEnd: endLine.
 	    self selectionEnd: endLine.
 	    ^each]]
 	    ^each]]
+
 ! !
 ! !
 
 
 !Workspace methodsFor: 'actions'!
 !Workspace methodsFor: 'actions'!
 
 
 handleKeyDown: anEvent
 handleKeyDown: anEvent
-    ^{'if(anEvent.ctrlKey) {
-		if(anEvent.keyCode === 68) { //ctrl+p
+    {'if(anEvent.ctrlKey) {
+		if(anEvent.keyCode === 80) { //ctrl+p
 			self._printIt();
 			self._printIt();
+			anEvent.preventDefault();
 			return false;
 			return false;
 		}
 		}
-		if(anEvent.keyCode === 80) { //ctrl+d
+		if(anEvent.keyCode === 68) { //ctrl+d
 			self._doIt();
 			self._doIt();
+			anEvent.preventDefault();
+			return false;
+		}
+		if(anEvent.keyCode === 73) { //ctrl+i
+			self._inspectIt();
+			anEvent.preventDefault();
 			return false;
 			return false;
 		}
 		}
 	}'}
 	}'}
+
 !
 !
 
 
 clearWorkspace
 clearWorkspace
     textarea asJQuery val: ''
     textarea asJQuery val: ''
-!
 
 
-doIt
-    self printIt
 !
 !
 
 
-printIt
+doIt
     | selection |
     | selection |
     textarea asJQuery focus.
     textarea asJQuery focus.
     self selectionStart = self selectionEnd
     self selectionStart = self selectionEnd
 	ifTrue: [selection := self currentLine]
 	ifTrue: [selection := self currentLine]
 	ifFalse: [
 	ifFalse: [
 	    selection := textarea asJQuery val copyFrom: self selectionStart + 1 to: self selectionEnd + 1].
 	    selection := textarea asJQuery val copyFrom: self selectionStart + 1 to: self selectionEnd + 1].
-    self print: (self eval: selection) printString
+    ^self eval: selection
+!
+
+printIt
+    self print: self doIt printString
+
 !
 !
 
 
 print: aString
 print: aString
@@ -291,6 +331,7 @@ print: aString
 	(textarea asJQuery val copyFrom: start + 1 to: textarea asJQuery val size)).
 	(textarea asJQuery val copyFrom: start + 1 to: textarea asJQuery val size)).
     self selectionStart: start.
     self selectionStart: start.
     self selectionEnd: start + aString size + 2
     self selectionEnd: start + aString size + 2
+
 !
 !
 
 
 eval: aString
 eval: aString
@@ -300,6 +341,12 @@ eval: aString
     node isParseFailure ifTrue: [
     node isParseFailure ifTrue: [
 	^self alert: node reason, ', position: ', node position].
 	^self alert: node reason, ', position: ', node position].
     ^compiler loadExpression: aString
     ^compiler loadExpression: aString
+
+!
+
+inspectIt
+    self doIt inspect
+
 ! !
 ! !
 
 
 !Workspace methodsFor: 'rendering'!
 !Workspace methodsFor: 'rendering'!
@@ -311,6 +358,7 @@ renderBoxOn: html
     textarea 
     textarea 
 	class: 'jt_workspace';
 	class: 'jt_workspace';
 	at: 'spellcheck' put: 'false'
 	at: 'spellcheck' put: 'false'
+
 !
 !
 
 
 renderButtonsOn: html
 renderButtonsOn: html
@@ -322,52 +370,25 @@ renderButtonsOn: html
 	with: 'PrintIt';
 	with: 'PrintIt';
 	title: 'ctrl+p';
 	title: 'ctrl+p';
 	onClick: [self printIt].
 	onClick: [self printIt].
+    html button
+	with: 'InspectIt';
+	title: 'ctrl+i';
+	onClick: [self inspectIt].
     html button
     html button
 	with: 'Clear workspace';
 	with: 'Clear workspace';
 	onClick: [self clearWorkspace]
 	onClick: [self clearWorkspace]
-! !
-
 
 
+! !
 
 
 TabWidget subclass: #Transcript
 TabWidget subclass: #Transcript
 	instanceVariableNames: 'textarea'
 	instanceVariableNames: 'textarea'
 	category: 'IDE'!
 	category: 'IDE'!
 
 
-Transcript class instanceVariableNames: 'current'!
-
-!Transcript class methodsFor: 'instance creation'!
-
-open
-    self current open
-!
-
-new
-    self shouldNotImplement
-!
-
-current
-    ^current ifNil: [current := super new]
-! !
-
-!Transcript class methodsFor: 'printing'!
-
-show: anObject
-    self current show: anObject
-!
-
-cr
-    self current show: String cr
-!
-
-clear
-    self current clear
-! !
-
-
 !Transcript methodsFor: 'accessing'!
 !Transcript methodsFor: 'accessing'!
 
 
 label
 label
     ^'[Transcript]'
     ^'[Transcript]'
+
 ! !
 ! !
 
 
 !Transcript methodsFor: 'actions'!
 !Transcript methodsFor: 'actions'!
@@ -375,14 +396,17 @@ label
 show: anObject
 show: anObject
     textarea asJQuery val: textarea asJQuery val, anObject asString.
     textarea asJQuery val: textarea asJQuery val, anObject asString.
 
 
+
 !
 !
 
 
 cr
 cr
     textarea asJQuery val: textarea asJQuery val, String cr.
     textarea asJQuery val: textarea asJQuery val, String cr.
+
 !
 !
 
 
 clear
 clear
     textarea asJQuery val: ''
     textarea asJQuery val: ''
+
 ! !
 ! !
 
 
 !Transcript methodsFor: 'rendering'!
 !Transcript methodsFor: 'rendering'!
@@ -393,45 +417,63 @@ renderBoxOn: html
     textarea 
     textarea 
 	class: 'jt_transcript';
 	class: 'jt_transcript';
 	at: 'spellcheck' put: 'false'
 	at: 'spellcheck' put: 'false'
+
 !
 !
 
 
 renderButtonsOn: html
 renderButtonsOn: html
     html button
     html button
 	with: 'Clear transcript';
 	with: 'Clear transcript';
 	onClick: [self clear]
 	onClick: [self clear]
+
 ! !
 ! !
 
 
-TabWidget subclass: #Browser
-	instanceVariableNames: 'selectedCategory selectedClass selectedProtocol selectedMethod commitButton categoriesList classesList protocolsList methodsList sourceTextarea tabsList selectedTab saveButton classButtons methodButtons unsavedChanges'
-	category: 'IDE'!
+Transcript class instanceVariableNames: 'current'!
 
 
-!Browser class methodsFor: 'convenience'!
+!Transcript class methodsFor: 'instance creation'!
+
+open
+    self current open
 
 
-openOn: aClass
-    self new
-	open;
-	selectCategory: aClass category;
-	selectClass: aClass
 !
 !
 
 
-open
-    self new open
+new
+    self shouldNotImplement
+
+!
+
+current
+    ^current ifNil: [current := super new]
+
 ! !
 ! !
 
 
-!Browser methodsFor: 'initialization'!
+!Transcript class methodsFor: 'printing'!
+
+show: anObject
+    self current show: anObject
+
+!
+
+cr
+    self current show: String cr
+
+!
+
+clear
+    self current clear
 
 
-initialize
-    super initialize.
-    selectedTab := #instance.
-    unsavedChanges := false
 ! !
 ! !
 
 
+TabWidget subclass: #Browser
+	instanceVariableNames: 'selectedCategory, selectedClass, selectedProtocol, selectedMethod, commitButton, categoriesList, classesList, protocolsList, methodsList, sourceTextarea, tabsList, selectedTab, saveButton, classButtons, methodButtons, unsavedChanges'
+	category: 'IDE'!
+
 !Browser methodsFor: 'accessing'!
 !Browser methodsFor: 'accessing'!
 
 
 label
 label
     ^selectedClass 
     ^selectedClass 
 	ifNil: ['Browser (nil)']
 	ifNil: ['Browser (nil)']
 	ifNotNil: [selectedClass name]
 	ifNotNil: [selectedClass name]
+
 !
 !
 
 
 categories
 categories
@@ -441,28 +483,27 @@ categories
 	(categories includes: each category) ifFalse: [
 	(categories includes: each category) ifFalse: [
 	    categories add: each category]].
 	    categories add: each category]].
     ^categories sort
     ^categories sort
+
 !
 !
 
 
 classes
 classes
     ^(Smalltalk current classes 
     ^(Smalltalk current classes 
 	select: [:each | each category = selectedCategory])
 	select: [:each | each category = selectedCategory])
 	sort: [:a :b | a name > b name]
 	sort: [:a :b | a name > b name]
+
 !
 !
 
 
 protocols
 protocols
-    | klass protocols |
-    protocols := Array new.
+    | klass |
     selectedClass ifNotNil: [
     selectedClass ifNotNil: [
 	selectedTab = #comment ifTrue: [^#()].
 	selectedTab = #comment ifTrue: [^#()].
 	klass := selectedTab = #instance
 	klass := selectedTab = #instance
 	    ifTrue: [selectedClass]
 	    ifTrue: [selectedClass]
 	    ifFalse: [selectedClass class].
 	    ifFalse: [selectedClass class].
 	klass methodDictionary isEmpty ifTrue: [
 	klass methodDictionary isEmpty ifTrue: [
-	    protocols add: 'not yet classified'].
-	klass methodDictionary do: [:each |
-	    (protocols includes: each category) ifFalse: [
-		protocols add: each category]]].
-    ^protocols sort
+	    ^Array with: 'not yet classified'].
+	^klass protocols].
+    ^Array new
 !
 !
 
 
 methods
 methods
@@ -480,6 +521,7 @@ methods
 	ifNotNil: [
 	ifNotNil: [
 	    klass methodDictionary values select: [:each |
 	    klass methodDictionary values select: [:each |
 		each category = selectedProtocol]]) sort: [:a :b | a selector > b selector]
 		each category = selectedProtocol]]) sort: [:a :b | a selector > b selector]
+
 !
 !
 
 
 source
 source
@@ -490,12 +532,14 @@ source
     ^selectedClass
     ^selectedClass
 	ifNil: ['']
 	ifNil: ['']
 	ifNotNil: [self classCommentSource]
 	ifNotNil: [self classCommentSource]
+
 !
 !
 
 
 methodSource
 methodSource
     ^selectedMethod
     ^selectedMethod
 	ifNil: [self dummyMethodSource]
 	ifNil: [self dummyMethodSource]
 	ifNotNil: [selectedMethod source]
 	ifNotNil: [selectedMethod source]
+
 !
 !
 
 
 dummyMethodSource
 dummyMethodSource
@@ -504,12 +548,14 @@ dummyMethodSource
 
 
 	| temporary variable names |
 	| temporary variable names |
 	statements'
 	statements'
+
 !
 !
 
 
 declarationSource
 declarationSource
     ^selectedTab = #instance
     ^selectedTab = #instance
 	ifTrue: [self classDeclarationSource]
 	ifTrue: [self classDeclarationSource]
 	ifFalse: [self metaclassDeclarationSource]
 	ifFalse: [self metaclassDeclarationSource]
+
 !
 !
 
 
 classDeclarationSource
 classDeclarationSource
@@ -520,17 +566,18 @@ classDeclarationSource
 	    nextPutAll: selectedClass superclass asString;
 	    nextPutAll: selectedClass superclass asString;
 	    nextPutAll: ' subclass: #';
 	    nextPutAll: ' subclass: #';
 	    nextPutAll: selectedClass name;
 	    nextPutAll: selectedClass name;
-	    nextPutAll: String cr, String tab;
+	    nextPutAll: String lf, String tab;
 	    nextPutAll: 'instanceVariableNames: '''.
 	    nextPutAll: 'instanceVariableNames: '''.
 	selectedClass instanceVariableNames 
 	selectedClass instanceVariableNames 
 	    do: [:each | stream nextPutAll: each] 
 	    do: [:each | stream nextPutAll: each] 
 	    separatedBy: [stream nextPutAll: ' '].
 	    separatedBy: [stream nextPutAll: ' '].
 	stream
 	stream
-	    nextPutAll: '''', String cr, String tab;
+	    nextPutAll: '''', String lf, String tab;
 	    nextPutAll: 'category: ''';
 	    nextPutAll: 'category: ''';
 	    nextPutAll: selectedClass category;
 	    nextPutAll: selectedClass category;
 	    nextPutAll: ''''].
 	    nextPutAll: ''''].
     ^stream contents
     ^stream contents
+
 !
 !
 
 
 metaclassDeclarationSource
 metaclassDeclarationSource
@@ -546,10 +593,12 @@ metaclassDeclarationSource
 	    separatedBy: [stream nextPutAll: ' '].
 	    separatedBy: [stream nextPutAll: ' '].
 	stream nextPutAll: ''''].
 	stream nextPutAll: ''''].
     ^stream contents
     ^stream contents
+
 !
 !
 
 
 classCommentSource
 classCommentSource
     ^selectedClass comment
     ^selectedClass comment
+
 ! !
 ! !
 
 
 !Browser methodsFor: 'actions'!
 !Browser methodsFor: 'actions'!
@@ -557,28 +606,34 @@ classCommentSource
 enableSaveButton
 enableSaveButton
     saveButton removeAt: 'disabled'.
     saveButton removeAt: 'disabled'.
     unsavedChanges := true
     unsavedChanges := true
+
 !
 !
 
 
 disableSaveButton
 disableSaveButton
     saveButton ifNotNil: [
     saveButton ifNotNil: [
 	saveButton at: 'disabled' put: true].
 	saveButton at: 'disabled' put: true].
     unsavedChanges := false
     unsavedChanges := false
+
 !
 !
 
 
 hideClassButtons
 hideClassButtons
     classButtons asJQuery hide
     classButtons asJQuery hide
+
 !
 !
 
 
 showClassButtons
 showClassButtons
     classButtons asJQuery show
     classButtons asJQuery show
+
 !
 !
 
 
 hideMethodButtons
 hideMethodButtons
     methodButtons asJQuery hide
     methodButtons asJQuery hide
+
 !
 !
 
 
 showMethodButtons
 showMethodButtons
     methodButtons asJQuery show
     methodButtons asJQuery show
+
 !
 !
 
 
 compile
 compile
@@ -589,16 +644,19 @@ compile
     (selectedProtocol notNil or: [selectedMethod notNil])
     (selectedProtocol notNil or: [selectedMethod notNil])
 	ifFalse: [self compileDefinition]
 	ifFalse: [self compileDefinition]
 	ifTrue: [self compileMethodDefinition]
 	ifTrue: [self compileMethodDefinition]
+
 !
 !
 
 
 compileClassComment
 compileClassComment
     selectedClass comment: sourceTextarea asJQuery val
     selectedClass comment: sourceTextarea asJQuery val
+
 !
 !
 
 
 compileMethodDefinition
 compileMethodDefinition
     selectedTab = #instance
     selectedTab = #instance
 	ifTrue: [self compileMethodDefinitionFor: selectedClass]
 	ifTrue: [self compileMethodDefinitionFor: selectedClass]
 	ifFalse: [self compileMethodDefinitionFor: selectedClass class]
 	ifFalse: [self compileMethodDefinitionFor: selectedClass class]
+
 !
 !
 
 
 compileMethodDefinitionFor: aClass
 compileMethodDefinitionFor: aClass
@@ -612,9 +670,14 @@ compileMethodDefinitionFor: aClass
     compiler currentClass: selectedClass.
     compiler currentClass: selectedClass.
     method := compiler eval: (compiler compileNode: node).
     method := compiler eval: (compiler compileNode: node).
     method category: selectedProtocol.
     method category: selectedProtocol.
+    compiler unknownVariables do: [:each |
+	(self confirm: 'Declare ''', each, ''' as instance variable?') ifTrue: [
+		self addInstanceVariableNamed: each toClass: aClass.
+		^self compileMethodDefinitionFor: aClass]].
     aClass addCompiledMethod: method.
     aClass addCompiledMethod: method.
     self updateMethodsList.
     self updateMethodsList.
     self selectMethod: method
     self selectMethod: method
+
 !
 !
 
 
 compileDefinition
 compileDefinition
@@ -623,23 +686,29 @@ compileDefinition
     self 
     self 
 	updateCategoriesList;
 	updateCategoriesList;
 	updateClassesList
 	updateClassesList
+
 !
 !
 
 
 commitCategory
 commitCategory
     selectedCategory ifNotNil: [
     selectedCategory ifNotNil: [
-	(Ajax url: 'js/', selectedCategory, '.js')
+	(Ajax url: self class commitPathJs, '/', selectedCategory, '.js')
 	    at: 'type' put: 'PUT';
 	    at: 'type' put: 'PUT';
 	    at: 'data' put: (Exporter new exportCategory: selectedCategory);
 	    at: 'data' put: (Exporter new exportCategory: selectedCategory);
-	    at: 'error' put: [self alert: 'Commit failed!!'];
+	    at: 'error' put: [self alert: 'Commit failed!'];
+	    send.
+	(Ajax url: self class commitPathSt, '/', selectedCategory, '.st')
+	    at: 'type' put: 'PUT';
+	    at: 'data' put: (ChunkExporter new exportCategory: selectedCategory);
+	    at: 'error' put: [self alert: 'Commit failed!'];
 	    send]
 	    send]
-!
-
 
 
+!
 
 
 cancelChanges
 cancelChanges
     ^unsavedChanges 
     ^unsavedChanges 
 	ifTrue: [self confirm: 'Cancel changes?']
 	ifTrue: [self confirm: 'Cancel changes?']
 	ifFalse: [true]
 	ifFalse: [true]
+
 !
 !
 
 
 removeClass
 removeClass
@@ -647,14 +716,18 @@ removeClass
 	ifTrue: [
 	ifTrue: [
 	    Smalltalk current basicDelete: selectedClass name.
 	    Smalltalk current basicDelete: selectedClass name.
 	    self selectClass: nil]
 	    self selectClass: nil]
+
 !
 !
 
 
 removeMethod
 removeMethod
     self cancelChanges ifTrue: [
     self cancelChanges ifTrue: [
 	(self confirm: 'Do you really want to remove #', selectedMethod selector, '?')
 	(self confirm: 'Do you really want to remove #', selectedMethod selector, '?')
 	    ifTrue: [
 	    ifTrue: [
-		selectedClass removeCompiledMethod: selectedMethod.
+		selectedTab = #instance 
+			ifTrue: [selectedClass removeCompiledMethod: selectedMethod]
+			ifFalse: [selectedClass class removeCompiledMethod: selectedMethod].
 		self selectMethod: nil]]
 		self selectMethod: nil]]
+
 !
 !
 
 
 setMethodProtocol: aString
 setMethodProtocol: aString
@@ -669,6 +742,7 @@ setMethodProtocol: aString
 		    updateProtocolsList;
 		    updateProtocolsList;
 		    updateMethodsList;
 		    updateMethodsList;
 		    updateSourceAndButtons]]
 		    updateSourceAndButtons]]
+
 !
 !
 
 
 addNewProtocol
 addNewProtocol
@@ -677,6 +751,7 @@ addNewProtocol
     newProtocol notEmpty ifTrue: [
     newProtocol notEmpty ifTrue: [
 	selectedMethod category: newProtocol.
 	selectedMethod category: newProtocol.
 	self setMethodProtocol: newProtocol]
 	self setMethodProtocol: newProtocol]
+
 !
 !
 
 
 selectCategory: aCategory
 selectCategory: aCategory
@@ -689,6 +764,7 @@ selectCategory: aCategory
 	    updateProtocolsList;
 	    updateProtocolsList;
 	    updateMethodsList;
 	    updateMethodsList;
 	    updateSourceAndButtons]
 	    updateSourceAndButtons]
+
 !
 !
 
 
 selectClass: aClass
 selectClass: aClass
@@ -700,6 +776,7 @@ selectClass: aClass
 	    updateProtocolsList;
 	    updateProtocolsList;
 	    updateMethodsList;
 	    updateMethodsList;
 	    updateSourceAndButtons]
 	    updateSourceAndButtons]
+
 !
 !
 
 
 selectProtocol: aString
 selectProtocol: aString
@@ -710,6 +787,7 @@ selectProtocol: aString
 	    updateProtocolsList;
 	    updateProtocolsList;
 	    updateMethodsList;
 	    updateMethodsList;
 	    updateSourceAndButtons]
 	    updateSourceAndButtons]
+
 !
 !
 
 
 selectMethod: aMethod
 selectMethod: aMethod
@@ -719,6 +797,7 @@ selectMethod: aMethod
 	    updateProtocolsList;
 	    updateProtocolsList;
 	    updateMethodsList;
 	    updateMethodsList;
 	    updateSourceAndButtons]
 	    updateSourceAndButtons]
+
 !
 !
 
 
 selectTab: aString
 selectTab: aString
@@ -726,8 +805,41 @@ selectTab: aString
 	selectedTab := aString.
 	selectedTab := aString.
 	self selectProtocol: nil.
 	self selectProtocol: nil.
 	self updateTabsList]
 	self updateTabsList]
+
+!
+
+renameClass
+    | newName |
+    newName := self prompt: 'Rename class ', selectedClass name.
+    newName notEmpty ifTrue: [
+	selectedClass rename: newName.
+	self 
+		updateClassesList;
+		updateSourceAndButtons]
+
+!
+
+addInstanceVariableNamed: aString toClass: aClass
+	ClassBuilder new
+		addSubclassOf: aClass superclass named: aClass name instanceVariableNames: (aClass instanceVariableNames copy add: aString; yourself)
+!
+
+searchReferencesOf: aString
+	ReferencesBrowser search: aString
+!
+
+searchClassReferences
+	ReferencesBrowser search: selectedClass name
 ! !
 ! !
 
 
+!Browser methodsFor: 'initialization'!
+
+initialize
+    super initialize.
+    selectedTab := #instance.
+    unsavedChanges := false
+
+! !
 
 
 !Browser methodsFor: 'rendering'!
 !Browser methodsFor: 'rendering'!
 
 
@@ -736,6 +848,7 @@ renderBoxOn: html
 	renderTopPanelOn: html;
 	renderTopPanelOn: html;
 	renderTabsOn: html;
 	renderTabsOn: html;
 	renderBottomPanelOn: html
 	renderBottomPanelOn: html
+
 !
 !
 
 
 renderTopPanelOn: html
 renderTopPanelOn: html
@@ -757,11 +870,13 @@ renderTopPanelOn: html
 		updateProtocolsList;
 		updateProtocolsList;
 		updateMethodsList.
 		updateMethodsList.
 	    html div class: 'jt_clear']
 	    html div class: 'jt_clear']
+
 !
 !
 
 
 renderTabsOn: html
 renderTabsOn: html
     tabsList := html ul class: 'jt_tabs'.
     tabsList := html ul class: 'jt_tabs'.
     self updateTabsList.
     self updateTabsList.
+
 !
 !
 
 
 renderBottomPanelOn: html
 renderBottomPanelOn: html
@@ -773,6 +888,7 @@ renderBottomPanelOn: html
 		class: 'source';
 		class: 'source';
 		at: 'spellcheck' put: 'false'.
 		at: 'spellcheck' put: 'false'.
 	    sourceTextarea asJQuery call: 'tabby']
 	    sourceTextarea asJQuery call: 'tabby']
+
 !
 !
 
 
 renderButtonsOn: html
 renderButtonsOn: html
@@ -783,19 +899,31 @@ renderButtonsOn: html
     methodButtons := html span.
     methodButtons := html span.
     classButtons := html span.
     classButtons := html span.
     self updateSourceAndButtons
     self updateSourceAndButtons
+
+! !
+
+!Browser methodsFor: 'testing'!
+
+canBeClosed
+    ^true
+
 ! !
 ! !
 
 
 !Browser methodsFor: 'updating'!
 !Browser methodsFor: 'updating'!
 
 
 updateCategoriesList
 updateCategoriesList
     categoriesList contents: [:html |
     categoriesList contents: [:html |
-	self categories do: [:each || li |
+	self categories do: [:each || li label |
+	    each isEmpty 
+		ifTrue: [label := 'Unclassified']
+		ifFalse: [label := each].
 	    li := html li.
 	    li := html li.
 	    selectedCategory = each ifTrue: [
 	    selectedCategory = each ifTrue: [
 		li class: 'selected'].
 		li class: 'selected'].
 	    li
 	    li
-		with: each;
+		with: label;
 		onClick: [self selectCategory: each]]]
 		onClick: [self selectCategory: each]]]
+
 !
 !
 
 
 updateClassesList
 updateClassesList
@@ -808,6 +936,7 @@ updateClassesList
 	    li
 	    li
 		with: each name;
 		with: each name;
 		onClick: [self selectClass: each]]]
 		onClick: [self selectClass: each]]]
+
 !
 !
 
 
 updateProtocolsList
 updateProtocolsList
@@ -819,6 +948,7 @@ updateProtocolsList
 	    li 
 	    li 
 		with: each;
 		with: each;
 		onClick: [self selectProtocol: each]]]
 		onClick: [self selectProtocol: each]]]
+
 !
 !
 
 
 updateMethodsList
 updateMethodsList
@@ -830,6 +960,7 @@ updateMethodsList
 	    li
 	    li
 		with: each selector;
 		with: each selector;
 		onClick: [self selectMethod: each]]]
 		onClick: [self selectMethod: each]]]
+
 !
 !
 
 
 updateTabsList
 updateTabsList
@@ -849,50 +980,470 @@ updateTabsList
 	li
 	li
 	    with: 'Comment';
 	    with: 'Comment';
 	    onClick: [self selectTab: #comment]]
 	    onClick: [self selectTab: #comment]]
+
 !
 !
 
 
 updateSourceAndButtons
 updateSourceAndButtons
-    self disableSaveButton.
-    classButtons contents: [:html |
-	html button
-	    with: 'Remove class';
-	    onClick: [self removeClass]].
-    methodButtons contents: [:html |
+	self disableSaveButton.
+	classButtons contents: [:html |
+		html button
+			with: 'Rename class';
+			onClick: [self renameClass].
+		html button
+			with: 'Remove class';
+			onClick: [self removeClass].
+		html button
+			with: 'References';
+			onClick: [self searchClassReferences]].
+	methodButtons contents: [:html |
+		html button
+			with: 'Remove method';
+			onClick: [self removeMethod].
+		html select 
+	    		onChange: [:e :select | self setMethodProtocol: select val];
+	    		with: [
+				html option
+		    			with: 'Method protocol';
+					at: 'disabled' put: 'disabled'.
+				html option
+		    			class: 'important';
+		    			with: 'New...'.
+				self protocols do: [:each |
+		    			html option with: each]].
+		selectedMethod isNil ifFalse: [
+			html select 
+	    			onChange: [:e :select | self searchReferencesOf: select val];
+	    			with: [
+					html option
+		    				with: 'References';
+						at: 'disabled' put: 'disabled'.
+					html option
+		    				class: 'important';
+		    				with: selectedMethod selector.
+					selectedMethod messageSends sorted do: [:each |
+		    				html option with: each]]]].
+    	selectedMethod isNil
+		ifTrue: [
+	    		self hideMethodButtons.
+	    			(selectedClass isNil or: [selectedProtocol notNil])
+					ifTrue: [self hideClassButtons]
+	    				ifFalse: [self showClassButtons]]
+		ifFalse: [
+	    		self hideClassButtons.
+	    		self showMethodButtons].
+    	sourceTextarea asJQuery val: self source
+
+! !
+
+!Browser class methodsFor: 'accessing'!
+
+commitPathJs
+	^'js'
+!
+
+commitPathSt
+	^'st'
+! !
+
+!Browser class methodsFor: 'convenience'!
+
+openOn: aClass
+    ^self new
+	open;
+	selectCategory: aClass category;
+	selectClass: aClass
+
+!
+
+open
+    self new open
+
+! !
+
+TabWidget subclass: #Inspector
+	instanceVariableNames: 'label, variables, object, selectedVariable, variablesList, valueTextarea, workspaceTextarea, diveButton'
+	category: 'IDE'!
+
+!Inspector methodsFor: 'accessing'!
+
+label
+	^label ifNil: ['Inspector (nil)']
+!
+
+variables
+	^variables
+!
+
+setVariables: aCollection
+	variables := aCollection
+!
+
+setLabel: aString
+	label := aString
+!
+
+selectedVariable
+	^selectedVariable
+!
+
+selectedVariable: aString
+	selectedVariable := aString
+! !
+
+!Inspector methodsFor: 'actions'!
+
+inspect: anObject
+	object := anObject.
+	variables := #().
+	object inspectOn: self
+!
+
+dive
+	(self variables at: self selectedVariable) inspect
+!
+
+refresh
+	self 
+		inspect: object; 
+		updateVariablesList;
+		updateValueTextarea
+! !
+
+!Inspector methodsFor: 'rendering'!
+
+renderBoxOn: html
+	self 
+		renderTopPanelOn: html;
+		renderBottomPanelOn: html
+!
+
+renderTopPanelOn: html
+    html div 
+	class: 'top'; 
+	with: [
+	    variablesList := html ul class: 'jt_column variables'.
+	    valueTextarea := html textarea class: 'jt_column value'; at: 'readonly' put: 'readonly'.
+	    self
+		updateVariablesList;
+		updateValueTextarea.
+	    html div class: 'jt_clear']
+
+!
+
+renderBottomPanelOn: html
+    html div
+	class: 'jt_sourceCode';
+	with: [
+	    workspaceTextarea := html textarea 
+		class: 'source';
+		at: 'spellcheck' put: 'false'.
+	    workspaceTextarea asJQuery call: 'tabby']
+
+!
+
+renderButtonsOn: html
 	html button
 	html button
-	    with: 'Remove method';
-	    onClick: [self removeMethod].
-	html select 
-	    onChange: [:s | self setMethodProtocol: s val];
-	    with: [
-		html option
-		    with: 'Method protocol';
-		    at: 'disabled' put: 'disabled'.
-		html option
-		    class: 'important';
-		    with: 'New...'.
-		self protocols do: [:each |
-		    html option with: each]]].
-    selectedMethod 
-	ifNil: [
-	    self hideMethodButtons.
-	    selectedClass 
-		ifNil: [self hideClassButtons]
-	    ifNotNil: [self showClassButtons]]
-	ifNotNil: [
-	    self hideClassButtons.
-	    self showMethodButtons].
-    sourceTextarea asJQuery val: self source
+		with: 'Refresh';
+		onClick: [self refresh].
+	diveButton := html button 
+		with: 'Dive'; 
+		onClick: [self dive].
+	self updateButtons
+	
 ! !
 ! !
 
 
-!Browser methodsFor: 'testing'!
+!Inspector methodsFor: 'testing'!
 
 
 canBeClosed
 canBeClosed
-    ^true
+	^true
 ! !
 ! !
+
+!Inspector methodsFor: 'updating'!
+
+updateVariablesList
+	variablesList contents: [:html |
+		self variables keys do: [:each || li |
+			li := html li.
+			li
+				with: each;
+				onClick: [self selectVariable: each].
+			self selectedVariable = each ifTrue: [
+				li class: 'selected']]]
+!
+
+selectVariable: aString
+	self selectedVariable: aString.
+	self 
+		updateVariablesList;
+		updateValueTextarea;
+		updateButtons
+!
+
+updateValueTextarea
+	valueTextarea asJQuery val: (self selectedVariable isNil
+		ifTrue: ['']
+		ifFalse: [(self variables at: self selectedVariable) printString])
+!
+
+updateButtons
+	(self selectedVariable notNil and: [(self variables at: self selectedVariable) notNil])
+		ifFalse: [diveButton at: 'disabled' put: true] 
+		ifTrue: [diveButton removeAt: 'disabled']
 		
 		
+! !
+
+!Inspector class methodsFor: 'instance creation'!
+
+on: anObject
+	^self new
+		inspect: anObject;
+		yourself
+! !
+
+TabWidget subclass: #ReferencesBrowser
+	instanceVariableNames: 'implementors, senders, implementorsList, input, timer, selector, sendersList, referencedClasses, referencedClassesList'
+	category: 'IDE'!
+
+!ReferencesBrowser methodsFor: 'accessing'!
+
+implementors
+	^implementors ifNil: [implementors := Array new]
+!
 
 
+label
+	^'[ReferencesBrowser]'
+!
+
+selector
+	^selector
+!
+
+senders
+	^senders ifNil: [senders := Array new]
+!
+
+classesAndMetaclasses
+	^Smalltalk current classes, (Smalltalk current classes collect: [:each | each class])
+!
+
+referencedClasses
+	^referencedClasses ifNil: [referencedClasses := Array new]
+! !
+
+!ReferencesBrowser methodsFor: 'actions'!
+
+openBrowserOn: aMethod
+       | browser |
+       browser := Browser openOn: (aMethod class isMetaclass 
+		ifTrue: [aMethod methodClass instanceClass] ifFalse: [aMethod methodClass]).
+       aMethod methodClass isMetaclass ifTrue: [browser selectTab: #class].
+       browser
+               selectProtocol: aMethod category;
+               selectMethod: aMethod
+!
+
+searchReferencesFor: aString
+	selector := aString.
+	implementors := Array new.
+	senders := Array new.
+	referencedClasses := Array new.
+	(selector match: '^[A-Z]') 
+		ifFalse: [self searchSelectorReferencesFor: selector]
+		ifTrue: [self searchReferencedClassesFor: selector]
+!
+
+search: aString
+	self 
+		searchReferencesFor: aString;
+		updateImplementorsList;
+		updateSendersList;
+		updateReferencedClassesList
+!
+
+searchReferencedClassesFor: aString
+	self classesAndMetaclasses do: [:each |
+		each methodDictionary values do: [:value |
+			(((value referencedClasses select: [:each | each notNil])collect: [:each | each name]) includes: selector) ifTrue: [
+				self referencedClasses add: value]]]
+!
+
+searchSelectorReferencesFor: aString
+	self classesAndMetaclasses do: [:each | 
+		each methodDictionary keysAndValuesDo: [:key :value | 
+			key = selector ifTrue: [self implementors add: value]].
+		each methodDictionary keysAndValuesDo: [:key :value | 
+			(value messageSends includes: selector) ifTrue: [
+				self senders add: value]]]
+! !
+
+!ReferencesBrowser methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	selector := ''
+! !
+
+!ReferencesBrowser methodsFor: 'private'!
+
+setInputEvents
+	input
+		onKeyUp: [timer := [self search: input asJQuery val] valueWithTimeout: 100];
+		onKeyDown: [timer ifNotNil: [timer clearTimeout]]
+! !
+
+!ReferencesBrowser methodsFor: 'rendering'!
+
+renderBoxOn: html
+	self 
+		renderInputOn: html;
+		renderImplementorsOn: html;
+		renderSendersOn: html;
+		renderReferencedClassesOn: html
+!
+
+renderInputOn: html
+	input := html input 
+		class: 'implementors';
+		yourself.
+	input asJQuery val: selector.
+	self setInputEvents
+!
+
+renderImplementorsOn: html
+    	implementorsList := html ul class: 'jt_column implementors'.
+	self updateImplementorsList
+!
+
+renderSendersOn: html
+    	sendersList := html ul class: 'jt_column senders'.
+	self updateSendersList
+!
 
 
+renderReferencedClassesOn: html
+    	referencedClassesList := html ul class: 'jt_column referenced_classes'.
+	self updateReferencedClassesList
+! !
 
 
+!ReferencesBrowser methodsFor: 'testing'!
 
 
+canBeClosed
+	^true
+! !
+
+!ReferencesBrowser methodsFor: 'updating'!
+
+updateImplementorsList
+    implementorsList contents: [:html |
+	html li
+		class: 'column_label'; 
+		with: 'Implementors';
+		style: 'font-weight: bold'.
+	self implementors do: [:each || li |
+	    li := html li.
+	    li
+		with: (each methodClass asString, ' >> ', self selector);
+		onClick: [self openBrowserOn: each]]]
+!
+
+updateSendersList
+    	sendersList contents: [:html |
+	html li
+		class: 'column_label'; 
+		with: 'Senders';
+		style: 'font-weight: bold'.
+	self senders do: [:each |
+		html li
+	    		with: (each methodClass asString, ' >> ', each selector);
+			onClick: [self openBrowserOn: each]]]
+!
+
+updateReferencedClassesList
+    	referencedClassesList contents: [:html |
+	html li
+		class: 'column_label'; 
+		with: 'Class references';
+		style: 'font-weight: bold'.
+	self referencedClasses do: [:each |
+		html li
+	    		with: (each methodClass asString, ' >> ', each selector);
+			onClick: [self openBrowserOn: each]]]
+! !
 
 
+!ReferencesBrowser class methodsFor: 'instance creation'!
+
+search: aString
+	^self new
+		searchReferencesFor: aString;
+		open
+! !
+
+
+
+inspect
+	Inspector new 
+		inspect: self;
+		open
+!
+
+inspectOn: anInspector
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self.
+	self class instanceVariableNames do: [:each |
+		variables at: each put: (self instVarAt: each)].
+	anInspector 
+		setLabel: self printString;
+		setVariables: variables
 	
 	
+	
+!
+
+inspectOn: anInspector
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self.
+	variables at: '#year' put: self year.
+	variables at: '#month' put: self month.
+	variables at: '#day' put: self day.
+	variables at: '#hours' put: self hours.
+	variables at: '#minutes' put: self minutes.
+	variables at: '#seconds' put: self seconds.
+	variables at: '#milliseconds' put: self milliseconds.
+	anInspector 
+		setLabel: self printString;
+		setVariables: variables
+	
+	
+!
+
+inspectOn: anInspector
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self.
+	self withIndexDo: [:each :i |
+		variables at: i put: each].
+	anInspector 
+		setLabel: self printString;
+		setVariables: variables
+!
+
+inspectOn: anInspector
+	| label |
+	super inspectOn: anInspector.
+	self printString size > 30 
+		ifTrue: [label := (self printString copyFrom: 1 to: 30), '...''']
+		ifFalse: [label := self printString]. 
+	anInspector setLabel: label
+!
+
+inspectOn: anInspector
+	| variables |
+	variables := Dictionary new.
+	variables at: '#self' put: self.
+	variables at: '#keys' put: self keys.
+	self keysAndValuesDo: [:key :value |
+		variables at: key put: value].
+	anInspector 
+		setLabel: self printString;
+		setVariables: variables
+!

+ 131 - 61
st/jQuery.st → st/JQuery.st

@@ -2,18 +2,34 @@ Object subclass: #JQuery
 	instanceVariableNames: 'jquery'
 	instanceVariableNames: 'jquery'
 	category: 'JQuery'!
 	category: 'JQuery'!
 
 
-!JQuery class methodsFor: 'instance creation'!
+!JQuery methodsFor: 'DOM insertion'!
+
+append: anObject
+    "Append anObject at the end of the element."
+    anObject appendToJQuery: self
 
 
-fromString: aString
-    | newJQuery |
-    {'newJQuery = jQuery(String(aString))'}.
-    ^self from: newJQuery
 !
 !
 
 
-from: anObject
-    ^self new
-	initializeWithJQueryObject: anObject;
-	yourself
+appendElement: anElement
+    "Append anElement at the end of the element.
+     Dont't call this method directly, use #append: instead"
+    self call: 'append' withArgument: anElement
+
+!
+
+appendToJQuery: aJQuery
+    aJQuery appendElement: jquery
+
+!
+
+contents: anObject
+    self empty.
+    self append: anObject
+
+!
+
+empty
+    ^self call: 'empty'
 ! !
 ! !
 
 
 !JQuery methodsFor: 'attributes'!
 !JQuery methodsFor: 'attributes'!
@@ -21,253 +37,307 @@ from: anObject
 removeAttribute: aString
 removeAttribute: aString
     "Remove an attribute from each element in the set of matched elements."
     "Remove an attribute from each element in the set of matched elements."
     ^self call: 'removeAttribute' withArgument: aString
     ^self call: 'removeAttribute' withArgument: aString
+
 !
 !
 
 
 attr: aString
 attr: aString
     "Get the value of an attribute for the first element in the set of matched elements."
     "Get the value of an attribute for the first element in the set of matched elements."
     ^self call: 'attr' withArgument: aString
     ^self call: 'attr' withArgument: aString
+
 !
 !
 
 
 val
 val
     "Get the current value of the first element in the set of matched elements."
     "Get the current value of the first element in the set of matched elements."
     ^self call: 'val'
     ^self call: 'val'
+
 !
 !
 
 
 val: aString
 val: aString
     self call: 'val' withArgument: aString
     self call: 'val' withArgument: aString
+
 ! !
 ! !
 
 
 !JQuery methodsFor: 'css'!
 !JQuery methodsFor: 'css'!
 
 
 cssAt: aString
 cssAt: aString
-    ^{'return self[''@jquery''].css(aString)'}
+	{'return self[''@jquery''].css(aString)'}
 !
 !
 
 
 cssAt: aString put: anotherString
 cssAt: aString put: anotherString
     {'self[''@jquery''].css(aString, anotherString)'}
     {'self[''@jquery''].css(aString, anotherString)'}
+
 !
 !
- 
+
 addClass: aString
 addClass: aString
     "Adds the specified class(es) to each of the set of matched elements."
     "Adds the specified class(es) to each of the set of matched elements."
     self call: 'addClass' withArgument: aString
     self call: 'addClass' withArgument: aString
+
 !
 !
 
 
 removeClass: aString
 removeClass: aString
     "Remove a single class, multiple classes, or all classes from each element in the set of matched elements."
     "Remove a single class, multiple classes, or all classes from each element in the set of matched elements."
     self call: 'removeClass' withArgument: aString
     self call: 'removeClass' withArgument: aString
+
 !
 !
 
 
 toggleClass: aString
 toggleClass: aString
     "Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument."
     "Add or remove one or more classes from each element in the set of matched elements, depending on either the class's presence or the value of the switch argument."
     self call: 'toggleClass' withArgument: aString
     self call: 'toggleClass' withArgument: aString
+
 !
 !
 
 
 height 
 height 
     "Get the current computed height for the first element in the set of matched elements."
     "Get the current computed height for the first element in the set of matched elements."
     ^self call: 'height'
     ^self call: 'height'
+
 !
 !
 
 
 height: anInteger
 height: anInteger
     self call: 'height' withArgument: anInteger
     self call: 'height' withArgument: anInteger
+
 !
 !
 
 
 width: anInteger
 width: anInteger
     self call: 'width' withArgument: anInteger
     self call: 'width' withArgument: anInteger
+
 !
 !
- 
+
 width
 width
     "Get the current computed width for the first element in the set of matched elements."
     "Get the current computed width for the first element in the set of matched elements."
     ^self call: 'width'
     ^self call: 'width'
+
 !
 !
 
 
 innerHeight
 innerHeight
     "Get the current computed height for the first element in the set of matched elements, including padding but not border."
     "Get the current computed height for the first element in the set of matched elements, including padding but not border."
     ^self call: 'innerHeight'
     ^self call: 'innerHeight'
+
 !
 !
 
 
 innerWidth
 innerWidth
     "Get the current computed width for the first element in the set of matched elements, including padding but not border."
     "Get the current computed width for the first element in the set of matched elements, including padding but not border."
     ^self call: 'innerWidth'
     ^self call: 'innerWidth'
+
 !
 !
 
 
 outerHeight
 outerHeight
     "Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin."
     "Get the current computed height for the first element in the set of matched elements, including padding, border, and optionally margin."
     ^self call: 'outerHeight'
     ^self call: 'outerHeight'
+
 !
 !
 
 
 outerWidth
 outerWidth
     "Get the current computed width for the first element in the set of matched elements, including padding and border."
     "Get the current computed width for the first element in the set of matched elements, including padding and border."
     ^self call: 'outerWidth'
     ^self call: 'outerWidth'
+
 !
 !
 
 
 top
 top
     "Get the current y coordinate of the first element in the set of matched elements, relative to the offset parent."
     "Get the current y coordinate of the first element in the set of matched elements, relative to the offset parent."
     ^(self call: 'position') basicAt: 'top'
     ^(self call: 'position') basicAt: 'top'
+
 !
 !
 
 
 left
 left
     "Get the current x coordinate of the first element in the set of matched elements, relative to the offset parent."
     "Get the current x coordinate of the first element in the set of matched elements, relative to the offset parent."
     ^(self call: 'position') basicAt: 'left'
     ^(self call: 'position') basicAt: 'left'
+
 !
 !
 
 
 offsetLeft
 offsetLeft
     "Get the current coordinates of the first element in the set of matched elements, relative to the document."
     "Get the current coordinates of the first element in the set of matched elements, relative to the document."
     ^(self call: 'offset') basicAt: 'left'
     ^(self call: 'offset') basicAt: 'left'
+
 !
 !
 
 
 offsetTop
 offsetTop
     "Get the current coordinates of the first element in the set of matched elements, relative to the document."
     "Get the current coordinates of the first element in the set of matched elements, relative to the document."
     ^(self call: 'offset') basicAt: 'top'
     ^(self call: 'offset') basicAt: 'top'
+
 !
 !
 
 
 scrollLeft
 scrollLeft
     "Get the current horizontal position of the scroll bar for the first element in the set of matched elements."
     "Get the current horizontal position of the scroll bar for the first element in the set of matched elements."
     ^self call: 'scrollLeft'
     ^self call: 'scrollLeft'
+
 !
 !
 
 
 scrollTop
 scrollTop
     "Get the current vertical position of the scroll bar for the first element in the set of matched elements."
     "Get the current vertical position of the scroll bar for the first element in the set of matched elements."
     ^self call: 'scrollTop'
     ^self call: 'scrollTop'
+
 !
 !
 
 
 scrollLeft: anInteger
 scrollLeft: anInteger
     self call: 'scrollLeft' withArgument: anInteger
     self call: 'scrollLeft' withArgument: anInteger
+
 !
 !
 
 
 scrollTop: anInteger
 scrollTop: anInteger
     self call: 'scrollTop' withArgument: anInteger
     self call: 'scrollTop' withArgument: anInteger
+
 ! !
 ! !
 
 
 !JQuery methodsFor: 'events'!
 !JQuery methodsFor: 'events'!
 
 
 focus
 focus
     self call: 'focus'
     self call: 'focus'
+
 !
 !
 
 
 show
 show
     self call: 'show'
     self call: 'show'
+
 !
 !
 
 
 hide
 hide
     self call: 'hide'
     self call: 'hide'
+
 !
 !
 
 
 remove
 remove
     self call: 'remove'
     self call: 'remove'
+
 !
 !
 
 
 on: anEventString do: aBlock
 on: anEventString do: aBlock
     "Attach aBlock for anEventString on the element"
     "Attach aBlock for anEventString on the element"
-    {'self[''@jquery''].bind(anEventString, function(e){aBlock(self)})'}
+    {'self[''@jquery''].bind(anEventString, function(e){aBlock(e, self)})'}
+
 !
 !
 
 
 removeEvents: aString
 removeEvents: aString
     "Unbind all handlers attached to the event aString"
     "Unbind all handlers attached to the event aString"
     self call: 'unbind' withArgument: aString
     self call: 'unbind' withArgument: aString
-! !
-
-!JQuery methodsFor: 'DOM insertion'!
-
-append: anObject
-    "Append anObject at the end of the element."
-    anObject appendToJQuery: self
-!
-
-appendElement: anElement
-    "Append anElement at the end of the element.
-     Dont't call this method directly, use #append: instead"
-    self call: 'append' withArgument: anElement
-!
-
-appendToJQuery: aJQuery
-    aJQuery appendElement: jquery
-!
-
-contents: anObject
-    self empty.
-    self append: anObject
-!
 
 
-empty
-    self call: 'empty'
 ! !
 ! !
 
 
 !JQuery methodsFor: 'initialization'!
 !JQuery methodsFor: 'initialization'!
 
 
 initializeWithJQueryObject: anObject
 initializeWithJQueryObject: anObject
     jquery := anObject
     jquery := anObject
+
 ! !
 ! !
 
 
 !JQuery methodsFor: 'private'!
 !JQuery methodsFor: 'private'!
 
 
 call: aString
 call: aString
-    ^{'return self[''@jquery''][aString]()'}
+	{'return self[''@jquery''][aString]()'}
 !
 !
 
 
 call: aString withArgument: anObject
 call: aString withArgument: anObject
-    ^{'return self[''@jquery''][aString](anObject)'}
+    {'return self[''@jquery''][aString](anObject)'}
 ! !
 ! !
 
 
-
 !JQuery methodsFor: 'testing'!
 !JQuery methodsFor: 'testing'!
 
 
 hasClass: aString
 hasClass: aString
     "Determine whether any of the matched elements are assigned the given class."
     "Determine whether any of the matched elements are assigned the given class."
     ^self call: 'hasClass' withArgument: aString
     ^self call: 'hasClass' withArgument: aString
-! !
-
 
 
-Object subclass: #Ajax
-	instanceVariableNames: 'settings'
-	category: 'JQuery'!
+! !
 
 
-!Ajax commentStamp!
+!JQuery class methodsFor: 'instance creation'!
 
 
-instance variable names:
-- settings  A set of key/value pairs that configure the Ajax request. All settings are optional.
+fromString: aString
+    | newJQuery |
+    {'newJQuery = jQuery(String(aString))'}.
+    ^self from: newJQuery
 
 
-Full list of settings options at http://api.jquery.com/jQuery.ajax/
 !
 !
 
 
-!Ajax class methodsFor: 'instance creation'!
-
-url: aString
+from: anObject
     ^self new
     ^self new
-	url: aString;
+	initializeWithJQueryObject: anObject;
 	yourself
 	yourself
-! !
 
 
-!Ajax methodsFor: 'initialization'!
+!
 
 
-initialize
-    super initialize.
-    settings := Dictionary new
+window
+	{'return self._from_(jQuery(window))'}
+!
+
+body
+	{'return self._from_(jQuery(body))'}
+!
+
+document
+	{'return self._from_(jQuery(document))'}
 ! !
 ! !
 
 
+Object subclass: #Ajax
+	instanceVariableNames: 'settings'
+	category: 'JQuery'!
+!Ajax commentStamp!
+instance%20variable%20names%3A%0A-%20settings%20%20A%20set%20of%20key/value%20pairs%20that%20configure%20the%20Ajax%20request.%20All%20settings%20are%20optional.%0A%0AFull%20list%20of%20settings%20options%20at%20http%3A//api.jquery.com/jQuery.ajax/%0A!
+
 !Ajax methodsFor: 'accessing'!
 !Ajax methodsFor: 'accessing'!
 
 
 at: aKey
 at: aKey
     ^settings at: aKey ifAbsent: [nil]
     ^settings at: aKey ifAbsent: [nil]
+
 !
 !
 
 
 at: aKey put: aValue
 at: aKey put: aValue
     settings at: aKey put: aValue
     settings at: aKey put: aValue
+
 !
 !
 
 
 url
 url
     ^self at: 'url'
     ^self at: 'url'
+
 !
 !
 
 
 url: aString
 url: aString
     self at: 'url' put: aString
     self at: 'url' put: aString
-! !
 
 
+! !
 
 
 !Ajax methodsFor: 'actions'!
 !Ajax methodsFor: 'actions'!
 
 
 send
 send
     {'jQuery.ajax(self[''@settings''])'}
     {'jQuery.ajax(self[''@settings''])'}
+
+! !
+
+!Ajax methodsFor: 'initialization'!
+
+initialize
+    super initialize.
+    settings := Dictionary new
+
+! !
+
+!Ajax class methodsFor: 'instance creation'!
+
+url: aString
+    ^self new
+	url: aString;
+	yourself
+
 ! !
 ! !
 
 
 
 
-    
+
+appendToJQuery: aJQuery
+	| canvas |
+	canvas := HTMLCanvas new.
+	self value: canvas.
+	aJQuery append: canvas
+
+!
+
+asJQuery
+    ^JQuery fromString: self
+
+!
+
+appendToJQuery: aJQuery
+    {'aJQuery._appendElement_(String(self))'}
+
+!
+
+appendToJQuery: aJQuery
+    aJQuery appendElement: root element
+
+!

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 373 - 209
st/Kernel.st


+ 286 - 173
st/parser.st → st/Parser.st

@@ -2,41 +2,65 @@ Object subclass: #PPParser
 	instanceVariableNames: 'memo'
 	instanceVariableNames: 'memo'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPParser methodsFor: 'accessing'!
 !PPParser methodsFor: 'accessing'!
 
 
 memo
 memo
 	^memo
 	^memo
-! !
-
-!PPParser methodsFor: 'error handling'!
 
 
-onFailure: aBlock
-	^PPFailureActionParser on: self block: aBlock
 ! !
 ! !
 
 
 !PPParser methodsFor: 'initialization'!
 !PPParser methodsFor: 'initialization'!
 
 
 initialize
 initialize
 	memo := Dictionary new
 	memo := Dictionary new
+
 ! !
 ! !
 
 
 !PPParser methodsFor: 'operations'!
 !PPParser methodsFor: 'operations'!
 
 
+flatten
+	^PPFlattenParser on: self
+
+!
+
+withSource
+	^PPSourceParser on: self
+
+!
+
+==> aBlock
+	^PPActionParser on: self block: aBlock
+
+!
+
 , aParser
 , aParser
 	^PPSequenceParser with: self with: aParser
 	^PPSequenceParser with: self with: aParser
+
 !
 !
 
 
 / aParser
 / aParser
 	^PPChoiceParser with: self with: aParser
 	^PPChoiceParser with: self with: aParser
+
 !
 !
 
 
-==> aBlock
-	^PPActionParser on: self block: aBlock
+plus
+	^PPRepeatingParser on: self min: 1
+
 !
 !
 
 
-flatten
-	^PPFlattenParser on: self
+star
+	^PPRepeatingParser on: self min: 0
+
+!
+
+not
+	^PPNotParser on: self
+
+!
+
+optional
+	^self / PPEpsilonParser new
+
 !
 !
 
 
 memoizedParse: aStream
 memoizedParse: aStream
@@ -51,32 +75,14 @@ memoizedParse: aStream
 		end := aStream position.
 		end := aStream position.
 		self memo at: start put: (Array with: node with: end).
 		self memo at: start put: (Array with: node with: end).
 		node]
 		node]
-!
-
-not
-	^PPNotParser on: self
-!
-
-optional
-	^self / PPEpsilonParser new
-!
-
-plus
-	^PPRepeatingParser on: self min: 1
-!
-
-star
-	^PPRepeatingParser on: self min: 0
-!
 
 
-withSource
-	^PPSourceParser on: self
 ! !
 ! !
 
 
 !PPParser methodsFor: 'parsing'!
 !PPParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
 	self subclassResponsibility
 	self subclassResponsibility
+
 !
 !
 
 
 parseAll: aStream
 parseAll: aStream
@@ -85,14 +91,13 @@ parseAll: aStream
 	^result isParseFailure 
 	^result isParseFailure 
 	    ifTrue: [self error: (result messageFor: aStream contents)]
 	    ifTrue: [self error: (result messageFor: aStream contents)]
 	    ifFalse: [result first]
 	    ifFalse: [result first]
-! !
 
 
+! !
 
 
 PPParser subclass: #PPEOFParser
 PPParser subclass: #PPEOFParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPEOFParser methodsFor: 'parsing'!
 !PPEOFParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
@@ -100,14 +105,13 @@ parse: aStream
 	    ifFalse: [
 	    ifFalse: [
 		PPFailure new reason: 'EOF expected' at: aStream position]
 		PPFailure new reason: 'EOF expected' at: aStream position]
 	    ifTrue: [nil]
 	    ifTrue: [nil]
-! !
 
 
+! !
 
 
 PPParser subclass: #PPAnyParser
 PPParser subclass: #PPAnyParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPAnyParser methodsFor: 'parsing'!
 !PPAnyParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
@@ -115,34 +119,34 @@ parse: aStream
 	    ifTrue: [PPFailure new
 	    ifTrue: [PPFailure new
 			 reason: 'did not expect EOF' at: aStream position]
 			 reason: 'did not expect EOF' at: aStream position]
 	    ifFalse: [aStream next]
 	    ifFalse: [aStream next]
-! !
 
 
+! !
 
 
 PPParser subclass: #PPEpsilonParser
 PPParser subclass: #PPEpsilonParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPEpsilonParser methodsFor: 'parsing'!
 !PPEpsilonParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
 	^nil
 	^nil
-! !
 
 
+! !
 
 
 PPParser subclass: #PPStringParser
 PPParser subclass: #PPStringParser
 	instanceVariableNames: 'string'
 	instanceVariableNames: 'string'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPStringParser methodsFor: 'accessing'!
 !PPStringParser methodsFor: 'accessing'!
 
 
 string
 string
 	^string
 	^string
+
 !
 !
 
 
 string: aString
 string: aString
 	string := aString
 	string := aString
+
 ! !
 ! !
 
 
 !PPStringParser methodsFor: 'parsing'!
 !PPStringParser methodsFor: 'parsing'!
@@ -156,18 +160,18 @@ parse: aStream
 	    ifFalse: [
 	    ifFalse: [
 		aStream position: position.
 		aStream position: position.
 		PPFailure new reason: 'Expected ', self string, ' but got ', (result at: position) printString; yourself]
 		PPFailure new reason: 'Expected ', self string, ' but got ', (result at: position) printString; yourself]
-! !
 
 
+! !
 
 
 PPParser subclass: #PPCharacterParser
 PPParser subclass: #PPCharacterParser
 	instanceVariableNames: 'regexp'
 	instanceVariableNames: 'regexp'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPCharacterParser methodsFor: 'accessing'!
 !PPCharacterParser methodsFor: 'accessing'!
 
 
 string: aString
 string: aString
 	regexp := RegularExpression fromString: '[', aString, ']'
 	regexp := RegularExpression fromString: '[', aString, ']'
+
 ! !
 ! !
 
 
 !PPCharacterParser methodsFor: 'parsing'!
 !PPCharacterParser methodsFor: 'parsing'!
@@ -176,58 +180,62 @@ parse: aStream
 	^(aStream peek notNil and: [self match: aStream peek])
 	^(aStream peek notNil and: [self match: aStream peek])
 	    ifTrue: [aStream next]
 	    ifTrue: [aStream next]
 	    ifFalse: [PPFailure new reason: 'Could not match' at: aStream position]
 	    ifFalse: [PPFailure new reason: 'Could not match' at: aStream position]
+
 ! !
 ! !
 
 
 !PPCharacterParser methodsFor: 'private'!
 !PPCharacterParser methodsFor: 'private'!
 
 
 match: aString
 match: aString
 	^aString match: regexp
 	^aString match: regexp
-! !
 
 
+! !
 
 
 PPParser subclass: #PPListParser
 PPParser subclass: #PPListParser
 	instanceVariableNames: 'parsers'
 	instanceVariableNames: 'parsers'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!PPListParser class methodsFor: 'instance creation'!
-
-with: aParser with: anotherParser
-	    ^self withAll: (Array with: aParser with: anotherParser)
-!
-
-withAll: aCollection
-	    ^self new
-		parsers: aCollection;
-		yourself
-! !
-
 !PPListParser methodsFor: 'accessing'!
 !PPListParser methodsFor: 'accessing'!
 
 
 parsers
 parsers
 	^parsers ifNil: [#()]
 	^parsers ifNil: [#()]
+
 !
 !
 
 
 parsers: aCollection
 parsers: aCollection
 	parsers := aCollection
 	parsers := aCollection
+
 ! !
 ! !
 
 
 !PPListParser methodsFor: 'copying'!
 !PPListParser methodsFor: 'copying'!
 
 
 copyWith: aParser
 copyWith: aParser
 	^self class withAll: (self parsers copyWith: aParser)
 	^self class withAll: (self parsers copyWith: aParser)
+
 ! !
 ! !
 
 
+!PPListParser class methodsFor: 'instance creation'!
+
+withAll: aCollection
+	    ^self new
+		parsers: aCollection;
+		yourself
+
+!
+
+with: aParser with: anotherParser
+	    ^self withAll: (Array with: aParser with: anotherParser)
+
+! !
 
 
 PPListParser subclass: #PPSequenceParser
 PPListParser subclass: #PPSequenceParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPSequenceParser methodsFor: 'copying'!
 !PPSequenceParser methodsFor: 'copying'!
 
 
 , aRule
 , aRule
 	^self copyWith: aRule
 	^self copyWith: aRule
+
 ! !
 ! !
 
 
 !PPSequenceParser methodsFor: 'parsing'!
 !PPSequenceParser methodsFor: 'parsing'!
@@ -245,18 +253,18 @@ parse: aStream
 	^element isParseFailure
 	^element isParseFailure
 	    ifFalse: [elements]
 	    ifFalse: [elements]
 	    ifTrue: [aStream position: start. element]
 	    ifTrue: [aStream position: start. element]
-! !
 
 
+! !
 
 
 PPListParser subclass: #PPChoiceParser
 PPListParser subclass: #PPChoiceParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPChoiceParser methodsFor: 'copying'!
 !PPChoiceParser methodsFor: 'copying'!
 
 
 / aRule
 / aRule
 	^self copyWith: aRule
 	^self copyWith: aRule
+
 ! !
 ! !
 
 
 !PPChoiceParser methodsFor: 'parsing'!
 !PPChoiceParser methodsFor: 'parsing'!
@@ -269,64 +277,65 @@ parse: aStream
 		result isParseFailure not]
 		result isParseFailure not]
 	    ifNone: [].
 	    ifNone: [].
 	^result
 	^result
-! !
 
 
+! !
 
 
 PPParser subclass: #PPDelegateParser
 PPParser subclass: #PPDelegateParser
 	instanceVariableNames: 'parser'
 	instanceVariableNames: 'parser'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!PPDelegateParser class methodsFor: 'instance creation'!
-
-on: aParser
-	    ^self new
-		parser: aParser;
-		yourself
-! !
-
 !PPDelegateParser methodsFor: 'accessing'!
 !PPDelegateParser methodsFor: 'accessing'!
 
 
 parser
 parser
 	^parser
 	^parser
+
 !
 !
 
 
 parser: aParser
 parser: aParser
 	parser := aParser
 	parser := aParser
+
 ! !
 ! !
 
 
 !PPDelegateParser methodsFor: 'parsing'!
 !PPDelegateParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
 	^self parser memoizedParse: aStream
 	^self parser memoizedParse: aStream
+
 ! !
 ! !
 
 
+!PPDelegateParser class methodsFor: 'instance creation'!
+
+on: aParser
+	    ^self new
+		parser: aParser;
+		yourself
+
+! !
 
 
 PPDelegateParser subclass: #PPAndParser
 PPDelegateParser subclass: #PPAndParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPAndParser methodsFor: 'parsing'!
 !PPAndParser methodsFor: 'parsing'!
 
 
+parse: aStream
+	^self basicParse: aStream
+
+!
+
 basicParse: aStream
 basicParse: aStream
 	| element position |
 	| element position |
 	position := aStream position.
 	position := aStream position.
 	element := self parser memoizedParse: aStream.
 	element := self parser memoizedParse: aStream.
 	aStream position: position.
 	aStream position: position.
 	^element
 	^element
-!
 
 
-parse: aStream
-	^self basicParse: aStream
 ! !
 ! !
 
 
-
 PPAndParser subclass: #PPNotParser
 PPAndParser subclass: #PPNotParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPNotParser methodsFor: 'parsing'!
 !PPNotParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
@@ -335,31 +344,23 @@ parse: aStream
 	^element isParseFailure 
 	^element isParseFailure 
 	    ifTrue: [nil]
 	    ifTrue: [nil]
 	    ifFalse: [PPFailure reason: element at: aStream position]
 	    ifFalse: [PPFailure reason: element at: aStream position]
-! !
 
 
+! !
 
 
 PPDelegateParser subclass: #PPActionParser
 PPDelegateParser subclass: #PPActionParser
 	instanceVariableNames: 'block'
 	instanceVariableNames: 'block'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!PPActionParser class methodsFor: 'instance creation'!
-
-on: aParser block: aBlock
-	    ^self new
-		parser: aParser;
-		block: aBlock;
-		yourself
-! !
-
 !PPActionParser methodsFor: 'accessing'!
 !PPActionParser methodsFor: 'accessing'!
 
 
 block
 block
 	^block
 	^block
+
 !
 !
 
 
 block: aBlock
 block: aBlock
 	block := aBlock
 	block := aBlock
+
 ! !
 ! !
 
 
 !PPActionParser methodsFor: 'parsing'!
 !PPActionParser methodsFor: 'parsing'!
@@ -370,14 +371,23 @@ parse: aStream
 	^element isParseFailure
 	^element isParseFailure
 	    ifFalse: [self block value: element]
 	    ifFalse: [self block value: element]
 	    ifTrue: [element]
 	    ifTrue: [element]
+
 ! !
 ! !
 
 
+!PPActionParser class methodsFor: 'instance creation'!
+
+on: aParser block: aBlock
+	    ^self new
+		parser: aParser;
+		block: aBlock;
+		yourself
+
+! !
 
 
 PPDelegateParser subclass: #PPFlattenParser
 PPDelegateParser subclass: #PPFlattenParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPFlattenParser methodsFor: 'parsing'!
 !PPFlattenParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
@@ -389,14 +399,13 @@ parse: aStream
 	    ifFalse: [aStream collection 
 	    ifFalse: [aStream collection 
 		copyFrom: start + 1 
 		copyFrom: start + 1 
 		to: aStream position]
 		to: aStream position]
-! !
 
 
+! !
 
 
 PPDelegateParser subclass: #PPSourceParser
 PPDelegateParser subclass: #PPSourceParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !PPSourceParser methodsFor: 'parsing'!
 !PPSourceParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
@@ -407,31 +416,23 @@ parse: aStream
 		ifTrue: [element]
 		ifTrue: [element]
 		ifFalse: [result := aStream collection copyFrom: start + 1 to: aStream position.
 		ifFalse: [result := aStream collection copyFrom: start + 1 to: aStream position.
 			Array with: element with: result].
 			Array with: element with: result].
-! !
 
 
+! !
 
 
 PPDelegateParser subclass: #PPRepeatingParser
 PPDelegateParser subclass: #PPRepeatingParser
 	instanceVariableNames: 'min'
 	instanceVariableNames: 'min'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!PPRepeatingParser class methodsFor: 'instance creation'!
-
-on: aParser min: aNumber
-	    ^self new
-		parser: aParser;
-		min: aNumber;
-		yourself
-! !
-
 !PPRepeatingParser methodsFor: 'accessing'!
 !PPRepeatingParser methodsFor: 'accessing'!
 
 
 min
 min
 	^min
 	^min
+
 !
 !
 
 
 min: aNumber
 min: aNumber
 	min := aNumber
 	min := aNumber
+
 ! !
 ! !
 
 
 !PPRepeatingParser methodsFor: 'parsing'!
 !PPRepeatingParser methodsFor: 'parsing'!
@@ -454,65 +455,72 @@ parse: aStream
 				ifFalse: [elements addLast: element]].
 				ifFalse: [elements addLast: element]].
 				elements]
 				elements]
 		ifNotNil: [failure].
 		ifNotNil: [failure].
-! !
-
-
-Object subclass: #PPFailure
-	instanceVariableNames: 'position reason'
-	category: 'Parser'!
 
 
+! !
 
 
-!PPFailure class methodsFor: 'instance creation'!
+!PPRepeatingParser class methodsFor: 'instance creation'!
 
 
-reason: aString at: anInteger
+on: aParser min: aNumber
 	    ^self new
 	    ^self new
-		reason: aString at: anInteger;
+		parser: aParser;
+		min: aNumber;
 		yourself
 		yourself
+
 ! !
 ! !
 
 
+Object subclass: #PPFailure
+	instanceVariableNames: 'position, reason'
+	category: 'Parser'!
+
 !PPFailure methodsFor: 'accessing'!
 !PPFailure methodsFor: 'accessing'!
 
 
 position
 position
 	^position ifNil: [0]
 	^position ifNil: [0]
+
 !
 !
 
 
 position: aNumber
 position: aNumber
 	position := aNumber
 	position := aNumber
+
 !
 !
 
 
 reason
 reason
 	^reason ifNil: ['']
 	^reason ifNil: ['']
+
 !
 !
 
 
 reason: aString
 reason: aString
 	reason := aString
 	reason := aString
+
 !
 !
 
 
 reason: aString at: anInteger
 reason: aString at: anInteger
 	self 
 	self 
 	    reason: aString; 
 	    reason: aString; 
 	    position: anInteger
 	    position: anInteger
+
 ! !
 ! !
 
 
 !PPFailure methodsFor: 'testing'!
 !PPFailure methodsFor: 'testing'!
 
 
 isParseFailure
 isParseFailure
 	^true
 	^true
+
 ! !
 ! !
 
 
+!PPFailure class methodsFor: 'instance creation'!
+
+reason: aString at: anInteger
+	    ^self new
+		reason: aString at: anInteger;
+		yourself
+
+! !
 
 
 Object subclass: #SmalltalkParser
 Object subclass: #SmalltalkParser
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!SmalltalkParser class methodsFor: 'instance creation'!
-
-parse: aStream
-	    ^self new
-		parse: aStream
-! !
-
 !SmalltalkParser methodsFor: 'grammar'!
 !SmalltalkParser methodsFor: 'grammar'!
 
 
 parser
 parser
@@ -678,115 +686,129 @@ parser
 		    yourself].
 		    yourself].
 	
 	
 	^method, PPEOFParser new ==> [:node | node first]
 	^method, PPEOFParser new ==> [:node | node first]
+
 ! !
 ! !
 
 
 !SmalltalkParser methodsFor: 'parsing'!
 !SmalltalkParser methodsFor: 'parsing'!
 
 
 parse: aStream
 parse: aStream
 	^self parser parse: aStream
 	^self parser parse: aStream
+
 ! !
 ! !
 
 
+!SmalltalkParser class methodsFor: 'instance creation'!
+
+parse: aStream
+	    ^self new
+		parse: aStream
+
+! !
 
 
 Object subclass: #Chunk
 Object subclass: #Chunk
 	instanceVariableNames: 'contents'
 	instanceVariableNames: 'contents'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !Chunk methodsFor: 'accessing'!
 !Chunk methodsFor: 'accessing'!
 
 
 contents
 contents
 	^contents ifNil: ['']
 	^contents ifNil: ['']
+
 !
 !
 
 
 contents: aString
 contents: aString
 	contents := aString
 	contents := aString
+
 ! !
 ! !
 
 
 !Chunk methodsFor: 'testing'!
 !Chunk methodsFor: 'testing'!
 
 
 isEmptyChunk
 isEmptyChunk
 	^false
 	^false
+
 !
 !
 
 
 isInstructionChunk
 isInstructionChunk
 	^false
 	^false
-! !
 
 
+! !
 
 
 Chunk subclass: #InstructionChunk
 Chunk subclass: #InstructionChunk
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !InstructionChunk methodsFor: 'testing'!
 !InstructionChunk methodsFor: 'testing'!
 
 
 isInstructionChunk
 isInstructionChunk
 	^true
 	^true
-! !
 
 
+! !
 
 
 Chunk subclass: #EmptyChunk
 Chunk subclass: #EmptyChunk
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !EmptyChunk methodsFor: 'testing'!
 !EmptyChunk methodsFor: 'testing'!
 
 
 isEmptyChunk
 isEmptyChunk
 	^true
 	^true
-! !
 
 
+! !
 
 
 Object subclass: #ChunkParser
 Object subclass: #ChunkParser
-	instanceVariableNames: 'parser separator eof ws chunk emptyChunk instructionChunk'
+	instanceVariableNames: 'parser, separator, eof, ws, chunk, emptyChunk, instructionChunk'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
+!ChunkParser methodsFor: ''!
+
+instructionChunk
+	^instructionChunk ifNil: [
+	    instructionChunk := self ws, '!' asParser, self chunk
+	    ==> [:node | InstructionChunk new contents: node last contents]]
+
+! !
 
 
 !ChunkParser methodsFor: 'accessing'!
 !ChunkParser methodsFor: 'accessing'!
 
 
-chunk
-	^chunk ifNil: [chunk := self ws, ('!!!!' asParser / ('!!' asParser not, PPAnyParser new)) plus flatten, '!!' asParser ==> [:node | Chunk new contents: (node second replace: '!!!!' with: '!!')]]
-!
+parser
+	^parser ifNil: [
+	    parser := self instructionChunk / self emptyChunk / self chunk / self eof]
 
 
-emptyChunk
-	^emptyChunk ifNil: [emptyChunk := self separator plus, '!!' asParser, self ws ==> [:node | EmptyChunk new]]
 !
 !
 
 
 eof
 eof
 	^eof ifNil: [eof := self ws, PPEOFParser new ==> [:node | nil]]
 	^eof ifNil: [eof := self ws, PPEOFParser new ==> [:node | nil]]
-!
 
 
-parser
-	^parser ifNil: [
-	    parser := self instructionChunk / self emptyChunk / self chunk / self eof]
 !
 !
 
 
 separator
 separator
 	^separator ifNil: [separator := (String cr, String space, String lf, String tab) asChoiceParser]
 	^separator ifNil: [separator := (String cr, String space, String lf, String tab) asChoiceParser]
+
 !
 !
 
 
 ws
 ws
 	^ws ifNil: [ws := self separator star]
 	^ws ifNil: [ws := self separator star]
-! !
 
 
-!ChunkParser methodsFor: nil!
+!
 
 
-instructionChunk
-	^instructionChunk ifNil: [
-	    instructionChunk := self ws, '!!' asParser, self chunk
-	    ==> [:node | InstructionChunk new contents: node last contents]]
-! !
+chunk
+	^chunk ifNil: [chunk := self ws, ('!!' asParser / ('!' asParser not, PPAnyParser new)) plus flatten, '!' asParser ==> [:node | Chunk new contents: (node second replace: '!!' with: '!')]]
+
+!
 
 
+emptyChunk
+	^emptyChunk ifNil: [emptyChunk := self separator plus, '!' asParser, self ws ==> [:node | EmptyChunk new]]
+
+! !
 
 
 Object subclass: #Importer
 Object subclass: #Importer
 	instanceVariableNames: 'chunkParser'
 	instanceVariableNames: 'chunkParser'
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
 !Importer methodsFor: 'accessing'!
 !Importer methodsFor: 'accessing'!
 
 
 chunkParser
 chunkParser
 	^chunkParser ifNil: [chunkParser := ChunkParser new parser]
 	^chunkParser ifNil: [chunkParser := ChunkParser new parser]
+
 ! !
 ! !
 
 
 !Importer methodsFor: 'fileIn'!
 !Importer methodsFor: 'fileIn'!
@@ -801,15 +823,14 @@ import: aStream
 					 scanFrom: aStream]
 					 scanFrom: aStream]
 		    ifFalse: [Compiler new loadExpression: nextChunk contents].
 		    ifFalse: [Compiler new loadExpression: nextChunk contents].
 		self import: aStream]]
 		self import: aStream]]
-! !
 
 
+! !
 
 
 Object subclass: #Exporter
 Object subclass: #Exporter
 	instanceVariableNames: ''
 	instanceVariableNames: ''
 	category: 'Parser'!
 	category: 'Parser'!
 
 
-
-!Exporter methodsFor: 'fileout'!
+!Exporter methodsFor: 'fileOut'!
 
 
 exportCategory: aString
 exportCategory: aString
 	| stream |
 	| stream |
@@ -817,42 +838,30 @@ exportCategory: aString
 	(Smalltalk current classes 
 	(Smalltalk current classes 
 	    select: [:each | each category = aString])
 	    select: [:each | each category = aString])
 	    do: [:each | stream nextPutAll: (self export: each)].
 	    do: [:each | stream nextPutAll: (self export: each)].
+	self exportCategoryExtensions: aString on: stream.
 	^stream contents
 	^stream contents
-! !
-
-!Exporter methodsFor: 'fileOut'!
+!
 
 
 export: aClass
 export: aClass
 	| stream |
 	| stream |
 	stream := '' writeStream.
 	stream := '' writeStream.
 	self exportDefinitionOf: aClass on: stream.
 	self exportDefinitionOf: aClass on: stream.
-	stream nextPutAll: String cr.
 	self exportMethodsOf: aClass on: stream.
 	self exportMethodsOf: aClass on: stream.
-	stream nextPutAll: String cr.
 	self exportMetaDefinitionOf: aClass on: stream.
 	self exportMetaDefinitionOf: aClass on: stream.
 	self exportMethodsOf: aClass class on: stream.
 	self exportMethodsOf: aClass class on: stream.
-	stream nextPutAll: String cr.
 	^stream contents
 	^stream contents
+
 ! !
 ! !
 
 
 !Exporter methodsFor: 'private'!
 !Exporter methodsFor: 'private'!
 
 
-classNameFor: aClass
-	^aClass isMetaclass
-	    ifTrue: [aClass instanceClass name, '.klass']
-	    ifFalse: [
-		aClass isNil
-		    ifTrue: ['nil']
-		    ifFalse: [aClass name]]
-!
-
 exportDefinitionOf: aClass on: aStream
 exportDefinitionOf: aClass on: aStream
 	aStream 
 	aStream 
 	    nextPutAll: 'smalltalk.addClass(';
 	    nextPutAll: 'smalltalk.addClass(';
 	    nextPutAll: '''', (self classNameFor: aClass), ''', ';
 	    nextPutAll: '''', (self classNameFor: aClass), ''', ';
 	    nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
 	    nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);
 	    nextPutAll: ', ['.
 	    nextPutAll: ', ['.
-	aClass instVarNames 
+	aClass instanceVariableNames 
 	    do: [:each | aStream nextPutAll: '''', each, '''']
 	    do: [:each | aStream nextPutAll: '''', each, '''']
 	    separatedBy: [aStream nextPutAll: ', '].
 	    separatedBy: [aStream nextPutAll: ', '].
 	aStream	
 	aStream	
@@ -861,37 +870,141 @@ exportDefinitionOf: aClass on: aStream
 	    nextPutAll: ');'.
 	    nextPutAll: ');'.
 	aClass comment notEmpty ifTrue: [
 	aClass comment notEmpty ifTrue: [
 	    aStream 
 	    aStream 
-	    	nextPutAll: String cr;
+	    	lf;
 		nextPutAll: 'smalltalk.';
 		nextPutAll: 'smalltalk.';
 		nextPutAll: (self classNameFor: aClass);
 		nextPutAll: (self classNameFor: aClass);
 		nextPutAll: '.comment=';
 		nextPutAll: '.comment=';
-		nextPutAll: 'unescape(''', aClass comment escaped, ''')']
+		nextPutAll: 'unescape(''', aClass comment escaped, ''')'].
+	aStream lf
+
 !
 !
 
 
 exportMetaDefinitionOf: aClass on: aStream
 exportMetaDefinitionOf: aClass on: aStream
-	aClass class instVarNames isEmpty ifFalse: [
+	aClass class instanceVariableNames isEmpty ifFalse: [
 	    aStream 
 	    aStream 
 		nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
 		nextPutAll: 'smalltalk.', (self classNameFor: aClass class);
 		nextPutAll: '.iVarNames = ['.
 		nextPutAll: '.iVarNames = ['.
-	    aClass class instVarNames
+	    aClass class instanceVariableNames
 		do: [:each | aStream nextPutAll: '''', each, '''']
 		do: [:each | aStream nextPutAll: '''', each, '''']
 		separatedBy: [aStream nextPutAll: ','].
 		separatedBy: [aStream nextPutAll: ','].
-	    aStream nextPutAll: '];', String cr]
+	    aStream nextPutAll: '];', String lf]
+
 !
 !
 
 
 exportMethodsOf: aClass on: aStream
 exportMethodsOf: aClass on: aStream
-	aClass methodDictionary keysAndValuesDo: [:key :value |
-	    aStream 
-		nextPutAll: 'smalltalk.addMethod(', String cr;
-		nextPutAll: '''', value selector asSelector, ''',', String cr;
-		nextPutAll: 'smalltalk.method({', String cr;
-		nextPutAll: 'selector: ''', value selector, ''',', String cr;
-		nextPutAll: 'category: ''', value category, ''',', String cr;
-		nextPutAll: 'fn: ', value fn compiledSource, ',', String cr;
-		nextPutAll: 'source: unescape(''', value source escaped, ''')';
-		nextPutAll: '}),', String cr;
+	aClass methodDictionary values do: [:each |
+		(each category match: '^\*') ifFalse: [
+			self exportMethod: each of: aClass on: aStream]].
+	aStream lf
+!
+
+classNameFor: aClass
+	^aClass isMetaclass
+	    ifTrue: [aClass instanceClass name, '.klass']
+	    ifFalse: [
+		aClass isNil
+		    ifTrue: ['nil']
+		    ifFalse: [aClass name]]
+
+!
+
+exportMethod: aMethod of: aClass on: aStream
+	aStream 
+		nextPutAll: 'smalltalk.addMethod(';lf;
+		nextPutAll: '''', aMethod selector asSelector, ''',';lf;
+		nextPutAll: 'smalltalk.method({';lf;
+		nextPutAll: 'selector: ''', aMethod selector, ''',';lf;
+		nextPutAll: 'category: ''', aMethod category, ''',';lf;
+		nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;
+		nextPutAll: 'source: unescape(''', aMethod source escaped, '''),';lf;
+		nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;
+		nextPutAll: 'referencedClasses: ['.
+	    		aMethod referencedClasses 
+				do: [:each | aStream nextPutAll: 'smalltalk.', (self classNameFor: each)]
+				separatedBy: [aStream nextPutAll: ','].
+	aStream
+		nextPutAll: ']';lf;
+		nextPutAll: '}),';lf;
 		nextPutAll: 'smalltalk.', (self classNameFor: aClass);
 		nextPutAll: 'smalltalk.', (self classNameFor: aClass);
-		nextPutAll: ');', String cr, String cr]
+		nextPutAll: ');';lf;lf
+!
+
+
+exportCategoryExtensions: aString on: aStream
+	Smalltalk current classes, (Smalltalk current classes collect: [:each | each class]) do: [:each |
+		each methodDictionary values do: [:method |
+			method category = ('*', aString) ifTrue: [
+				self exportMethod: method of: each on: aStream]]]
 ! !
 ! !
 
 
+Exporter subclass: #ChunkExporter
+	instanceVariableNames: ''
+	category: 'Parser'!
+
+!ChunkExporter methodsFor: 'not yet classified'!
+
+exportDefinitionOf: aClass on: aStream
+	"Chunk format."
+
+	aStream 
+	    nextPutAll: (self classNameFor: aClass superclass);
+	    nextPutAll: ' subclass: #', (self classNameFor: aClass); lf;
+	    nextPutAll: '	instanceVariableNames: '''.
+	aClass instanceVariableNames 
+	    do: [:each | aStream nextPutAll: each]
+	    separatedBy: [aStream nextPutAll: ', '].
+	aStream	
+	    nextPutAll: ''''; lf;
+	    nextPutAll: '	category: ''', aClass category, '''!'; lf.
+ 	aClass comment notEmpty ifTrue: [
+	    aStream 
+		nextPutAll: '!', (self classNameFor: aClass), ' commentStamp!';lf;
+		nextPutAll: aClass comment escaped, '!';lf].
+	aStream lf
+
+!
+
+exportMethod: aMethod of: aClass on: aStream
+	aStream 
+		lf; lf; nextPutAll: aMethod source; lf;
+		nextPutAll: '!'
+!
+
+exportMethodsOf: aClass on: aStream
+
+    | methodsByCategory |
+    methodsByCategory := Dictionary new.
+    aClass methodDictionary values do: [:m |
+	(methodsByCategory at: m category ifAbsentPut: [Array new])
+ 		add: m]. 
+    aClass protocols do: [:category |       
+	aStream
+		nextPutAll: '!', (self classNameFor: aClass);
+		nextPutAll: ' methodsFor: ''', category, '''!'.
+    	(methodsByCategory at: category) do: [:each |
+		self exportMethod: each of: aClass on: aStream].
+	aStream nextPutAll: ' !'; lf; lf]
+!
+
+exportMetaDefinitionOf: aClass on: aStream
+
+	aClass class instanceVariableNames isEmpty ifFalse: [
+		aStream 
+		    nextPutAll: (self classNameFor: aClass class);
+		    nextPutAll: ' instanceVariableNames: '''.
+		aClass class instanceVariableNames 
+		    do: [:each | aStream nextPutAll: each]
+		    separatedBy: [aStream nextPutAll: ', '].
+		aStream	
+		    nextPutAll: '''!'; lf; lf]
+!
+
+classNameFor: aClass
+	^aClass isMetaclass
+	    ifTrue: [aClass instanceClass name, ' class']
+	    ifFalse: [
+		aClass isNil
+		    ifTrue: ['nil']
+		    ifFalse: [aClass name]]
+! !
 
 

+ 453 - 0
st/SUnit.st

@@ -0,0 +1,453 @@
+Object subclass: #TestCase
+	instanceVariableNames: 'testedClass'
+	category: 'SUnit'!
+
+!TestCase methodsFor: 'accessing'!
+
+testedClass
+	^testedClass
+!
+
+testedClass: aClass
+	testedClass := aClass
+! !
+
+!TestCase methodsFor: 'private'!
+
+cleanUpInstanceVariables
+	self class instanceVariableNames do: [ :name |
+		name = 'testSelector' ifFalse: [
+			self instVarAt: name put: nil ]]
+!
+
+signalFailure: aString
+	TestFailure new
+		messageText: aString;
+		signal
+! !
+
+!TestCase methodsFor: 'running'!
+
+setUp
+!
+
+tearDown
+!
+
+methods
+	^self class methodDictionary keys select: [:each | each match: '^test']
+!
+
+runCaseFor: aTestResult
+	[self setUp.
+	self performTestFor: aTestResult]
+		on: Error
+		do: [:ex |
+			self tearDown.
+			self cleanUpInstanceVariables.
+			ex signal].
+	self tearDown.
+	self cleanUpInstanceVariables
+!
+
+performTestFor: aResult
+	self methods do: [:each | 
+		[[self perform: each]
+			on: TestFailure do: [:ex | aResult addFailure: self class name, '>>', each]]
+			on: Error do: [:ex | aResult addError: self class name, '>>', each].
+		aResult increaseRuns]
+! !
+
+!TestCase methodsFor: 'testing'!
+
+assert: aBoolean
+	aBoolean ifFalse: [self signalFailure: 'Assertion failed']
+!
+
+deny: aBoolean
+	self assert: aBoolean not
+! !
+
+TestCase subclass: #ExampleTest
+	instanceVariableNames: 'test'
+	category: 'SUnit'!
+
+!ExampleTest methodsFor: 'not yet classified'!
+
+testFailure
+	self deny: true
+	
+!
+
+testPasses
+	100000 timesRepeat: [self assert: 1 + 1 = 2]
+!
+
+testError
+	self assert: 1 foo
+! !
+
+TabWidget subclass: #ProgressBar
+	instanceVariableNames: 'percent, progressDiv'
+	category: 'SUnit'!
+
+!ProgressBar methodsFor: 'accessing'!
+
+percent
+	^percent ifNil: [0]
+!
+
+percent: aNumber
+	percent := aNumber
+! !
+
+!ProgressBar methodsFor: 'rendering'!
+
+renderOn: html 
+	html div 
+		class: 'progress_bar';
+		with: [
+			html div 
+				class: 'progress';
+				style: 'width:', self percent asString, '%']
+! !
+
+!ProgressBar methodsFor: 'updating'!
+
+updatePercent: aNumber
+	self percent: aNumber.
+	self update
+! !
+
+Error subclass: #TestFailure
+	instanceVariableNames: ''
+	category: 'SUnit'!
+
+TabWidget subclass: #TestRunner
+	instanceVariableNames: 'selectedCategories, categoriesList, selectedClasses, classesList, selectedMethods, progressBar, methodsList, result, statusDiv'
+	category: 'SUnit'!
+
+!TestRunner methodsFor: 'accessing'!
+
+label
+    ^'[Test runner]'
+
+!
+
+categories
+    | categories |
+    categories := Array new.
+    self allClasses do: [:each |
+	(categories includes: each category) ifFalse: [
+	    categories add: each category]].
+    ^categories sort
+!
+
+classes
+    ^(self allClasses 
+	select: [:each | self selectedCategories includes: each category])
+	sort: [:a :b | a name > b name]
+!
+
+selectedCategories
+	^selectedCategories ifNil: [selectedCategories := Array new]
+!
+
+allClasses
+	^TestCase allSubclasses
+!
+
+selectedClasses
+	^selectedClasses  ifNil: [selectedClasses := Array new]
+!
+
+progressBar
+	^progressBar ifNil: [progressBar := ProgressBar new]
+!
+
+selectedMethods
+	^selectedMethods ifNil: [self selectedClasses collect: [:each |
+		each methodDictionary keys select: [:key |  key beginsWith: 'test' ]]]
+!
+
+statusInfo
+	^self printTotal, self printPasses, self printErrors, self printFailures
+!
+
+result
+	^result
+!
+
+failedMethods
+	self result failures collect: [:each |
+		html li 
+			class: 'failures';
+			with: each]
+! !
+
+!TestRunner methodsFor: 'actions'!
+
+selectAllCategories
+	self categories do: [:each | 
+		(selectedCategories includes: each) ifFalse: [
+			self selectedCategories add: each]].
+	self 
+	    updateCategoriesList;
+	    updateClassesList
+!
+
+toggleCategory: aCategory
+	(self isSelectedCategory: aCategory) 
+		ifFalse: [selectedCategories add: aCategory]
+		ifTrue: [selectedCategories remove: aCategory].
+	self 
+	    updateCategoriesList;
+	    updateClassesList
+!
+
+toggleClass: aClass
+	(self isSelectedClass: aClass) 
+		ifFalse: [selectedClasses add: aClass]
+		ifTrue: [selectedClasses remove: aClass].
+	self 
+	    updateClassesList
+!
+
+selectAllClasses
+	self classes do: [:each | 
+		(selectedClasses includes: each) ifFalse: [
+			self selectedClasses add: each]].
+	self 
+	    updateCategoriesList;
+	    updateClassesList
+!
+
+run: aCollection
+	result := TestResult new.
+	self 
+		updateStatusDiv;
+		updateMethodsList.
+	self progressBar updatePercent: 0.
+	result total: (aCollection inject: 0 into: [:acc :each | acc + each methods size]).
+	aCollection do: [:each | 
+		[each runCaseFor: result.
+		self progressBar updatePercent: result runs / result total * 100.
+		self updateStatusDiv.
+		self updateMethodsList] valueWithTimeout: 100].
+! !
+
+!TestRunner methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	result := TestResult new
+! !
+
+!TestRunner methodsFor: 'printing'!
+
+printErrors
+	^self result errors size asString , ' errors, '
+!
+
+printFailures
+	^self result failures size asString, ' failures'
+!
+
+printPasses
+	^(((self result total) - (self result errors size + (self result failures size))) asString) , ' passes, '
+!
+
+printTotal
+	^self result total asString, ' runs, '
+! !
+
+!TestRunner methodsFor: 'rendering'!
+
+renderBoxOn: html
+    self 
+	renderCategoriesOn: html;
+	renderClassesOn: html;
+	renderResultsOn: html
+!
+
+renderButtonsOn: html
+    html button
+	with: 'Run selected';
+	onClick: [self run: (self selectedClasses collect: [:each | each new])]
+
+!
+
+renderCategoriesOn: html
+    	categoriesList := html ul class: 'jt_column sunit categories'.
+	self updateCategoriesList
+!
+
+renderClassesOn: html
+    	classesList := html ul class: 'jt_column sunit classes'.
+	self updateClassesList
+!
+
+renderResultsOn: html
+    	statusDiv := html div.
+	html with: self progressBar.
+   	methodsList := html ul class: 'jt_column sunit methods'.
+	self updateMethodsList.
+	self updateStatusDiv
+!
+
+renderFailuresOn: html
+	self result failures do: [:each |
+		html li 
+			class: 'failures';
+			with: each]
+!
+
+renderErrorsOn: html
+	self result errors do: [:each |
+		html li 
+			class: 'errors';
+			with: each]
+! !
+
+!TestRunner methodsFor: 'testing'!
+
+canBeClosed
+    ^true
+
+!
+
+isSelectedClass: aClass
+	^(self selectedClasses includes: aClass)
+!
+
+isSelectedCategory: aCategory
+	^(self selectedCategories includes: aCategory)
+! !
+
+!TestRunner methodsFor: 'updating'!
+
+updateCategoriesList
+    categoriesList contents: [:html |
+	    html li 
+		class: 'all';
+		with: 'All';
+		onClick: [self selectAllCategories].
+	self categories do: [:each || li |
+	    li := html li.
+	    (self selectedCategories includes: each) ifTrue: [
+		li class: 'selected'].
+	    li
+		with: each;
+		onClick: [self toggleCategory: each]]]
+!
+
+updateClassesList
+    classesList contents: [:html |
+	(self selectedCategories isEmpty) ifFalse: [
+		html li
+			class: 'all';
+			with: 'All';
+			onClick: [self selectAllClasses]].
+	self classes do: [:each || li |
+		li := html li.
+		(self selectedClasses includes: each) ifTrue: [
+			li class: 'selected'].
+		li
+			with: each name;
+			onClick: [self toggleClass: each]]]
+!
+
+updateMethodsList
+	methodsList contents: [:html |
+		self renderFailuresOn: html.
+                self renderErrorsOn: html]
+!
+
+updateStatusDiv
+	statusDiv class: 'sunit status ', result status.
+	statusDiv contents: [:html |
+		html span with: self statusInfo]
+! !
+
+Object subclass: #TestResult
+	instanceVariableNames: 'timestamp, runs, errors, failures, total'
+	category: 'SUnit'!
+
+!TestResult methodsFor: 'accessing'!
+
+timestamp
+	^timestamp
+!
+
+errors
+	^errors
+!
+
+failures
+	^failures
+!
+
+total
+	^total
+!
+
+total: aNumber
+	total := aNumber
+!
+
+addError: anError
+	self errors add: anError
+!
+
+addFailure: aFailure
+	self failures add: aFailure
+!
+
+runs
+	^runs
+!
+
+increaseRuns
+	runs := runs + 1
+!
+
+status
+	^self errors isEmpty 
+		ifTrue: [
+			self failures isEmpty 
+				ifTrue: ['success']
+				ifFalse: ['failure']]
+		ifFalse: ['error']
+! !
+
+!TestResult methodsFor: 'initialization'!
+
+initialize
+	super initialize.
+	timestamp := Date now.
+	runs := 0.
+	errors := Array new.
+	failures := Array new.
+	total := 0
+! !
+
+TestCase subclass: #ExampleTest2
+	instanceVariableNames: ''
+	category: 'SUnit'!
+
+!ExampleTest2 methodsFor: 'not yet classified'!
+
+testPasses
+	100000 timesRepeat: [self assert: 1 + 1 = 2]
+! !
+
+TestCase subclass: #ExampleTest3
+	instanceVariableNames: ''
+	category: 'SUnit'!
+
+!ExampleTest3 methodsFor: 'not yet classified'!
+
+testPasses
+	100000 timesRepeat: [self assert: 1 + 1 = 2]
+! !
+

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels