Browse Source

chunk of error reported

Herbert Vojčík 10 years ago
parent
commit
9388cf0fa9
3 changed files with 121 additions and 18 deletions
  1. 12 1
      cli/support/amberc.js
  2. 84 12
      js/Kernel-ImportExport.js
  3. 25 5
      st/Kernel-ImportExport.st

+ 12 - 1
cli/support/amberc.js

@@ -453,7 +453,18 @@ AmberC.prototype.compile = function() {
 		Array.prototype.slice.call(arguments).forEach(function(code) {
 			if (undefined !== code[0]) {
 				// get element 0 of code since all return values are stored inside an array by Combo
-				self.defaults.smalltalk.Importer._new()._import_(code[0]._stream());
+                var importer = self.defaults.smalltalk.Importer._new();
+                try {
+                    importer._import_(code[0]._stream());
+                } catch (ex) {
+                    throw new Error("Import error in section:\n" +
+                        importer._lastSection() +
+                        "\n\n" +
+                        "while processing chunk:\n" +
+                        importer._lastChunk() +
+                        "\n\n" +
+                        (ex._messageText && ex._messageText() || ex.message || ex));
+                }
 			}
 		});
 		self.category_export();

+ 84 - 12
js/Kernel-ImportExport.js

@@ -1105,8 +1105,26 @@ smalltalk.AmdExporter);
 
 
 
-smalltalk.addClass('ChunkParser', smalltalk.Object, ['stream'], 'Kernel-ImportExport');
+smalltalk.addClass('ChunkParser', smalltalk.Object, ['stream', 'last'], 'Kernel-ImportExport');
 smalltalk.ChunkParser.comment="I am responsible for parsing aStream contents in the chunk format.\x0a\x0a## API\x0a\x0a    ChunkParser new\x0a        stream: aStream;\x0a        nextChunk";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "last",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@last"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"last",{},smalltalk.ChunkParser)})},
+args: [],
+source: "last\x0a\x09^ last",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.ChunkParser);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "nextChunk",
@@ -1115,7 +1133,7 @@ fn: function (){
 var self=this;
 var char,result,chunk;
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3;
+var $1,$2,$3,$4;
 var $early={};
 try {
 result=""._writeStream();
@@ -1134,18 +1152,21 @@ $2=_st(_st(self["@stream"])._peek()).__eq("!");
 if(smalltalk.assert($2)){
 _st(self["@stream"])._next();
 } else {
-$3=_st(_st(result)._contents())._trimBoth();
+self["@last"]=_st(_st(result)._contents())._trimBoth();
+$3=self["@last"];
 throw $early=[$3];
 };
 };
 return _st(result)._nextPut_(char);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
-return nil;
+self["@last"]=nil;
+$4=self["@last"];
+return $4;
 }
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"nextChunk",{char:char,result:result,chunk:chunk},smalltalk.ChunkParser)})},
 args: [],
-source: "nextChunk\x0a\x09\x22The chunk format (Smalltalk Interchange Format or Fileout format)\x0a\x09is a trivial format but can be a bit tricky to understand:\x0a\x09\x09- Uses the exclamation mark as delimiter of chunks.\x0a\x09\x09- Inside a chunk a normal exclamation mark must be doubled.\x0a\x09\x09- A non empty chunk must be a valid Smalltalk expression.\x0a\x09\x09- A chunk on top level with a preceding empty chunk is an instruction chunk:\x0a\x09\x09\x09- The object created by the expression then takes over reading chunks.\x0a\x0a\x09This method returns next chunk as a String (trimmed), empty String (all whitespace) or nil.\x22\x0a\x0a\x09| char result chunk |\x0a\x09result := '' writeStream.\x0a\x09\x09[ char := stream next.\x0a\x09\x09char notNil ] whileTrue: [\x0a\x09\x09\x09\x09char = '!' ifTrue: [\x0a\x09\x09\x09\x09\x09\x09stream peek = '!'\x0a\x09\x09\x09\x09\x09\x09\x09\x09ifTrue: [ stream next \x22skipping the escape double\x22 ]\x0a\x09\x09\x09\x09\x09\x09\x09\x09ifFalse: [ ^ result contents trimBoth \x22chunk end marker found\x22 ]].\x0a\x09\x09\x09\x09result nextPut: char ].\x0a\x09^ nil \x22a chunk needs to end with !\x22",
+source: "nextChunk\x0a\x09\x22The chunk format (Smalltalk Interchange Format or Fileout format)\x0a\x09is a trivial format but can be a bit tricky to understand:\x0a\x09\x09- Uses the exclamation mark as delimiter of chunks.\x0a\x09\x09- Inside a chunk a normal exclamation mark must be doubled.\x0a\x09\x09- A non empty chunk must be a valid Smalltalk expression.\x0a\x09\x09- A chunk on top level with a preceding empty chunk is an instruction chunk:\x0a\x09\x09\x09- The object created by the expression then takes over reading chunks.\x0a\x0a\x09This method returns next chunk as a String (trimmed), empty String (all whitespace) or nil.\x22\x0a\x0a\x09| char result chunk |\x0a\x09result := '' writeStream.\x0a\x09\x09[ char := stream next.\x0a\x09\x09char notNil ] whileTrue: [\x0a\x09\x09\x09\x09char = '!' ifTrue: [\x0a\x09\x09\x09\x09\x09\x09stream peek = '!'\x0a\x09\x09\x09\x09\x09\x09\x09\x09ifTrue: [ stream next \x22skipping the escape double\x22 ]\x0a\x09\x09\x09\x09\x09\x09\x09\x09ifFalse: [ ^ last := result contents trimBoth \x22chunk end marker found\x22 ]].\x0a\x09\x09\x09\x09result nextPut: char ].\x0a\x09^ last := nil \x22a chunk needs to end with !\x22",
 messageSends: ["writeStream", "whileTrue:", "next", "notNil", "ifTrue:", "=", "ifTrue:ifFalse:", "peek", "trimBoth", "contents", "nextPut:"],
 referencedClasses: []
 }),
