string concat (WIP)

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2023-02-27 19:10:06 -08:00
committed by Anand Krishnamoorthi
parent e93b33ea05
commit 89e26e37a2
4 changed files with 130 additions and 13 deletions

View File

@@ -6,6 +6,7 @@ pub mod arrays;
pub mod comparison;
pub mod numbers;
pub mod sets;
pub mod strings;
pub mod types;
pub mod utils;
@@ -24,12 +25,15 @@ pub type BuiltinFcn = fn(&Span, &[Expr], &[Value]) -> Result<Value>;
lazy_static! {
pub static ref BUILTINS: HashMap<&'static str, BuiltinFcn> = {
let mut m : HashMap<&'static str, BuiltinFcn> = HashMap::new();
// comparison functions are directly called.
numbers::register(&mut m);
aggregates::register(&mut m);
arrays::register(&mut m);
sets::register(&mut m);
types::register(&mut m);
strings::register(&mut m);
m
};
}

View File

@@ -1,19 +1,24 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use crate::ast::Expr;
use crate::builtins;
use crate::builtins::utils::{ensure_args_count, ensure_string, ensure_string_collection};
use crate::lexer::Span;
use crate::value::Value;
use anyhow::{bail, Result};
use std::collections::HashMap;
fn ensure_numeric(fcn: &str, arg: &Expr, v: &Value) -> Result<Float> {
Ok(match &v {
Value::Number(n) => n.0 .0,
_ => {
let span = arg.span();
bail!(
span.error(format!("`{fcn}` expects numeric argument. Got `{v}` instead").as_str())
)
}
})
use anyhow::Result;
pub fn register(m: &mut HashMap<&'static str, builtins::BuiltinFcn>) {
m.insert("concat", concat);
}
fn concat(span: &Span, params: &[Expr], args: &[Value]) -> Result<Value> {
let name = "concat";
ensure_args_count(span, name, params, args, 2)?;
let delimiter = ensure_string(name, &params[0], &args[0])?;
let collection = ensure_string_collection(name, &params[1], &args[1])?;
Ok(Value::String(collection.join(&delimiter)))
}

View File

@@ -53,6 +53,45 @@ pub fn ensure_string(fcn: &str, arg: &Expr, v: &Value) -> Result<String> {
})
}
pub fn ensure_string_element<'a>(
fcn: &str,
arg: &Expr,
v: &'a Value,
idx: usize,
) -> Result<&'a str> {
Ok(match &v {
Value::String(s) => s.as_str(),
_ => {
let span = arg.span();
bail!(span.error(
format!("`{fcn}` expects string collection. Element {idx} is not a string.")
.as_str()
))
}
})
}
pub fn ensure_string_collection<'a>(fcn: &str, arg: &Expr, v: &'a Value) -> Result<Vec<&'a str>> {
let mut collection = vec![];
match &v {
Value::Array(a) => {
for (idx, elem) in a.iter().enumerate() {
collection.push(ensure_string_element(fcn, arg, elem, idx)?);
}
}
Value::Set(s) => {
for (idx, elem) in s.iter().enumerate() {
collection.push(ensure_string_element(fcn, arg, elem, idx)?);
}
}
_ => {
let span = arg.span();
bail!(span.error(format!("`{fcn}` expects array/set of strings.").as_str()))
}
}
Ok(collection)
}
pub fn ensure_array(fcn: &str, arg: &Expr, v: Value) -> Result<Rc<Vec<Value>>> {
Ok(match v {
Value::Array(a) => a,

View File

@@ -0,0 +1,69 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: all
data: {}
modules:
- |
package test
# Arrays
a1 = concat(", ", ["Hello", "world"])
a2 = concat("", ["Hello", "world"]) # empty delimiter
a3 = concat(",", []) # empty array
a4 = concat("", []) # empty array and delimiter
# Sets
s1 = concat(", ", {"world", "Hello"})
s2 = concat("", {"world", "Hello"}) # empty delimiter
s3 = concat(",", set()) # empty set
s4 = concat("", set()) # empty set and delimiter
query: data.test
want_result:
a1: "Hello, world"
a2: "Helloworld"
a3: ""
a4: ""
s1: "Hello, world"
s2: "Helloworld"
s3: ""
s4: ""
- note: invalid-null-delimiter
data: {}
modules: ["package test\nx=concat(null, [])"]
query: data.test
error: "`concat` expects string argument."
- note: invalid-bool-delimiter
data: {}
modules: ["package test\nx=concat(true, [])"]
query: data.test
error: "`concat` expects string argument."
- note: invalid-number-delimiter
data: {}
modules: ["package test\nx=concat(1, [])"]
query: data.test
error: "`concat` expects string argument."
- note: invalid-array-delimiter
data: {}
modules: ["package test\nx=concat([], [])"]
query: data.test
error: "`concat` expects string argument."
- note: invalid-set-delimiter
data: {}
modules: ["package test\nx=concat(set(), [])"]
query: data.test
error: "`concat` expects string argument."
- note: invalid-object-delimiter
data: {}
modules: ["package test\nx=concat({}, [])"]
query: data.test
error: "`concat` expects string argument."