List destructuring
This commit is contained in:
@@ -64,8 +64,7 @@ class SpecialForms {
|
|||||||
EBinop(OpAssign, convert(args[0]), convert(args[1])).withContextPos();
|
EBinop(OpAssign, convert(args[0]), convert(args[1])).withContextPos();
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO allow var bindings to destructure lists and key-value pairs
|
function toVar(nameExp:ReaderExp, valueExp:ReaderExp, isFinal:Bool, convert:ExprConversion):Var {
|
||||||
function toVar(nameExp:ReaderExp, valueExp:ReaderExp, isFinal:Bool, convert:ExprConversion) {
|
|
||||||
return {
|
return {
|
||||||
name: switch (nameExp.def) {
|
name: switch (nameExp.def) {
|
||||||
case Symbol(name) | TypedExp(_, {pos: _, def: Symbol(name)}):
|
case Symbol(name) | TypedExp(_, {pos: _, def: Symbol(name)}):
|
||||||
@@ -83,6 +82,23 @@ class SpecialForms {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toVars(namesExp:ReaderExp, valueExp:ReaderExp, isFinal:Bool, convert:ExprConversion):Array<Var> {
|
||||||
|
return switch (namesExp.def) {
|
||||||
|
case Symbol(_) | TypedExp(_, {pos: _, def: Symbol(_)}):
|
||||||
|
[toVar(namesExp, valueExp, isFinal, convert)];
|
||||||
|
case ListExp(nameExps):
|
||||||
|
var idx = 0;
|
||||||
|
[
|
||||||
|
for (nameExp in nameExps)
|
||||||
|
toVar(nameExp,
|
||||||
|
CallExp(Symbol("nth").withPosOf(valueExp), [valueExp, Symbol(Std.string(idx++)).withPosOf(valueExp)]).withPosOf(valueExp),
|
||||||
|
isFinal, convert)
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
throw CompileError.fromExp(namesExp, "Can only bind variables to a symbol or list of symbols for destructuring");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
map["deflocal"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
map["deflocal"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
||||||
wholeExp.checkNumArgs(2, 3, "(deflocal [optional :type] [variable] [optional: &mut] [value])");
|
wholeExp.checkNumArgs(2, 3, "(deflocal [optional :type] [variable] [optional: &mut] [value])");
|
||||||
var valueIndex = 1;
|
var valueIndex = 1;
|
||||||
@@ -93,7 +109,7 @@ class SpecialForms {
|
|||||||
default:
|
default:
|
||||||
true;
|
true;
|
||||||
};
|
};
|
||||||
EVars([toVar(args[0], args[valueIndex], isFinal, convert)]).withContextPos();
|
EVars(toVars(args[0], args[valueIndex], isFinal, convert)).withContextPos();
|
||||||
};
|
};
|
||||||
|
|
||||||
map["let"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
map["let"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
||||||
@@ -114,10 +130,10 @@ class SpecialForms {
|
|||||||
throw CompileError.fromExp(args[bindingListIndex], 'let bindings should be a list expression with an even number of sub expressions');
|
throw CompileError.fromExp(args[bindingListIndex], 'let bindings should be a list expression with an even number of sub expressions');
|
||||||
};
|
};
|
||||||
var bindingPairs = bindingList.groups(2);
|
var bindingPairs = bindingList.groups(2);
|
||||||
var varDefs = [
|
var varDefs = [];
|
||||||
for (bindingPair in bindingPairs)
|
for (bindingPair in bindingPairs) {
|
||||||
toVar(bindingPair[0], bindingPair[1], isFinal, convert)
|
varDefs = varDefs.concat(toVars(bindingPair[0], bindingPair[1], isFinal, convert));
|
||||||
];
|
}
|
||||||
|
|
||||||
var body = args.slice(bindingListIndex + 1);
|
var body = args.slice(bindingListIndex + 1);
|
||||||
if (body.length == 0) {
|
if (body.length == 0) {
|
||||||
@@ -151,7 +167,6 @@ class SpecialForms {
|
|||||||
}).withContextPos();
|
}).withContextPos();
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO will this return null if there are no catches? It probably should, for last-expression return semantics
|
|
||||||
map["try"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
map["try"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, convert:ExprConversion) -> {
|
||||||
wholeExp.checkNumArgs(1, null, "(try [thing] [catches...])");
|
wholeExp.checkNumArgs(1, null, "(try [thing] [catches...])");
|
||||||
var tryKissExp = args[0];
|
var tryKissExp = args[0];
|
||||||
@@ -179,7 +194,7 @@ class SpecialForms {
|
|||||||
};
|
};
|
||||||
default:
|
default:
|
||||||
throw CompileError.fromExp(catchKissExp,
|
throw CompileError.fromExp(catchKissExp,
|
||||||
'expressions following the first expression in a (try... ) should all be (catch... ) expressions');
|
'expressions following the first expression in a (try... ) should all be (catch [[error]] [body...]) expressions');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]).withContextPos();
|
]).withContextPos();
|
||||||
|
|||||||
@@ -198,4 +198,8 @@ class BasicTestCase extends Test {
|
|||||||
function testQuickNths() {
|
function testQuickNths() {
|
||||||
_testQuickNths();
|
_testQuickNths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function testListDestructuring() {
|
||||||
|
_testListDestructuring();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,4 +163,17 @@
|
|||||||
(Assert.equals 8 (eighth myListOfTen))
|
(Assert.equals 8 (eighth myListOfTen))
|
||||||
(Assert.equals 9 (ninth myListOfTen))
|
(Assert.equals 9 (ninth myListOfTen))
|
||||||
(Assert.equals 10 (tenth myListOfTen))
|
(Assert.equals 10 (tenth myListOfTen))
|
||||||
(Assert.equals 10 (last myListOfTen)))
|
(Assert.equals 10 (last myListOfTen)))
|
||||||
|
|
||||||
|
(defun _testListDestructuring []
|
||||||
|
(deflocal [a b c d e f g h i j] myListOfTen)
|
||||||
|
(Assert.equals 1 a)
|
||||||
|
(Assert.equals 2 b)
|
||||||
|
(Assert.equals 3 c)
|
||||||
|
(Assert.equals 4 d)
|
||||||
|
(Assert.equals 5 e)
|
||||||
|
(Assert.equals 6 f)
|
||||||
|
(Assert.equals 7 g)
|
||||||
|
(Assert.equals 8 h)
|
||||||
|
(Assert.equals 9 i)
|
||||||
|
(Assert.equals 10 j))
|
||||||
Reference in New Issue
Block a user