Map destructuring

This commit is contained in:
2020-12-07 18:52:33 -07:00
parent b28a39250d
commit 6866c7133d
3 changed files with 29 additions and 12 deletions

View File

@@ -146,7 +146,10 @@ class Helpers {
};
}
// TODO use let instead of begin to make the args immutable by default
// To make function args immutable by default, we would use (let...) instead of (begin...)
// to make the body expression.
// But setting default arguments is so common, and arguments are not settable references,
// so function args are not immutable.
return {
ret: if (name != null) switch (name.def) {
case TypedExp(type, _): Helpers.parseComplexType(type, name);

View File

@@ -91,6 +91,17 @@ class SpecialForms {
EBinop(OpAssign, k.convert(args[0]), k.convert(args[1])).withMacroPosOf(wholeExp);
};
function varName(nameExp:ReaderExp) {
return switch (nameExp.def) {
case Symbol(name) | TypedExp(_, {pos: _, def: Symbol(name)}):
name;
case KeyValueExp(_, valueNameExp):
varName(valueNameExp);
default:
throw CompileError.fromExp(nameExp, 'expected a symbol, typed symbol, or keyed symbol for variable name in a var binding');
};
}
function toVar(nameExp:ReaderExp, valueExp:ReaderExp, k:KissState, ?isFinal:Bool):Var {
// This check seems like unnecessary repetition but it's not. It allows is so that individual destructured bindings can specify mutability
return if (isFinal == null) {
@@ -101,12 +112,7 @@ class SpecialForms {
toVar(nameExp, valueExp, k, true);
};
} else {
name: switch (nameExp.def) {
case Symbol(name) | TypedExp(_, {pos: _, def: Symbol(name)}):
name;
default:
throw CompileError.fromExp(nameExp, 'expected a symbol or typed symbol for variable name in a var binding');
},
name: varName(nameExp),
type: switch (nameExp.def) {
case TypedExp(type, _):
Helpers.parseComplexType(type, nameExp);
@@ -136,10 +142,13 @@ class SpecialForms {
// Only evaluate the list expression being destructured once:
[toVar(uniqueVarSymbol, valueExp, k, true)].concat([
for (nameExp in nameExps)
toVar(nameExp,
CallExp(Symbol("nth").withPosOf(valueExp),
[uniqueVarSymbol, Symbol(Std.string(idx++)).withPosOf(valueExp)]).withPosOf(valueExp),
k, if (isFinal == false) false else null)
toVar(nameExp, switch (nameExp.def) {
case KeyValueExp(keyExp, nameExp):
CallExp(Symbol("dict-get").withPosOf(valueExp), [uniqueVarSymbol, keyExp]).withPosOf(valueExp);
default:
CallExp(Symbol("nth").withPosOf(valueExp),
[uniqueVarSymbol, Symbol(Std.string(idx++)).withPosOf(valueExp)]).withPosOf(valueExp);
}, k, if (isFinal == false) false else null)
]);
default:
throw CompileError.fromExp(namesExp, "Can only bind variables to a symbol or list of symbols for destructuring");

View File

@@ -348,4 +348,9 @@
(Assert.equals "me" (dict-get myMap "found"))
(doFor =>key value myMap
(Assert.isTrue (<= 0 (.indexOf ["hey" "found"] key)))
(Assert.isTrue (<= 0 (.indexOf ["you" "me"] value)))))
(Assert.isTrue (<= 0 (.indexOf ["you" "me"] value))))
// Map destructuring:
(let [[=>"hey" v1 =>"found" v2] myMap]
(Assert.equals "you" v1)
(Assert.equals "me" v2)))