@@ -1304,7 +1325,7 @@ referencedClasses: []
 smalltalk.ExportMethodProtocol.klass);
 
 
-smalltalk.addClass('Importer', smalltalk.Object, [], 'Kernel-ImportExport');
+smalltalk.addClass('Importer', smalltalk.Object, ['lastSection', 'lastChunk'], 'Kernel-ImportExport');
 smalltalk.Importer.comment="I can import Amber code from a string in the chunk format.\x0a\x0a## API\x0a\x0a    Importer new import: aString";
 smalltalk.addMethod(
 smalltalk.method({
@@ -1315,22 +1336,29 @@ var self=this;
 var chunk,result,parser,lastEmpty;
 function $ChunkParser(){return smalltalk.ChunkParser||(typeof ChunkParser=="undefined"?nil:ChunkParser)}
 function $Compiler(){return smalltalk.Compiler||(typeof Compiler=="undefined"?nil:Compiler)}
+function $Error(){return smalltalk.Error||(typeof Error=="undefined"?nil:Error)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
 parser=_st($ChunkParser())._on_(aStream);
 lastEmpty=false;
+self["@lastSection"]="n/a, not started";
+self["@lastChunk"]=nil;
 _st((function(){
 return smalltalk.withContext(function($ctx2) {
+_st((function(){
+return smalltalk.withContext(function($ctx3) {
 chunk=_st(parser)._nextChunk();
 chunk;
 return _st(chunk)._isNil();
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._whileFalse_((function(){
-return smalltalk.withContext(function($ctx2) {
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)})}))._whileFalse_((function(){
+return smalltalk.withContext(function($ctx3) {
 $1=_st(chunk)._isEmpty();
 if(smalltalk.assert($1)){
 lastEmpty=true;
 return lastEmpty;
 } else {
+self["@lastSection"]=chunk;
+self["@lastSection"];
 result=_st(_st($Compiler())._new())._evaluateExpression_(chunk);
 result;
 $2=lastEmpty;
@@ -1340,12 +1368,56 @@ lastEmpty;
 return _st(result)._scanFrom_(parser);
 };
 };
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)})}));
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)})}));
+self["@lastSection"]="n/a, finished";
+return self["@lastSection"];
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)})}))._on_do_($Error(),(function(e){
+return smalltalk.withContext(function($ctx2) {
+self["@lastChunk"]=_st(parser)._last();
+self["@lastChunk"];
+return _st(e)._signal();
+}, function($ctx2) {$ctx2.fillBlock({e:e},$ctx1,7)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"import:",{aStream:aStream,chunk:chunk,result:result,parser:parser,lastEmpty:lastEmpty},smalltalk.Importer)})},
 args: ["aStream"],
-source: "import: aStream\x0a\x09| chunk result parser lastEmpty |\x0a\x09parser := ChunkParser on: aStream.\x0a\x09lastEmpty := false.\x0a\x09[ chunk := parser nextChunk.\x0a\x09chunk isNil ] whileFalse: [\x0a\x09\x09chunk isEmpty\x0a\x09\x09\x09ifTrue: [ lastEmpty := true ]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09result := Compiler new evaluateExpression: chunk.\x0a\x09\x09\x09\x09lastEmpty\x0a\x09\x09\x09\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09lastEmpty := false.\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09result scanFrom: parser ]] ]",
-messageSends: ["on:", "whileFalse:", "nextChunk", "isNil", "ifTrue:ifFalse:", "isEmpty", "evaluateExpression:", "new", "ifTrue:", "scanFrom:"],
-referencedClasses: ["ChunkParser", "Compiler"]
+source: "import: aStream\x0a\x09| chunk result parser lastEmpty |\x0a\x09parser := ChunkParser on: aStream.\x0a\x09lastEmpty := false.\x0a\x09lastSection := 'n/a, not started'.\x0a\x09lastChunk := nil.\x0a\x09[\x0a\x09[ chunk := parser nextChunk.\x0a\x09chunk isNil ] whileFalse: [\x0a\x09\x09chunk isEmpty\x0a\x09\x09\x09ifTrue: [ lastEmpty := true ]\x0a\x09\x09\x09ifFalse: [\x0a\x09\x09\x09\x09lastSection := chunk.\x0a\x09\x09\x09\x09result := Compiler new evaluateExpression: chunk.\x0a\x09\x09\x09\x09lastEmpty\x0a\x09\x09\x09\x09\x09\x09ifTrue: [\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09lastEmpty := false.\x0a\x09\x09\x09\x09\x09\x09\x09\x09\x09result scanFrom: parser ]] ].\x0a\x09lastSection := 'n/a, finished'\x0a\x09] on: Error do: [:e | lastChunk := parser last. e signal ].",
+messageSends: ["on:", "on:do:", "whileFalse:", "nextChunk", "isNil", "ifTrue:ifFalse:", "isEmpty", "evaluateExpression:", "new", "ifTrue:", "scanFrom:", "last", "signal"],
+referencedClasses: ["ChunkParser", "Compiler", "Error"]
+}),
+smalltalk.Importer);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "lastChunk",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@lastChunk"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"lastChunk",{},smalltalk.Importer)})},
+args: [],
+source: "lastChunk\x0a\x09^ lastChunk",
+messageSends: [],
+referencedClasses: []
+}),
+smalltalk.Importer);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "lastSection",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=self["@lastSection"];
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"lastSection",{},smalltalk.Importer)})},
+args: [],
+source: "lastSection\x0a\x09^ lastSection",
+messageSends: [],
+referencedClasses: []
 }),
 smalltalk.Importer);
 

