Skip to content

Commit 5f33200

Browse files
A little more work on generic functions
--HG-- branch : com.mozilla.es4.smlnj extra : convert_revision : 614977bdd5bfd65375a0994cd5734d96808ed898
1 parent 06f91f7 commit 5f33200

File tree

4 files changed

+291
-255
lines changed

4 files changed

+291
-255
lines changed

builtins/GenericFunction.es

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -64,24 +64,25 @@
6464
6565
The translator will see a generic function definition like this:
6666
67-
generic function f(a, b, ...rest);
67+
generic function f(a:int, b, c=10, ...rest);
6868
6969
and will turn it into something like this:
7070
71-
var f = new GenericFunction(2, true);
71+
var f = new GenericFunction([int,AnyType,AnyType], [,,10], true);
7272
7373
Then methods scattered throughout the program, like these:
7474
75-
generic function f(a: int, b: boolean, ...rest) {
75+
generic function f(a: int, b: boolean, c: Numeric, ...rest) {
7676
return a+b
7777
}
7878
7979
are turned into calls to addMethod:
8080
81-
f.addMethod([int, boolean], function (nextMethod, a:int, b:boolean, ...rest) { return a+b })
81+
f.addMethod([int, boolean, Numeric],
82+
function (nextMethod, a:int, b:boolean, c:Numeric, ...rest) { return a+b })
8283
83-
Generally very few errors are signalled when a method is added,
84-
most of the interesting work happens when f is called.
84+
Generally few errors are signalled when a method is added, most of
85+
the interesting work happens when f is called.
8586
8687
Note that the translator must translate the annotations '*' into
8788
AnyType, 'null' into NullType, and 'undefined' into UndefinedType.
@@ -122,7 +123,12 @@
122123
if any, followed by the list of implemented interfaces in order,
123124
if any. This seems reasonable but there may or may not be a
124125
more reasonable approach for ECMAScript, as that is modelled on
125-
a multiple-inheritance language.
126+
a multiple-inheritance language. MultiJava may offer insight.
127+
128+
(7) GenericFunction subclasses Object instead of Function because the
129+
meta invoke() method of the latter is final. I don't know why
130+
it should be, really; it would be reasonable for GenericFunction
131+
to subclass Function.
126132
*/
127133

128134
package
@@ -135,32 +141,54 @@ package
135141

136142
public class GenericFunction extends Object
137143
{
138-
function GenericFunction(required: uint, more: boolean)
139-
: required = required
144+
function GenericFunction(constraints:Array, defaults:Array, more: boolean)
145+
: required = constraints.length
146+
, constraints = constraints
147+
, defaults = defaults
140148
, more = more
141149
{
142150
}
143151

144152
public function addMethod(specializers: Array, body: function()) {
145153
if (specializers.length != required)
146154
throw "Generic function requires exactly " + required + " specializers";
155+
156+
for ( let i=0, limit=specializers.length ; i < limit ; i++ )
157+
if (!isSubtype(specializers[i], constraints[i]))
158+
throw "Specializer fails subtype check";
159+
160+
for ( let i=0, limit=methods.length ; i < limit ; i++ ) {
161+
let thesame = true;
162+
let m_specializers = methods[i].specializers;
163+
for ( let j=0, limit=specializers.length ; thesame && j < limit ; j++ )
164+
if (specializers[j] !== m_specializers[j])
165+
thesame = false;
166+
if (thesame)
167+
throw "Generic method redefinition is not allowed.";
168+
}
169+
147170
methods.push({specializers: specializers, body: body});
148171
}
149172

150173
meta final function invoke(...args) {
151-
checkCongruence(args.length);
174+
checkCongruence(args);
152175

153176
let types = computeManifestTypes(args);
154177
let [applicable, uncomparable] = sortMethods(selectApplicableMethods(methods, types), types);
155178

156179
return callMethodsInOrder(applicable, args);
157180
}
158181

159-
function checkCongruence(nactuals) {
160-
if (nactuals < required)
161-
throw new TypeError("Not enough arguments to generic function");
182+
function checkCongruence(args) {
183+
let nactuals = args.length;
162184
if (nactuals > required && !more)
163185
throw new TypeError("Too many arguments to generic function");
186+
if (nactuals < required) {
187+
if (defaults == null || !defaults.hasOwnProperty(nactuals))
188+
throw new TypeError("Not enough arguments to generic function");
189+
for ( let i=nactuals ; i < required ; i++ )
190+
args[i] = defaults[i];
191+
}
164192
}
165193

166194
function computeManifestTypes(args) {
@@ -267,6 +295,8 @@ package
267295
}
268296

269297
var required;
298+
var defaults;
299+
var constraints;
270300
var more;
271301
const methods = new Array;
272302
}
@@ -383,7 +413,7 @@ package
383413
* System hooks -- a sketch for meta-objects functionality.
384414
*/
385415

386-
function typeOf(v) {
416+
public function typeOf(v) {
387417
switch type (v) {
388418
case (v:undefined) { return UndefinedType }
389419
case (v:null) { return NullType }
@@ -480,6 +510,7 @@ package
480510
if (x == int) return "int";
481511
if (x == double) return "double";
482512
if (x == AnyType) return "*";
513+
if (x == Number) return "Number";
483514
return "???";
484515
}
485516

native.sml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ fun getClassOfObject (regs:Mach.REGS)
271271
val Mach.Obj { magic, tag, ... } = nthAsObj vals 0
272272
val globalScope = Eval.getGlobalScope ()
273273
in
274+
(* This is wrong, because eg "Number" is classified as "Double" because it
275+
* stores a double value magically.
274276
case !magic of
275277
SOME (Mach.Function _) => Eval.findVal globalScope Name.nons_Function
276278
| SOME (Mach.NativeFunction _) => Eval.findVal globalScope Name.nons_Function
@@ -287,6 +289,13 @@ fun getClassOfObject (regs:Mach.REGS)
287289
| Mach.FunctionTag _ => Eval.findVal globalScope Name.nons_Function
288290
| Mach.ClassTag name => Eval.findVal globalScope name
289291
| Mach.NoTag => Eval.findVal globalScope Name.nons_Object)
292+
*)
293+
case tag of
294+
Mach.ObjectTag _ => Eval.findVal globalScope Name.nons_Object
295+
| Mach.ArrayTag _ => Eval.findVal globalScope Name.nons_Array
296+
| Mach.FunctionTag _ => Eval.findVal globalScope Name.nons_Function
297+
| Mach.ClassTag name => Eval.findVal globalScope name
298+
| Mach.NoTag => Eval.findVal globalScope Name.nons_Object
290299
end
291300

292301

0 commit comments

Comments
 (0)