working to adapt the primitives

This commit is contained in:
Danny Yoo 2011-06-15 17:54:39 -04:00
parent 6b8a3f30ea
commit da95994360
3 changed files with 685 additions and 553 deletions

View File

@ -0,0 +1,47 @@
#lang racket/base
(require racket/runtime-path
racket/file
racket/contract
racket/list)
;; Get the list of primitives implemented in js-vm-primitives.js
(define-runtime-path js-vm-primitives.js "runtime-src/js-vm-primitives.js")
(define-runtime-path whalesong-primitives.js "runtime-src/primitives.js")
;; sort&unique: (listof string) -> (listof string)
(define (sort&unique names)
(let ([ht (make-hash)])
(for ([name names])
(hash-set! ht name #t))
(sort (for/list ([name (in-hash-keys ht)])
name)
string<?)))
;; primitive-names: (listof symbol)
(define js-vm-primitive-names
(map string->symbol
(sort&unique
(map (lambda (a-str)
(substring a-str
(string-length "PRIMITIVES['")
(- (string-length a-str) (string-length "']"))))
(let ([contents (file->string js-vm-primitives.js)])
(regexp-match* #px"PRIMITIVES\\[('|\")[^\\]]*('|\")\\]" contents))))))
(define whalesong-primitive-names
(map string->symbol
(sort&unique
(map (lambda (a-str)
(let ([match (regexp-match
#px"installPrimitiveProcedure\\(\\s+('|\")([^\\]]*)('|\")" a-str)])
(third match)))
(let ([contents (file->string whalesong-primitives.js)])
(regexp-match* #px"installPrimitiveProcedure\\(\\s+('|\")[^\\']*('|\")" contents))))))
(provide/contract [js-vm-primitive-names (listof symbol?)]
[whalesong-primitive-names (listof symbol?)])

View File

@ -1,9 +1,7 @@
if(this['plt'] === undefined) { this['plt'] = {}; }
// All of the values here are namespaced under "plt.runtime".
(function(scope) {
var runtime = {};
scope['runtime'] = runtime;
@ -19,10 +17,6 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
};
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// We try to isolate the effect of external modules: all the identifiers we
@ -33,6 +27,9 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
var isPair = types.isPair;
var isList = types.isList;
var isVector = types.isVector;
var isEqual = types.isEqual;
var NULL = types.EMPTY;
var VOID = types.VOID;
@ -542,8 +539,11 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
};
installPrimitiveConstant('pi', jsnums.pi);
installPrimitiveConstant('e', jsnums.e);
installPrimitiveConstant('null', NULL);
installPrimitiveProcedure(
'display', makeList(1, 2),
@ -638,7 +638,10 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
// TODO: use installPrimitiveProcedure for the rest...
Primitives['<'] = function(MACHINE) {
installPrimitiveProcedure(
'<',
new ArityAtLeast(2),
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
testArgument(MACHINE,
'number', isNumber, firstArg, 0, '<');
@ -655,11 +658,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
}
return true;
};
Primitives['<'].arity = new ArityAtLeast(2);
Primitives['<'].displayName = '<';
});
Primitives['>'] = function(MACHINE) {
installPrimitiveProcedure(
'>',
new ArityAtLeast(2),
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
testArgument(MACHINE,
'number', isNumber, firstArg, 0, '>');
@ -676,11 +681,12 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
}
return true;
};
Primitives['>'].arity = new ArityAtLeast(2);
Primitives['>'].displayName = '>';
});
Primitives['<='] = function(MACHINE) {
installPrimitiveProcedure(
'<=',
new ArityAtLeast(2),
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
testArgument(MACHINE,
'number', isNumber, firstArg, 0, '<=');
@ -697,12 +703,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
}
return true;
};
Primitives['<='].arity = new ArityAtLeast(2);
Primitives['<='].displayName = '<=';
});
Primitives['>='] = function(MACHINE) {
installPrimitiveProcedure(
'>=',
new ArityAtLeast(2),
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
testArgument(MACHINE,
'number', isNumber, firstArg, 0, '>=');
@ -719,12 +726,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
}
return true;
};
Primitives['>='].arity = new ArityAtLeast(2);
Primitives['>='].displayName = '>=';
});
Primitives['+'] = function(MACHINE) {
installPrimitiveProcedure(
'+',
new ArityAtLeast(0),
function(MACHINE) {
var result = 0;
var i = 0;
for (i=0; i < MACHINE.argcount; i++) {
@ -737,12 +745,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
result = jsnums.add(result, MACHINE.env[MACHINE.env.length - 1 - i]);
};
return result;
};
Primitives['+'].arity = new ArityAtLeast(0);
Primitives['+'].displayName = '+';
});
Primitives['*'] = function(MACHINE) {
installPrimitiveProcedure(
'*',
new ArityAtLeast(0),
function(MACHINE) {
var result = 1;
var i = 0;
for (i=0; i < MACHINE.argcount; i++) {
@ -755,11 +764,12 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
result = jsnums.multiply(result, MACHINE.env[MACHINE.env.length - 1 - i]);
}
return result;
};
Primitives['*'].arity = new ArityAtLeast(0);
Primitives['*'].displayName = '*';
});
Primitives['-'] = function(MACHINE) {
installPrimitiveProcedure(
'-',
new ArityAtLeast(1),
function(MACHINE) {
if (MACHINE.argcount === 1) {
testArgument(MACHINE,
'number',
@ -780,11 +790,12 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
result = jsnums.subtract(result, MACHINE.env[MACHINE.env.length - 1 - i]);
}
return result;
};
Primitives['-'].arity = new ArityAtLeast(1);
Primitives['-'].displayName = '-';
});
Primitives['/'] = function(MACHINE) {
installPrimitiveProcedure(
'/',
new ArityAtLeast(1),
function(MACHINE) {
testArgument(MACHINE,
'number',
isNumber,
@ -802,13 +813,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
result = jsnums.divide(result, MACHINE.env[MACHINE.env.length - 1 - i]);
}
return result;
};
Primitives['/'].arity = new ArityAtLeast(1);
Primitives['/'].displayName = '/';
});
Primitives['add1'] = function(MACHINE) {
installPrimitiveProcedure(
'add1',
1,
function(MACHINE) {
testArgument(MACHINE,
'number',
isNumber,
@ -817,11 +828,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
'add1');
var firstArg = MACHINE.env[MACHINE.env.length-1];
return jsnums.add(firstArg, 1);
};
Primitives['add1'].arity = 1;
Primitives['add1'].displayName = 'add1';
});
Primitives['sub1'] = function(MACHINE) {
installPrimitiveProcedure(
'sub1',
1,
function(MACHINE) {
testArgument(MACHINE,
'number',
isNumber,
@ -830,45 +843,44 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
'sub1');
var firstArg = MACHINE.env[MACHINE.env.length-1];
return jsnums.subtract(firstArg, 1);
};
Primitives['sub1'].arity = 1;
Primitives['sub1'].displayName = 'sub1';
});
Primitives['zero?'] = function(MACHINE) {
installPrimitiveProcedure(
'zero?',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return jsnums.equals(firstArg, 0);
};
Primitives['zero?'].arity = 1;
Primitives['zero?'].displayName = 'zero?';
});
Primitives['cons'] = function(MACHINE) {
installPrimitiveProcedure(
'cons',
2,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2];
return makePair(firstArg, secondArg);
};
Primitives['cons'].arity = 2;
Primitives['cons'].displayName = 'cons';
});
Primitives['list'] = function(MACHINE) {
installPrimitiveProcedure(
'list',
new ArityAtLeast(0),
function(MACHINE) {
var result = NULL;
for (var i = 0; i < MACHINE.argcount; i++) {
result = makePair(MACHINE.env[MACHINE.env.length - (MACHINE.argcount - i)],
result);
}
return result;
};
Primitives['list'].arity = new ArityAtLeast(0);
Primitives['list'].displayName = 'list';
});
Primitives['car'] = function(MACHINE) {
installPrimitiveProcedure(
'car',
1,
function(MACHINE) {
testArgument(MACHINE,
'pair',
isPair,
@ -877,11 +889,12 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
'car');
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg.first;
};
Primitives['car'].arity = 1;
Primitives['car'].displayName = 'car';
});
Primitives['cdr'] = function(MACHINE) {
installPrimitiveProcedure(
'cdr',
1,
function(MACHINE) {
testArgument(MACHINE,
'pair',
isPair,
@ -890,18 +903,20 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
'cdr');
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg.rest;
};
Primitives['cdr'].arity = 1;
Primitives['cdr'].displayName = 'cdr';
});
Primitives['pair?'] = function(MACHINE) {
installPrimitiveProcedure(
'pair?',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return isPair(firstArg);
};
Primitives['pair?'].arity = 1;
Primitives['pair?'].displayName = 'pair?';
});
Primitives['set-car!'] = function(MACHINE) {
installPrimitiveProcedure(
'set-car!',
2,
function(MACHINE) {
testArgument(MACHINE,
'pair',
isPair,
@ -912,11 +927,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg.first = secondArg;
return VOID;
};
Primitives['set-car!'].arity = 2;
Primitives['set-car!'].displayName = 'set-car!';
});
Primitives['set-cdr!'] = function(MACHINE) {
installPrimitiveProcedure(
'set-cdr!',
2,
function(MACHINE) {
testArgument(MACHINE,
'pair',
isPair,
@ -927,27 +944,31 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg.rest = secondArg;
return VOID;
};
Primitives['set-cdr!'].arity = 2;
Primitives['set-cdr!'].displayName = 'set-cdr!';
});
Primitives['not'] = function(MACHINE) {
installPrimitiveProcedure(
'not',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return (firstArg === false);
};
Primitives['not'].arity = 1;
Primitives['not'].displayName = 'not';
});
Primitives['null'] = NULL;
Primitives['null?'] = function(MACHINE) {
installPrimitiveProcedure(
'null?',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg === NULL;
};
Primitives['null?'].arity = 1;
Primitives['null?'].displayName = 'null?';
});
Primitives['vector'] = function(MACHINE) {
installPrimitiveProcedure(
'vector',
new ArityAtLeast(0),
function(MACHINE) {
var i;
var result = [];
for (i = 0; i < MACHINE.argcount; i++) {
@ -955,11 +976,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
var newVector = makeVector.apply(null, result);
return newVector;
};
Primitives['vector'].arity = new ArityAtLeast(0);
Primitives['vector'].displayName = 'vector';
});
Primitives['vector->list'] = function(MACHINE) {
installPrimitiveProcedure(
'vector->list',
1,
function(MACHINE) {
testArgument(MACHINE,
'vector',
isVector,
@ -973,11 +996,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
result = makePair(elts[elts.length - 1 - i], result);
}
return result;
};
Primitives['vector->list'].arity = 1;
Primitives['vector->list'].displayName = 'vector->list';
});
Primitives['list->vector'] = function(MACHINE) {
installPrimitiveProcedure(
'list->vector',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var result = [];
while (firstArg !== NULL) {
@ -985,11 +1010,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
firstArg = firstArg.rest;
}
return makeVector.apply(null, result);
};
Primitives['list->vector'].arity = 1;
Primitives['list->vector'].displayName = 'list->vector';
});
Primitives['vector-ref'] = function(MACHINE) {
installPrimitiveProcedure(
'vector-ref',
2,
function(MACHINE) {
testArgument(MACHINE,
'vector',
isVector,
@ -999,11 +1026,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
var elts = MACHINE.env[MACHINE.env.length-1].elts;
var index = MACHINE.env[MACHINE.env.length-2];
return elts[index];
};
Primitives['vector-ref'].arity = 2;
Primitives['vector-ref'].displayName = 'vector-ref';
});
Primitives['vector-set!'] = function(MACHINE) {
installPrimitiveProcedure(
'vector-set!',
3,
function(MACHINE) {
testArgument(MACHINE,
'vector',
isVector,
@ -1021,12 +1050,12 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
var val = MACHINE.env[MACHINE.env.length-3];
elts[index] = val;
return VOID;
};
Primitives['vector-set!'].arity = 3;
Primitives['vector-set!'].displayName = 'vector-set!';
});
Primitives['vector-length'] = function(MACHINE) {
installPrimitiveProcedure(
'vector-length',
1,
function(MACHINE) {
testArgument(MACHINE,
'vector',
isVector,
@ -1035,12 +1064,13 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
'vector-length');
var firstArg = MACHINE.env[MACHINE.env.length-1].elts;
return firstArg.length;
};
Primitives['vector-length'].arity = 1;
Primitives['vector-length'].displayName = 'vector-length';
});
Primitives['make-vector'] = function(MACHINE) {
installPrimitiveProcedure(
'make-vector',
makeList(1, 2),
function(MACHINE) {
var value = 0;
testArgument(MACHINE,
'natural',
@ -1057,97 +1087,104 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
arr[i] = value;
}
return makeVector.apply(null, arr);
};
Primitives['make-vector'].arity = makeList(1, 2);
Primitives['make-vector'].displayName = 'make-vector';
});
Primitives['symbol?'] = function(MACHINE) {
installPrimitiveProcedure(
'symbol?',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return typeof(firstArg) === 'string';
};
Primitives['symbol?'].arity = 1;
Primitives['symbol?'].displayName = 'symbol?';
});
Primitives['symbol->string'] = function(MACHINE) {
installPrimitiveProcedure(
'symbol->string',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg;
};
Primitives['symbol->string'].arity = 1;
Primitives['symbol->string'].displayName = 'symbol->string';
});
Primitives['string-append'] = function(MACHINE) {
installPrimitiveProcedure(
'string-append',
new ArityAtLeast(0),
function(MACHINE) {
var buffer = [];
var i;
for (i = 0; i < MACHINE.argcount; i++) {
buffer.push(MACHINE.env[MACHINE.env.length - 1 - i]);
}
return buffer.join('');
};
Primitives['string-append'].arity = new ArityAtLeast(0);
Primitives['string-append'].displayName = 'string-append';
});
Primitives['string-length'] = function(MACHINE) {
installPrimitiveProcedure(
'string-length',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg.length;
};
Primitives['string-length'].arity = 1;
Primitives['string-length'].displayName = 'string-length';
});
Primitives['box'] = function(MACHINE) {
installPrimitiveProcedure(
'box',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var result = [firstArg];
return result;
};
Primitives['box'].arity = 1;
Primitives['box'].displayName = 'box';
});
Primitives['unbox'] = function(MACHINE) {
installPrimitiveProcedure(
'unbox',
1,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
return firstArg[0];
};
Primitives['unbox'].arity = 1;
Primitives['unbox'].displayName = 'unbox';
});
Primitives['set-box!'] = function(MACHINE) {
installPrimitiveProcedure(
'set-box!',
2,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2];
firstArg[0] = secondArg;
return VOID;
};
Primitives['set-box!'].arity = 2;
Primitives['set-box!'].displayName = 'set-box!';
});
Primitives['void'] = function(MACHINE) {
installPrimitiveProcedure(
'void',
new ArityAtLeast(0),
function(MACHINE) {
return VOID;
};
Primitives['void'].arity = new ArityAtLeast(0);
Primitives['void'].displayName = 'void';
});
Primitives['eq?'] = function(MACHINE) {
installPrimitiveProcedure(
'eq?',
2,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2];
return firstArg === secondArg;
};
Primitives['eq?'].arity = 2;
Primitives['eq?'].displayName = 'eq?';
});
Primitives['equal?'] = function(MACHINE) {
installPrimitiveProcedure(
'equal?',
2,
function(MACHINE) {
var firstArg = MACHINE.env[MACHINE.env.length-1];
var secondArg = MACHINE.env[MACHINE.env.length-2];
return isEqual(firstArg, secondArg);
};
Primitives['equal?'].arity = 2;
Primitives['equal?'].displayName = 'equal?';
});
var isEqual = types.isEqual;
Primitives['member'] = function(MACHINE) {
installPrimitiveProcedure(
'member',
2,
function(MACHINE) {
var x = MACHINE.env[MACHINE.env.length-1];
var lst = MACHINE.env[MACHINE.env.length-2];
var originalLst = lst;
@ -1165,13 +1202,14 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
}
lst = lst.rest;
}
};
Primitives['member'].arity = 2;
Primitives['member'].displayName = 'member';
});
Primitives['reverse'] = function(MACHINE) {
installPrimitiveProcedure(
'reverse',
1,
function(MACHINE) {
var rev = NULL;
var lst = MACHINE.env[MACHINE.env.length-1];
while(lst !== NULL) {
@ -1181,9 +1219,7 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
lst = lst.rest;
}
return rev;
};
Primitives['reverse'].arity = 1;
Primitives['reverse'].displayName = 'reverse';
});
@ -1474,7 +1510,5 @@ if(this['plt'] === undefined) { this['plt'] = {}; }
exports['HaltError'] = HaltError;
scope.link.announceReady('runtime');
})(this['plt']);

