diff --git a/src/builtins.rs b/src/builtins.rs index f333097..2789712 100644 --- a/src/builtins.rs +++ b/src/builtins.rs @@ -83,6 +83,7 @@ pub enum Function { DataUrl, DateTime, Shlex, + Func, FromJson, ToJson, VarDump, @@ -338,6 +339,7 @@ static_map!( ["path", Function::Path], ["datetime", Function::DateTime], ["shlex", Function::Shlex], + ["func", Function::Func], ["http_get", Function::HttpGet], ["http_post", Function::HttpPost], ["s3_get", Function::S3Get], @@ -650,6 +652,7 @@ impl Function { DataUrl => (smallvec![Str], MapStrStr), DateTime => (smallvec![Str], MapStrInt), Shlex => (smallvec![Str], MapIntStr), + Func => (smallvec![Str], MapIntStr), HttpGet => (smallvec![Str, MapStrStr], MapStrStr), HttpPost => (smallvec![Str, MapStrStr, Str ], MapStrStr), S3Get => (smallvec![Str, Str], Str), @@ -730,7 +733,7 @@ impl Function { Whoami | Os | OsFamily | Arch | Pwd | UserHome => 0, Exit | ToUpper | ToLower | Clear | Srand | System | HexToInt | ToInt | EscapeCSV | EscapeTSV | Close | Length | ReadErr | ReadErrCmd | Nextline | NextlineCmd - | Uuid | SnowFlake | Fend | Url | SemVer | Path | DataUrl | DateTime | Shlex | ToJson | FromJson | ToCsv | FromCsv | TypeOfVariable | IsArray | Unop(_) => 1, + | Uuid | SnowFlake | Fend | Url | SemVer | Path | DataUrl | DateTime | Shlex | Func | ToJson | FromJson | ToCsv | FromCsv | TypeOfVariable | IsArray | Unop(_) => 1, SetFI | SubstrIndex | Match | Setcol | Binop(_) => 2, JoinCSV | JoinTSV | Delete | Contains => 2, DefaultIfEmpty => 2, @@ -840,7 +843,7 @@ impl Function { val: BaseTy::Int }.abs()) } - Shlex => { + Shlex | Func => { Ok(Map { key: BaseTy::Int, val: BaseTy::Str diff --git a/src/bytecode.rs b/src/bytecode.rs index 30cbdb8..01e023e 100644 --- a/src/bytecode.rs +++ b/src/bytecode.rs @@ -225,6 +225,7 @@ pub(crate) enum Instr<'a> { DataUrl(Reg>>, Reg>), DateTime(Reg>, Reg>), Shlex(Reg>>, Reg>), + Func(Reg>>, Reg>), Uniq(Reg>>, Reg>>, Reg>), TypeOfArray(Reg>), TypeOfNumber(Reg>), @@ -669,6 +670,10 @@ impl<'a> Instr<'a> { dst.accum(&mut f); text.accum(&mut f); } + Func(dst, text) => { + dst.accum(&mut f); + text.accum(&mut f); + } HttpGet(dst, url,headers) => { dst.accum(&mut f); url.accum(&mut f); diff --git a/src/codegen/intrinsics.rs b/src/codegen/intrinsics.rs index 6c5fbd4..24f16e5 100644 --- a/src/codegen/intrinsics.rs +++ b/src/codegen/intrinsics.rs @@ -8,7 +8,7 @@ use crate::runtime::{self, printf::{printf, FormatArg}, splitter::{ batch::{ByteReader, CSVReader, WhitespaceOffsets}, chunk::{ChunkProducer, OffsetChunk}, regex::RegexSplitter, -}, ChainedReader, FileRead, Float, Int, IntMap, Line, LineReader, RegexCache, Str, StrMap, math_util}; +}, ChainedReader, FileRead, Float, Int, IntMap, Line, LineReader, RegexCache, Str, StrMap, math_util, string_util}; use crate::{ builtins::Variable, common::{CancelSignal, Cleanup, FileSpec, Notification, Result}, @@ -193,6 +193,7 @@ pub(crate) fn register_all(cg: &mut impl Backend) -> Result<()> { [ReadOnly] data_url(str_ref_ty) -> map_ty; [ReadOnly] datetime(str_ref_ty) -> map_ty; [ReadOnly] shlex(str_ref_ty) -> map_ty; + [ReadOnly] func(str_ref_ty) -> map_ty; [ReadOnly] sqlite_query(str_ref_ty, str_ref_ty) -> map_ty; [ReadOnly] sqlite_execute(str_ref_ty, str_ref_ty) -> int_ty; [ReadOnly] mysql_query(str_ref_ty, str_ref_ty) -> map_ty; @@ -1304,6 +1305,12 @@ pub(crate) unsafe extern "C" fn shlex(text: *mut U128) -> *mut c_void { mem::transmute::, *mut c_void>(res) } +pub(crate) unsafe extern "C" fn func(text: *mut U128) -> *mut c_void { + let text = &*(text as *mut Str); + let res = string_util::func(text.as_str()); + mem::transmute::, *mut c_void>(res) +} + pub(crate) unsafe extern "C" fn sqlite_query(db_path: *mut U128, sql: *mut U128) -> *mut c_void { let db_path = &*(db_path as *mut Str); let sql = &*(sql as *mut Str); diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index ce49538..64c3969 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -969,6 +969,7 @@ pub(crate) trait CodeGenerator: Backend { self.bind_val(dst.reflect(), resv) } Shlex(dst,text) => self.unop(intrinsic!(shlex), dst, text), + Func(dst,text) => self.unop(intrinsic!(func), dst, text), SqliteQuery(dst,db_path,sql) => { let db_path = self.get_val(db_path.reflect())?; let sql = self.get_val(sql.reflect())?; diff --git a/src/compile.rs b/src/compile.rs index fa86594..8e03bc0 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -2080,6 +2080,11 @@ impl<'a, 'b> View<'a, 'b> { self.pushl(LL::Shlex(res_reg.into(), conv_regs[0].into())) } } + Func => { + if res_reg != UNUSED { + self.pushl(LL::Func(res_reg.into(), conv_regs[0].into())) + } + } HttpGet => { if res_reg != UNUSED { self.pushl(LL::HttpGet(res_reg.into(), conv_regs[0].into(), conv_regs[1].into())) diff --git a/src/dataflow.rs b/src/dataflow.rs index e30f46b..94058d5 100644 --- a/src/dataflow.rs +++ b/src/dataflow.rs @@ -261,6 +261,7 @@ pub(crate) mod boilerplate { DataUrl(dst, src) => f(dst.into(), Some(src.into())), DateTime(dst, timestamp) => f(dst.into(), Some(timestamp.into())), Shlex(dst, text) => f(dst.into(), Some(text.into())), + Func(dst, text) => f(dst.into(), Some(text.into())), FromJson(dst, src) => f(dst.into(), Some(src.into())), MapIntIntToJson(dst, arr) => f(dst.into(), Some(arr.into())), MapIntFloatToJson(dst, arr) => f(dst.into(), Some(arr.into())), diff --git a/src/display.rs b/src/display.rs index 07b321c..fa3a140 100644 --- a/src/display.rs +++ b/src/display.rs @@ -215,6 +215,7 @@ impl Display for Function { DataUrl => write!(f, "data_url"), DateTime => write!(f, "datetime"), Shlex => write!(f, "shlex"), + Func => write!(f, "func"), HttpGet => write!(f, "http_get"), HttpPost => write!(f, "http_post"), S3Get => write!(f, "s3_get"), diff --git a/src/interp.rs b/src/interp.rs index c0010f7..d7278ef 100644 --- a/src/interp.rs +++ b/src/interp.rs @@ -855,6 +855,12 @@ impl<'a, LR: LineReader> Interp<'a, LR> { let dst = *dst; *self.get_mut(dst) = res; } + Func(dst, text) => { + let text = index(&self.strs, text); + let res = runtime::string_util::func(text.as_str()); + let dst = *dst; + *self.get_mut(dst) = res; + } HttpGet(dst, url, headers) => { let url = index(&self.strs, url); let headers = self.get(*headers);