continuing to add

This commit is contained in:
Danny Yoo 2011-06-27 16:32:58 -04:00
parent 48f8acf121
commit 0ea0b05206
4 changed files with 210 additions and 34 deletions

View File

@ -27,12 +27,13 @@ if (! this['plt']) { this['plt'] = {}; }
// format: string [X ...] string -> string
// String formatting.
var format = function(formatStr, args, functionName) {
var throwFormatError = function() {
functionName = functionName || '#<procedure>';
functionName = functionName || 'format';
var matches = formatStr.match(new RegExp('~[sSaA]', 'g'));
var expectedNumberOfArgs = matches == null ? 0 : matches.length;
var expectedNumberOfArgs = (matches === null ? 0 : matches.length);
var errorStrBuffer = [functionName + ': format string requires ' + expectedNumberOfArgs
+ ' arguments, given ' + args.length + '; arguments were:',
toWrittenString(formatStr)];
@ -40,38 +41,47 @@ if (! this['plt']) { this['plt'] = {}; }
errorStrBuffer.push( toWrittenString(args[i]) );
}
raise( types.incompleteExn(types.exnFailContract, errorStrBuffer.join(' '), []) );
throw new Error(errorStrBuffer.join(' '));
}
var pattern = new RegExp("~[sSaAneE%~]", "g");
var buffer = args.slice(0);;
function f(s) {
if (s == "~~") {
var pattern = new RegExp("~[sSaAnevE%~]", "g");
var buffer = args.slice(0);
var onTemplate = function(s) {
if (s === "~~") {
return "~";
} else if (s == '~n' || s == '~%') {
} else if (s === '~n' || s === '~%') {
return "\n";
} else if (s == '~s' || s == "~S") {
if (buffer.length == 0) {
} else if (s === '~s' || s === "~S") {
if (buffer.length === 0) {
throwFormatError();
}
return toWrittenString(buffer.shift());
} else if (s == '~e' || s == "~E") {
} else if (s === '~e' || s === "~E") {
// FIXME: we don't yet have support for the error-print
// handler, and currently treat ~e just like ~s.
if (buffer.length == 0) {
if (buffer.length === 0) {
throwFormatError();
}
return toWrittenString(buffer.shift());
}
else if (s === '~v') {
if (buffer.length === 0) {
throwFormatError();
}
// fprintf must do something more interesting here by
// printing the dom representation directly...
return toWrittenString(buffer.shift());
} else if (s == '~a' || s == "~A") {
if (buffer.length == 0) {
} else if (s === '~a' || s === "~A") {
if (buffer.length === 0) {
throwFormatError();
}
return toDisplayedString(buffer.shift());
} else {
throw types.internalError('format: string.replace matched invalid regexp', false);
throw new Error(functionName +
': string.replace matched invalid regexp');
}
}
var result = formatStr.replace(pattern, f);
var result = formatStr.replace(pattern, onTemplate);
if (buffer.length > 0) {
throwFormatError();
}
@ -79,6 +89,8 @@ if (! this['plt']) { this['plt'] = {}; }
};
// forEachK: CPS( array CPS(array -> void) (error -> void) -> void )
// Iterates through an array and applies f to each element using CPS
// If an error is thrown, it catches the error and calls f_error on it

View File

@ -113,7 +113,7 @@
'numBouncesBeforeYield': 2000, // self-adjusting
'maxNumBouncesBeforeYield': 2000, // self-adjusting
'current-print': new Closure(
'currentPrint': new Closure(
function(MACHINE) {
if(--MACHINE.callsBeforeTrampoline<0) { throw arguments.callee; }
@ -562,7 +562,7 @@
var outputPort = MACHINE.params.currentOutputPort;
if (MACHINE.argcount === 2) {
testArgument(MACHINE,
'isOutputPort',
'output-port',
isOutputPort,
MACHINE.env.length-2,
1,
@ -579,7 +579,7 @@
var outputPort = MACHINE.params.currentOutputPort;
if (MACHINE.argcount === 1) {
testArgument(MACHINE,
'isOutputPort',
'output-port',
isOutputPort,
MACHINE.env.length-1,
1,
@ -598,7 +598,7 @@
var outputPort = MACHINE.params.currentOutputPort;
if (MACHINE.argcount === 2) {
testArgument(MACHINE,
'isOutputPort',
'output-port',
isOutputPort,
MACHINE.env.length-2,
1,
@ -611,19 +611,110 @@
});
installPrimitiveProcedure(
'format',
new ArityAtLeast(1),
function(MACHINE) {
var args = [], i, formatString;
testArgument(MACHINE,
'string',
isString,
MACHINE.env[MACHINE.env.length-1],
0,
'format');
for(i = 0; i < MACHINE.argcount; i++) {
args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
}
formatString = args.shift();
return helpers.format(formatString, args, 'format');
});
installPrimitiveProcedure(
'printf',
new ArityAtLeast(1),
function(MACHINE) {
var args = [], i, formatString;
testArgument(MACHINE,
'string',
isString,
MACHINE.env[MACHINE.env.length-1],
0,
'printf');
for(i = 0; i < MACHINE.argcount; i++) {
args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
}
formatString = args.shift();
var result = helpers.format(formatString, args, 'format');
var outputPort = MACHINE.params.currentOutputPort;
outputPort.writeDomNode(MACHINE, toDomNode(result, 'display'));
return VOID;
});
installPrimitiveProcedure(
'fprintf',
new ArityAtLeast(2),
function(MACHINE) {
var args = [], i, formatString;
testArgument(MACHINE,
'output-port',
isOutputPort,
MACHINE.env[MACHINE.env.length-1],
0,
'fprintf');
testArgument(MACHINE,
'string',
isString,
MACHINE.env[MACHINE.env.length-2],
1,
'fprintf');
for(i = 1; i < MACHINE.argcount; i++) {
args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
}
formatString = args.shift();
var result = helpers.format(formatString, args, 'format');
var outputPort = MACHINE.env[MACHINE.env.length-1];
outputPort.writeDomNode(MACHINE, toDomNode(result, 'display'));
return VOID;
});
installPrimitiveProcedure(
'current-print',
makeList(0, 1),
function(MACHINE) {
if (MACHINE.argcount === 1) {
MACHINE.params['current-print'] = MACHINE.env[MACHINE.env.length - 1];
MACHINE.params['currentPrint'] = MACHINE.env[MACHINE.env.length - 1];
return VOID;
} else {
return MACHINE.params['current-print'];
return MACHINE.params['currentPrint'];
}
});
installPrimitiveProcedure(
'current-output-port',
makeList(0, 1),
function(MACHINE) {
if (MACHINE.argcount === 1) {
MACHINE.params['currentOutputPort'] = MACHINE.env[MACHINE.env.length - 1];
return VOID;
} else {
return MACHINE.params['currentOutputPort'];
}
});
installPrimitiveProcedure(
'=',
new ArityAtLeast(2),
@ -1885,6 +1976,23 @@
installPrimitiveProcedure(
'format',
new ArityAtLeast(1),
function(MACHINE) {
var args = [], i, formatString;
testArgument(MACHINE,
'string',
isString,
MACHINE.env[MACHINE.env.length-1],
0,
'format');
for(i = 0; i < MACHINE.argcount; i++) {
args.push(MACHINE.env[MACHINE.env.length - 1 - i]);
}
formatString = args.shift();
return helpers.format(formatString, args, 'format');
});
@ -1936,9 +2044,26 @@
};
var HaltError = function() {}
var HaltError = function(onHalt) {
// onHalt: MACHINE -> void
this.onHalt = onHalt || function(MACHINE) {};
};
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// The toplevel trampoline.
//
//
// trampoline: MACHINE (MACHINE -> void) -> void
//
// All evaluation in Racketland happens in the context of this
// trampoline.
//
var trampoline = function(MACHINE, initialJump) {
var thunk = initialJump;
var startTime = (new Date()).valueOf();
@ -1947,11 +2072,23 @@
MACHINE.params.maxNumBouncesBeforeYield;
MACHINE.running = true;
while(thunk) {
while(true) {
try {
thunk(MACHINE);
break;
} catch (e) {
// There are a few kinds of things that can get thrown
// during racket evaluation:
//
// functions: this gets thrown if the Racket code realizes
// that the number of bounces has grown too large. The thrown
// function represents a restarter function.
//
// HaltError: causes evaluation to immediately halt. We schedule
// the onHalt function of the HaltError to call afterwards.
//
// everything else: otherwise, we send the exception value
// to the current error handler and exit.
if (typeof(e) === 'function') {
thunk = e;
MACHINE.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;
@ -1961,24 +2098,36 @@
MACHINE,
(new Date()).valueOf() - startTime);
setTimeout(
function() {
trampoline(MACHINE, thunk);
},
function() { trampoline(MACHINE, thunk); },
0);
return;
}
} else {
continue;
}
} else if (e instanceof HaltError) {
// FIXME: work out what it really means to Halt.
MACHINE.running = false;
setTimeout(
function() { e.onHalt(MACHINE); },
0);
return;
} else {
MACHINE.running = false;
return MACHINE.params.currentErrorHandler(MACHINE, e);
setTimeout(
function() { MACHINE.params.currentErrorHandler(MACHINE, e); },
0);
return;
}
}
}
MACHINE.running = false;
return MACHINE.params.currentSuccessHandler(MACHINE);
setTimeout(
function() { MACHINE.params.currentSuccessHandler(MACHINE); },
0);
return;
};
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////

View File

@ -145,6 +145,8 @@
;; Racket's compiler can optimize these.
(provide-stub-function
current-output-port
write
display
newline
@ -338,8 +340,9 @@
;; string-copy
;; string->symbol
;; symbol->string
;; format
;; printf
format
printf
fprintf
;; build-string
;; string->immutable-string
;; string-set!

View File

@ -623,6 +623,18 @@ EOF
(test '(displayln (string->number "42"))
"42\n")
(test '(displayln (format "The number is ~a" 42))
"The number is 42\n")
(test '(printf "The number is ~a" 42)
"The number is 42")
(test '(fprintf (current-output-port) "The number is ~a" 42)
"The number is 42")