Browse Source

Rudimentary traits can be defined but not used yet.

Herbert Vojčík 7 years ago
parent
commit
f867b96abd
6 changed files with 583 additions and 6 deletions
  1. 216 0
      src/Kernel-Classes.js
  2. 49 0
      src/Kernel-Classes.st
  3. 238 0
      src/Platform-ImportExport.js
  4. 46 0
      src/Platform-ImportExport.st
  5. 31 5
      support/boot.js
  6. 3 1
      support/kernel-runtime.js

+ 216 - 0
src/Kernel-Classes.js

@@ -2235,6 +2235,222 @@ $globals.Metaclass);
 
 
 
+$core.addClass('Trait', $globals.Behavior, [], 'Kernel-Classes');
+$core.addMethod(
+$core.method({
+selector: "basicNew",
+protocol: 'instance creation',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+self._error_("A trait cannot be instantiated.");
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"basicNew",{},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "basicNew\x0a\x09self error: 'A trait cannot be instantiated.'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["error:"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$receiver;
+$1=self._package();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["package"]=1;
+//>>excludeEnd("ctx");
+if(($receiver = $1) == null || $receiver.isNil){
+return "Unclassified";
+} else {
+return $recv(self._package())._name();
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"category",{},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "category\x0a\x09^ self package ifNil: [ 'Unclassified' ] ifNotNil: [ self package name ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["ifNil:ifNotNil:", "package", "name"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "classTag",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "trait";
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "classTag\x0a\x09^ 'trait'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "definition",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($globals.String)._streamContents_((function(stream){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$recv(stream)._nextPutAll_("Trait named: #");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=1;
+//>>excludeEnd("ctx");
+$recv(stream)._nextPutAll_(self._name());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=2;
+//>>excludeEnd("ctx");
+$recv(stream)._nextPutAll_($recv($recv($globals.String)._lf()).__comma($recv($globals.String)._tab()));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=3;
+//>>excludeEnd("ctx");
+$recv(stream)._nextPutAll_("package: '");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=4;
+//>>excludeEnd("ctx");
+$recv(stream)._nextPutAll_(self._category());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=5;
+//>>excludeEnd("ctx");
+return $recv(stream)._nextPutAll_("'");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({stream:stream},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"definition",{},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "definition\x0a\x09^ String streamContents: [ :stream |\x0a\x09\x09stream\x0a\x09\x09\x09nextPutAll: 'Trait named: #';\x0a\x09\x09\x09nextPutAll: self name;\x0a\x09\x09\x09nextPutAll: String lf, String tab;\x0a\x09\x09\x09nextPutAll: 'package: ''';\x0a\x09\x09\x09nextPutAll: self category;\x0a\x09\x09\x09nextPutAll: '''' ]",
+referencedClasses: ["String"],
+//>>excludeEnd("ide");
+messageSends: ["streamContents:", "nextPutAll:", "name", ",", "lf", "tab", "category"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "package",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return self._basicAt_("pkg");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"package",{},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "package\x0a\x09^ self basicAt: 'pkg'",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["basicAt:"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "theMetaClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($globals.Trait)._class();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"theMetaClass",{},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "theMetaClass\x0a\x09^ Trait class",
+referencedClasses: ["Trait"],
+//>>excludeEnd("ide");
+messageSends: ["class"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "theNonMetaClass",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return self;
+
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "theNonMetaClass\x0a\x09^ self",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.Trait);
+
+
+$core.addMethod(
+$core.method({
+selector: "named:package:",
+protocol: 'instance creation',
+fn: function (aString,anotherString){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $core.addTrait(aString, anotherString);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"named:package:",{aString:aString,anotherString:anotherString},$globals.Trait.klass)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString", "anotherString"],
+source: "named: aString package: anotherString\x0a\x09<return $core.addTrait(aString, anotherString)>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: []
+}),
+$globals.Trait.klass);
+
+
 $core.addClass('ClassBuilder', $globals.Object, [], 'Kernel-Classes');
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.ClassBuilder.comment="I am responsible for compiling new classes or modifying existing classes in the system.\x0a\x0aRather than using me directly to compile a class, use `Class >> subclass:instanceVariableNames:package:`.";

+ 49 - 0
src/Kernel-Classes.st

@@ -521,6 +521,55 @@ isMetaclass
 	^ true
 ! !
 
+Behavior subclass: #Trait
+	instanceVariableNames: ''
+	package: 'Kernel-Classes'!
+
+!Trait methodsFor: 'accessing'!
+
+category
+	^ self package ifNil: [ 'Unclassified' ] ifNotNil: [ self package name ]
+!
+
+classTag
+	^ 'trait'
+!
+
+definition
+	^ String streamContents: [ :stream |
+		stream
+			nextPutAll: 'Trait named: #';
+			nextPutAll: self name;
+			nextPutAll: String lf, String tab;
+			nextPutAll: 'package: ''';
+			nextPutAll: self category;
+			nextPutAll: '''' ]
+!
+
+package
+	^ self basicAt: 'pkg'
+!
+
+theMetaClass
+	^ Trait class
+!
+
+theNonMetaClass
+	^ self
+! !
+
+!Trait methodsFor: 'instance creation'!
+
+basicNew
+	self error: 'A trait cannot be instantiated.'
+! !
+
+!Trait class methodsFor: 'instance creation'!
+
+named: aString package: anotherString
+	<return $core.addTrait(aString, anotherString)>
+! !
+
 Object subclass: #ClassBuilder
 	instanceVariableNames: ''
 	package: 'Kernel-Classes'!

+ 238 - 0
src/Platform-ImportExport.js

@@ -800,6 +800,98 @@ messageSends: ["do:", "exportProtocol:on:"]
 }),
 $globals.ChunkExporter);
 
+$core.addMethod(
+$core.method({
+selector: "exportTraitDefinitionOf:on:",
+protocol: 'output',
+fn: function (aClass,aStream){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $2,$1,$4,$3,$5,$6,$8,$7,$9;
+$2=self._classNameFor_(aClass);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["classNameFor:"]=1;
+//>>excludeEnd("ctx");
+$1="Trait named: #".__comma($2);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=1;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($1);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=1;
+//>>excludeEnd("ctx");
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["lf"]=1;
+//>>excludeEnd("ctx");
+$recv(aStream)._tab();
+$4="package: '".__comma($recv(aClass)._category());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=3;
+//>>excludeEnd("ctx");
+$3=$recv($4).__comma("'!");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=2;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($3);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=2;
+//>>excludeEnd("ctx");
+$5=$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["lf"]=2;
+//>>excludeEnd("ctx");
+$6=$recv(aClass)._comment();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["comment"]=1;
+//>>excludeEnd("ctx");
+$recv($6)._ifNotEmpty_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$8="!".__comma(self._classNameFor_(aClass));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx[","]=5;
+//>>excludeEnd("ctx");
+$7=$recv($8).__comma(" commentStamp!");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx[","]=4;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($7);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=3;
+//>>excludeEnd("ctx");
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["lf"]=3;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($recv(self._chunkEscape_($recv(aClass)._comment())).__comma("!"));
+$9=$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["lf"]=4;
+//>>excludeEnd("ctx");
+return $9;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$recv(aStream)._lf();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"exportTraitDefinitionOf:on:",{aClass:aClass,aStream:aStream},$globals.ChunkExporter)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aClass", "aStream"],
+source: "exportTraitDefinitionOf: aClass on: aStream\x0a\x09\x22Chunk format.\x22\x0a\x0a\x09aStream\x0a\x09\x09nextPutAll: 'Trait named: #', (self classNameFor: aClass); lf;\x0a\x09\x09tab; nextPutAll: 'package: ''', aClass category, '''!'; lf.\x0a\x09aClass comment ifNotEmpty: [\x0a\x09\x09aStream\x0a\x09\x09nextPutAll: '!', (self classNameFor: aClass), ' commentStamp!';lf;\x0a\x09\x09nextPutAll: (self chunkEscape: aClass comment), '!';lf ].\x0a\x09aStream lf",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["nextPutAll:", ",", "classNameFor:", "lf", "tab", "category", "ifNotEmpty:", "comment", "chunkEscape:"]
+}),
+$globals.ChunkExporter);
+
 $core.addMethod(
 $core.method({
 selector: "extensionCategoriesOfPackage:",
@@ -1769,6 +1861,104 @@ messageSends: ["nextPutAll:", "asJavascript", "name", "asJSONString", "transport
 }),
 $globals.Exporter);
 
+$core.addMethod(
+$core.method({
+selector: "exportTraitDefinitionOf:on:",
+protocol: 'output',
+fn: function (aClass,aStream){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $2,$1,$3,$4;
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["lf"]=1;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_("$core.addTrait(");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=1;
+//>>excludeEnd("ctx");
+$2="'".__comma(self._classNameFor_(aClass));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=2;
+//>>excludeEnd("ctx");
+$1=$recv($2).__comma("', '");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx[","]=1;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($1);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=2;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($recv($recv(aClass)._category()).__comma("'"));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=3;
+//>>excludeEnd("ctx");
+$3=$recv(aStream)._nextPutAll_(");");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["nextPutAll:"]=4;
+//>>excludeEnd("ctx");
+$4=$recv(aClass)._comment();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx1.sendIdx["comment"]=1;
+//>>excludeEnd("ctx");
+$recv($4)._ifNotEmpty_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["lf"]=2;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_("//>>excludeStart(\x22ide\x22, pragmas.excludeIdeData);");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=5;
+//>>excludeEnd("ctx");
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["lf"]=3;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_(self._jsClassNameFor_(aClass));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=6;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_(".comment=");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=7;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_($recv($recv($recv(aClass)._comment())._crlfSanitized())._asJavascript());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=8;
+//>>excludeEnd("ctx");
+$recv(aStream)._nextPutAll_(";");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["nextPutAll:"]=9;
+//>>excludeEnd("ctx");
+$recv(aStream)._lf();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["lf"]=4;
+//>>excludeEnd("ctx");
+return $recv(aStream)._nextPutAll_("//>>excludeEnd(\x22ide\x22);");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+$recv(aStream)._lf();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"exportTraitDefinitionOf:on:",{aClass:aClass,aStream:aStream},$globals.Exporter)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aClass", "aStream"],
+source: "exportTraitDefinitionOf: aClass on: aStream\x0a\x09aStream\x0a\x09\x09lf;\x0a\x09\x09nextPutAll: '$core.addTrait(';\x0a\x09\x09nextPutAll: '''', (self classNameFor: aClass), ''', ''';\x0a\x09\x09nextPutAll: aClass category, '''';\x0a\x09\x09nextPutAll: ');'.\x0a\x09aClass comment ifNotEmpty: [\x0a\x09\x09aStream\x0a\x09\x09\x09lf;\x0a\x09\x09\x09nextPutAll: '//>>excludeStart(\x22ide\x22, pragmas.excludeIdeData);';\x0a\x09\x09\x09lf;\x0a\x09\x09\x09nextPutAll: (self jsClassNameFor: aClass);\x0a\x09\x09\x09nextPutAll: '.comment=';\x0a\x09\x09\x09nextPutAll: aClass comment crlfSanitized asJavascript;\x0a\x09\x09\x09nextPutAll: ';';\x0a\x09\x09\x09lf;\x0a\x09\x09\x09nextPutAll: '//>>excludeEnd(\x22ide\x22);' ].\x0a\x09aStream lf",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["lf", "nextPutAll:", ",", "classNameFor:", "category", "ifNotEmpty:", "comment", "jsClassNameFor:", "asJavascript", "crlfSanitized"]
+}),
+$globals.Exporter);
+
 $core.addMethod(
 $core.method({
 selector: "jsClassNameFor:",
@@ -4550,4 +4740,52 @@ messageSends: ["loadFromNamespace:", "named:"]
 }),
 $globals.Package.klass);
 
+$core.addMethod(
+$core.method({
+selector: "exportBehaviorDefinitionTo:using:",
+protocol: '*Platform-ImportExport',
+fn: function (aStream,anExporter){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(anExporter)._exportTraitDefinitionOf_on_(self,aStream);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"exportBehaviorDefinitionTo:using:",{aStream:aStream,anExporter:anExporter},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aStream", "anExporter"],
+source: "exportBehaviorDefinitionTo: aStream using: anExporter\x0a\x09anExporter exportTraitDefinitionOf: self on: aStream",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["exportTraitDefinitionOf:on:"]
+}),
+$globals.Trait);
+
+$core.addMethod(
+$core.method({
+selector: "exportBehaviorDefinitionTo:using:",
+protocol: '*Platform-ImportExport',
+fn: function (aStream,anExporter){
+var self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv(anExporter)._exportTraitDefinitionOf_on_(self,aStream);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"exportBehaviorDefinitionTo:using:",{aStream:aStream,anExporter:anExporter},$globals.Trait)});
+//>>excludeEnd("ctx");
+},
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aStream", "anExporter"],
+source: "exportBehaviorDefinitionTo: aStream using: anExporter\x0a\x09anExporter exportTraitDefinitionOf: self on: aStream",
+referencedClasses: [],
+//>>excludeEnd("ide");
+messageSends: ["exportTraitDefinitionOf:on:"]
+}),
+$globals.Trait);
+
 });

