| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378 | Smalltalk current createPackage: 'Compiler'!Object subclass: #ChunkParser	instanceVariableNames: 'stream'	package:'Compiler'!!ChunkParser methodsFor: '*Compiler'!stream: aStream	stream := aStream! !!ChunkParser methodsFor: '*Compiler'!nextChunk	"The chunk format (Smalltalk Interchange Format or Fileout format)	is a trivial format but can be a bit tricky to understand:		- Uses the exclamation mark as delimiter of chunks.		- Inside a chunk a normal exclamation mark must be doubled.		- A non empty chunk must be a valid Smalltalk expression.		- A chunk on top level with a preceding empty chunk is an instruction chunk:			- The object created by the expression then takes over reading chunks.	This metod returns next chunk as a String (trimmed), empty String (all whitespace) or nil."	| char result chunk |	result := '' writeStream.        [char := stream next.        char notNil] whileTrue: [                 char = '!!' ifTrue: [                         stream peek = '!!'                                ifTrue: [stream next "skipping the escape double"]                                ifFalse: [^result contents trimBoth  "chunk end marker found"]].                 result nextPut: char].	^nil "a chunk needs to end with !!"! !!ChunkParser class methodsFor: '*Compiler'!on: aStream	^self new stream: aStream! !Object subclass: #Exporter	instanceVariableNames: ''	package:'Compiler'!!Exporter methodsFor: '*Compiler'!exportAll    "Export all packages in the system."    ^String streamContents: [:stream |    	Smalltalk current packages do: [:pkg |		stream nextPutAll: (self exportPackage: pkg name)]]!exportClass: aClass	"Export a single class. Subclasses override these methods."	^String streamContents: [:stream |		self exportDefinitionOf: aClass on: stream.		self exportMethodsOf: aClass on: stream.		self exportMetaDefinitionOf: aClass on: stream.		self exportMethodsOf: aClass class on: stream]!exportPackage: packageName	"Export a given package by name."	| package |	^String streamContents: [:stream |                package := Smalltalk current packageAt: packageName.                self exportPackageDefinitionOf: package on: stream.		"Export classes in dependency order.		Update (issue #171): Remove duplicates for export"	    	package sortedClasses asSet do: [:each |                        stream nextPutAll: (self exportClass: each)].		self exportPackageExtensionsOf: package on: stream]! !!Exporter methodsFor: '*Compiler'!classNameFor: aClass	^aClass isMetaclass	    ifTrue: [aClass instanceClass name, '.klass']	    ifFalse: [		aClass isNil		    ifTrue: ['nil']		    ifFalse: [aClass name]]!exportDefinitionOf: aClass on: aStream	aStream 	    nextPutAll: 'smalltalk.addClass(';	    nextPutAll: '''', (self classNameFor: aClass), ''', ';	    nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);	    nextPutAll: ', ['.	aClass instanceVariableNames 	    do: [:each | aStream nextPutAll: '''', each, '''']	    separatedBy: [aStream nextPutAll: ', '].	aStream		    nextPutAll: '], ''';	    nextPutAll: aClass category, '''';	    nextPutAll: ');'.	aClass comment notEmpty ifTrue: [	    aStream 	    	lf;		nextPutAll: 'smalltalk.';		nextPutAll: (self classNameFor: aClass);		nextPutAll: '.comment=';		nextPutAll: aClass comment asJavascript].	aStream lf!exportMetaDefinitionOf: aClass on: aStream	aClass class instanceVariableNames isEmpty ifFalse: [	    aStream 		nextPutAll: 'smalltalk.', (self classNameFor: aClass class);		nextPutAll: '.iVarNames = ['.	    aClass class instanceVariableNames		do: [:each | aStream nextPutAll: '''', each, '''']		separatedBy: [aStream nextPutAll: ','].	    aStream nextPutAll: '];', String lf]!exportMethod: aMethod of: aClass on: aStream	aStream 		nextPutAll: 'smalltalk.addMethod(';lf;		nextPutAll: aMethod selector asSelector asJavascript, ',';lf;		nextPutAll: 'smalltalk.method({';lf;		nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;		nextPutAll: 'category: ''', aMethod category, ''',';lf;		nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;		nextPutAll: 'args: ', aMethod arguments asJavascript, ','; lf;		nextPutAll: 'source: ', aMethod source asJavascript, ',';lf;		nextPutAll: 'messageSends: ', aMethod messageSends asJavascript, ',';lf;		nextPutAll: 'referencedClasses: ', aMethod referencedClasses asJavascript.	aStream		lf;		nextPutAll: '}),';lf;		nextPutAll: 'smalltalk.', (self classNameFor: aClass);		nextPutAll: ');';lf;lf!exportMethodsOf: aClass on: aStream	"Issue #143: sort methods alphabetically"	((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector]) do: [:each |		(each category match: '^\*') ifFalse: [			self exportMethod: each of: aClass on: aStream]].	aStream lf!exportPackageDefinitionOf: package on: aStream	aStream 	    nextPutAll: 'smalltalk.addPackage(';	    nextPutAll: '''', package name, ''');';        lf!exportPackageExtensionsOf: package on: aStream	"Issue #143: sort classes and methods alphabetically"	| name |	name := package name.	(Package sortedClasses: Smalltalk current classes) do: [:each |		{each. each class} do: [:aClass | 			((aClass methodDictionary values) sorted: [:a :b | a selector <= b selector]) do: [:method |				(method category match: '^\*', name) ifTrue: [					self exportMethod: method of: aClass on: aStream ]]]]! !Exporter subclass: #ChunkExporter	instanceVariableNames: ''	package:'Compiler'!!ChunkExporter methodsFor: '*Compiler'!chunkEscape: aString	"Replace all occurrences of !! with !!!! and trim at both ends."	^(aString replace: '!!' with: '!!!!') trimBoth!classNameFor: aClass	^aClass isMetaclass	    ifTrue: [aClass instanceClass name, ' class']	    ifFalse: [		aClass isNil		    ifTrue: ['nil']		    ifFalse: [aClass name]]!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: '	package: ''', aClass category, '''!!'; lf.    aClass comment notEmpty ifTrue: [        aStream         nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;        nextPutAll: (self chunkEscape: aClass comment), '!!';lf].    aStream 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]!exportMethod: aMethod of: aClass on: aStream	aStream 		lf; lf; nextPutAll: (self chunkEscape: aMethod source); lf;		nextPutAll: '!!'!exportMethods: methods category: category of: aClass on: aStream	"Issue #143: sort methods alphabetically"	aStream		nextPutAll: '!!', (self classNameFor: aClass);		nextPutAll: ' methodsFor: ''', category, '''!!'.		(methods sorted: [:a :b | a selector <= b selector]) do: [:each |				self exportMethod: each of: aClass on: aStream].	aStream nextPutAll: ' !!'; lf; lf!exportMethodsOf: aClass on: aStream	"Issue #143: sort protocol alphabetically"	| map |	map := Dictionary new.	aClass protocolsDo: [:category :methods | 		(category match: '^\*') ifFalse: [ map at: category put: methods ]].	(map keys sorted: [:a :b | a <= b ]) do: [:category | | methods |		methods := map at: category.		self			exportMethods: methods			category: category			of: aClass			on: aStream ]!exportPackageDefinitionOf: package on: aStream	"Chunk format."	aStream 		nextPutAll: 'Smalltalk current createPackage: ''', package name, '''!!';		lf!exportPackageExtensionsOf: package on: aStream	"We need to override this one too since we need to group	all methods in a given protocol under a leading methodsFor: chunk	for that class."	"Issue #143: sort protocol alphabetically"	| name map |	name := package name.	(Package sortedClasses: Smalltalk current classes) do: [:each |		{each. each class} do: [:aClass |			map := Dictionary new.			aClass protocolsDo: [:category :methods | 				(category match: '^\*', name) ifTrue: [ map at: category put: methods ]].			(map keys sorted: [:a :b | a <= b ]) do: [:category | | methods |				methods := map at: category.					self exportMethods: methods category: category of: aClass on: aStream ]]]! !Exporter subclass: #StrippedExporter	instanceVariableNames: ''	package:'Compiler'!!StrippedExporter methodsFor: '*Compiler'!exportDefinitionOf: aClass on: aStream	aStream 	    nextPutAll: 'smalltalk.addClass(';	    nextPutAll: '''', (self classNameFor: aClass), ''', ';	    nextPutAll: 'smalltalk.', (self classNameFor: aClass superclass);	    nextPutAll: ', ['.	aClass instanceVariableNames 	    do: [:each | aStream nextPutAll: '''', each, '''']	    separatedBy: [aStream nextPutAll: ', '].	aStream		    nextPutAll: '], ''';	    nextPutAll: aClass category, '''';	    nextPutAll: ');'.	aStream lf!exportMethod: aMethod of: aClass on: aStream	aStream 		nextPutAll: 'smalltalk.addMethod(';lf;		nextPutAll: aMethod selector asSelector asJavascript, ',';lf;		nextPutAll: 'smalltalk.method({';lf;		nextPutAll: 'selector: ', aMethod selector asJavascript, ',';lf;		nextPutAll: 'fn: ', aMethod fn compiledSource, ',';lf;		nextPutAll: 'messageSends: ', aMethod messageSends asJavascript;		nextPutAll: '}),';lf;		nextPutAll: 'smalltalk.', (self classNameFor: aClass);		nextPutAll: ');';lf;lf! !Object subclass: #Importer	instanceVariableNames: ''	package:'Compiler'!!Importer methodsFor: '*Compiler'!import: aStream    | chunk result parser lastEmpty |    parser := ChunkParser on: aStream.    lastEmpty := false.    [chunk := parser nextChunk.     chunk isNil] whileFalse: [        chunk isEmpty       		ifTrue: [lastEmpty := true]       		ifFalse: [        		result := Compiler new evaluateExpression: chunk.        		lastEmpty             			ifTrue: [                                  	lastEmpty := false.                                  	result scanFrom: parser]]]! !Object subclass: #PackageLoader	instanceVariableNames: ''	package:'Compiler'!!PackageLoader methodsFor: '*Compiler'!initializePackageNamed: packageName prefix: aString	(Package named: packageName)     	setupClasses;        commitPathJs: '/', aString, '/js';        commitPathSt: '/', aString, '/st'!loadPackage: packageName prefix: aString		| url |    url := '/', aString, '/js/', packageName, '.js'.	jQuery 		ajax: url        options: #{			'type' -> 'GET'.			'dataType' -> 'script'.    		'complete' -> [ :jqXHR :textStatus | 				jqXHR readyState = 4                 	ifTrue: [ self initializePackageNamed: packageName prefix: aString ] ].			'error' -> [ window alert: 'Could not load package at:  ', url ]		}!loadPackages: aCollection prefix: aString	aCollection do: [ :each |    	self loadPackage: each prefix: aString ]! !!PackageLoader class methodsFor: '*Compiler'!loadPackages: aCollection prefix: aString	^ self new loadPackages: aCollection prefix: aString! !Error subclass: #CompilerError	instanceVariableNames: ''	package:'Compiler'!!CompilerError commentStamp!I am the common superclass of all compiling errors.!CompilerError subclass: #ParseError	instanceVariableNames: ''	package:'Compiler'!!ParseError commentStamp!Instance of ParseError are signaled on any parsing error. See `Smalltalk >> #parse:`!CompilerError subclass: #SemanticError	instanceVariableNames: ''	package:'Compiler'!!SemanticError commentStamp!I represent an abstract semantic error thrown by the SemanticAnalyzer.Semantic errors can be unknown variable errors, etc.See my subclasses for concrete errors.The IDE should catch instances of Semantic error to deal with them when compiling!SemanticError subclass: #InliningError	instanceVariableNames: ''	package:'Compiler'!!InliningError commentStamp!Instances of InliningError are signaled when using an `InliningCodeGenerator`in a `Compiler`.!SemanticError subclass: #InvalidAssignmentError	instanceVariableNames: 'variableName'	package:'Compiler'!!InvalidAssignmentError commentStamp!I get signaled when a pseudo variable gets assigned.!!InvalidAssignmentError methodsFor: '*Compiler'!messageText	^ ' Invalid assignment to variable: ', self variableName!variableName	^ variableName!variableName: aString	variableName := aString! !SemanticError subclass: #ShadowingVariableError	instanceVariableNames: 'variableName'	package:'Compiler'!!ShadowingVariableError commentStamp!I get signaled when a variable in a block or method scope shadows a variable of the same name in an outer scope.!!ShadowingVariableError methodsFor: '*Compiler'!messageText	^ 'Variable shadowing error: ', self variableName, ' is already defined'!variableName	^ variableName!variableName: aString	variableName := aString! !SemanticError subclass: #UnknownVariableError	instanceVariableNames: 'variableName'	package:'Compiler'!!UnknownVariableError commentStamp!I get signaled when a variable is not defined.The default behavior is to allow it, as this is how Amber currently is able to seamlessly send messages to JavaScript objects.!!UnknownVariableError methodsFor: '*Compiler'!messageText	^ 'Unknown Variable error: ', self variableName, ' is not defined'!variableName	^ variableName!variableName: aString	variableName := aString! !ErrorHandler subclass: #RethrowErrorHandler	instanceVariableNames: ''	package:'Compiler'!!RethrowErrorHandler commentStamp!This class is used in the commandline version of the compiler.It uses the handleError: message of ErrorHandler for printing the stacktrace and throws the error again as JS exception.As a result Smalltalk errors are not swallowd by the Amber runtime and compilation can be aborted.!!RethrowErrorHandler methodsFor: '*Compiler'!basicSignal: anError	<throw anError>!handleError: anError	super handleError: anError.    self basicSignal: anError! !Object subclass: #Compiler	instanceVariableNames: 'currentClass source unknownVariables codeGeneratorClass'	package:'Compiler'!!Compiler commentStamp!I provide the public interface for compiling Amber source code into JavaScript.The code generator used to produce JavaScript can be plugged with `#codeGeneratorClass`. The default code generator is an instance of `InlinedCodeGenerator`!!Compiler methodsFor: '*Compiler'!codeGeneratorClass	^codeGeneratorClass ifNil: [InliningCodeGenerator]!codeGeneratorClass: aClass	codeGeneratorClass := aClass!currentClass	^currentClass!currentClass: aClass	currentClass := aClass!source	^source ifNil: ['']!source: aString	source := aString!unknownVariables	^unknownVariables!unknownVariables: aCollection	unknownVariables := aCollection! !!Compiler methodsFor: '*Compiler'!compile: aString	^self compileNode: (self parse: aString)!compile: aString forClass: aClass	self currentClass: aClass.	self source: aString.	^self compile: aString!compileExpression: aString	self currentClass: DoIt.	self source: 'doIt ^[', aString, '] value'.	^self compileNode: (self parse: self source)!compileNode: aNode	| generator result |	generator := self codeGeneratorClass new.	generator		source: self source;		currentClass: self currentClass.	result := generator compileNode: aNode.	self unknownVariables: #().	^result!eval: aString	<return eval(aString)>!evaluateExpression: aString	"Unlike #eval: evaluate a Smalltalk expression and answer the returned object"	| result |	DoIt addCompiledMethod: (self eval: (self compileExpression: aString)).	result := DoIt new doIt.	DoIt removeCompiledMethod: (DoIt methodDictionary at: 'doIt').	^result!install: aString forClass: aBehavior category: anotherString   	^ ClassBuilder new    	installMethod: (self eval: (self compile: aString forClass: aBehavior))        forClass: aBehavior        category: anotherString!parse: aString    ^Smalltalk current parse: aString!parseExpression: aString    ^self parse: 'doIt ^[', aString, '] value'!recompile: aClass	aClass methodDictionary do: [:each |		console log: aClass name, ' >> ', each selector.		self install: each source forClass: aClass category: each category].	"self setupClass: aClass."	aClass isMetaclass ifFalse: [self recompile: aClass class]!recompileAll	Smalltalk current classes do: [:each |		Transcript show: each; cr.		[self recompile: each] valueWithTimeout: 100]! !!Compiler class methodsFor: '*Compiler'!recompile: aClass	self new recompile: aClass!recompileAll	Smalltalk current classes do: [:each |		self recompile: each]! !Object subclass: #DoIt	instanceVariableNames: ''	package:'Compiler'!!DoIt commentStamp!`DoIt` is the class used to compile and evaluate expressions. See `Compiler >> evaluateExpression:`.!Object subclass: #NodeVisitor	instanceVariableNames: ''	package:'Compiler'!!NodeVisitor commentStamp!I am the abstract super class of all AST node visitors.!!NodeVisitor methodsFor: '*Compiler'!visit: aNode	^ aNode accept: self!visitAll: aCollection	^ aCollection collect: [ :each | self visit: each ]!visitAssignmentNode: aNode	^ self visitNode: aNode!visitBlockNode: aNode	^ self visitNode: aNode!visitBlockSequenceNode: aNode	^ self visitSequenceNode: aNode!visitCascadeNode: aNode	^ self visitNode: aNode!visitClassReferenceNode: aNode	^ self visitVariableNode: aNode!visitDynamicArrayNode: aNode	^ self visitNode: aNode!visitDynamicDictionaryNode: aNode	^ self visitNode: aNode!visitJSStatementNode: aNode	^ self visitNode: aNode!visitMethodNode: aNode	^ self visitNode: aNode!visitNode: aNode	^ self visitAll: aNode nodes!visitReturnNode: aNode	^ self visitNode: aNode!visitSendNode: aNode	^ self visitNode: aNode!visitSequenceNode: aNode	^ self visitNode: aNode!visitValueNode: aNode	^ self visitNode: aNode!visitVariableNode: aNode	^ self visitNode: aNode! !NodeVisitor subclass: #AbstractCodeGenerator	instanceVariableNames: 'currentClass source'	package:'Compiler'!!AbstractCodeGenerator commentStamp!I am the abstract super class of all code generators and provide their common API.!!AbstractCodeGenerator methodsFor: '*Compiler'!classNameFor: aClass	^aClass isMetaclass	    ifTrue: [aClass instanceClass name, '.klass']	    ifFalse: [		aClass isNil		    ifTrue: ['nil']		    ifFalse: [aClass name]]!currentClass	^currentClass!currentClass: aClass	currentClass := aClass!pseudoVariables	^#('self' 'super' 'true' 'false' 'nil' 'thisContext')!safeVariableNameFor: aString	^(Smalltalk current reservedWords includes: aString)		ifTrue: [aString, '_']		ifFalse: [aString]!source	^source ifNil: ['']!source: aString	source := aString! !!AbstractCodeGenerator methodsFor: '*Compiler'!compileNode: aNode	self subclassResponsibility! !AbstractCodeGenerator subclass: #CodeGenerator	instanceVariableNames: ''	package:'Compiler'!!CodeGenerator commentStamp!I am a basic code generator. I generate a valid JavaScript output, but no not perform any inlining.See `InliningCodeGenerator` for an optimized JavaScript code generation.!!CodeGenerator methodsFor: '*Compiler'!compileNode: aNode	| ir stream |	self semanticAnalyzer visit: aNode.	ir := self translator visit: aNode.	^ self irTranslator		visit: ir;		contents!irTranslator	^ IRJSTranslator new!semanticAnalyzer	^ SemanticAnalyzer on: self currentClass!translator	^ IRASTTranslator new		source: self source;		theClass: self currentClass;		yourself! !Object subclass: #Node	instanceVariableNames: 'position nodes shouldBeInlined shouldBeAliased'	package:'Compiler'!!Node commentStamp!I am the abstract root class of the abstract syntax tree.position: holds a point containing lline- and column number of the symbol location in the original source file!!Node methodsFor: '*Compiler'!addNode: aNode	self nodes add: aNode!nodes	^nodes ifNil: [nodes := Array new]!position	^position ifNil: [position := 0@0]!shouldBeAliased	^ shouldBeAliased ifNil: [ false ]!shouldBeAliased: aBoolean	shouldBeAliased := aBoolean!shouldBeInlined	^ shouldBeInlined ifNil: [ false ]!shouldBeInlined: aBoolean	shouldBeInlined := aBoolean! !!Node methodsFor: '*Compiler'!nodes: aCollection	nodes := aCollection!position: aPosition	position := aPosition! !!Node methodsFor: '*Compiler'!isAssignmentNode	^ false!isBlockNode	^false!isBlockSequenceNode	^false!isImmutable	^false!isNode	^ true!isReturnNode	^false!isSendNode	^false!isValueNode	^false!subtreeNeedsAliasing    ^(self shouldBeAliased or: [ self shouldBeInlined ]) or: [        (self nodes detect: [ :each | each subtreeNeedsAliasing ] ifNone: [ false ]) ~= false ]! !!Node methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitNode: self! !Node subclass: #AssignmentNode	instanceVariableNames: 'left right'	package:'Compiler'!!AssignmentNode methodsFor: '*Compiler'!left	^left!left: aNode	left := aNode!nodes	^ Array with: self left with: self right!right	^right!right: aNode	right := aNode! !!AssignmentNode methodsFor: '*Compiler'!isAssignmentNode	^ true! !!AssignmentNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitAssignmentNode: self! !Node subclass: #BlockNode	instanceVariableNames: 'parameters scope'	package:'Compiler'!!BlockNode methodsFor: '*Compiler'!parameters	^parameters ifNil: [parameters := Array new]!parameters: aCollection	parameters := aCollection!scope	^ scope!scope: aLexicalScope	scope := aLexicalScope! !!BlockNode methodsFor: '*Compiler'!isBlockNode	^true!subtreeNeedsAliasing    ^ self shouldBeAliased or: [ self shouldBeInlined ]! !!BlockNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitBlockNode: self! !Node subclass: #CascadeNode	instanceVariableNames: 'receiver'	package:'Compiler'!!CascadeNode methodsFor: '*Compiler'!receiver	^receiver!receiver: aNode	receiver := aNode! !!CascadeNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitCascadeNode: self! !Node subclass: #DynamicArrayNode	instanceVariableNames: ''	package:'Compiler'!!DynamicArrayNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitDynamicArrayNode: self! !Node subclass: #DynamicDictionaryNode	instanceVariableNames: ''	package:'Compiler'!!DynamicDictionaryNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitDynamicDictionaryNode: self! !Node subclass: #JSStatementNode	instanceVariableNames: 'source'	package:'Compiler'!!JSStatementNode methodsFor: '*Compiler'!source	^source ifNil: ['']!source: aString	source := aString! !!JSStatementNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitJSStatementNode: self! !Node subclass: #MethodNode	instanceVariableNames: 'selector arguments source scope classReferences messageSends superSends'	package:'Compiler'!!MethodNode methodsFor: '*Compiler'!arguments	^arguments ifNil: [#()]!arguments: aCollection	arguments := aCollection!classReferences	^ classReferences!classReferences: aCollection	classReferences := aCollection!messageSends	^ messageSends!messageSends: aCollection	messageSends := aCollection!scope	^ scope!scope: aMethodScope	scope := aMethodScope!selector	^selector!selector: aString	selector := aString!source	^source!source: aString	source := aString!superSends	^ superSends!superSends: aCollection	superSends := aCollection! !!MethodNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitMethodNode: self! !Node subclass: #ReturnNode	instanceVariableNames: 'scope'	package:'Compiler'!!ReturnNode methodsFor: '*Compiler'!scope	^ scope!scope: aLexicalScope	scope := aLexicalScope! !!ReturnNode methodsFor: '*Compiler'!isReturnNode	^ true!nonLocalReturn	^ self scope isMethodScope not! !!ReturnNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitReturnNode: self! !Node subclass: #SendNode	instanceVariableNames: 'selector arguments receiver superSend index'	package:'Compiler'!!SendNode methodsFor: '*Compiler'!arguments	^arguments ifNil: [arguments := #()]!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!index	^ index!index: anInteger	index := anInteger!nodes	^ (Array withAll: self arguments)		add: self receiver;		yourself!receiver	^receiver!receiver: aNode	receiver := aNode!selector	^selector!selector: aString	selector := aString!superSend	^ superSend ifNil: [ false ]!superSend: aBoolean	superSend := aBoolean!valueForReceiver: anObject	^SendNode new	    receiver: (self receiver 		ifNil: [anObject]		ifNotNil: [self receiver valueForReceiver: anObject]);	    selector: self selector;	    arguments: self arguments;	    yourself! !!SendNode methodsFor: '*Compiler'!isSendNode	^ true! !!SendNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitSendNode: self! !Node subclass: #SequenceNode	instanceVariableNames: 'temps scope'	package:'Compiler'!!SequenceNode methodsFor: '*Compiler'!scope	^ scope!scope: aLexicalScope	scope := aLexicalScope!temps	^temps ifNil: [#()]!temps: aCollection	temps := aCollection! !!SequenceNode methodsFor: '*Compiler'!asBlockSequenceNode	^BlockSequenceNode new	    nodes: self nodes;	    temps: self temps;	    yourself! !!SequenceNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitSequenceNode: self! !SequenceNode subclass: #BlockSequenceNode	instanceVariableNames: ''	package:'Compiler'!!BlockSequenceNode methodsFor: '*Compiler'!isBlockSequenceNode	^true! !!BlockSequenceNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitBlockSequenceNode: self! !Node subclass: #ValueNode	instanceVariableNames: 'value'	package:'Compiler'!!ValueNode methodsFor: '*Compiler'!value	^value!value: anObject	value := anObject! !!ValueNode methodsFor: '*Compiler'!isImmutable	^true!isValueNode	^true! !!ValueNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitValueNode: self! !ValueNode subclass: #VariableNode	instanceVariableNames: 'assigned binding'	package:'Compiler'!!VariableNode methodsFor: '*Compiler'!alias	^ self binding alias!assigned	^assigned ifNil: [false]!assigned: aBoolean	assigned := aBoolean!beAssigned	self binding validateAssignment.	assigned := true!binding	^ binding!binding: aScopeVar	binding := aScopeVar! !!VariableNode methodsFor: '*Compiler'!isImmutable	^false! !!VariableNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitVariableNode: self! !VariableNode subclass: #ClassReferenceNode	instanceVariableNames: ''	package:'Compiler'!!ClassReferenceNode methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitClassReferenceNode: self! !!Object methodsFor: '*Compiler'!isNode	^ false! !Object subclass: #LexicalScope	instanceVariableNames: 'node instruction temps args outerScope'	package:'Compiler'!!LexicalScope commentStamp!I represent a lexical scope where variable names are associated with ScopeVarsInstances are used for block scopes. Method scopes are instances of MethodLexicalScope.I am attached to a ScopeVar and method/block nodes.Each context (method/closure) get a fresh scope that inherits from its outer scope.!!LexicalScope methodsFor: '*Compiler'!alias	^ '$ctx', self scopeLevel asString!allVariableNames	^ self args keys, self temps keys!args	^ args ifNil: [ args := Dictionary new ]!bindingFor: aStringOrNode	^ self pseudoVars at: aStringOrNode value ifAbsent: [ 		self args at: aStringOrNode value ifAbsent: [			self temps at: aStringOrNode value ifAbsent: [ nil ]]]!instruction	^ instruction!instruction: anIRInstruction	instruction := anIRInstruction!lookupVariable: aNode	| lookup |	lookup := (self bindingFor: aNode).	lookup ifNil: [		lookup := self outerScope ifNotNil: [ 			(self outerScope lookupVariable: aNode) ]].	^ lookup!methodScope	^ self outerScope ifNotNil: [		self outerScope methodScope ]!node	"Answer the node in which I am defined"		^ node!node: aNode	node := aNode!outerScope	^ outerScope!outerScope: aLexicalScope	outerScope := aLexicalScope!pseudoVars	^ self methodScope pseudoVars!scopeLevel	self outerScope ifNil: [ ^ 1 ].	self isInlined ifTrue: [ ^ self outerScope scopeLevel ].    	^ self outerScope scopeLevel + 1!temps	^ temps ifNil: [ temps := Dictionary new ]! !!LexicalScope methodsFor: '*Compiler'!addArg: aString	self args at: aString put: (ArgVar on: aString).	(self args at: aString) scope: self!addTemp: aString	self temps at: aString put: (TempVar on: aString).	(self temps at: aString) scope: self! !!LexicalScope methodsFor: '*Compiler'!canInlineNonLocalReturns	^ self isInlined and: [ self outerScope canInlineNonLocalReturns ]!isBlockScope	^ self isMethodScope not!isInlined	^ self instruction notNil and: [      	self instruction isInlined ]!isMethodScope	^ false! !LexicalScope subclass: #MethodLexicalScope	instanceVariableNames: 'iVars pseudoVars unknownVariables localReturn nonLocalReturns'	package:'Compiler'!!MethodLexicalScope commentStamp!I represent a method scope.!!MethodLexicalScope methodsFor: '*Compiler'!allVariableNames	^ super allVariableNames, self iVars keys!bindingFor: aNode	^ (super bindingFor: aNode) ifNil: [		self iVars at: aNode value ifAbsent: [ nil ]]!iVars	^ iVars ifNil: [ iVars := Dictionary new ]!localReturn	^ localReturn ifNil: [ false ]!localReturn: aBoolean	localReturn := aBoolean!methodScope	^ self!nonLocalReturns	^ nonLocalReturns ifNil: [ nonLocalReturns := OrderedCollection new ]!pseudoVars	pseudoVars ifNil: [		pseudoVars := Dictionary new.		Smalltalk current pseudoVariableNames do: [ :each |			pseudoVars at: each put: ((PseudoVar on: each)				scope: self methodScope;				yourself) ]].	^ pseudoVars!unknownVariables	^ unknownVariables ifNil: [ unknownVariables := OrderedCollection new ]! !!MethodLexicalScope methodsFor: '*Compiler'!addIVar: aString	self iVars at: aString put: (InstanceVar on: aString).	(self iVars at: aString) scope: self!addNonLocalReturn: aScope	self nonLocalReturns add: aScope!removeNonLocalReturn: aScope	self nonLocalReturns remove: aScope ifAbsent: []! !!MethodLexicalScope methodsFor: '*Compiler'!canInlineNonLocalReturns	^ true!hasLocalReturn	^ self localReturn!hasNonLocalReturn	^ self nonLocalReturns notEmpty!isMethodScope	^ true! !Object subclass: #ScopeVar	instanceVariableNames: 'scope name'	package:'Compiler'!!ScopeVar commentStamp!I am an entry in a LexicalScope that gets associated with variable nodes of the same name.  There are 4 different subclasses of vars: temp vars, local vars, args, and unknown/global vars.!!ScopeVar methodsFor: '*Compiler'!alias	^ self name asVariableName!name	^ name!name: aString	name := aString!scope	^ scope!scope: aScope	scope := aScope! !!ScopeVar methodsFor: '*Compiler'!isArgVar	^ false!isClassRefVar	^ false!isInstanceVar	^ false!isPseudoVar	^ false!isTempVar	^ false!isUnknownVar	^ false!validateAssignment	(self isArgVar or: [ self isPseudoVar ]) ifTrue: [		InvalidAssignmentError new			variableName: self name;			signal]! !!ScopeVar class methodsFor: '*Compiler'!on: aString	^ self new 		name: aString;		yourself! !ScopeVar subclass: #AliasVar	instanceVariableNames: 'node'	package:'Compiler'!!AliasVar commentStamp!I am an internally defined variable by the compiler!!AliasVar methodsFor: '*Compiler'!node	^ node!node: aNode	node := aNode! !ScopeVar subclass: #ArgVar	instanceVariableNames: ''	package:'Compiler'!!ArgVar commentStamp!I am an argument of a method or block.!!ArgVar methodsFor: '*Compiler'!isArgVar	^ true! !ScopeVar subclass: #ClassRefVar	instanceVariableNames: ''	package:'Compiler'!!ClassRefVar commentStamp!I am an class reference variable!!ClassRefVar methodsFor: '*Compiler'!alias	^ '(smalltalk.', self name, ' || ', self name, ')'! !!ClassRefVar methodsFor: '*Compiler'!isClassRefVar	^ true! !ScopeVar subclass: #InstanceVar	instanceVariableNames: ''	package:'Compiler'!!InstanceVar commentStamp!I am an instance variable of a method or block.!!InstanceVar methodsFor: '*Compiler'!alias	^ 'self["@', self name, '"]'!isInstanceVar	^ true! !ScopeVar subclass: #PseudoVar	instanceVariableNames: ''	package:'Compiler'!!PseudoVar commentStamp!I am an pseudo variable.The five Smalltalk pseudo variables are: 'self', 'super', 'nil', 'true' and 'false'!!PseudoVar methodsFor: '*Compiler'!alias	^ self name! !!PseudoVar methodsFor: '*Compiler'!isPseudoVar	^ true! !ScopeVar subclass: #TempVar	instanceVariableNames: ''	package:'Compiler'!!TempVar commentStamp!I am an temporary variable of a method or block.!!TempVar methodsFor: '*Compiler'!isTempVar	^ true! !ScopeVar subclass: #UnknownVar	instanceVariableNames: ''	package:'Compiler'!!UnknownVar commentStamp!I am an unknown variable. Amber uses unknown variables as JavaScript globals!!UnknownVar methodsFor: '*Compiler'!isUnknownVar	^ true! !NodeVisitor subclass: #SemanticAnalyzer	instanceVariableNames: 'currentScope theClass classReferences messageSends superSends'	package:'Compiler'!!SemanticAnalyzer commentStamp!I semantically analyze the abstract syntax tree and annotate it with informations such as non local returns and variable scopes.!!SemanticAnalyzer methodsFor: '*Compiler'!classReferences	^ classReferences ifNil: [ classReferences := Set new ]!messageSends	^ messageSends ifNil: [ messageSends := Dictionary new ]!superSends	^ superSends ifNil: [ superSends := Dictionary new ]!theClass	^ theClass!theClass: aClass	theClass := aClass! !!SemanticAnalyzer methodsFor: '*Compiler'!errorShadowingVariable: aString	ShadowingVariableError new		variableName: aString;		signal!errorUnknownVariable: aNode	"Throw an error if the variable is undeclared in the global JS scope (i.e. window).    We allow four variable names in addition: `jQuery`, `window`, `process` and `global`     for nodejs and browser environments.         This is only to make sure compilation works on both browser-based and nodejs environments.    The ideal solution would be to use a pragma instead"	| identifier |    identifier := aNode value.    	((#('jQuery' 'window' 'document' 'process' 'global') includes: identifier) not         and: [ self isVariableGloballyUndefined: identifier ])         	ifTrue: [				UnknownVariableError new					variableName: aNode value;					signal ]			ifFalse: [				currentScope methodScope unknownVariables add: aNode value ]! !!SemanticAnalyzer methodsFor: '*Compiler'!newBlockScope	^ self newScopeOfClass: LexicalScope!newMethodScope	^ self newScopeOfClass: MethodLexicalScope!newScopeOfClass: aLexicalScopeClass	^ aLexicalScopeClass new 		outerScope: currentScope;		yourself! !!SemanticAnalyzer methodsFor: '*Compiler'!popScope	currentScope ifNotNil: [		currentScope := currentScope outerScope ]!pushScope: aScope	aScope outerScope: currentScope.	currentScope := aScope!validateVariableScope: aString	"Validate the variable scope in by doing a recursive lookup, up to the method scope"	(currentScope lookupVariable: aString) ifNotNil: [		self errorShadowingVariable: aString ]! !!SemanticAnalyzer methodsFor: '*Compiler'!isVariableGloballyUndefined: aString	<return eval('typeof ' + aString + ' == "undefined"')>! !!SemanticAnalyzer methodsFor: '*Compiler'!visitAssignmentNode: aNode	super visitAssignmentNode: aNode.	aNode left beAssigned!visitBlockNode: aNode	self pushScope: self newBlockScope.	aNode scope: currentScope.	currentScope node: aNode.		aNode parameters do: [ :each | 		self validateVariableScope: each.		currentScope addArg: each ].	super visitBlockNode: aNode.	self popScope!visitCascadeNode: aNode	"Populate the receiver into all children"	aNode nodes do: [ :each | 		each receiver: aNode receiver ].	super visitCascadeNode: aNode.	aNode nodes first superSend ifTrue: [		aNode nodes do: [ :each | each superSend: true ]]!visitClassReferenceNode: aNode	self classReferences add: aNode value.	aNode binding: (ClassRefVar new name: aNode value; yourself)!visitMethodNode: aNode	self pushScope: self newMethodScope.	aNode scope: currentScope.	currentScope node: aNode.	self theClass allInstanceVariableNames do: [:each | 		currentScope addIVar: each ].	aNode arguments do: [ :each | 		self validateVariableScope: each.		currentScope addArg: each ].	super visitMethodNode: aNode.	aNode 		classReferences: self classReferences;		messageSends: self messageSends keys;        superSends: self superSends keys.	self popScope!visitReturnNode: aNode	aNode scope: currentScope.	currentScope isMethodScope		ifTrue: [ currentScope localReturn: true ]		ifFalse: [ currentScope methodScope addNonLocalReturn: currentScope ].	super visitReturnNode: aNode!visitSendNode: aNode	aNode receiver value = 'super' 		ifTrue: [			aNode superSend: true.			aNode receiver value: 'self'.			self superSends at: aNode selector ifAbsentPut: [ Set new ].			(self superSends at: aNode selector) add: aNode ]          		ifFalse: [ (IRSendInliner inlinedSelectors includes: aNode selector) ifTrue: [			aNode shouldBeInlined: true.			aNode receiver shouldBeAliased: true ] ].	self messageSends at: aNode selector ifAbsentPut: [ Set new ].	(self messageSends at: aNode selector) add: aNode.	aNode index: (self messageSends at: aNode selector) size.	super visitSendNode: aNode!visitSequenceNode: aNode	aNode temps do: [ :each | 		self validateVariableScope: each.		currentScope addTemp: each ].	super visitSequenceNode: aNode!visitVariableNode: aNode	"Bind a ScopeVar to aNode by doing a lookup in the current scope.	If no ScopeVar is found, bind a UnknowVar and throw an error"	aNode binding: ((currentScope lookupVariable: aNode) ifNil: [ 		self errorUnknownVariable: aNode.		UnknownVar new name: aNode value; yourself ])! !!SemanticAnalyzer class methodsFor: '*Compiler'!on: aClass	^ self new		theClass: aClass;		yourself! !NodeVisitor subclass: #IRASTTranslator	instanceVariableNames: 'source theClass method sequence nextAlias'	package:'Compiler'!!IRASTTranslator commentStamp!I am the AST (abstract syntax tree) visitor responsible for building the intermediate representation graph.I rely on a builder object, instance of IRBuilder.!!IRASTTranslator methodsFor: '*Compiler'!method	^ method!method: anIRMethod	method := anIRMethod!nextAlias	nextAlias ifNil: [ nextAlias := 0 ].	nextAlias := nextAlias + 1.	^ nextAlias asString!sequence	^ sequence!sequence: anIRSequence	sequence := anIRSequence!source	^ source!source: aString	source := aString!theClass	^ theClass!theClass: aClass	theClass := aClass!withSequence: aSequence do: aBlock	| outerSequence |	outerSequence := self sequence.	self sequence: aSequence.	aBlock value.	self sequence: outerSequence.	^ aSequence! !!IRASTTranslator methodsFor: '*Compiler'!alias: aNode	| variable |	aNode isImmutable ifTrue: [ ^ self visit: aNode ].	variable := IRVariable new 		variable: (AliasVar new name: '$', self nextAlias); 		yourself.	self sequence add: (IRAssignment new		add: variable;		add: (self visit: aNode);		yourself).	self method internalVariables add: variable.	^ variable!aliasTemporally: aCollection	"https://github.com/NicolasPetton/amber/issues/296        If a node is aliased, all preceding ones are aliased as well.    The tree is iterated twice. First we get the aliasing dependency,     then the aliasing itself is done"	| threshold result |    threshold := 0.        aCollection withIndexDo: [ :each :i |        each subtreeNeedsAliasing		    ifTrue: [ threshold := i ]].	result := OrderedCollection new.	aCollection withIndexDo: [ :each :i | 		result add: (i <= threshold			ifTrue: [ self alias: each ]			ifFalse: [ self visit: each ])].    ^result!visitAssignmentNode: aNode	| left right assignment |	right := self visit: aNode right.	left := self visit: aNode left.	self sequence add: (IRAssignment new 		add: left;		add: right;		yourself).	^ left!visitBlockNode: aNode	| closure |	closure := IRClosure new		arguments: aNode parameters;		scope: aNode scope;		yourself.	aNode scope temps do: [ :each |		closure add: (IRTempDeclaration new 			name: each name;            scope: aNode scope;			yourself) ].	aNode nodes do: [ :each | closure add: (self visit: each) ].	^ closure!visitBlockSequenceNode: aNode	^ self		withSequence: IRBlockSequence new		do: [ 			aNode nodes ifNotEmpty: [				aNode nodes allButLast do: [ :each | 					self sequence add: (self visit: each) ].				aNode nodes last isReturnNode 					ifFalse: [ self sequence add: (IRBlockReturn new add: (self visit: aNode nodes last); yourself) ]					ifTrue: [ self sequence add: (self visit: aNode nodes last) ]]]!visitCascadeNode: aNode	| alias |	aNode receiver isImmutable ifFalse: [ 		alias := self alias: aNode receiver.		aNode nodes do: [ :each |			each receiver: (VariableNode new binding: alias variable) ]].	aNode nodes allButLast do: [ :each |		self sequence add: (self visit: each) ].	^ self alias: aNode nodes last!visitDynamicArrayNode: aNode	| array |	array := IRDynamicArray new.	(self aliasTemporally: aNode nodes) do: [:each | array add: each].	^ array!visitDynamicDictionaryNode: aNode	| dictionary |	dictionary := IRDynamicDictionary new.    (self aliasTemporally: aNode nodes) do: [:each | dictionary add: each].	^ dictionary!visitJSStatementNode: aNode	^ IRVerbatim new		source: aNode source;		yourself!visitMethodNode: aNode	self method: (IRMethod new		source: self source;        theClass: self theClass;		arguments: aNode arguments;		selector: aNode selector;		messageSends: aNode messageSends;        superSends: aNode superSends;		classReferences: aNode classReferences;		scope: aNode scope;		yourself).	aNode scope temps do: [ :each |		self method add: (IRTempDeclaration new			name: each name;            scope: aNode scope;			yourself) ].	aNode nodes do: [ :each | self method add: (self visit: each) ].	aNode scope hasLocalReturn ifFalse: [		(self method add: IRReturn new) add: (IRVariable new			variable: (aNode scope pseudoVars at: 'self');			yourself) ].	^ self method!visitReturnNode: aNode	| return |	return := aNode nonLocalReturn 		ifTrue: [ IRNonLocalReturn new ]		ifFalse: [ IRReturn new ].	return scope: aNode scope.	aNode nodes do: [ :each |		return add: (self alias: each) ].	^ return!visitSendNode: aNode	| send all receiver arguments |	send := IRSend new.	send 		selector: aNode selector;		index: aNode index.	aNode superSend ifTrue: [ send classSend: self theClass superclass ].        all := self aliasTemporally: { aNode receiver }, aNode arguments.	receiver := all first.	arguments := all allButFirst.	send add: receiver.	arguments do: [ :each | send add: each ].	^ send!visitSequenceNode: aNode	^ self 		withSequence: IRSequence new 			do: [			aNode nodes do: [ :each | | instruction |				instruction := self visit: each.				instruction isVariable ifFalse: [					self sequence add: instruction ]]]!visitValueNode: aNode	^ IRValue new 		value: aNode value; 		yourself!visitVariableNode: aNode	^ IRVariable new 		variable: aNode binding; 		yourself! !Object subclass: #IRInstruction	instanceVariableNames: 'parent instructions'	package:'Compiler'!!IRInstruction commentStamp!I am the abstract root class of the IR (intermediate representation) instructions class hierarchy.The IR graph is used to emit JavaScript code using a JSStream.!!IRInstruction methodsFor: '*Compiler'!instructions	^ instructions ifNil: [ instructions := OrderedCollection new ]!method	^ self parent method!parent	^ parent!parent: anIRInstruction	parent := anIRInstruction! !!IRInstruction methodsFor: '*Compiler'!add: anObject	anObject parent: self.	^ self instructions add: anObject!remove	self parent remove: self!remove: anIRInstruction	self instructions remove: anIRInstruction!replace: anIRInstruction with: anotherIRInstruction	anotherIRInstruction parent: self.	self instructions 		at: (self instructions indexOf: anIRInstruction)		put: anotherIRInstruction!replaceWith: anIRInstruction	self parent replace: self with: anIRInstruction! !!IRInstruction methodsFor: '*Compiler'!canBeAssigned	^ true!isClosure	^ false!isInlined	^ false!isLocalReturn	^ false!isMethod	^ false!isReturn	^ false!isSend	^ false!isSequence	^ false!isTempDeclaration	^ false!isVariable	^ false! !!IRInstruction methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRInstruction: self! !!IRInstruction class methodsFor: '*Compiler'!on: aBuilder	^ self new		builder: aBuilder;		yourself! !IRInstruction subclass: #IRAssignment	instanceVariableNames: ''	package:'Compiler'!!IRAssignment methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRAssignment: self! !IRInstruction subclass: #IRDynamicArray	instanceVariableNames: ''	package:'Compiler'!!IRDynamicArray methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRDynamicArray: self! !IRInstruction subclass: #IRDynamicDictionary	instanceVariableNames: ''	package:'Compiler'!!IRDynamicDictionary methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRDynamicDictionary: self! !IRInstruction subclass: #IRScopedInstruction	instanceVariableNames: 'scope'	package:'Compiler'!!IRScopedInstruction methodsFor: '*Compiler'!scope	^ scope!scope: aScope	scope := aScope! !IRScopedInstruction subclass: #IRClosureInstruction	instanceVariableNames: 'arguments'	package:'Compiler'!!IRClosureInstruction methodsFor: '*Compiler'!arguments	^ arguments ifNil: [ #() ]!arguments: aCollection	arguments := aCollection!locals	^ self arguments copy    	addAll: (self tempDeclarations collect: [ :each | each name ]);         yourself!scope: aScope	super scope: aScope.	aScope instruction: self!tempDeclarations	^ self instructions select: [ :each |     	each isTempDeclaration ]! !IRClosureInstruction subclass: #IRClosure	instanceVariableNames: ''	package:'Compiler'!!IRClosure methodsFor: '*Compiler'!sequence	^ self instructions last! !!IRClosure methodsFor: '*Compiler'!isClosure	^ true! !!IRClosure methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRClosure: self! !IRClosureInstruction subclass: #IRMethod	instanceVariableNames: 'theClass source selector classReferences messageSends superSends internalVariables'	package:'Compiler'!!IRMethod commentStamp!I am a method instruction!!IRMethod methodsFor: '*Compiler'!classReferences	^ classReferences!classReferences: aCollection	classReferences := aCollection!internalVariables	^ internalVariables ifNil: [ internalVariables := Set new ]!isMethod	^ true!messageSends	^ messageSends!messageSends: aCollection	messageSends := aCollection!method	^ self!selector	^ selector!selector: aString	selector := aString!source	^ source!source: aString	source := aString!superSends	^ superSends!superSends: aCollection	superSends := aCollection!theClass	^ theClass!theClass: aClass	theClass := aClass! !!IRMethod methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRMethod: self! !IRScopedInstruction subclass: #IRReturn	instanceVariableNames: ''	package:'Compiler'!!IRReturn commentStamp!I am a local return instruction.!!IRReturn methodsFor: '*Compiler'!canBeAssigned	^ false!isBlockReturn	^ false!isLocalReturn	^ true!isNonLocalReturn	^ self isLocalReturn not!isReturn	^ true! !!IRReturn methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRReturn: self! !IRReturn subclass: #IRBlockReturn	instanceVariableNames: ''	package:'Compiler'!!IRBlockReturn commentStamp!Smalltalk blocks return their last statement. I am a implicit block return instruction.!!IRBlockReturn methodsFor: '*Compiler'!isBlockReturn	^ true! !!IRBlockReturn methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRBlockReturn: self! !IRReturn subclass: #IRNonLocalReturn	instanceVariableNames: ''	package:'Compiler'!!IRNonLocalReturn commentStamp!I am a non local return instruction.Non local returns are handled using a try/catch JS statement.See IRNonLocalReturnHandling class!!IRNonLocalReturn methodsFor: '*Compiler'!isLocalReturn	^ false! !!IRNonLocalReturn methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRNonLocalReturn: self! !IRScopedInstruction subclass: #IRTempDeclaration	instanceVariableNames: 'name'	package:'Compiler'!!IRTempDeclaration methodsFor: '*Compiler'!name	^ name!name: aString	name := aString! !!IRTempDeclaration methodsFor: '*Compiler'!isTempDeclaration	^ true! !!IRTempDeclaration methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRTempDeclaration: self! !IRInstruction subclass: #IRSend	instanceVariableNames: 'selector classSend index'	package:'Compiler'!!IRSend commentStamp!I am a message send instruction.!!IRSend methodsFor: '*Compiler'!classSend	^ classSend!classSend: aClass	classSend := aClass!index	^ index!index: anInteger	index := anInteger!javascriptSelector	^ self classSend     	ifNil: [ self selector asSelector ]      	ifNotNil: [ self selector asSuperSelector ]!selector	^ selector!selector: aString	selector := aString! !!IRSend methodsFor: '*Compiler'!isSend	^ true! !!IRSend methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRSend: self! !IRInstruction subclass: #IRSequence	instanceVariableNames: ''	package:'Compiler'!!IRSequence methodsFor: '*Compiler'!isSequence	^ true! !!IRSequence methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRSequence: self! !IRSequence subclass: #IRBlockSequence	instanceVariableNames: ''	package:'Compiler'!!IRBlockSequence methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRBlockSequence: self! !IRInstruction subclass: #IRValue	instanceVariableNames: 'value'	package:'Compiler'!!IRValue commentStamp!I am the simplest possible instruction. I represent a value.!!IRValue methodsFor: '*Compiler'!value	^value!value: aString	value := aString! !!IRValue methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRValue: self! !IRInstruction subclass: #IRVariable	instanceVariableNames: 'variable'	package:'Compiler'!!IRVariable commentStamp!I am a variable instruction.!!IRVariable methodsFor: '*Compiler'!variable	^ variable!variable: aScopeVariable	variable := aScopeVariable! !!IRVariable methodsFor: '*Compiler'!isVariable	^ true! !!IRVariable methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRVariable: self! !IRInstruction subclass: #IRVerbatim	instanceVariableNames: 'source'	package:'Compiler'!!IRVerbatim methodsFor: '*Compiler'!source	^ source!source: aString	source := aString! !!IRVerbatim methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRVerbatim: self! !Object subclass: #IRVisitor	instanceVariableNames: ''	package:'Compiler'!!IRVisitor methodsFor: '*Compiler'!visit: anIRInstruction	^ anIRInstruction accept: self!visitIRAssignment: anIRAssignment	^ self visitIRInstruction: anIRAssignment!visitIRBlockReturn: anIRBlockReturn	^ self visitIRReturn: anIRBlockReturn!visitIRBlockSequence: anIRBlockSequence	^ self visitIRSequence: anIRBlockSequence!visitIRClosure: anIRClosure	^ self visitIRInstruction: anIRClosure!visitIRDynamicArray: anIRDynamicArray	^ self visitIRInstruction: anIRDynamicArray!visitIRDynamicDictionary: anIRDynamicDictionary	^ self visitIRInstruction: anIRDynamicDictionary!visitIRInlinedClosure: anIRInlinedClosure	^ self visitIRClosure: anIRInlinedClosure!visitIRInlinedSequence: anIRInlinedSequence	^ self visitIRSequence: anIRInlinedSequence!visitIRInstruction: anIRInstruction	anIRInstruction instructions do: [ :each | self visit: each ].	^ anIRInstruction!visitIRMethod: anIRMethod	^ self visitIRInstruction: anIRMethod!visitIRNonLocalReturn: anIRNonLocalReturn	^ self visitIRInstruction: anIRNonLocalReturn!visitIRNonLocalReturnHandling: anIRNonLocalReturnHandling	^ self visitIRInstruction: anIRNonLocalReturnHandling!visitIRReturn: anIRReturn	^ self visitIRInstruction: anIRReturn!visitIRSend: anIRSend	^ self visitIRInstruction: anIRSend!visitIRSequence: anIRSequence	^ self visitIRInstruction: anIRSequence!visitIRTempDeclaration: anIRTempDeclaration	^ self visitIRInstruction: anIRTempDeclaration!visitIRValue: anIRValue	^ self visitIRInstruction: anIRValue!visitIRVariable: anIRVariable	^ self visitIRInstruction: anIRVariable!visitIRVerbatim: anIRVerbatim	^ self visitIRInstruction: anIRVerbatim! !IRVisitor subclass: #IRJSTranslator	instanceVariableNames: 'stream'	package:'Compiler'!!IRJSTranslator methodsFor: '*Compiler'!contents	^ self stream contents!stream	^ stream!stream: aStream	stream := aStream! !!IRJSTranslator methodsFor: '*Compiler'!initialize	super initialize.	stream := JSStream new.! !!IRJSTranslator methodsFor: '*Compiler'!visitIRAssignment: anIRAssignment	self visit: anIRAssignment instructions first.	self stream nextPutAssignment.	self visit: anIRAssignment instructions last.!visitIRClosure: anIRClosure	self stream 		nextPutClosureWith: [         	self stream nextPutVars: (anIRClosure tempDeclarations collect: [ :each |    				each name asVariableName ]).        	self stream             	nextPutBlockContextFor: anIRClosure                during: [ super visitIRClosure: anIRClosure ] ]		arguments: anIRClosure arguments!visitIRDynamicArray: anIRDynamicArray	self stream nextPutAll: '['.	anIRDynamicArray instructions		do: [ :each | self visit: each ]		separatedBy: [ self stream nextPutAll: ',' ].	stream nextPutAll: ']'!visitIRDynamicDictionary: anIRDynamicDictionary	self stream nextPutAll: 'smalltalk.HashedCollection._fromPairs_(['.		anIRDynamicDictionary instructions 			do: [ :each | self visit: each ]			separatedBy: [self stream nextPutAll: ',' ].	self stream nextPutAll: '])'!visitIRMethod: anIRMethod	self stream		nextPutMethodDeclaration: anIRMethod 		with: [ self stream 			nextPutFunctionWith: [             	self stream nextPutVars: (anIRMethod tempDeclarations collect: [ :each |    				each name asVariableName ]).            	self stream nextPutContextFor: anIRMethod during: [				anIRMethod internalVariables notEmpty ifTrue: [					self stream nextPutVars: (anIRMethod internalVariables asArray collect: [ :each |						each variable alias ]) ].				anIRMethod scope hasNonLocalReturn 					ifTrue: [						self stream nextPutNonLocalReturnHandlingWith: [							super visitIRMethod: anIRMethod ]]					ifFalse: [ super visitIRMethod: anIRMethod ]]]			arguments: anIRMethod arguments ]!visitIRNonLocalReturn: anIRNonLocalReturn	self stream nextPutNonLocalReturnWith: [		super visitIRNonLocalReturn: anIRNonLocalReturn ]!visitIRReturn: anIRReturn	self stream nextPutReturnWith: [		super visitIRReturn: anIRReturn ]!visitIRSend: anIRSend	anIRSend classSend     	ifNil: [			self stream nextPutAll: '_st('.			self visit: anIRSend instructions first.   		 	self stream nextPutAll: ').', anIRSend selector asSelector, '('.			anIRSend instructions allButFirst				do: [ :each | self visit: each ]				separatedBy: [ self stream nextPutAll: ',' ].			self stream nextPutAll: ')' ]		ifNotNil: [ 			self stream             	nextPutAll: anIRSend classSend asJavascript, '.fn.prototype.';				nextPutAll: anIRSend selector asSelector, '.apply(';				nextPutAll: '_st('.			self visit: anIRSend instructions first.			self stream nextPutAll: '), ['.			anIRSend instructions allButFirst				do: [ :each | self visit: each ]				separatedBy: [ self stream nextPutAll: ',' ].			self stream nextPutAll: '])' ]!visitIRSequence: anIRSequence	self stream nextPutSequenceWith: [		anIRSequence instructions do: [ :each |			self stream nextPutStatementWith: (self visit: each) ]]!visitIRTempDeclaration: anIRTempDeclaration	"self stream     	nextPutAll: 'var ', anIRTempDeclaration name asVariableName, ';';         lf"!visitIRValue: anIRValue	self stream nextPutAll: anIRValue value asJavascript!visitIRVariable: anIRVariable	anIRVariable variable name = 'thisContext'    	ifTrue: [ self stream nextPutAll: 'smalltalk.getThisContext()' ]      	ifFalse: [ self stream nextPutAll: anIRVariable variable alias ]!visitIRVerbatim: anIRVerbatim	self stream nextPutStatementWith: [		self stream nextPutAll: anIRVerbatim source ]! !Object subclass: #JSStream	instanceVariableNames: 'stream'	package:'Compiler'!!JSStream methodsFor: '*Compiler'!contents	^ stream contents! !!JSStream methodsFor: '*Compiler'!initialize	super initialize.	stream := '' writeStream.! !!JSStream methodsFor: '*Compiler'!lf	stream lf!nextPut: aString	stream nextPut: aString!nextPutAll: aString	stream nextPutAll: aString!nextPutAssignment	stream nextPutAll: '='!nextPutBlockContextFor: anIRClosure during: aBlock	self     	nextPutAll: 'return smalltalk.withContext(function(', anIRClosure scope alias, ') {';         nextPutAll: String cr.        aBlock value.        self     	nextPutAll: '}, function(', anIRClosure scope alias, ') {';        nextPutAll: anIRClosure scope alias, '.fillBlock({'.        anIRClosure locals     	do: [ :each |    		self         		nextPutAll: each asVariableName;           	 	nextPutAll: ':';        		nextPutAll: each asVariableName]		separatedBy: [ self nextPutAll: ',' ].        self    	nextPutAll: '},';        nextPutAll:  anIRClosure method scope alias, ')})'!nextPutClosureWith: aBlock arguments: anArray	stream nextPutAll: '(function('.	anArray 		do: [ :each | stream nextPutAll: each asVariableName ]		separatedBy: [ stream nextPut: ',' ].	stream nextPutAll: '){'; lf.	aBlock value.	stream nextPutAll: '})'!nextPutContextFor: aMethod during: aBlock	self     	nextPutAll: 'return smalltalk.withContext(function(', aMethod scope alias, ') { ';         nextPutAll: String cr.    aBlock value.        self     	nextPutAll: '}, function(', aMethod scope alias, ') {', aMethod scope alias;         nextPutAll: '.fill(self,', aMethod selector asJavascript, ',{'.    aMethod locals     	do: [ :each |    		self         		nextPutAll: each asVariableName;           	 	nextPutAll: ':';        		nextPutAll: each asVariableName]		separatedBy: [ self nextPutAll: ',' ].        self    	nextPutAll: '}, ';        nextPutAll: aMethod theClass asJavascript;        nextPutAll: ')})'!nextPutFunctionWith: aBlock arguments: anArray	stream nextPutAll: 'fn: function('.	anArray 		do: [ :each | stream nextPutAll: each asVariableName ]		separatedBy: [ stream nextPut: ',' ].	stream nextPutAll: '){'; lf.	stream nextPutAll: 'var self=this;'; lf.	aBlock value.	stream nextPutAll: '}'!nextPutIf: aBlock with: anotherBlock	stream nextPutAll: 'if('.	aBlock value.	stream nextPutAll: '){'; lf.	anotherBlock value.	stream nextPutAll: '}'!nextPutIfElse: aBlock with: ifBlock with: elseBlock	stream nextPutAll: 'if('.	aBlock value.	stream nextPutAll: '){'; lf.	ifBlock value.	stream nextPutAll: '} else {'; lf.	elseBlock value.	stream nextPutAll: '}'!nextPutMethodDeclaration: aMethod with: aBlock	stream 		nextPutAll: 'smalltalk.method({'; lf;		nextPutAll: 'selector: "', aMethod selector, '",'; lf;		nextPutAll: 'source: ', aMethod source asJavascript, ',';lf. 	aBlock value.	stream 		nextPutAll: ',', String lf, 'messageSends: ';		nextPutAll: aMethod messageSends asArray asJavascript, ','; lf;        nextPutAll: 'args: ', (aMethod arguments collect: [ :each | each value ]) asArray asJavascript, ','; lf;		nextPutAll: 'referencedClasses: ['.	aMethod classReferences 		do: [:each | stream nextPutAll: each asJavascript]		separatedBy: [stream nextPutAll: ','].	stream 		nextPutAll: ']';		nextPutAll: '})'!nextPutNonLocalReturnHandlingWith: aBlock	stream 		nextPutAll: 'var $early={};'; lf;		nextPutAll: 'try {'; lf.	aBlock value.	stream 		nextPutAll: '}'; lf;		nextPutAll: 'catch(e) {if(e===$early)return e[0]; throw e}'; lf!nextPutNonLocalReturnWith: aBlock	stream nextPutAll: 'throw $early=['.	aBlock value.	stream nextPutAll: ']'!nextPutReturn	stream nextPutAll: 'return '!nextPutReturnWith: aBlock	self nextPutReturn.	aBlock value!nextPutSequenceWith: aBlock	"stream 		nextPutAll: 'switch(smalltalk.thisContext.pc){'; lf."	aBlock value.	"stream 		nextPutAll: '};'; lf"!nextPutStatement: anInteger with: aBlock	stream nextPutAll: 'case ', anInteger asString, ':'; lf.	self nextPutStatementWith: aBlock.	stream nextPutAll: 'smalltalk.thisContext.pc=', (anInteger + 1) asString, ';'; lf!nextPutStatementWith: aBlock	aBlock value.	stream nextPutAll: ';'; lf!nextPutVar: aString	stream nextPutAll: 'var ', aString, ';'; lf!nextPutVars: aCollection	aCollection ifEmpty: [ ^self ].    	stream nextPutAll: 'var '.	aCollection 		do: [ :each | stream nextPutAll: each ]		separatedBy: [ stream nextPutAll: ',' ].	stream nextPutAll: ';'; lf! !!BlockClosure methodsFor: '*Compiler'!appendToInstruction: anIRInstruction    anIRInstruction appendBlock: self! !!String methodsFor: '*Compiler'!asVariableName	^ (Smalltalk current reservedWords includes: self)		ifTrue: [ self, '_' ]		ifFalse: [ self ]! !IRAssignment subclass: #IRInlinedAssignment	instanceVariableNames: ''	package:'Compiler'!!IRInlinedAssignment commentStamp!I represent an inlined assignment instruction.!!IRInlinedAssignment methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedAssignment methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRInlinedAssignment: self! !IRClosure subclass: #IRInlinedClosure	instanceVariableNames: ''	package:'Compiler'!!IRInlinedClosure commentStamp!I represent an inlined closure instruction.!!IRInlinedClosure methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedClosure methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedClosure: self! !IRReturn subclass: #IRInlinedReturn	instanceVariableNames: ''	package:'Compiler'!!IRInlinedReturn commentStamp!I represent an inlined local return instruction.!!IRInlinedReturn methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedReturn methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRInlinedReturn: self! !IRInlinedReturn subclass: #IRInlinedNonLocalReturn	instanceVariableNames: ''	package:'Compiler'!!IRInlinedNonLocalReturn commentStamp!I represent an inlined non local return instruction.!!IRInlinedNonLocalReturn methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedNonLocalReturn methodsFor: '*Compiler'!accept: aVisitor	^ aVisitor visitIRInlinedNonLocalReturn: self! !IRSend subclass: #IRInlinedSend	instanceVariableNames: ''	package:'Compiler'!!IRInlinedSend commentStamp!I am the abstract super class of inlined message send instructions.!!IRInlinedSend methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedSend methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitInlinedSend: self! !IRInlinedSend subclass: #IRInlinedIfFalse	instanceVariableNames: ''	package:'Compiler'!!IRInlinedIfFalse methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedIfFalse: self! !IRInlinedSend subclass: #IRInlinedIfNilIfNotNil	instanceVariableNames: ''	package:'Compiler'!!IRInlinedIfNilIfNotNil methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedIfNilIfNotNil: self! !IRInlinedSend subclass: #IRInlinedIfTrue	instanceVariableNames: ''	package:'Compiler'!!IRInlinedIfTrue methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedIfTrue: self! !IRInlinedSend subclass: #IRInlinedIfTrueIfFalse	instanceVariableNames: ''	package:'Compiler'!!IRInlinedIfTrueIfFalse methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedIfTrueIfFalse: self! !IRBlockSequence subclass: #IRInlinedSequence	instanceVariableNames: ''	package:'Compiler'!!IRInlinedSequence commentStamp!I represent a (block) sequence inside an inlined closure instruction (instance of `IRInlinedClosure`).!!IRInlinedSequence methodsFor: '*Compiler'!isInlined	^ true! !!IRInlinedSequence methodsFor: '*Compiler'!accept: aVisitor	aVisitor visitIRInlinedSequence: self! !IRVisitor subclass: #IRInliner	instanceVariableNames: ''	package:'Compiler'!!IRInliner commentStamp!I visit an IR tree, inlining message sends and block closures.Message selectors that can be inlined are answered by `IRSendInliner >> #inlinedSelectors`!!IRInliner methodsFor: '*Compiler'!assignmentInliner	^ IRAssignmentInliner new 		translator: self;		yourself!nonLocalReturnInliner	^ IRNonLocalReturnInliner new 		translator: self;		yourself!returnInliner	^ IRReturnInliner new 		translator: self;		yourself!sendInliner	^ IRSendInliner new 		translator: self;		yourself! !!IRInliner methodsFor: '*Compiler'!shouldInlineAssignment: anIRAssignment	^ anIRAssignment isInlined not and: [ 		anIRAssignment instructions last isSend and: [				self shouldInlineSend: (anIRAssignment instructions last) ]]!shouldInlineReturn: anIRReturn	^ anIRReturn isInlined not and: [ 		anIRReturn instructions first isSend and: [				self shouldInlineSend: (anIRReturn instructions first) ]]!shouldInlineSend: anIRSend	^ anIRSend isInlined not and: [		IRSendInliner shouldInline: anIRSend ]! !!IRInliner methodsFor: '*Compiler'!transformNonLocalReturn: anIRNonLocalReturn	"Replace a non local return into a local return"	| localReturn |	anIRNonLocalReturn scope canInlineNonLocalReturns ifTrue: [		anIRNonLocalReturn scope methodScope removeNonLocalReturn: anIRNonLocalReturn scope.		localReturn := IRReturn new			scope: anIRNonLocalReturn scope;			yourself.		anIRNonLocalReturn instructions do: [ :each |			localReturn add: each ].		anIRNonLocalReturn replaceWith: localReturn.		^ localReturn ].	^ super visitIRNonLocalReturn: anIRNonLocalReturn!visitIRAssignment: anIRAssignment	^ (self shouldInlineAssignment: anIRAssignment) 		ifTrue: [ self assignmentInliner inlineAssignment: anIRAssignment ]		ifFalse: [ super visitIRAssignment: anIRAssignment ]!visitIRNonLocalReturn: anIRNonLocalReturn	^ (self shouldInlineReturn: anIRNonLocalReturn) 		ifTrue: [ self nonLocalReturnInliner inlineReturn: anIRNonLocalReturn ]		ifFalse: [ self transformNonLocalReturn: anIRNonLocalReturn ]!visitIRReturn: anIRReturn	^ (self shouldInlineReturn: anIRReturn) 		ifTrue: [ self returnInliner inlineReturn: anIRReturn ]		ifFalse: [ super visitIRReturn: anIRReturn ]!visitIRSend: anIRSend	^ (self shouldInlineSend: anIRSend)		ifTrue: [ self sendInliner inlineSend: anIRSend ]		ifFalse: [ super visitIRSend: anIRSend ]! !IRJSTranslator subclass: #IRInliningJSTranslator	instanceVariableNames: ''	package:'Compiler'!!IRInliningJSTranslator commentStamp!I am a specialized JavaScript translator able to write inlined IR instructions to JavaScript stream (`JSStream` instance).!!IRInliningJSTranslator methodsFor: '*Compiler'!visitIRInlinedAssignment: anIRInlinedAssignment	self visit: anIRInlinedAssignment instructions last!visitIRInlinedClosure: anIRInlinedClosure	anIRInlinedClosure instructions do: [ :each |		self visit: each ]!visitIRInlinedIfFalse: anIRInlinedIfFalse	self stream nextPutIf: [ 		self stream nextPutAll: '!! smalltalk.assert('.		self visit: anIRInlinedIfFalse instructions first.		self stream nextPutAll: ')' ]		with: [ self visit: anIRInlinedIfFalse instructions last ]!visitIRInlinedIfNil: anIRInlinedIfNil	self stream nextPutIf: [ 		self stream nextPutAll: '($receiver = '. 		self visit: anIRInlinedIfNil instructions first.		self stream nextPutAll: ') == nil || $receiver == undefined' ]		with: [ self visit: anIRInlinedIfNil instructions last ]!visitIRInlinedIfNilIfNotNil: anIRInlinedIfNilIfNotNil	self stream 		nextPutIfElse: [ 			self stream nextPutAll: '($receiver = '. 			self visit: anIRInlinedIfNilIfNotNil instructions first.			self stream nextPutAll: ') == nil || $receiver == undefined' ]		with: [ self visit: anIRInlinedIfNilIfNotNil instructions second ]		with: [ self visit: anIRInlinedIfNilIfNotNil instructions third ]!visitIRInlinedIfTrue: anIRInlinedIfTrue	self stream nextPutIf: [ 		self stream nextPutAll: 'smalltalk.assert('. 		self visit: anIRInlinedIfTrue instructions first.		self stream nextPutAll: ')' ]		with: [ self visit: anIRInlinedIfTrue instructions last ]!visitIRInlinedIfTrueIfFalse: anIRInlinedIfTrueIfFalse	self stream 		nextPutIfElse: [ 			self stream nextPutAll: 'smalltalk.assert('. 			self visit: anIRInlinedIfTrueIfFalse instructions first.			self stream nextPutAll: ')' ]		with: [ self visit: anIRInlinedIfTrueIfFalse instructions second ]		with: [ self visit: anIRInlinedIfTrueIfFalse instructions third ]!visitIRInlinedNonLocalReturn: anIRInlinedReturn	self stream nextPutStatementWith: [		self visit: anIRInlinedReturn instructions last ].	self stream nextPutNonLocalReturnWith: [ ]!visitIRInlinedReturn: anIRInlinedReturn	self visit: anIRInlinedReturn instructions last!visitIRInlinedSequence: anIRInlinedSequence	anIRInlinedSequence instructions do: [ :each | 		self stream nextPutStatementWith: [ self visit: each ]]! !Object subclass: #IRSendInliner	instanceVariableNames: 'send translator'	package:'Compiler'!!IRSendInliner commentStamp!I inline some message sends and block closure arguments. I heavily rely on #perform: to dispatch inlining methods.!!IRSendInliner methodsFor: '*Compiler'!send	^ send!send: anIRSend	send := anIRSend!translator	^ translator!translator: anASTTranslator	translator := anASTTranslator! !!IRSendInliner methodsFor: '*Compiler'!inliningError: aString	InliningError signal: aString! !!IRSendInliner methodsFor: '*Compiler'!inlinedClosure	^ IRInlinedClosure new!inlinedSequence	^ IRInlinedSequence new! !!IRSendInliner methodsFor: '*Compiler'!ifFalse: anIRInstruction	^ self inlinedSend: IRInlinedIfFalse new with: anIRInstruction!ifFalse: anIRInstruction ifTrue: anotherIRInstruction	^ self perform: #ifTrue:ifFalse: withArguments: { anotherIRInstruction. anIRInstruction }!ifNil: anIRInstruction	^ self 		inlinedSend: IRInlinedIfNilIfNotNil new 		with: anIRInstruction		with: (IRClosure new			scope: anIRInstruction scope copy;			add: (IRBlockSequence new				add: self send instructions first;				yourself);			yourself)!ifNil: anIRInstruction ifNotNil: anotherIRInstruction	^ self inlinedSend: IRInlinedIfNilIfNotNil new with: anIRInstruction with: anotherIRInstruction!ifNotNil: anIRInstruction	^ self 		inlinedSend: IRInlinedIfNilIfNotNil new		with: (IRClosure new			scope: anIRInstruction scope copy;			add: (IRBlockSequence new				add: self send instructions first;				yourself);			yourself)		with: anIRInstruction!ifNotNil: anIRInstruction ifNil: anotherIRInstruction	^ self inlinedSend: IRInlinedIfNilIfNotNil new with: anotherIRInstruction with: anIRInstruction!ifTrue: anIRInstruction	^ self inlinedSend: IRInlinedIfTrue new with: anIRInstruction!ifTrue: anIRInstruction ifFalse: anotherIRInstruction	^ self inlinedSend: IRInlinedIfTrueIfFalse new with: anIRInstruction with: anotherIRInstruction!inlineClosure: anIRClosure	| inlinedClosure sequence statements |	inlinedClosure := self inlinedClosure.	inlinedClosure scope: anIRClosure scope.	"Add the possible temp declarations"	anIRClosure instructions do: [ :each | 		each isSequence ifFalse: [			inlinedClosure add: each ]].	"Add a block sequence"	sequence := self inlinedSequence.	inlinedClosure add: sequence.	"Get all the statements"	statements := anIRClosure instructions last instructions.		statements ifNotEmpty: [		statements allButLast do: [ :each | sequence add: each ].		"Inlined closures don't have implicit local returns"		(statements last isReturn and: [ statements last isBlockReturn ])			ifTrue: [ sequence add: statements last instructions first ]			ifFalse: [ sequence add: statements last ] ].	^ inlinedClosure!inlineSend: anIRSend	self send: anIRSend.	^ self 		perform: self send selector 		withArguments: self send instructions allButFirst!inlinedSend: inlinedSend with: anIRInstruction	| inlinedClosure |	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].	inlinedClosure := self translator visit: (self inlineClosure: anIRInstruction).	inlinedSend		add: self send instructions first;		add: inlinedClosure.	self send replaceWith: inlinedSend.	^ inlinedSend!inlinedSend: inlinedSend with: anIRInstruction with: anotherIRInstruction	| inlinedClosure1 inlinedClosure2 |	anIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].	anIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].	anotherIRInstruction isClosure ifFalse: [ self inliningError: 'Message argument should be a block' ].	anotherIRInstruction arguments size = 0 ifFalse: [ self inliningError: 'Inlined block should have zero argument' ].	inlinedClosure1 := self translator visit: (self inlineClosure: anIRInstruction).	inlinedClosure2 := self translator visit: (self inlineClosure: anotherIRInstruction).	inlinedSend		add: self send instructions first;		add: inlinedClosure1;		add: inlinedClosure2.	self send replaceWith: inlinedSend.	^ inlinedSend! !!IRSendInliner class methodsFor: '*Compiler'!inlinedSelectors	^ #('ifTrue:' 'ifFalse:' 'ifTrue:ifFalse:' 'ifFalse:ifTrue:' 'ifNil:' 'ifNotNil:' 'ifNil:ifNotNil:' 'ifNotNil:ifNil')!shouldInline: anIRInstruction	(self inlinedSelectors includes: anIRInstruction selector) ifFalse: [ ^ false ].	anIRInstruction instructions allButFirst do: [ :each |		each isClosure ifFalse: [ ^ false ]].	^ true! !IRSendInliner subclass: #IRAssignmentInliner	instanceVariableNames: 'assignment'	package:'Compiler'!!IRAssignmentInliner commentStamp!I inline message sends together with assignments by moving them around into the inline closure instructions. ##Example	foo		| a |		a := true ifTrue: [ 1 ]Will produce:	if(smalltalk.assert(true) {		a = 1;	};!!IRAssignmentInliner methodsFor: '*Compiler'!assignment	^ assignment!assignment: aNode	assignment := aNode! !!IRAssignmentInliner methodsFor: '*Compiler'!inlineAssignment: anIRAssignment	| inlinedAssignment |	self assignment: anIRAssignment.	inlinedAssignment := IRInlinedAssignment new.	anIRAssignment instructions do: [ :each |		inlinedAssignment add: each ].	anIRAssignment replaceWith: inlinedAssignment.	self inlineSend: inlinedAssignment instructions last.	^ inlinedAssignment!inlineClosure: anIRClosure	| inlinedClosure statements |	inlinedClosure := super inlineClosure: anIRClosure.	statements := inlinedClosure instructions last instructions.		statements ifNotEmpty: [		statements last canBeAssigned ifTrue: [			statements last replaceWith: (IRAssignment new				add: self assignment instructions first;				add: statements last copy;				yourself) ] ].	^ inlinedClosure! !IRSendInliner subclass: #IRNonLocalReturnInliner	instanceVariableNames: ''	package:'Compiler'!!IRNonLocalReturnInliner methodsFor: '*Compiler'!inlinedReturn	^ IRInlinedNonLocalReturn new! !!IRNonLocalReturnInliner methodsFor: '*Compiler'!inlineClosure: anIRClosure	"| inlinedClosure statements |	inlinedClosure := super inlineClosure: anIRClosure.	statements := inlinedClosure instructions last instructions.		statements ifNotEmpty: [		statements last replaceWith: (IRNonLocalReturn new			add: statements last copy;			yourself) ].	^ inlinedClosure"	^ super inlineCLosure: anIRClosure! !IRSendInliner subclass: #IRReturnInliner	instanceVariableNames: ''	package:'Compiler'!!IRReturnInliner commentStamp!I inline message sends with inlined closure together with a return instruction.!!IRReturnInliner methodsFor: '*Compiler'!inlinedReturn	^ IRInlinedReturn new! !!IRReturnInliner methodsFor: '*Compiler'!inlineClosure: anIRClosure	| closure statements |	closure := super inlineClosure: anIRClosure.	statements := closure instructions last instructions.		statements ifNotEmpty: [		statements last isReturn			ifFalse: [ statements last replaceWith: (IRReturn new				add: statements last copy;				yourself)] ].	^ closure!inlineReturn: anIRReturn	| return |	return := self inlinedReturn.	anIRReturn instructions do: [ :each |		return add: each ].	anIRReturn replaceWith: return.	self inlineSend: return instructions last.	^ return! !CodeGenerator subclass: #InliningCodeGenerator	instanceVariableNames: ''	package:'Compiler'!!InliningCodeGenerator commentStamp!I am a specialized code generator that uses inlining to produce more optimized JavaScript output!!InliningCodeGenerator methodsFor: '*Compiler'!compileNode: aNode	| ir stream |	self semanticAnalyzer visit: aNode.	ir := self translator visit: aNode.	self inliner visit: ir.	^ self irTranslator		visit: ir;		contents!inliner	^ IRInliner new!irTranslator	^ IRInliningJSTranslator new! !NodeVisitor subclass: #AIContext	instanceVariableNames: 'outerContext pc locals method'	package:'Compiler'!!AIContext commentStamp!AIContext is like a `MethodContext`, used by the `ASTInterpreter`.Unlike a `MethodContext`, it is not read-only.When debugging, `AIContext` instances are created by copying the current `MethodContext` (thisContext)!!AIContext methodsFor: '*Compiler'!localAt: aString	^ self locals at: aString ifAbsent: [ nil ]!localAt: aString put: anObject	self locals at: aString put: anObject!locals	^ locals ifNil: [ locals := Dictionary new ]!method	^ method!method: aCompiledMethod	method := aCompiledMethod!outerContext	^ outerContext!outerContext: anAIContext	outerContext := anAIContext!pc	^ pc ifNil: [ pc := 0 ]!pc: anInteger	pc := anInteger!receiver	^ self localAt: 'self'!receiver: anObject	self localAt: 'self' put: anObject!selector	^ self metod    	ifNotNil: [ self method selector ]! !!AIContext methodsFor: '*Compiler'!initializeFromMethodContext: aMethodContext	self pc: aMethodContext pc.    self receiver: aMethodContext receiver.    self method: aMethodContext method.    aMethodContext outerContext ifNotNil: [		self outerContext: (self class fromMethodContext: aMethodContext outerContext) ].    aMethodContext locals keysAndValuesDo: [ :key :value |    	self locals at: key put: value ]! !!AIContext class methodsFor: '*Compiler'!fromMethodContext: aMethodContext	^ self new    	initializeFromMethodContext: aMethodContext;        yourself! !Object subclass: #ASTDebugger	instanceVariableNames: 'interpreter context'	package:'Compiler'!!ASTDebugger commentStamp!ASTDebugger is a debugger to Amber.It uses an AST interpreter to step through the code.ASTDebugger instances are created from a `MethodContext` with `ASTDebugger class >> context:`.They hold an `AIContext` instance internally, recursive copy of the `MethodContext`.Use the methods of the 'stepping' protocol to do stepping.!!ASTDebugger methodsFor: '*Compiler'!context	^ context!context: aContext	context := AIContext new.!interpreter	^ interpreter ifNil: [ interpreter := self defaultInterpreterClass new ]!interpreter: anInterpreter	interpreter := anInterpreter!method	^ self context method! !!ASTDebugger methodsFor: '*Compiler'!defaultInterpreterClass	^ ASTSteppingInterpreter! !!ASTDebugger methodsFor: '*Compiler'!buildAST	"Build the AST tree from the method source code.    The AST is annotated with a SemanticAnalyzer,     to know the semantics and bindings of each node needed for later debugging"        | ast |        ast := Smalltalk current parse: self method source.    (SemanticAnalyzer on: self context receiver class)    	visit: ast.            ^ ast!initializeInterpreter	self interpreter interpret: self buildAST nodes first!initializeWithContext: aMethodContext	"TODO: do we need to handle block contexts?"        self context: (AIContext fromMethodContext: aMethodContext).    self initializeInterpreter! !!ASTDebugger methodsFor: '*Compiler'!restart	self shouldBeImplemented!resume	self shouldBeImplemented!step	"The ASTSteppingInterpreter stops at each node interpretation.     One step will interpret nodes until:    - we get at the end    - the next node is a stepping node (send, assignment, etc.)"    	[ (self interpreter nextNode notNil and: [ self interpreter nextNode stopOnStepping ])		or: [ self interpreter atEnd not ] ]  			whileFalse: [				self interpreter step.                 self step ]!stepInto	self shouldBeImplemented!stepOver	self step! !!ASTDebugger class methodsFor: '*Compiler'!context: aMethodContext	^ self new    	initializeWithContext: aMethodContext;        yourself! !Object subclass: #ASTInterpreter	instanceVariableNames: 'currentNode context shouldReturn result'	package:'Compiler'!!ASTInterpreter commentStamp!ASTIntepreter is like a `NodeVisitor`, interpreting nodes one after each other.It is built using Continuation Passing Style for stepping purposes.Usage example:    | ast interpreter |    ast := Smalltalk current parse: 'foo 1+2+4'.    (SemanticAnalyzer on: Object) visit: ast.    ASTInterpreter new        interpret: ast nodes first;        result "Answers 7"!!ASTInterpreter methodsFor: '*Compiler'!context	^ context ifNil: [ context := AIContext new ]!context: anAIContext	context := anAIContext!currentNode	^ currentNode!result	^ result! !!ASTInterpreter methodsFor: '*Compiler'!initialize	super initialize.    shouldReturn := false! !!ASTInterpreter methodsFor: '*Compiler'!interpret: aNode	shouldReturn := false.    self interpret: aNode continue: [ :value |    	result := value ]!interpret: aNode continue: aBlock	shouldReturn ifTrue: [ ^ self ].	aNode isNode     	ifTrue: [ 	        	currentNode := aNode.            self interpretNode: aNode continue: [ :value |  				self continue: aBlock value: value ] ]        ifFalse: [ self continue: aBlock value: aNode ]!interpretAssignmentNode: aNode continue: aBlock	self interpret: aNode right continue: [ :value |    	self         	continue: aBlock            value: (self assign: aNode left to: value) ]!interpretBlockNode: aNode continue: aBlock	"TODO: Context should be set"        self     	continue: aBlock         value: [ self interpret: aNode nodes first; result ]!interpretBlockSequenceNode: aNode continue: aBlock	self interpretSequenceNode: aNode continue: aBlock!interpretCascadeNode: aNode continue: aBlock	"TODO: Handle super sends"	    self interpret: aNode receiver continue: [ :receiver |		"Only interpret the receiver once"        aNode nodes do: [ :each | each receiver: receiver ].      	self         	interpretAll: aNode nodes allButLast    		continue: [              	self                 	interpret: aNode nodes last                	continue: [ :val | self continue: aBlock value: val ] ] ]!interpretClassReferenceNode: aNode continue: aBlock	self continue: aBlock value: (Smalltalk current at: aNode value)!interpretDynamicArrayNode: aNode continue: aBlock	self interpretAll: aNode nodes continue: [ :array |    	self         	continue: aBlock			value: array ]!interpretDynamicDictionaryNode: aNode continue: aBlock    self interpretAll: aNode nodes continue: [ :array | | hashedCollection |    	hashedCollection := HashedCollection new.        array do: [ :each | hashedCollection add: each ].        self 	        	continue: aBlock            value: hashedCollection ]!interpretJSStatementNode: aNode continue: aBlock	shouldReturn := true.	self continue: aBlock value: (self eval: aNode source)!interpretMethodNode: aNode continue: aBlock	self interpretAll: aNode nodes continue: [ :array |    	self continue: aBlock value: array first ]!interpretNode: aNode continue: aBlock    aNode interpreter: self continue: aBlock!interpretReturnNode: aNode continue: aBlock    self interpret: aNode nodes first continue: [ :value |    	shouldReturn := true.		self continue: aBlock value: value ]!interpretSendNode: aNode continue: aBlock	"TODO: Handle super sends"        self interpret: aNode receiver continue: [ :receiver |    	self interpretAll: aNode arguments continue: [ :args |    		self             	messageFromSendNode: aNode                 arguments: args                do: [ :message |        			self context pc: self context pc + 1.        			self             			continue: aBlock                 		value: (message sendTo: receiver) ] ] ]!interpretSequenceNode: aNode continue: aBlock	self interpretAll: aNode nodes continue: [ :array |    	self continue: aBlock value: array last ]!interpretValueNode: aNode continue: aBlock	self continue: aBlock value: aNode value!interpretVariableNode: aNode continue: aBlock    self     	continue: aBlock        value: (aNode binding isInstanceVar			ifTrue: [ self context receiver instVarAt: aNode value ]			ifFalse: [ self context localAt: aNode value ])! !!ASTInterpreter methodsFor: '*Compiler'!assign: aNode to: anObject	^ aNode binding isInstanceVar     	ifTrue: [ self context receiver instVarAt: aNode value put: anObject ]      	ifFalse: [ self context localAt: aNode value put: anObject ]!continue: aBlock value: anObject	result := anObject.    aBlock value: anObject!eval: aString	"Evaluate aString as JS source inside an JS function.     aString is not sandboxed."        | source function |        source := String streamContents: [ :str |    	str nextPutAll: '(function('.        self context locals keys         	do: [ :each | str nextPutAll: each ]          	separatedBy: [ str nextPutAll: ',' ].        str         	nextPutAll: '){ return (function() {';        	nextPutAll: aString;            nextPutAll: '})() })' ].            	function := Compiler new eval: source.    	^ function valueWithPossibleArguments: self context locals values!interpretAll: aCollection continue: aBlock	self     	interpretAll: aCollection         continue: aBlock         result: OrderedCollection new!interpretAll: nodes continue: aBlock result: aCollection	nodes isEmpty     	ifTrue: [ self continue: aBlock value: aCollection ]    	ifFalse: [    		self interpret: nodes first continue: [:value |    			self                 	interpretAll: nodes allButFirst                     continue: aBlock  					result: aCollection, { value } ] ]!messageFromSendNode: aSendNode arguments: aCollection do: aBlock    self         continue: aBlock        value: (Message new    		selector: aSendNode selector;        	arguments: aCollection;        	yourself)! !!ASTInterpreter methodsFor: '*Compiler'!shouldReturn	^ shouldReturn ifNil: [ false ]! !ASTInterpreter subclass: #ASTSteppingInterpreter	instanceVariableNames: 'continuation nextNode'	package:'Compiler'!!ASTSteppingInterpreter commentStamp!ASTSteppingInterpreter is an interpreter with stepping capabilities.Use `#step` to actually interpret the next node.Usage example:    | ast interpreter |    ast := Smalltalk current parse: 'foo 1+2+4'.    (SemanticAnalyzer on: Object) visit: ast.    interpreter := ASTSteppingInterpreter new        interpret: ast nodes first;        yourself.            debugger step; step.    debugger step; step.    debugger result."Answers 1"    debugger step.    debugger result. "Answers 3"    debugger step.    debugger result. "Answers 7"!!ASTSteppingInterpreter methodsFor: '*Compiler'!nextNode	^ nextNode! !!ASTSteppingInterpreter methodsFor: '*Compiler'!initialize	super initialize.    continuation := [  ]! !!ASTSteppingInterpreter methodsFor: '*Compiler'!interpret: aNode continue: aBlock	nextNode := aNode.	continuation := [     	super interpret: aNode continue: aBlock ]! !!ASTSteppingInterpreter methodsFor: '*Compiler'!step	continuation value! !!ASTSteppingInterpreter methodsFor: '*Compiler'!atEnd	^ self shouldReturn or: [ self nextNode == self currentNode ]! !!Node methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretNode: self continue: aBlock!isSteppingNode	^ false! !!AssignmentNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretAssignmentNode: self continue: aBlock!isSteppingNode	^ true! !!BlockNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretBlockNode: self continue: aBlock!isSteppingNode	^ true! !!CascadeNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretCascadeNode: self continue: aBlock! !!DynamicArrayNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretDynamicArrayNode: self continue: aBlock!isSteppingNode	^ true! !!DynamicDictionaryNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretDynamicDictionaryNode: self continue: aBlock!isSteppingNode	^ true! !!JSStatementNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretJSStatementNode: self continue: aBlock!isSteppingNode	^ true! !!MethodNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretMethodNode: self continue: aBlock! !!ReturnNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretReturnNode: self continue: aBlock! !!SendNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretSendNode: self continue: aBlock!isSteppingNode	^ true! !!SequenceNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretSequenceNode: self continue: aBlock! !!BlockSequenceNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretBlockSequenceNode: self continue: aBlock! !!ValueNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretValueNode: self continue: aBlock! !!VariableNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretVariableNode: self continue: aBlock! !!ClassReferenceNode methodsFor: '*Compiler'!interpreter: anInterpreter continue: aBlock	^ anInterpreter interpretClassReferenceNode: self continue: aBlock! !
 |