///|
fn dict_clear(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() == 0 else {
raise StarlarkError::TypeError(
message="clear() takes no arguments (\{pos.length()} given)",
span~,
)
}
dict.val = {}
@value.Value::None
}
///|
fn dict_get(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() >= 1 && pos.length() <= 2 else {
raise StarlarkError::TypeError(
message="get() takes at least 1 and at most 2 arguments (\{pos.length()} given)",
span~,
)
}
let key = match pos[0] {
String(s) => s
_ =>
raise StarlarkError::TypeError(
message="dict key must be a string, got '\{pos[0].type_name()}'",
span~,
)
}
let default = if pos.length() >= 2 { pos[1] } else { @value.Value::None }
match dict.val.get(key) {
Some(v) => v
None => default
}
}
///|
fn dict_items(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() == 0 else {
raise StarlarkError::TypeError(
message="items() takes no arguments (\{pos.length()} given)",
span~,
)
}
let result : Array[@value.Value] = []
for k, v in dict.val {
result.push(@value.Value::Tuple([@value.Value::String(k), v]))
}
@value.Value::List(Ref::new(result))
}
///|
fn dict_keys(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() == 0 else {
raise StarlarkError::TypeError(
message="keys() takes no arguments (\{pos.length()} given)",
span~,
)
}
let result : Array[@value.Value] = []
for k, _ in dict.val {
result.push(@value.Value::String(k))
}
@value.Value::List(Ref::new(result))
}
///|
fn dict_values(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() == 0 else {
raise StarlarkError::TypeError(
message="values() takes no arguments (\{pos.length()} given)",
span~,
)
}
let result : Array[@value.Value] = []
for _, v in dict.val {
result.push(v)
}
@value.Value::List(Ref::new(result))
}
///|
fn dict_pop(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() >= 1 && pos.length() <= 2 else {
raise StarlarkError::TypeError(
message="pop() takes at least 1 and at most 2 arguments (\{pos.length()} given)",
span~,
)
}
let key = match pos[0] {
String(s) => s
_ =>
raise StarlarkError::TypeError(
message="dict key must be a string, got '\{pos[0].type_name()}'",
span~,
)
}
match dict.val.get(key) {
Some(v) => {
dict.val.remove(key)
v
}
None =>
if pos.length() >= 2 {
pos[1]
} else {
raise StarlarkError::KeyError(key~, span~)
}
}
}
///|
fn dict_popitem(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() == 0 else {
raise StarlarkError::TypeError(
message="popitem() takes no arguments (\{pos.length()} given)",
span~,
)
}
if dict.val.length() == 0 {
raise StarlarkError::KeyError(key="popitem(): dictionary is empty", span~)
}
// Get the first key-value pair
let mut first_key = ""
let mut first_val : @value.Value = @value.Value::None
for k, v in dict.val {
first_key = k
first_val = v
break
}
dict.val.remove(first_key)
@value.Value::Tuple([@value.Value::String(first_key), first_val])
}
///|
fn dict_setdefault(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
_kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() >= 1 && pos.length() <= 2 else {
raise StarlarkError::TypeError(
message="setdefault() takes at least 1 and at most 2 arguments (\{pos.length()} given)",
span~,
)
}
let key = match pos[0] {
String(s) => s
_ =>
raise StarlarkError::TypeError(
message="dict key must be a string, got '\{pos[0].type_name()}'",
span~,
)
}
let default = if pos.length() >= 2 { pos[1] } else { @value.Value::None }
match dict.val.get(key) {
Some(v) => v
None => {
dict.val.set(key, default)
default
}
}
}
///|
fn dict_update(
dict : Ref[Map[String, @value.Value]],
pos : Array[@value.Value],
kw : Map[String, @value.Value],
span : @ast.Span,
) -> @value.Value raise StarlarkError {
guard pos.length() <= 1 else {
raise StarlarkError::TypeError(
message="update() takes at most 1 positional argument (\{pos.length()} given)",
span~,
)
}
if pos.length() == 1 {
match pos[0] {
Dict(other) =>
for k, v in other.val {
dict.val.set(k, v)
}
_ => {
// Try iterable of pairs
let items = iterable_to_array(pos[0], span)
for item in items {
match item {
Tuple(pair) =>
if pair.length() == 2 {
match pair[0] {
String(k) => dict.val.set(k, pair[1])
_ =>
raise StarlarkError::TypeError(
message="dict keys must be strings",
span~,
)
}
} else {
raise StarlarkError::ValueError(
message="dictionary update sequence element has length \{pair.length()}; 2 is required",
span~,
)
}
List(pair) =>
if pair.val.length() == 2 {
match pair.val[0] {
String(k) => dict.val.set(k, pair.val[1])
_ =>
raise StarlarkError::TypeError(
message="dict keys must be strings",
span~,
)
}
} else {
raise StarlarkError::ValueError(
message="dictionary update sequence element has length \{pair.val.length()}; 2 is required",
span~,
)
}
_ =>
raise StarlarkError::TypeError(
message="cannot convert dictionary update element to a pair",
span~,
)
}
}
}
}
}
// Also apply keyword args
for k, v in kw {
dict.val.set(k, v)
}
@value.Value::None
}
///|
fn dict_methods() -> Map[
String,
(
Ref[Map[String, @value.Value]],
Array[@value.Value],
Map[String, @value.Value],
@ast.Span,
) -> @value.Value raise StarlarkError,
] {
let m : Map[
String,
(
Ref[Map[String, @value.Value]],
Array[@value.Value],
Map[String, @value.Value],
@ast.Span,
) -> @value.Value raise StarlarkError,
] = {}
m["clear"] = dict_clear
m["get"] = dict_get
m["items"] = dict_items
m["keys"] = dict_keys
m["values"] = dict_values
m["pop"] = dict_pop
m["popitem"] = dict_popitem
m["setdefault"] = dict_setdefault
m["update"] = dict_update
m
}