+ 46 - 0
src/Platform-ImportExport.st

@@ -230,6 +230,19 @@ exportProtocolPrologueOf: aProtocol on: aStream
 exportProtocols: aCollection on: aStream
 	aCollection do: [ :each |
 		self exportProtocol: each on: aStream ]
+!
+
+exportTraitDefinitionOf: aClass on: aStream
+	"Chunk format."
+
+	aStream
+		nextPutAll: 'Trait named: #', (self classNameFor: aClass); lf;
+		tab; nextPutAll: 'package: ''', aClass category, '''!!'; lf.
+	aClass comment ifNotEmpty: [
+		aStream
+		nextPutAll: '!!', (self classNameFor: aClass), ' commentStamp!!';lf;
+		nextPutAll: (self chunkEscape: aClass comment), '!!';lf ].
+	aStream lf
 ! !
 
 AbstractExporter subclass: #Exporter
@@ -410,6 +423,27 @@ exportPackageTransportOf: aPackage on: aStream
 		nextPutAll: aPackage transport asJSONString;
 		nextPutAll: ';';
 		lf
+!
+
+exportTraitDefinitionOf: aClass on: aStream
+	aStream
+		lf;
+		nextPutAll: '$core.addTrait(';
+		nextPutAll: '''', (self classNameFor: aClass), ''', ''';
+		nextPutAll: aClass category, '''';
+		nextPutAll: ');'.
+	aClass comment ifNotEmpty: [
+		aStream
+			lf;
+			nextPutAll: '//>>excludeStart("ide", pragmas.excludeIdeData);';
+			lf;
+			nextPutAll: (self jsClassNameFor: aClass);
+			nextPutAll: '.comment=';
+			nextPutAll: aClass comment crlfSanitized asJavascript;
+			nextPutAll: ';';
+			lf;
+			nextPutAll: '//>>excludeEnd("ide");' ].
+	aStream lf
 ! !
 
 Exporter subclass: #AmdExporter
