continuing to add
This commit is contained in:
parent
48f8acf121
commit
0ea0b05206
|
@ -27,12 +27,13 @@ if (! this['plt']) { this['plt'] = {}; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// format: string [X ...] string -> string
|
||||||
|
// String formatting.
|
||||||
var format = function(formatStr, args, functionName) {
|
var format = function(formatStr, args, functionName) {
|
||||||
var throwFormatError = function() {
|
var throwFormatError = function() {
|
||||||
functionName = functionName || '#<procedure>';
|
functionName = functionName || 'format';
|
||||||
var matches = formatStr.match(new RegExp('~[sSaA]', 'g'));
|
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
|
var errorStrBuffer = [functionName + ': format string requires ' + expectedNumberOfArgs
|
||||||
+ ' arguments, given ' + args.length + '; arguments were:',
|
+ ' arguments, given ' + args.length + '; arguments were:',
|
||||||
toWrittenString(formatStr)];
|
toWrittenString(formatStr)];
|
||||||
|
@ -40,38 +41,47 @@ if (! this['plt']) { this['plt'] = {}; }
|
||||||
errorStrBuffer.push( toWrittenString(args[i]) );
|
errorStrBuffer.push( toWrittenString(args[i]) );
|
||||||
}
|
}
|
||||||
|
|
||||||
raise( types.incompleteExn(types.exnFailContract, errorStrBuffer.join(' '), []) );
|
throw new Error(errorStrBuffer.join(' '));
|
||||||
}
|
}
|
||||||
|
|
||||||
var pattern = new RegExp("~[sSaAneE%~]", "g");
|
var pattern = new RegExp("~[sSaAnevE%~]", "g");
|
||||||
var buffer = args.slice(0);;
|
var buffer = args.slice(0);
|
||||||
function f(s) {
|
var onTemplate = function(s) {
|
||||||
if (s == "~~") {
|
if (s === "~~") {
|
||||||
return "~";
|
return "~";
|
||||||
} else if (s == '~n' || s == '~%') {
|
} else if (s === '~n' || s === '~%') {
|
||||||
return "\n";
|
return "\n";
|
||||||
} else if (s == '~s' || s == "~S") {
|
} else if (s === '~s' || s === "~S") {
|
||||||
if (buffer.length == 0) {
|
if (buffer.length === 0) {
|
||||||
throwFormatError();
|
throwFormatError();
|
||||||
}
|
}
|
||||||
return toWrittenString(buffer.shift());
|
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
|
// FIXME: we don't yet have support for the error-print
|
||||||
// handler, and currently treat ~e just like ~s.
|
// handler, and currently treat ~e just like ~s.
|
||||||
if (buffer.length == 0) {
|
if (buffer.length === 0) {
|
||||||
throwFormatError();
|
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());
|
return toWrittenString(buffer.shift());
|
||||||
} else if (s == '~a' || s == "~A") {
|
} else if (s === '~a' || s === "~A") {
|
||||||
if (buffer.length == 0) {
|
if (buffer.length === 0) {
|
||||||
throwFormatError();
|
throwFormatError();
|
||||||
}
|
}
|
||||||
return toDisplayedString(buffer.shift());
|
return toDisplayedString(buffer.shift());
|
||||||
} else {
|
} 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) {
|
if (buffer.length > 0) {
|
||||||
throwFormatError();
|
throwFormatError();
|
||||||
}
|
}
|
||||||
|
@ -79,6 +89,8 @@ if (! this['plt']) { this['plt'] = {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// forEachK: CPS( array CPS(array -> void) (error -> void) -> void )
|
// forEachK: CPS( array CPS(array -> void) (error -> void) -> void )
|
||||||
// Iterates through an array and applies f to each element using CPS
|
// 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
|
// If an error is thrown, it catches the error and calls f_error on it
|
||||||
|
|
|
@ -113,7 +113,7 @@
|
||||||
'numBouncesBeforeYield': 2000, // self-adjusting
|
'numBouncesBeforeYield': 2000, // self-adjusting
|
||||||
'maxNumBouncesBeforeYield': 2000, // self-adjusting
|
'maxNumBouncesBeforeYield': 2000, // self-adjusting
|
||||||
|
|
||||||
'current-print': new Closure(
|
'currentPrint': new Closure(
|
||||||
function(MACHINE) {
|
function(MACHINE) {
|
||||||
if(--MACHINE.callsBeforeTrampoline<0) { throw arguments.callee; }
|
if(--MACHINE.callsBeforeTrampoline<0) { throw arguments.callee; }
|
||||||
|
|
||||||
|
@ -562,7 +562,7 @@
|
||||||
var outputPort = MACHINE.params.currentOutputPort;
|
var outputPort = MACHINE.params.currentOutputPort;
|
||||||
if (MACHINE.argcount === 2) {
|
if (MACHINE.argcount === 2) {
|
||||||
testArgument(MACHINE,
|
testArgument(MACHINE,
|
||||||
'isOutputPort',
|
'output-port',
|
||||||
isOutputPort,
|
isOutputPort,
|
||||||
MACHINE.env.length-2,
|
MACHINE.env.length-2,
|
||||||
1,
|
1,
|
||||||
|
@ -579,7 +579,7 @@
|
||||||
var outputPort = MACHINE.params.currentOutputPort;
|
var outputPort = MACHINE.params.currentOutputPort;
|
||||||
if (MACHINE.argcount === 1) {
|
if (MACHINE.argcount === 1) {
|
||||||
testArgument(MACHINE,
|
testArgument(MACHINE,
|
||||||
'isOutputPort',
|
'output-port',
|
||||||
isOutputPort,
|
isOutputPort,
|
||||||
MACHINE.env.length-1,
|
MACHINE.env.length-1,
|
||||||
1,
|
1,
|
||||||
|
@ -598,7 +598,7 @@
|
||||||
var outputPort = MACHINE.params.currentOutputPort;
|
var outputPort = MACHINE.params.currentOutputPort;
|
||||||
if (MACHINE.argcount === 2) {
|
if (MACHINE.argcount === 2) {
|
||||||
testArgument(MACHINE,
|
testArgument(MACHINE,
|
||||||
'isOutputPort',
|
'output-port',
|
||||||
isOutputPort,
|
isOutputPort,
|
||||||
MACHINE.env.length-2,
|
MACHINE.env.length-2,
|
||||||
1,
|
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(
|
installPrimitiveProcedure(
|
||||||
'current-print',
|
'current-print',
|
||||||
makeList(0, 1),
|
makeList(0, 1),
|
||||||
function(MACHINE) {
|
function(MACHINE) {
|
||||||
if (MACHINE.argcount === 1) {
|
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;
|
return VOID;
|
||||||
} else {
|
} 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(
|
installPrimitiveProcedure(
|
||||||
'=',
|
'=',
|
||||||
new ArityAtLeast(2),
|
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 trampoline = function(MACHINE, initialJump) {
|
||||||
var thunk = initialJump;
|
var thunk = initialJump;
|
||||||
var startTime = (new Date()).valueOf();
|
var startTime = (new Date()).valueOf();
|
||||||
|
@ -1947,11 +2072,23 @@
|
||||||
MACHINE.params.maxNumBouncesBeforeYield;
|
MACHINE.params.maxNumBouncesBeforeYield;
|
||||||
MACHINE.running = true;
|
MACHINE.running = true;
|
||||||
|
|
||||||
while(thunk) {
|
while(true) {
|
||||||
try {
|
try {
|
||||||
thunk(MACHINE);
|
thunk(MACHINE);
|
||||||
break;
|
break;
|
||||||
} catch (e) {
|
} 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') {
|
if (typeof(e) === 'function') {
|
||||||
thunk = e;
|
thunk = e;
|
||||||
MACHINE.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;
|
MACHINE.callsBeforeTrampoline = STACK_LIMIT_ESTIMATE;
|
||||||
|
@ -1961,24 +2098,36 @@
|
||||||
MACHINE,
|
MACHINE,
|
||||||
(new Date()).valueOf() - startTime);
|
(new Date()).valueOf() - startTime);
|
||||||
setTimeout(
|
setTimeout(
|
||||||
function() {
|
function() { trampoline(MACHINE, thunk); },
|
||||||
trampoline(MACHINE, thunk);
|
|
||||||
},
|
|
||||||
0);
|
0);
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
} else if (e instanceof HaltError) {
|
} else if (e instanceof HaltError) {
|
||||||
// FIXME: work out what it really means to Halt.
|
MACHINE.running = false;
|
||||||
|
setTimeout(
|
||||||
|
function() { e.onHalt(MACHINE); },
|
||||||
|
0);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
MACHINE.running = false;
|
MACHINE.running = false;
|
||||||
return MACHINE.params.currentErrorHandler(MACHINE, e);
|
setTimeout(
|
||||||
|
function() { MACHINE.params.currentErrorHandler(MACHINE, e); },
|
||||||
|
0);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MACHINE.running = false;
|
MACHINE.running = false;
|
||||||
return MACHINE.params.currentSuccessHandler(MACHINE);
|
setTimeout(
|
||||||
|
function() { MACHINE.params.currentSuccessHandler(MACHINE); },
|
||||||
|
0);
|
||||||
|
return;
|
||||||
};
|
};
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -145,6 +145,8 @@
|
||||||
;; Racket's compiler can optimize these.
|
;; Racket's compiler can optimize these.
|
||||||
(provide-stub-function
|
(provide-stub-function
|
||||||
|
|
||||||
|
current-output-port
|
||||||
|
|
||||||
write
|
write
|
||||||
display
|
display
|
||||||
newline
|
newline
|
||||||
|
@ -338,8 +340,9 @@
|
||||||
;; string-copy
|
;; string-copy
|
||||||
;; string->symbol
|
;; string->symbol
|
||||||
;; symbol->string
|
;; symbol->string
|
||||||
;; format
|
format
|
||||||
;; printf
|
printf
|
||||||
|
fprintf
|
||||||
;; build-string
|
;; build-string
|
||||||
;; string->immutable-string
|
;; string->immutable-string
|
||||||
;; string-set!
|
;; string-set!
|
||||||
|
|
|
@ -623,6 +623,18 @@ EOF
|
||||||
(test '(displayln (string->number "42"))
|
(test '(displayln (string->number "42"))
|
||||||
"42\n")
|
"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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user