List destructuring

This commit is contained in:
2020-11-29 19:09:11 -07:00
parent 23b978740b
commit 1a06266987
3 changed files with 42 additions and 10 deletions

View File

@@ -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();

View File

@@ -198,4 +198,8 @@ class BasicTestCase extends Test {
function testQuickNths() { function testQuickNths() {
_testQuickNths(); _testQuickNths();
} }
function testListDestructuring() {
_testListDestructuring();
}
} }

View File

@@ -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))