difftreelog
refactor drop impl ArgsLike for HashMap
in: master
2 files changed
crates/jrsonnet-evaluator/src/function/arglike.rsdiffbeforeafterboth1use std::collections::HashMap;2use std::rc::Rc;34use jrsonnet_gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};78use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};910pub trait ArgLike {11 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;12}1314impl ArgLike for &Rc<Spanned<Expr>> {15 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {16 Ok(if tailstrict {17 Thunk::evaluated(evaluate(ctx, self)?)18 } else {19 let expr = (*self).clone();20 Thunk!(move || evaluate(ctx, &expr))21 })22 }23}2425impl<T> ArgLike for T26where27 T: Typed + Clone,28{29 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30 if T::provides_lazy() && !tailstrict {31 return Ok(T::into_lazy_untyped(self.clone()));32 }33 let val = T::into_untyped(self.clone())?;34 Ok(Thunk::evaluated(val))35 }36}3738#[derive(Clone, Trace)]39pub enum TlaArg {40 String(IStr),41 Val(Val),42 Lazy(Thunk<Val>),43 Import(String),44 ImportStr(String),45 InlineCode(String),46}47impl TlaArg {48 pub fn evaluate_tailstrict(&self) -> Result<Val> {49 match self {50 Self::String(s) => Ok(Val::string(s.clone())),51 Self::Val(val) => Ok(val.clone()),52 Self::Lazy(lazy) => Ok(lazy.evaluate()?),53 Self::Import(p) => with_state(|s| {54 let resolved = s.resolve_from_default(&p.as_str())?;55 s.import_resolved(resolved)56 }),57 Self::ImportStr(p) => with_state(|s| {58 let resolved = s.resolve_from_default(&p.as_str())?;59 s.import_resolved_str(resolved).map(Val::string)60 }),61 Self::InlineCode(p) => with_state(|s| {62 let resolved =63 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));64 s.import_resolved(resolved)65 }),66 }67 }68 pub fn evaluate(&self) -> Result<Thunk<Val>> {69 match self {70 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),71 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),72 Self::Lazy(lazy) => Ok(lazy.clone()),73 Self::Import(p) => with_state(|s| {74 let resolved = s.resolve_from_default(&p.as_str())?;75 Ok(Thunk!(move || s.import_resolved(resolved)))76 }),77 Self::ImportStr(p) => with_state(|s| {78 let resolved = s.resolve_from_default(&p.as_str())?;79 Ok(Thunk!(move || s80 .import_resolved_str(resolved)81 .map(Val::string)))82 }),83 Self::InlineCode(p) => with_state(|s| {84 let resolved =85 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));86 Ok(Thunk!(move || s.import_resolved(resolved)))87 }),88 }89 }90}9192// TODO: Is this implementation really required, as there is no Context to use?93// Maybe something a bit stricter is possible to add, especially with precompiled calls?94impl ArgLike for TlaArg {95 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {96 if tailstrict {97 self.evaluate_tailstrict().map(Thunk::evaluated)98 } else {99 self.evaluate()100 }101 }102}103104pub trait ArgsLike {105 fn unnamed_len(&self) -> usize;106 fn unnamed_iter(107 &self,108 ctx: Context,109 tailstrict: bool,110 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,111 ) -> Result<()>;112 fn named_iter(113 &self,114 ctx: Context,115 tailstrict: bool,116 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,117 ) -> Result<()>;118 fn named_names(&self, handler: &mut dyn FnMut(&IStr));119 fn is_empty(&self) -> bool;120}121122impl ArgsLike for Vec<Val> {123 fn unnamed_len(&self) -> usize {124 self.len()125 }126 fn unnamed_iter(127 &self,128 _ctx: Context,129 _tailstrict: bool,130 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,131 ) -> Result<()> {132 for (idx, el) in self.iter().enumerate() {133 handler(idx, Thunk::evaluated(el.clone()))?;134 }135 Ok(())136 }137 fn named_iter(138 &self,139 _ctx: Context,140 _tailstrict: bool,141 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,142 ) -> Result<()> {143 Ok(())144 }145 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}146 fn is_empty(&self) -> bool {147 self.is_empty()148 }149}150151impl ArgsLike for ArgsDesc {152 fn unnamed_len(&self) -> usize {153 self.unnamed.len()154 }155156 fn unnamed_iter(157 &self,158 ctx: Context,159 tailstrict: bool,160 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,161 ) -> Result<()> {162 for (id, arg) in self.unnamed.iter().enumerate() {163 handler(164 id,165 if tailstrict {166 Thunk::evaluated(evaluate(ctx.clone(), arg)?)167 } else {168 let ctx = ctx.clone();169 let arg = arg.clone();170171 Thunk!(move || evaluate(ctx, &arg))172 },173 )?;174 }175 Ok(())176 }177178 fn named_iter(179 &self,180 ctx: Context,181 tailstrict: bool,182 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,183 ) -> Result<()> {184 for (name, arg) in &self.named {185 handler(186 name,187 if tailstrict {188 Thunk::evaluated(evaluate(ctx.clone(), arg)?)189 } else {190 let ctx = ctx.clone();191 let arg = arg.clone();192193 Thunk!(move || evaluate(ctx, &arg))194 },195 )?;196 }197 Ok(())198 }199200 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {201 for (name, _) in &self.named {202 handler(name);203 }204 }205206 fn is_empty(&self) -> bool {207 self.unnamed.is_empty() && self.named.is_empty()208 }209}210211impl<V: ArgLike, S> ArgsLike for HashMap<IStr, V, S> {212 fn unnamed_len(&self) -> usize {213 0214 }215216 fn unnamed_iter(217 &self,218 _ctx: Context,219 _tailstrict: bool,220 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,221 ) -> Result<()> {222 Ok(())223 }224225 fn named_iter(226 &self,227 ctx: Context,228 tailstrict: bool,229 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,230 ) -> Result<()> {231 for (name, value) in self {232 handler(name, value.evaluate_arg(ctx.clone(), tailstrict)?)?;233 }234 Ok(())235 }236237 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {238 for name in self.keys() {239 handler(name);240 }241 }242243 fn is_empty(&self) -> bool {244 self.is_empty()245 }246}247248macro_rules! impl_args_like {249 ($count:expr; $($gen:ident)*) => {250 impl<$($gen: ArgLike,)*> ArgsLike for ($($gen,)*) {251 fn unnamed_len(&self) -> usize {252 $count253 }254 #[allow(non_snake_case, unused_assignments)]255 fn unnamed_iter(256 &self,257 ctx: Context,258 tailstrict: bool,259 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,260 ) -> Result<()> {261 let mut i = 0usize;262 let ($($gen,)*) = self;263 $(264 handler(i, $gen.evaluate_arg(ctx.clone(), tailstrict)?)?;265 i+=1;266 )*267 Ok(())268 }269 fn named_iter(270 &self,271 _ctx: Context,272 _tailstrict: bool,273 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,274 ) -> Result<()> {275 Ok(())276 }277 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}278279 fn is_empty(&self) -> bool {280 // impl_args_like only implements non-empty tuples.281 false282 }283 }284 };285 ($count:expr; $($cur:ident)* @ $c:ident $($rest:ident)*) => {286 impl_args_like!($count; $($cur)*);287 impl_args_like!($count + 1usize; $($cur)* $c @ $($rest)*);288 };289 ($count:expr; $($cur:ident)* @) => {290 impl_args_like!($count; $($cur)*);291 }292}293impl_args_like! {294 // First argument is already in position, so count starts from 1295 1usize; A @ B C D E F G H I J K L296}297298impl ArgsLike for () {299 fn unnamed_len(&self) -> usize {300 0301 }302303 fn unnamed_iter(304 &self,305 _ctx: Context,306 _tailstrict: bool,307 _handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,308 ) -> Result<()> {309 Ok(())310 }311312 fn named_iter(313 &self,314 _ctx: Context,315 _tailstrict: bool,316 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,317 ) -> Result<()> {318 Ok(())319 }320321 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}322 fn is_empty(&self) -> bool {323 true324 }325}1use std::collections::HashMap;2use std::rc::Rc;34use jrsonnet_gcmodule::Trace;5use jrsonnet_interner::IStr;6use jrsonnet_parser::{ArgsDesc, Expr, SourceFifo, SourcePath, Spanned};78use crate::{evaluate, typed::Typed, with_state, Context, Result, Thunk, Val};910pub trait ArgLike {11 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>>;12}1314impl ArgLike for &Rc<Spanned<Expr>> {15 fn evaluate_arg(&self, ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {16 Ok(if tailstrict {17 Thunk::evaluated(evaluate(ctx, self)?)18 } else {19 let expr = (*self).clone();20 Thunk!(move || evaluate(ctx, &expr))21 })22 }23}2425impl<T> ArgLike for T26where27 T: Typed + Clone,28{29 fn evaluate_arg(&self, _ctx: Context, tailstrict: bool) -> Result<Thunk<Val>> {30 if T::provides_lazy() && !tailstrict {31 return Ok(T::into_lazy_untyped(self.clone()));32 }33 let val = T::into_untyped(self.clone())?;34 Ok(Thunk::evaluated(val))35 }36}3738#[derive(Clone, Trace)]39pub enum TlaArg {40 String(IStr),41 Val(Val),42 Lazy(Thunk<Val>),43 Import(String),44 ImportStr(String),45 InlineCode(String),46}47impl TlaArg {48 pub fn evaluate_tailstrict(&self) -> Result<Val> {49 match self {50 Self::String(s) => Ok(Val::string(s.clone())),51 Self::Val(val) => Ok(val.clone()),52 Self::Lazy(lazy) => Ok(lazy.evaluate()?),53 Self::Import(p) => with_state(|s| {54 let resolved = s.resolve_from_default(&p.as_str())?;55 s.import_resolved(resolved)56 }),57 Self::ImportStr(p) => with_state(|s| {58 let resolved = s.resolve_from_default(&p.as_str())?;59 s.import_resolved_str(resolved).map(Val::string)60 }),61 Self::InlineCode(p) => with_state(|s| {62 let resolved =63 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));64 s.import_resolved(resolved)65 }),66 }67 }68 pub fn evaluate(&self) -> Result<Thunk<Val>> {69 match self {70 Self::String(s) => Ok(Thunk::evaluated(Val::string(s.clone()))),71 Self::Val(val) => Ok(Thunk::evaluated(val.clone())),72 Self::Lazy(lazy) => Ok(lazy.clone()),73 Self::Import(p) => with_state(|s| {74 let resolved = s.resolve_from_default(&p.as_str())?;75 Ok(Thunk!(move || s.import_resolved(resolved)))76 }),77 Self::ImportStr(p) => with_state(|s| {78 let resolved = s.resolve_from_default(&p.as_str())?;79 Ok(Thunk!(move || s80 .import_resolved_str(resolved)81 .map(Val::string)))82 }),83 Self::InlineCode(p) => with_state(|s| {84 let resolved =85 SourcePath::new(SourceFifo("<inline code>".to_owned(), p.as_bytes().into()));86 Ok(Thunk!(move || s.import_resolved(resolved)))87 }),88 }89 }90}9192pub trait ArgsLike {93 fn unnamed_len(&self) -> usize;94 fn unnamed_iter(95 &self,96 ctx: Context,97 tailstrict: bool,98 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,99 ) -> Result<()>;100 fn named_iter(101 &self,102 ctx: Context,103 tailstrict: bool,104 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,105 ) -> Result<()>;106 fn named_names(&self, handler: &mut dyn FnMut(&IStr));107 fn is_empty(&self) -> bool;108}109110impl ArgsLike for Vec<Val> {111 fn unnamed_len(&self) -> usize {112 self.len()113 }114 fn unnamed_iter(115 &self,116 _ctx: Context,117 _tailstrict: bool,118 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,119 ) -> Result<()> {120 for (idx, el) in self.iter().enumerate() {121 handler(idx, Thunk::evaluated(el.clone()))?;122 }123 Ok(())124 }125 fn named_iter(126 &self,127 _ctx: Context,128 _tailstrict: bool,129 _handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,130 ) -> Result<()> {131 Ok(())132 }133 fn named_names(&self, _handler: &mut dyn FnMut(&IStr)) {}134 fn is_empty(&self) -> bool {135 self.is_empty()136 }137}138139impl ArgsLike for ArgsDesc {140 fn unnamed_len(&self) -> usize {141 self.unnamed.len()142 }143144 fn unnamed_iter(145 &self,146 ctx: Context,147 tailstrict: bool,148 handler: &mut dyn FnMut(usize, Thunk<Val>) -> Result<()>,149 ) -> Result<()> {150 for (id, arg) in self.unnamed.iter().enumerate() {151 handler(152 id,153 if tailstrict {154 Thunk::evaluated(evaluate(ctx.clone(), arg)?)155 } else {156 let ctx = ctx.clone();157 let arg = arg.clone();158159 Thunk!(move || evaluate(ctx, &arg))160 },161 )?;162 }163 Ok(())164 }165166 fn named_iter(167 &self,168 ctx: Context,169 tailstrict: bool,170 handler: &mut dyn FnMut(&IStr, Thunk<Val>) -> Result<()>,171 ) -> Result<()> {172 for (name, arg) in &self.named {173 handler(174 name,175 if tailstrict {176 Thunk::evaluated(evaluate(ctx.clone(), arg)?)177 } else {178 let ctx = ctx.clone();179 let arg = arg.clone();180181 Thunk!(move || evaluate(ctx, &arg))182 },183 )?;184 }185 Ok(())186 }187188 fn named_names(&self, handler: &mut dyn FnMut(&IStr)) {189 for (name, _) in &self.named {190 handler(name);191 }192 }193194 fn is_empty(&self) -> bool {195 self.unnamed.is_empty() && self.named.is_empty()196 }197}crates/jrsonnet-evaluator/src/tla.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/tla.rs
+++ b/crates/jrsonnet-evaluator/src/tla.rs
@@ -1,11 +1,10 @@
use std::{collections::HashMap, hash::BuildHasher};
use jrsonnet_interner::IStr;
-use jrsonnet_parser::Source;
use crate::{
- function::{CallLocation, TlaArg},
- in_description_frame, with_state, Result, Val,
+ function::{CallLocation, PreparedFuncVal, TlaArg},
+ in_description_frame, Result, Val,
};
pub fn apply_tla<H: BuildHasher>(args: &HashMap<IStr, TlaArg, H>, val: Val) -> Result<Val> {
@@ -13,17 +12,14 @@
in_description_frame(
|| "during TLA call".to_owned(),
|| {
- func.evaluate(
- with_state(|s| {
- s.create_default_context(Source::new_virtual(
- "<top-level-arg>".into(),
- IStr::empty(),
- ))
- }),
- CallLocation::native(),
- args,
- false,
- )
+ let mut names = Vec::with_capacity(args.len());
+ let mut values = Vec::with_capacity(args.len());
+ for (name, value) in args {
+ names.push(name.clone());
+ values.push(value.evaluate()?);
+ }
+ let prepared = PreparedFuncVal::new(func, 0, &names)?;
+ prepared.call(CallLocation::native(), &[], &values)
},
)?
} else {