@@ -1137,3 +1171,15 @@ load: aPackageName fromNamespace: aString
 	(self named: aPackageName) loadFromNamespace: aString
 ! !
 
+!Trait methodsFor: '*Platform-ImportExport'!
+
+exportBehaviorDefinitionTo: aStream using: anExporter
+	anExporter exportTraitDefinitionOf: self on: aStream
+! !
+
+!Trait methodsFor: '*Platform-ImportExport'!
+
+exportBehaviorDefinitionTo: aStream using: anExporter
+	anExporter exportTraitDefinitionOf: self on: aStream
+! !
+

+ 31 - 5
support/boot.js

@@ -245,6 +245,9 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
         function SmalltalkBehavior () {
         }
 
+        function SmalltalkTrait () {
+        }
+
         function SmalltalkClass () {
         }
 
@@ -252,6 +255,7 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
         }
 
         inherits(SmalltalkBehavior, SmalltalkObject);
+        inherits(SmalltalkTrait, SmalltalkBehavior);
         inherits(SmalltalkClass, SmalltalkBehavior);
         inherits(SmalltalkMetaclass, SmalltalkBehavior);
 
@@ -259,6 +263,8 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
             return 'Smalltalk ' + this.className;
         };
 
+        SmalltalkTrait.prototype.trait = true;
+
         SmalltalkMetaclass.prototype.meta = true;
 
         this.__init__ = function () {
@@ -268,6 +274,7 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
             addCoupledClass("Behavior", globals.Object, "Kernel-Classes", SmalltalkBehavior);
             addCoupledClass("Metaclass", globals.Behavior, "Kernel-Classes", SmalltalkMetaclass);
             addCoupledClass("Class", globals.Behavior, "Kernel-Classes", SmalltalkClass);
+            addCoupledClass("Trait", globals.Behavior, "Kernel-Classes", SmalltalkTrait);
 
             // Manually bootstrap the metaclass hierarchy
             globals.ProtoObject.klass.superclass = nilAsClass.klass = globals.Class;
@@ -284,6 +291,13 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
          should be added to the system, see smalltalk.addClass().
          Superclass linking is *not* handled here, see api.initialize()  */
 
+        function trait (spec) {
+            var that = new SmalltalkTrait();
+            that.className = spec.className;
+            setupClass(that, spec);
+            return that;
+        }
+
         function klass (spec) {
             var setSuperClass = spec.superclass;
             if (!spec.superclass) {
@@ -351,6 +365,10 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
             return rawAddClass(pkgName, className, superclass, iVarNames, null);
         };
 
+        st.addTrait = function (className, pkgName) {
+            return rawAddClass(pkgName, className, "trait");
+        };
+
         function rawAddClass (pkgName, className, superclass, iVarNames, fn) {
             var pkg = st.packages[pkgName];
 
@@ -358,7 +376,8 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
                 throw new Error("Missing package " + pkgName);
             }
 
-            if (superclass == null || superclass.isNil) {
+            var isTrait = superclass === "trait";
+            if (isTrait || superclass == null || superclass.isNil) {
                 superclass = null;
             }
             var theClass = globals.hasOwnProperty(className) && globals[className];
@@ -370,7 +389,11 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
                     iVarNames = iVarNames || theClass.iVarNames;
                     st.removeClass(theClass);
                 }
-                theClass = globals[className] = klass({
+
+                theClass = globals[className] = isTrait ? trait({
+                    className: className,
+                    pkg: pkg
+                }) : klass({
                     className: className,
                     superclass: superclass,
                     pkg: pkg,
@@ -383,7 +406,8 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
 
             classes.addElement(theClass);
             addOrganizationElement(pkg, theClass);
-            if (st._classAdded) st._classAdded(theClass);
+            if (!isTrait && st._classAdded) st._classAdded(theClass);
+            if (isTrait && st._traitAdded) st._traitAdded(theClass);
             return theClass;
         }
 
@@ -507,7 +531,8 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
             selectorInUse(method.selector);
             method.messageSends.forEach(selectorInUse);
 
-            if (st._methodAdded) st._methodAdded(method, klass);
+            if (!klass.trait && st._methodAdded) st._methodAdded(method, klass);
+            if (klass.trait && st._traitMethodAdded) st._traitMethodAdded(method, klass);
             if (st._selectorsAdded) st._selectorsAdded(newSelectors);
         };
 
@@ -516,7 +541,8 @@ define(['require', './brikz', './compatibility'], function (require, Brikz) {
 
             delete klass.methods[method.selector];
 
-            if (st._methodRemoved) st._methodRemoved(method, klass);
+            if (!klass.trait && st._methodRemoved) st._methodRemoved(method, klass);
+            if (klass.trait && st._traitMethodRemoved) st._traitMethodRemoved(method, klass);
 
             // Do *not* delete protocols from here.
             // This is handled by #removeCompiledMethod

+ 3 - 1
support/kernel-runtime.js

@@ -81,7 +81,9 @@ define(function () {
             }
         }
 
-        classes().forEach(initClassAndMetaclass);
+        classes().forEach(function (klass) {
+            if (!klass.trait) initClassAndMetaclass(klass);
+        });
 
         st._classAdded = initClassAndMetaclass;