mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
string concat (WIP)
Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
committed by
Anand Krishnamoorthi
parent
e93b33ea05
commit
89e26e37a2
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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, ¶ms[0], &args[0])?;
|
||||
let collection = ensure_string_collection(name, ¶ms[1], &args[1])?;
|
||||
Ok(Value::String(collection.join(&delimiter)))
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
69
tests/interpreter/cases/builtins/strings/tests.yaml
Normal file
69
tests/interpreter/cases/builtins/strings/tests.yaml
Normal 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."
|
||||
|
||||
Reference in New Issue
Block a user