View File

@ -4,8 +4,12 @@
planet/resolver
scribble/eval
racket/sandbox
(for-label racket/base))
(for-label racket/base)
racket/runtime-path
"../js-assembler/get-js-vm-implemented-primitives.rkt")
@(define-runtime-path whalesong-path "..")
@;; I may need an evaluator for some small examples.
@ -228,12 +232,15 @@ commands to do something interesting...)
@section{Internals}
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Skip this section if you're a regular user: this is really notes internal
to Whalesong development.
Please skip this section if you're a regular user: this is really
notes internal to Whalesong development, and is not relevant to most
people.
(This section should describe the internal details of the runtime,
including the type map from Racket values to JavaScript values. It
should also describe how to write FFI bindings.)
These are notes that describe the internal details of the
implementation, including the type map from Racket values to
JavaScript values. It should also describe how to write FFI
bindings, eventually.
@subsection{Architecture}
@ -246,15 +253,15 @@ compile that to an
intermediate language, and finally assemble JavaScript.
@verbatim|{
AST IL JS
parse-bytecode.rkt ----------> compiler.rkt --------> assembler.rkt ------->
(todo)
AST IL
parse-bytecode.rkt -----> compiler.rkt ----> assembler.rkt
}|
The IL is intended to be translated straightforwardly. We currently
have an assembler to JavaScript, as well as a simulator
in @filepath{simulator.rkt}. The simulator allows us to test the compiler in a
controlled environment.
have an assembler to JavaScript @filepath{js-assembler/assemble.rkt},
as well as a simulator in @filepath{simulator/simulator.rkt}. The
simulator allows us to test the compiler in a controlled environment.
@subsection{parser/parse-bytecode.rkt}
@ -275,7 +282,7 @@ we don't need any of the register-saving infrastructure in the
original compiler. We also need to support slightly different linkage
structures, since we want to support multiple value contexts. We're
trying to generate code that works effectively on a machine like the
one described in \url{http://plt.eecs.northwestern.edu/racket-machine/}.
one described in @url{http://plt.eecs.northwestern.edu/racket-machine/}.
The intermediate language is defined in @filepath{il-structs.rkt}, and a
@ -313,7 +320,7 @@ calls work:
@item{ The head of each basic-blocked function checks to see if we
should trampoline
(http://en.wikipedia.org/wiki/Trampoline_(computers))}
(@url{http://en.wikipedia.org/wiki/Trampoline_(computers)})}
@item{We support a limited form of computed jump by assigning an
attribute to the function corresponding to a return point. See
@ -350,11 +357,55 @@ browser for testing output.
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@section{Incomplete features}
@subsection{Incomplete features}
@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(This section should describe what needs to get done next.)
The only types that are mapped so far are
@itemlist[
@item{immutable strings}
@item{numbers}
@item{pairs}
@item{null}
@item{void}
@item{vectors}
]
We need to bring around the following types previously defined in @tt{js-vm}:
(This list will shrink as I get to the work!)
@itemlist[
@item{immutable vectors}
@item{regexp}
@item{byteRegexp}
@item{character}
@item{box}
@item{placeholder}
@item{path}
@item{bytes}
@item{immutable bytes}
@item{keywords}
@item{hash}
@item{hasheq}
@item{color}
@item{structs}
@item{struct types}
@item{exceptions}
@item{thread cells}
@item{big bang info}
@item{worldConfig}
@item{effectType}
@item{renderEffectType}
@item{readerGraph}
]
What are the list of primitives in @filepath{js-vm-primitives.js}? They are:
@(apply itemlist (map (lambda (name)
(item (symbol->string name)))
js-vm-primitive-names))
(I should catalog the bug list in GitHub, as well as the feature list,
so I have a better idea of what's needed to complete the project.)