///|
priv struct StandardOverload {
name : String
receiver : CelType?
parameters : Array[CelType]
result : CelType
}
///|
fn global_overload(
name : String,
parameters : Array[CelType],
result : CelType,
) -> StandardOverload {
{ name, receiver: None, parameters, result }
}
///|
fn receiver_overload(
name : String,
receiver : CelType,
parameters : Array[CelType],
result : CelType,
) -> StandardOverload {
{ name, receiver: Some(receiver), parameters, result }
}
///|
fn standard_overloads() -> Array[StandardOverload] {
[
global_overload("size", [CelType::String], CelType::Int),
global_overload("size", [CelType::Bytes], CelType::Int),
global_overload("size", [CelType::List(CelType::Dyn)], CelType::Int),
global_overload(
"size",
[CelType::Map(CelType::Dyn, CelType::Dyn)],
CelType::Int,
),
global_overload("type", [CelType::Dyn], CelType::String),
global_overload("int", [CelType::UInt], CelType::Int),
global_overload("int", [CelType::Double], CelType::Int),
global_overload("int", [CelType::String], CelType::Int),
global_overload("uint", [CelType::Int], CelType::UInt),
global_overload("uint", [CelType::Double], CelType::UInt),
global_overload("uint", [CelType::String], CelType::UInt),
global_overload("double", [CelType::Int], CelType::Double),
global_overload("double", [CelType::UInt], CelType::Double),
global_overload("double", [CelType::String], CelType::Double),
global_overload("string", [CelType::Bool], CelType::String),
global_overload("string", [CelType::Int], CelType::String),
global_overload("string", [CelType::UInt], CelType::String),
global_overload("string", [CelType::Double], CelType::String),
global_overload("string", [CelType::Bytes], CelType::String),
global_overload("bytes", [CelType::String], CelType::Bytes),
receiver_overload("size", CelType::String, [], CelType::Int),
receiver_overload("size", CelType::Bytes, [], CelType::Int),
receiver_overload("size", CelType::List(CelType::Dyn), [], CelType::Int),
receiver_overload(
"size",
CelType::Map(CelType::Dyn, CelType::Dyn),
[],
CelType::Int,
),
receiver_overload(
"contains",
CelType::String,
[CelType::String],
CelType::Bool,
),
receiver_overload(
"startsWith",
CelType::String,
[CelType::String],
CelType::Bool,
),
receiver_overload(
"endsWith",
CelType::String,
[CelType::String],
CelType::Bool,
),
receiver_overload(
"matches",
CelType::String,
[CelType::String],
CelType::Bool,
),
]
}
///|
fn StandardOverload::matches(
self : StandardOverload,
receiver : CelType?,
arguments : Array[CelType],
) -> Bool {
let receiver_matches = match (self.receiver, receiver) {
(None, None) => true
(Some(expected), Some(actual)) => expected.accepts(actual)
_ => false
}
if !receiver_matches || self.parameters.length() != arguments.length() {
return false
}
for index = 0; index < arguments.length(); index = index + 1 {
if !self.parameters[index].accepts(arguments[index]) {
return false
}
}
true
}
///|
fn StandardOverload::signature(self : StandardOverload) -> String {
let arguments = self.parameters.map(item => item.display()).join(", ")
match self.receiver {
Some(receiver) =>
"\{receiver.display()}.\{self.name}(\{arguments}) -> \{self.result.display()}"
None => "\{self.name}(\{arguments}) -> \{self.result.display()}"
}
}
///|
fn Checker::resolve_standard_call(
self : Checker,
name : String,
receiver : CelType?,
arguments : Array[CelType],
span : SourceSpan,
) -> CelType {
let named = standard_overloads().filter(overload => overload.name == name)
if named.is_empty() {
self.error("CEL-CHECK-FUNCTION", "unknown function '\{name}'", span)
return CelType::Dyn
}
match named.search_by(overload => overload.matches(receiver, arguments)) {
Some(index) => named[index].result
None => {
let actual_arguments = arguments.map(item => item.display()).join(", ")
let actual = match receiver {
Some(target) => "\{target.display()}.\{name}(\{actual_arguments})"
None => "\{name}(\{actual_arguments})"
}
let expected = named.map(overload => overload.signature()).join("; ")
self.error(
"CEL-CHECK-OVERLOAD",
"no matching overload for \{actual}; expected \{expected}",
span,
)
CelType::Dyn
}
}
}
///|
/// Names provided by the v0.1 standard environment.
pub fn standard_function_names() -> Array[String] {
[
"bytes", "double", "int", "size", "string", "type", "uint", "contains", "endsWith",
"matches", "startsWith",
]
}