+ 25 - 5
st/Kernel-ImportExport.st

@@ -404,7 +404,7 @@ amdNamespaceOfPackage: aPackage
 ! !
 
 Object subclass: #ChunkParser
-	instanceVariableNames: 'stream'
+	instanceVariableNames: 'stream last'
 	package: 'Kernel-ImportExport'!
 !ChunkParser commentStamp!
 I am responsible for parsing aStream contents in the chunk format.
@@ -417,6 +417,10 @@ I am responsible for parsing aStream contents in the chunk format.
 
 !ChunkParser methodsFor: 'accessing'!
 
+last
+	^ last
+!
+
 stream: aStream
 	stream := aStream
 ! !
@@ -441,9 +445,9 @@ nextChunk
 				char = '!!' ifTrue: [
 						stream peek = '!!'
 								ifTrue: [ stream next "skipping the escape double" ]
-								ifFalse: [ ^ result contents trimBoth "chunk end marker found" ]].
+								ifFalse: [ ^ last := result contents trimBoth "chunk end marker found" ]].
 				result nextPut: char ].
-	^ nil "a chunk needs to end with !!"
+	^ last := nil "a chunk needs to end with !!"
 ! !
 
 !ChunkParser class methodsFor: 'instance creation'!
@@ -494,7 +498,7 @@ name: aString theClass: aClass
 ! !
 
 Object subclass: #Importer
-	instanceVariableNames: ''
+	instanceVariableNames: 'lastSection lastChunk'
 	package: 'Kernel-ImportExport'!
 !Importer commentStamp!
 I can import Amber code from a string in the chunk format.
@@ -503,22 +507,38 @@ I can import Amber code from a string in the chunk format.
 
     Importer new import: aString!
 
+!Importer methodsFor: 'accessing'!
+
+lastChunk
+	^ lastChunk
+!
+
+lastSection
+	^ lastSection
+! !
+
 !Importer methodsFor: 'fileIn'!
 
 import: aStream
 	| chunk result parser lastEmpty |
 	parser := ChunkParser on: aStream.
 	lastEmpty := false.
+	lastSection := 'n/a, not started'.
+	lastChunk := nil.
+	[
 	[ chunk := parser nextChunk.
 	chunk isNil ] whileFalse: [
 		chunk isEmpty
 			ifTrue: [ lastEmpty := true ]
 			ifFalse: [
+				lastSection := chunk.
 				result := Compiler new evaluateExpression: chunk.
 				lastEmpty
 						ifTrue: [
 									lastEmpty := false.
-									result scanFrom: parser ]] ]
+									result scanFrom: parser ]] ].
+	lastSection := 'n/a, finished'
+	] on: Error do: [:e | lastChunk := parser last. e signal ].
 ! !
 
 InterfacingObject subclass: #PackageHandler