'From Moshi of 3 March 2007 [latest update: #455] on 12 October 2007 at 1:36:23 pm'! "Change Set: TileDemo Date: 12 October 2007 Author: Takashi Yamamiya A Simple tilescript demo."! Morph subclass: #Tile instanceVariableNames: 'model' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! !Tile commentStamp: 'tak 9/30/2007 17:51' prior: 0! Tile new openInHand | o | o := JSObject new. o jsAt: #prop put: 'hello'. GetTile new model: o; openInHand ! Tile subclass: #AppTile instanceVariableNames: 'args' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #ArrTile instanceVariableNames: 'elements' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #FuncTile instanceVariableNames: 'formals' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #GetTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #IfTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #PrimTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Tile subclass: #SetTile instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Model subclass: #TileBrowser instanceVariableNames: 'context fieldList selectionIndex transcript' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Object subclass: #TileDemo instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! Morph subclass: #TileEditor instanceVariableNames: 'model contentsSel acceptSel menuSel' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! ScrollPane subclass: #TileList instanceVariableNames: 'panel' classVariableNames: '' poolDictionaries: '' category: 'Tilescript-View'! !Tile methodsFor: 'initialize' stamp: 'tak 10/12/2007 10:39'! initialize "Tile new openInHand" super initialize. self borderWidth: 1. self borderColor: Color gray. self color: Color white. self layoutPolicy: TableLayout new. self listDirection: #leftToRight. self wrapCentering: #topLeft. self hResizing: #shrinkWrap. self vResizing: #shrinkWrap. self layoutInset: 1. self rubberBandCells: true. self cornerStyle: #rounded. self color: self standardColor! ! !Tile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:46'! highlightColor ^ Color yellow! ! !Tile methodsFor: 'accessing' stamp: 'aw 10/1/2007 14:35'! makeLabel: aString ^ (StringMorph new contents: aString) font: ScriptingSystem fontForTiles; yourself! ! !Tile methodsFor: 'accessing' stamp: 'tak 10/9/2007 10:22'! model ^ model! ! !Tile methodsFor: 'accessing' stamp: 'tak 9/30/2007 17:52'! model: aJSObject model := aJSObject. self updateView.! ! !Tile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:43'! standardColor ^ Color r: 0.80 g: 0.95 b: 0.85! ! !Tile methodsFor: 'accessing' stamp: 'tak 10/4/2007 10:39'! updateView | label | self removeAllMorphs. label _ self makeLabel: model printString. self addMorphBack: label. self layoutInset: 3! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/11/2007 15:05'! acceptDroppingMorph: aMorph event: evt (owner isKindOf: Tile) ifTrue: [^ owner replace: aMorph with: self evt: evt]. ! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/11/2007 13:19'! handlesMouseDown: evt ^true.! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/11/2007 17:13'! handlesMouseOverDragging: evt ^ true! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/12/2007 00:07'! highlight: evt | highlighted | (self containsPoint: evt position) ifFalse: [self color: Color white. ^ false]. highlighted := (submorphs select: [:each | each isKindOf: Tile]) detect: [:each | each highlight: evt] ifNone: []. highlighted = nil ifTrue: [self color: Color yellow] ifFalse: [self color: Color white]. ^ true! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/11/2007 14:25'! mouseDown: evt | selectors | selectors := Array with: #click: with: #doubleClick: with: nil with: #startDrag:. evt hand waitForClicksOrDrag: self event: evt selectors: selectors threshold: 4! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/12/2007 10:48'! mouseEnterDragging: evt (evt hand hasSubmorphs and: [self wantsDroppedMorph: evt hand firstSubmorph event: evt]) ifFalse: [^ self]. self color: self highlightColor. (owner isKindOf: Tile) ifTrue: [owner color: owner standardColor]! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/12/2007 10:47'! mouseLeaveDragging: evt self color: self standardColor. (owner isKindOf: Tile) ifTrue: [owner mouseEnterDragging: evt]! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/11/2007 14:35'! startDrag: evt (owner isKindOf: Tile) ifTrue: [^ owner take: self evt: evt]. evt hand grabMorph: self! ! !Tile methodsFor: 'event handling' stamp: 'tak 10/12/2007 13:36'! wantsDroppedMorph: aMorph event: anEvent "TODO: Put type checking here." ^ aMorph isKindOf: Tile! ! !Tile methodsFor: 'updating' stamp: 'tak 10/11/2007 15:34'! replace: newMorph with: oldMorph evt: evt newMorph rejectDropMorphEvent: evt! ! !Tile methodsFor: 'updating' stamp: 'tak 10/12/2007 11:27'! take: aTile evt: evt (owner isKindOf: Tile) ifTrue: [^ owner take: aTile evt: evt]! ! !AppTile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:42'! standardColor ^ Color r: 0.95 g: 0.95 b: 0.80! ! !AppTile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:53'! updateView | func | self removeAllMorphs. func := self class model: (model jsAt: #func). args := self class model: (model jsAt: #args). func lock: true. self addMorphBack: func. self addMorphBack: args. ! ! !AppTile methodsFor: 'event handling' stamp: 'tak 10/9/2007 11:40'! doubleClick: evt model jsSend: #ev withArguments: #()! ! !AppTile methodsFor: 'event handling' stamp: 'tak 10/9/2007 12:44'! handlesMouseOverDragging: evt ^ true! ! !AppTile methodsFor: 'event handling' stamp: 'tak 10/9/2007 12:44'! mouseEnter: evt ^ true! ! !AppTile methodsFor: 'updating' stamp: 'tak 10/11/2007 15:50'! replace: newTile with: oldTile evt: evt | index | index _ args elements indexOf: oldTile. index = 0 ifTrue: [^ super replace: newTile with: oldTile evt: evt]. (args model jsAt: #elements) jsAt: index - 1 put: newTile model. self updateView! ! !AppTile methodsFor: 'updating' stamp: 'tak 10/11/2007 15:37'! take: aTile evt: evt | takenNode index | index := args elements indexOf: aTile. index = 0 ifTrue: [^ super take: aTile evt: evt]. takenNode := model jsSend: #takeAt withArguments: {index - 1}. evt hand grabMorph: (Tile model: takenNode). self updateView! ! !AppTile methodsFor: 'initialize' stamp: 'tak 10/12/2007 13:28'! initialize super initialize. self layoutInset: 2! ! !ArrTile methodsFor: 'accessing' stamp: 'tak 10/11/2007 12:07'! elements ^ elements! ! !ArrTile methodsFor: 'accessing' stamp: 'tak 10/11/2007 12:06'! updateView | jsElements | self removeAllMorphs. jsElements := model jsAt: #elements. elements := jsElements jsKeys collect: [:i | self class model: (jsElements at: i)]. self addAllMorphs: elements! ! !ArrTile methodsFor: 'updating' stamp: 'tak 10/11/2007 15:36'! replace: newMorph with: oldMorph evt: evt (owner isKindOf: Tile) ifTrue: [^ owner replace: newMorph with: oldMorph evt: evt]. super replace: newMorph with: oldMorph evt: evt! ! !FuncTile methodsFor: 'accessing' stamp: 'tak 10/12/2007 11:20'! updateView | body label | self removeAllMorphs. formals := self class model: (model jsAt: #formals). body := self class model: (model jsAt: #body). label := Tile new. label addMorphBack: (self makeLabel: 'function ('). label addMorphBack: formals. label addMorphBack: (self makeLabel: ')'). self addMorphBack: label. self addMorphBack: body! ! !FuncTile methodsFor: 'initialize' stamp: 'tak 10/12/2007 10:49'! initialize super initialize. self listDirection: #topToBottom. self cellPositioning: #topLeft. self layoutInset: 3! ! !FuncTile methodsFor: 'event handling' stamp: 'tak 10/12/2007 10:15'! wantsDroppedMorph: aMorph event: anEvent ^ false! ! !FuncTile methodsFor: 'updating' stamp: 'tak 10/12/2007 11:30'! take: aTile evt: evt | index getter | index := formals elements indexOf: aTile. index = 0 ifTrue: [^ super take: aTile evt: evt]. getter := model jsSend: #getNodeAt withArguments: {index - 1}. evt hand grabMorph: (self class model: getter)! ! !GetTile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:54'! updateView | label | self removeAllMorphs. label _ StringMorph new contents: (model jsAt: #prop) printString. self addMorphBack: label. ! ! !GetTile methodsFor: 'initialize' stamp: 'tak 10/12/2007 10:54'! initialize super initialize. self layoutInset: 3! ! !IfTile methodsFor: 'as yet unclassified' stamp: 'aw 10/1/2007 14:36'! updateView | cond trueBranch falseBranch | self removeAllMorphs. cond := self class model: (model jsAt: #cond). trueBranch := self class model: (model jsAt: #trueBranch). falseBranch := self class model: (model jsAt: #falseBranch). self addMorphBack: (self makeLabel: 'if'). self addMorphBack: cond. self addMorphBack: (self makeLabel: 'then'). self addMorphBack: trueBranch. self addMorphBack: (self makeLabel: 'else'). self addMorphBack: falseBranch. self layoutInset: 3! ! !PrimTile methodsFor: 'accessing' stamp: 'tak 10/9/2007 11:34'! label ^ (model jsAt: #p) printString! ! !PrimTile methodsFor: 'accessing' stamp: 'tak 10/9/2007 11:43'! label: aString "Now only Number is suppoted" ^ model jsAt: #p put: aString asNumber! ! !PrimTile methodsFor: 'accessing' stamp: 'tak 10/12/2007 10:41'! standardColor ^ Color white! ! !PrimTile methodsFor: 'accessing' stamp: 'tak 10/9/2007 11:34'! updateView | label | self removeAllMorphs. label := self makeLabel: self label. self addMorphBack: label. self layoutInset: 3! ! !PrimTile methodsFor: 'event handling' stamp: 'tak 10/9/2007 11:32'! doubleClick: evt self editWithEvent: evt! ! !PrimTile methodsFor: 'event handling' stamp: 'tak 10/9/2007 11:36'! editWithEvent: evt | m | self removeAllMorphs. m := UpdatingStringMorph new. m useStringFormat; target: self; putSelector: #label:; contents: self label. m font: ScriptingSystem fontForTiles. self addMorphBack: m. m launchMiniEditor: evt! ! !SetTile methodsFor: 'accessing' stamp: 'tak 9/30/2007 21:07'! updateView | prop val label | self removeAllMorphs. prop := self class model: (model jsAt: #prop). val := self class model: (model jsAt: #val). label := StringMorph new contents: '='. label font: ScriptingSystem fontForTiles. self addMorphBack: prop. self addMorphBack: label. self addMorphBack: val. self layoutInset: 3! ! !Tile class methodsFor: 'instance creation' stamp: 'tak 9/30/2007 21:47'! model: aJSObject | viewClass tile morph | viewClass := aJSObject jsAt: #tileClass. viewClass = 'none' ifTrue: [morph := PluggableTextMorph new. morph setText: aJSObject printString. morph hResizing: #spaceFill. morph vResizing: #spaceFill. ^ morph]. tile := (Smalltalk at: viewClass asSymbol) new. tile model: aJSObject. ^ tile openInHand! ! !TileBrowser methodsFor: 'initialize' stamp: 'tak 10/11/2007 16:58'! initialize super initialize. selectionIndex := 0. fieldList := #(). transcript := TranscriptStream new.! ! !TileBrowser methodsFor: 'initialize' stamp: 'tak 10/11/2007 17:04'! open "TileBrowser new open" | window listPane valuePane transcriptPane | window := (SystemWindow labelled: self name) model: self. listPane := TileList new. listPane model: self. valuePane := TileEditor on: self contents: #contents accept: #accept: menu: #codePaneMenu:shifted:. transcriptPane := PluggableTextMorph on: transcript text: nil accept: nil readSelection: nil menu: #codePaneMenu:shifted:. transcriptPane font: ScriptingSystem fontForTiles. window addMorph: listPane frame: (0 @ 0 corner: 0.3 @ 0.7). window addMorph: valuePane frame: (0.3 @ 0 corner: 1 @ 0.7). window addMorph: transcriptPane frame: (0 @ 0.7 corner: 1 @ 1). ^ window openInWorld! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 9/30/2007 21:36'! contents ^ self selection! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 9/30/2007 17:02'! context: aJSObject context := aJSObject! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 10/8/2007 13:35'! fieldList ^ fieldList := (context jsSend: #keys withArguments: #()) asArray! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 10/12/2007 13:16'! partsAt: aString ^ context jsSend: #partsAt withArguments: {aString}! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 10/8/2007 13:44'! selection selectionIndex = 0 ifTrue: [^ context]. ^ context jsSend: #get withArguments: {fieldList at: selectionIndex}! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 9/30/2007 17:06'! selectionIndex ^ selectionIndex! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 10/7/2007 18:52'! toggleIndex: anInteger selectionIndex _ anInteger. self changed: #contents. self changed: #selectionIndex. self changed: #selection! ! !TileBrowser methodsFor: 'accessing' stamp: 'tak 10/11/2007 17:00'! transcript ^ transcript! ! !TileBrowser methodsFor: 'actions' stamp: 'tak 10/9/2007 09:08'! startDragTile ActiveHand grabMorph: (Tile model: (self partsAt: (fieldList at: selectionIndex)))! ! !TileBrowser class methodsFor: 'instance creation' stamp: 'tak 9/30/2007 17:18'! openOn: aJSObject TileBrowser new context: aJSObject; open! ! !TileDemo class methodsFor: 'constants' stamp: 'tak 9/29/2007 11:25'! newTurtle ^ SketchMorph withForm: self turtleForm! ! !TileDemo class methodsFor: 'constants' stamp: 'tak 9/29/2007 11:19'! turtleForm "(SketchMorph withForm: self turtleForm) openInHand" ^ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: 'iVBORw0KGgoAAAANSUhEUgAAAFoAAABkCAYAAAAG2CffAAAABHNCSVQFBQUBSsjp7wAAA0ZJ REFUeF7l3c1x4zAMBWCVsaWkjBxTSkpIGSljS3BJuSWTg2a9HskiiPcAEI8zPIomP9P8ES1o WzW93rbvkbzpJy6wPngwsD54ArI+diCyPrY+dB3kPy//shX26Fp94QPoeygr9tm1+sIDyKPY V9fqQ+tD60PLTISoMVof+mRZh1516EMT189l1tNVKtMWulqlWkJXrJg+tD70ZR1hDeqCffv6 +82sF6QxXaD3zKoTpDEIzPvGHuUI5FFwl1HWGHcFnAV9Bu42ioYewX372P7L0ciP2BCjyJnb CszA/i1rFBr1i4JOOh7kZ8Ao8NHyGcMWfHa3QFtwPeAzZaPnBvhSagTZCxyZaSasgldERmHT NglHyCsCI7DpO7L7sjwNtKwOUJMtCjxk6+tFRgEzwOEbOMR6tQow+guA7pKjkLNw0ev50Ltn qwLPYMPvZDKQP7/enzYwE9rSHvgtYzTynp/1omzokXaFQs8i77ni8GJpX8hJhwe4CzQUm4Uc AT1bXjj2DjIDfYXMhkaUOdrW2YPep9AoZCY0ulwq9iOKZTbuBj2CbT1RP4W+grEirwZNw56B tiB3hJ4aQqwwVuTO0CZsdm9eEZoyfFiQlTIcWx/afzpkgtaH8x1i6EPrQ/eCvsTWh56fEPWh gb01FHpm7bz6OlofemJToQ+tD70GdMTwoQ+tD60P7VrerQgd/UWWhj76R1NraObwgS63yn3p 9tCP6K2gPShM6JF6Rw1L+tDVoDPODBHQo5/BnmSh0Oi/G0RCW7ChvbnC/zoioK3Y8N58Bo3G XgkafrLi7dX6x1cgaH1scG/W79VBvVkfOhBZHzsQWX+sJo7L+thjTzZAga+gPbvGiHX0yGdZ n5mkB1v09mrL012R0CmRDZi9+rHCK0GHhxFl95qK0GkxW88aMxsUhQ0dGVOJju2NQJNx4z8t cBXqEWYEdsZkR495xwyc4oVeMbBgaMAU9FCyCjAUOzJ6WET+/eUworGnh4SvgrvnyBCiKbH3 M3HPgJkhRFNfcFARGNXucm+S8MYxpQWUynqVCntWzsZsBT3yOdWQZ9qfNhFuDVJ56K1RKrtR 2ZqmMttu/deNrjJO6UPrQ/eaEPRT0ITQKP0A885wevjeSyUAAAAASUVORK5CYII=' readStream) readStream) nextImage. " | f string | f _ FileDirectory default readOnlyFileNamed: 'Turtle.png'. f binary. [string _ (Base64MimeConverter mimeEncode: f contents readStream) contents. Transcript cr; show: string printString. ] ensure: [f close]. form _ (PNGReadWriter on: (Base64MimeConverter mimeDecodeToBytes: string readStream) readStream) nextImage. form asMorph openInHand "! ! !TileDemo class methodsFor: 'examples' stamp: 'tak 9/30/2007 10:32'! example1 "self example1" | morph global workspace | morph := self newTurtle. morph openInWorld. morph center: 200 @ 200. global := self newGlobal. global jsAt: #turtle put: morph assuredPlayer. workspace := JSWorkspace global: global. workspace contents: self example1Contents. workspace open! ! !TileDemo class methodsFor: 'examples' stamp: 'tak 9/30/2007 11:01'! example2 "self example2" | morph global workspace | morph := self newTurtle. morph openInWorld. morph center: 200 @ 200. global := self newGlobal. global jsAt: #turtle put: morph assuredPlayer. JSObject eval: self initializeTile withGlobal: global. workspace := JSWorkspace global: global. workspace contents: self example2Contents. workspace open! ! !TileDemo class methodsFor: 'initialize' stamp: 'tak 9/30/2007 10:32'! example1Contents ^ ' forward(30); turn(30); '! ! !TileDemo class methodsFor: 'initialize' stamp: 'tak 10/11/2007 12:02'! example2Contents ^ '// Tile Demo forward(30); // Primitive function turn(30); // Primitive function // Define new function named "back" (new Set(("back").asNode(), new Func([("step").asNode()].asNode(), new App(("forward").get(), [ new App(("sub").get(), [(0).asNode(), ("step").get()].asNode()) ].asNode()), Global) )).ev() // Browse defined names Global.browse(); // Apply a defined function. (new App(("back").get(), [(30).asNode()].asNode())).ev() (new App(("back").get(), [(30).asNode()].asNode())).makeTile() // initializeTile(); test() '! ! !TileDemo class methodsFor: 'initialize' stamp: 'tak 10/12/2007 13:35'! initializeTile "Javascript source code to set up the tile environment" | f | false ifTrue: [f := FileDirectory default readOnlyFileNamed: 'tilescript', FileDirectory slash, 'minitiles.js'. [^ f contents] ensure: [f close]]. ^'// Minimal Tile Definition for TileDemo. isRhino = false; if (isRhino) { __global__ = new Object(); forward = turn = new Object(); } // Base class function Node() { } Node.prototype.name = "Node" Node.prototype.eval = function(ctxt) { return this } Node.prototype.toString = function() { return this.name } Node.prototype.ev = function() { return this.eval(Global) } Node.prototype.isNode = function() { return true }; // easy error check Node.prototype.tileClass = "Tile"; Node.prototype.printString = function () { return this.toString()}; Node.prototype.toCode = function () { return this.toString()}; // Context function Context(parent) { this.local = new Object(); this.parent = parent; } Context.prototype = new Node() Context.prototype.name = "Context" Context.prototype.get = function(name) { if (this.local[name] == undefined) return this.parent.get(name) return this.local[name] } Context.prototype.set = function(name, value) { return this.local[name] = value } Context.prototype.keys = function() { var result = new Array(); for (var key in this.local) { result.push(key); } return result; } // Answer a useful object for parts bin. // Get object for a prim value, or App for a function, etc. Context.prototype.partsAt = function(name) { var getter = new Get(new Prim(name)); var value = this.get(name); var type = value.type(); var returnType = value.type()[type.length - 1]; if (value.name == "Func" || (value.name == "Prim" && value.p.isFunction == true)) { var argTypes = new Array(); for (var i = 0; i < type.length - 1; i++) { argTypes.push((5).asNode()); // TODO: example value should depend on the type. } return new App(getter, argTypes.asNode()); } return getter; } Context.prototype.getters = function() { return this.keys().map(function(each) {return new Get(new Prim(each))}); } Global = new Context(null); Global.get = function(name) { return this.local[name] } Global.set = function(name, value) { return this.local[name] = value } // Primitive Value for Number, String, and Function function Prim(p) { this.p = p.valueOf() } Prim.prototype = new Node() Prim.prototype.name = "Prim" Prim.prototype.tileClass = "PrimTile"; Prim.prototype.toString = function() { return "[" + this.p.toString() + "]"}; Prim.prototype.eval = function(ctxt) { return this.p }; Prim.prototype.toCode = function() { return this.p.printString() }; // type is an array represent arguments with a result, // e.g. ["String","Number"] is a function String -> Number (like length) // ["Any"] is any type Prim.prototype.type = function() { return this.p.type(); } Boolean.prototype.type = function() { return ["Boolean"] }; Number.prototype.type = function() { return ["Number"] }; String.prototype.type = function() { return ["String"] }; Function.prototype.type = function() { return this.signature; } Function.prototype.signature = ["Any"]; Function.prototype.isFunction = true; Number.prototype.asNode = function() { return new Prim(this) }; String.prototype.asNode = function() { return new Prim(this) }; Function.prototype.asNode = function() { return new Prim(this) }; // Accessors function Get(prop) { this.prop = prop } Get.prototype = new Node() Get.prototype.name = "Get" Get.prototype.eval = function(ctxt) { return ctxt.get(this.prop.eval(ctxt)) } Get.prototype.toString = function() { return this.prop.p } Get.prototype.toCode = function () { return this.prop.p }; // Just a utility function String.prototype.get = function () { return new Get(this.asNode()) } function Set(prop, val) { this.prop = prop this.val = val } Set.prototype = new Node(); Set.prototype.name = "Set"; Set.prototype.tileClass = "SetTile"; Set.prototype.eval = function(ctxt) { return ctxt.set(this.prop.eval(ctxt), this.val.eval(ctxt)) } Set.prototype.toString = function() { return this.prop.toString() + " = " + this.val.toString(); } Set.prototype.toCode = function () { return "(" + this.prop.p + " = " + this.val.toCode() + ")"; } // Array function Arr(elements) { this.elements = elements } Arr.prototype = new Node() Arr.prototype.name = "Arr" Arr.prototype.tileClass = "ArrTile" Arr.prototype.map = function(f) { var newElements = new Array(this.elements.length) for (var idx = 0; idx < this.elements.length; idx++) { newElements[idx] = f(this.elements[idx]); } return newElements; } Arr.prototype.eval = function(ctxt) { var newElements = new Array(this.elements.length) for (var idx=0; idx < this.elements.length; idx++) newElements[idx] = this.elements[idx].eval(ctxt) return newElements } Arr.prototype.toString = function() { return "[" + this.elements.toString() + "]" } Arr.prototype.toCode = function () { return this.elements.reduce( function(x, y) { return x == "[" ? "[" + y.toCode() : x + "," + y.toCode() }, "[" ) + "]"; } Array.prototype.asNode = function() { return new Arr(this) } // Function Application function App(func, args) { func.isNode(); args.isNode() this.func = func this.args = args } App.prototype = new Node() App.prototype.name = "App" App.prototype.tileClass = "AppTile"; App.prototype.eval = function(ctxt) { var func = this.func.eval(ctxt); return func.apply(ctxt, this.args); } App.prototype.toString = function() { return this.func.toString() + " " + this.args.toString(); } // Get an argument node and replace it as a proto value. App.prototype.takeAt = function(index) { var result = this.args.elements[index]; this.args.elements[index] = (5).asNode(); return result; } Prim.prototype.apply = function (ctxt, args) { var primArgs = args.eval(ctxt) return (this.p).apply(ctxt, primArgs); } function Func (formals, body, env) { formals.isNode(); body.isNode(); env.isNode(); this.formals = formals; this.body = body; this.env = env; } Func.prototype = new Node(); Func.prototype.name = "Func"; Func.prototype.tileClass = "FuncTile"; Func.prototype.type = function() { var signature = new Array(); for (var i = 0; i < this.formals.elements.length; i++) { signature.push("Any"); } signature.push("Any"); return signature; } Func.prototype.apply = function(ctxt, args) { var activation = new Context(this.env); for (var idx = 0; idx < this.formals.elements.length; idx++) { activation.set(this.formals.elements[idx].p, args.elements[idx].p); } activation.set("thisContext", activation); return this.body.eval(activation); } Func.prototype.toString = function () { return "function " + this.formals.toString() + " {" + this.body.toString() + "}"; } // Answer Get node at the index in the formals Func.prototype.getNodeAt = function(index) { return new Get(this.formals.elements[index]); } function If(cond, trueBranch, falseBranch) { cond.isNode(); trueBranch.isNode(); falseBranch.isNode(); this.cond = cond; this.trueBranch = trueBranch; this.falseBranch = falseBranch; } If.prototype = new Node(); If.prototype.name = "If"; If.prototype.tileClass = "IfTile"; If.prototype.toString = function() { return "if (" + this.cond.toString() + ") " + trueBranch.toString() + " else " + falseBranch.toString() } If.prototype.eval = function(ctxt) { return (this.cond.eval(ctxt) ? this.trueBranch : this.falseBranch).eval(ctxt) } function Seq(before, after) { this.before = before; this.after = after } Seq.prototype = new Node() Seq.prototype.name = "Seq" Seq.prototype.tileClass = "SeqTile" Seq.prototype.eval = function(ctxt) { this.before.eval(ctxt) return this.after.eval(ctxt) } function Repeat(body) { body.isNode(); this.body = body; } Repeat.prototype = new Node(); Repeat.prototype.name = "Repeat"; Repeat.prototype.tileClass = "RepeatTile"; Repeat.prototype.eval = function(ctxt) { while (true) this.body.eval(ctxt) } // Primitive functions var add = function (x, y) { return x + y; }; var sub = function (x, y) { return x - y; }; var eq = function (x, y) { return x == y; }; add.signature = ["Number", "Number", "Number"]; sub.signature = ["Number", "Number", "Number"]; eq.signature = ["Any", "Any", "Boolean"]; forward.signature = ["Number", "Number"]; turn.signature = ["Number", "Number"]; Global.set("add", new Prim(add)); Global.set("sub", new Prim(sub)); Global.set("eq", new Prim(eq)); Global.set("forward", new Prim(forward)); Global.set("turn", new Prim(turn)); test1 = function () { show("-- Primitive Test --"); show((1).asNode().name == "Prim"); show((1).asNode().p == 1); // show("-- Context Test --"); // child = new Context(Global); // child.set("hello", "world"); // show(child.get("hello") == "world"); // show(Global.get("hello") == undefined); // Global.set("hop", "step"); // show(Global.get("hop") == "step"); // show(child.keys()[0] == "hello"); show("-- Accessor Test --"); var env = new Context(Global); (new Set(("magicNum").asNode(), (42).asNode())).eval(env); show((new Get(("magicNum").asNode())).eval(env) == 42); show("-- Primitive Function Test --"); show((new App( new Get(("add").asNode()), [(3).asNode(), (4).asNode()].asNode())).ev() == 7); show("-- Array Test --"); env.set("x", 4); arr = [(3).asNode(), new Get(("x").asNode())].asNode().eval(env); show(arr[0] == 3); show(arr[1] == 4); show("-- Apply Test --"); app = (new App(new Get(("add").asNode()), [(3).asNode(), new Get(("x").asNode())].asNode())) show(app.eval(env) == 7); show(app.takeAt(1).prop.p == "x"); show(app.args.elements[1].p == 5); done(); } test2 = function () { env = new Context(Global); show("-- Function Test --"); var f = new Func([("x").asNode()].asNode(), (new App(new Get(("add").asNode()), [(3).asNode(), new Get(("x").asNode())].asNode())), Global); var a = new App(f, [(5).asNode()].asNode()); show(a.ev() == 8); show("-- Function Definition Test --"); (new Set(("funcName").asNode(), f)).eval(env); show((new App(("funcName").get(), [(7).asNode()].asNode(), env)).eval(env) == 10); show("-- Type Test --"); show((1).asNode().type()[0] == "Number"); show(("hello").asNode().type()[0] == "String"); show(Global.get("add").type()[0] == "Number"); show("-- Parts Bin Prototype Test --"); env.set("seven", 7); show(env.partsAt("seven").prop.p == "seven"); show(env.partsAt("add").name == "App"); show(env.partsAt("add").ev() == 10); show(env.partsAt("funcName").eval(env) == 8); show("-- If Test --"); show(new If(new Prim(true), new Prim(5), new Prim(6)).ev() == 5); show(new If(new Prim(false), new Prim(5), new Prim(6)).ev() == 6); show("-- To Code Test --"); show(new Get(("getter").asNode()).toCode() == "getter") show((new Set(("hello").asNode(), ("world").asNode())).toCode() == "(hello = \"world\")") show([("step").asNode(), ("hello").asNode()].asNode().toCode() == "[\"step\",\"hello\"]") show((1).asNode().p == 1); done(); } test = function () { test1(); test2() } if (isRhino) { show= print; done= function() {}; Number.prototype.printString = toString; String.prototype.printString = function () { return "\"" + this.toString() + "\""; } Array.prototype.reduce = function(f, z) { var r = z; for (var idx= 0; idx < this.length; idx ++) r = f(r, this[idx]); return r; } } else { var lines= ""; show= function (line) {lines+= line + "\r\n"} done= function () { alert(lines); lines= "" } } '! ! !TileDemo class methodsFor: 'initialize' stamp: 'tak 9/30/2007 22:56'! newGlobal "Add accessors for the turtle into a sandbox." | sandbox | sandbox := JSObject global makeSandbox. JSObject objectProto jsAt: #inspect put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | (ctxt jsAt: #this) jsInspect ]). JSObject objectProto jsAt: #browse put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | TileBrowser openOn: (ctxt jsAt: #this)]). JSObject objectProto jsAt: #makeTile put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | Tile model: (ctxt jsAt: #this) ]). sandbox jsAt: #initializeTile put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | JSObject eval: self initializeTile withGlobal: sandbox ]). "These function doesn't answer the player because tilescript don't have player tile yet" sandbox jsAt: #forward put: (JSObject functionWithEnv: sandbox args: #(x) body: [:ctxt | (ctxt jsAt: #turtle) forward: (ctxt jsAt: #x). ctxt jsAt: #x]); jsAt: #turn put: (JSObject functionWithEnv: sandbox args: #(x) body: [:ctxt | (ctxt jsAt: #turtle) turn: (ctxt jsAt: #x). ctxt jsAt: #x]); jsAt: #x put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | | args | args := ctxt jsAt: #arguments. args ifEmpty: [(ctxt jsAt: #turtle) getX] ifNotEmpty: [(ctxt jsAt: #turtle) setX: args first] ]); jsAt: #y put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | | args | args := ctxt jsAt: #arguments. args ifEmpty: [(ctxt jsAt: #turtle) getY] ifNotEmpty: [(ctxt jsAt: #turtle) setY: args first] ]); jsAt: #heading put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | (ctxt jsAt: #turtle) getHeading]); jsAt: #upDown put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | (ctxt jsAt: #turtle) getUpDown]); jsAt: #leftRight put: (JSObject functionWithEnv: sandbox args: #() body: [:ctxt | (ctxt jsAt: #turtle) getLeftRight]). ^ sandbox! ! !TileEditor methodsFor: 'initiazlie' stamp: 'tak 10/9/2007 10:27'! initialize super initialize. self layoutPolicy: TableLayout new. self wrapCentering: #topLeft. self clipSubmorphs: true! ! !TileEditor methodsFor: 'initiazlie' stamp: 'tak 9/30/2007 21:17'! on: model0 contents: contentsSel0 accept: acceptSel0 menu: menuSel0 self model: model0. contentsSel := contentsSel0. acceptSel := acceptSel0. menuSel := menuSel0! ! !TileEditor methodsFor: 'accessing' stamp: 'tak 10/7/2007 18:38'! model: anObject model ifNotNil: [model removeDependent: self]. anObject ifNotNil: [anObject addDependent: self]. model _ anObject! ! !TileEditor methodsFor: 'updating' stamp: 'tak 9/30/2007 21:35'! updateContents | target morph | self removeAllMorphs. target := model perform: contentsSel. morph := Tile model: target. self addMorph: morph! ! !TileEditor methodsFor: 'updating' stamp: 'tak 9/30/2007 21:23'! update: aSymbol aSymbol == contentsSel ifTrue: [^ self updateContents]. " aSymbol halt".! ! !TileEditor class methodsFor: 'initialize' stamp: 'tak 9/30/2007 21:19'! on: model contents: contentsSel accept: acceptSel menu: menuSel ^ self new on: model contents: contentsSel accept: acceptSel menu: menuSel! ! !TileList methodsFor: 'event handling' stamp: 'tak 10/12/2007 13:22'! click: evt | transformedEvt | transformedEvt := evt transformedBy: (scroller transformFrom: self). panel submorphs keysAndValuesDo: [:index :morph | (morph containsPoint: transformedEvt position) ifTrue: [model toggleIndex: index]]! ! !TileList methodsFor: 'event handling' stamp: 'tak 10/12/2007 13:26'! doubleClick: evt | result transformedEvt target | transformedEvt := evt transformedBy: (scroller transformFrom: self). target := panel submorphs detect: [:morph | morph containsPoint: transformedEvt position] ifNone: [^ self]. result := target model jsSend: #ev withArguments: #(). model transcript nextPutAll: result printString; cr; endEntry! ! !TileList methodsFor: 'event handling' stamp: 'tak 10/8/2007 13:57'! handleMouseMove: anEvent ^ true! ! !TileList methodsFor: 'event handling' stamp: 'tak 10/12/2007 13:23'! mouseDown: evt | selectors | selectors := Array with: #click: with: #doubleClick: with: nil with: #startDrag:. evt hand waitForClicksOrDrag: self event: evt selectors: selectors threshold: 10! ! !TileList methodsFor: 'event handling' stamp: 'tak 10/12/2007 13:22'! startDrag: evt | transformedEvt | transformedEvt := evt transformedBy: (scroller transformFrom: self). panel submorphs keysAndValuesDo: [:index :morph | (morph containsPoint: transformedEvt position) ifTrue: [^ evt hand grabMorph: (Tile model: (model partsAt: (self getList at: index)))]]! ! !TileList methodsFor: 'initialize' stamp: 'tak 10/12/2007 10:45'! initialize super initialize. panel := Morph new. panel color: Color transparent. panel layoutPolicy: TableLayout new. panel hResizing: #shrinkWrap. panel vResizing: #shrinkWrap. panel cellPositioning: #topLeft. panel cellInset: 2. panel layoutInset: 2. self scroller addMorph: panel.! ! !TileList methodsFor: 'initialize' stamp: 'tak 10/8/2007 13:49'! model: aTileBrowser super model: aTileBrowser. self updateList! ! !TileList methodsFor: 'updating' stamp: 'tak 10/8/2007 13:47'! getList ^ model fieldList ! ! !TileList methodsFor: 'updating' stamp: 'tak 10/9/2007 09:08'! updateList | list tile | list _ self getList. panel addAllMorphs: (list collect: [:each | tile _ Tile model: (model partsAt: each). tile lock: true. tile])! ! !TileList methodsFor: 'updating' stamp: 'tak 10/8/2007 13:47'! update: aSymbol "Refer to the comment in View|update:." aSymbol == #fieldList ifTrue: [self updateList. ^ self].! ! !TileList reorganize! ('event handling' click: doubleClick: handleMouseMove: mouseDown: startDrag:) ('initialize' initialize model:) ('updating' getList updateList update:) !