@@ -2238,6 +2238,125 @@ impl<'e> Vm<'e> {
22382238 Ok ( ( ) )
22392239 }
22402240
2241+ // Some syntactic calls can be self-implemented or short-circuited.
2242+ fn call_syntactic (
2243+ & mut self ,
2244+ program : & Program ,
2245+ name : & str ,
2246+ argc : usize ,
2247+ first : usize ,
2248+ scope : & mut Scope ,
2249+ pos : Position ,
2250+ ) -> Result < Option < Dynamic > , Box < EvalAltResult > > {
2251+ match name {
2252+ #[ cfg( not( feature = "no_closure" ) ) ]
2253+ crate :: engine:: KEYWORD_IS_SHARED => {
2254+ return Err ( EvalAltResult :: ErrorFunctionNotFound ( name. to_string ( ) , pos) . into ( ) )
2255+ }
2256+ crate :: engine:: KEYWORD_IS_DEF_VAR => {
2257+ if argc != 1 {
2258+ return Err ( EvalAltResult :: ErrorFunctionNotFound ( name. to_string ( ) , pos) . into ( ) ) ;
2259+ }
2260+ let var_name = self . stack [ first] . as_immutable_string_ref ( ) . map_err ( |typ| {
2261+ self . engine
2262+ . make_type_mismatch_err :: < ImmutableString > ( typ, pos)
2263+ } ) ?;
2264+ return Ok ( Some ( scope. contains ( & var_name) . into ( ) ) ) ;
2265+ }
2266+ #[ cfg( not( feature = "no_function" ) ) ]
2267+ crate :: engine:: KEYWORD_IS_DEF_FN => {
2268+ let ( this_type, fn_name, arity) = match argc {
2269+ 2 => {
2270+ let var_name = self . stack [ first]
2271+ . as_immutable_string_ref ( )
2272+ . as_deref ( )
2273+ . cloned ( )
2274+ . map_err ( |typ| {
2275+ self . engine
2276+ . make_type_mismatch_err :: < ImmutableString > ( typ, pos)
2277+ } ) ?;
2278+ let arity = self . stack [ first + 1 ]
2279+ . as_int ( )
2280+ . map_err ( |typ| self . engine . make_type_mismatch_err :: < INT > ( typ, pos) ) ?;
2281+ ( None , var_name, arity as usize )
2282+ }
2283+ 3 => {
2284+ let this_type = self . stack [ first]
2285+ . as_immutable_string_ref ( )
2286+ . as_deref ( )
2287+ . cloned ( )
2288+ . map_err ( |typ| {
2289+ self . engine
2290+ . make_type_mismatch_err :: < ImmutableString > ( typ, pos)
2291+ } ) ?;
2292+ let var_name = self . stack [ first + 1 ]
2293+ . as_immutable_string_ref ( )
2294+ . as_deref ( )
2295+ . cloned ( )
2296+ . map_err ( |typ| {
2297+ self . engine
2298+ . make_type_mismatch_err :: < ImmutableString > ( typ, pos)
2299+ } ) ?;
2300+ let arity = self . stack [ first + 2 ]
2301+ . as_int ( )
2302+ . map_err ( |typ| self . engine . make_type_mismatch_err :: < INT > ( typ, pos) ) ?;
2303+ ( Some ( this_type) , var_name, arity as usize )
2304+ }
2305+ _ => {
2306+ return Err (
2307+ EvalAltResult :: ErrorFunctionNotFound ( name. to_string ( ) , pos) . into ( )
2308+ )
2309+ }
2310+ } ;
2311+
2312+ // Check if there is a compiled function.
2313+ for f in program. functions ( ) {
2314+ let local_name = program
2315+ . name ( f. name )
2316+ . ok_or_else ( || malformed ( format ! ( "no name {}" , f. name) ) ) ?;
2317+
2318+ if local_name == fn_name. as_str ( ) && f. params . len ( ) == arity {
2319+ if let Some ( ref this_type) = this_type {
2320+ if let Some ( local_this_type_index) = f. this_type {
2321+ let local_this_type_name =
2322+ program. name ( local_this_type_index) . ok_or_else ( || {
2323+ malformed ( format ! ( "no name {local_this_type_index}" ) )
2324+ } ) ?;
2325+
2326+ if local_this_type_name == this_type {
2327+ return Ok ( Some ( Dynamic :: TRUE ) ) ;
2328+ }
2329+ }
2330+ } else if f. this_type . is_none ( ) {
2331+ return Ok ( Some ( Dynamic :: TRUE ) ) ;
2332+ }
2333+ }
2334+ }
2335+
2336+ // Call into Rhai.
2337+ let mut args = self . stack [ first..] . iter_mut ( ) . collect :: < FnArgsVec < _ > > ( ) ;
2338+
2339+ return self
2340+ . engine
2341+ . exec_syntactic_fn_call (
2342+ & mut self . global ,
2343+ & mut self . caches ,
2344+ name,
2345+ & mut args,
2346+ pos,
2347+ )
2348+ . map_err ( |err| dispatch_failure ( err, pos) ) ?
2349+ . ok_or_else ( || {
2350+ EvalAltResult :: ErrorFunctionNotFound ( name. to_string ( ) , pos) . into ( )
2351+ } )
2352+ . map ( Some ) ;
2353+ }
2354+ _ => { }
2355+ }
2356+
2357+ Ok ( None )
2358+ }
2359+
22412360 /// Call `name` with `argc` arguments sitting contiguously from `first` up.
22422361 ///
22432362 /// A function this compiler lowered is called directly, with no hash and no
@@ -2248,15 +2367,13 @@ impl<'e> Vm<'e> {
22482367 & mut self ,
22492368 program : & Program ,
22502369 name_index : u32 ,
2370+ name : & str ,
22512371 argc : usize ,
22522372 first : usize ,
22532373 scope : & mut Scope ,
22542374 pos : Position ,
22552375 ) -> VmResult {
2256- let name = program
2257- . name ( name_index)
2258- . ok_or_else ( || malformed ( format ! ( "no name {name_index}" ) ) ) ?;
2259-
2376+ // Run compiled function if available.
22602377 if let Some ( function) = program. function ( name_index, argc) {
22612378 return self . call_compiled (
22622379 program,
@@ -2299,17 +2416,14 @@ impl<'e> Vm<'e> {
22992416 & mut self ,
23002417 program : & Program ,
23012418 name_index : u32 ,
2419+ name : & str ,
23022420 argc : usize ,
23032421 receiver : Receiver ,
23042422 scope : & mut Scope ,
23052423 base : usize ,
23062424 capture_parent_scope : bool ,
23072425 pos : Position ,
23082426 ) -> VmResult {
2309- let name = program
2310- . name ( name_index)
2311- . ok_or_else ( || malformed ( format ! ( "no name {name_index}" ) ) ) ?;
2312-
23132427 // Every argument count here includes the receiver, so zero of them
23142428 // names no receiver at all and the instruction is nonsense. Only an
23152429 // artifact can say it; the compiler emits one of these for a call that
@@ -2323,17 +2437,15 @@ impl<'e> Vm<'e> {
23232437 // The register is not a scope entry, so it takes a path of its own
23242438 // rather than a third [`Site`].
23252439 if let Receiver :: This = receiver {
2326- let mut new_scope;
2327- let use_scope = if capture_parent_scope {
2328- // Reuse parent scope.
2329- scope
2330- } else {
2331- // Create detached scope.
2332- new_scope = Scope :: new ( ) ;
2333- & mut new_scope
2334- } ;
2335-
2336- return self . call_by_this ( program, name_index, name, argc, use_scope, pos) ;
2440+ return self . call_by_this (
2441+ program,
2442+ name_index,
2443+ name,
2444+ argc,
2445+ scope,
2446+ capture_parent_scope,
2447+ pos,
2448+ ) ;
23372449 }
23382450
23392451 // A named receiver's value is already argument zero — [`Op::LoadNamed`]
@@ -2387,20 +2499,23 @@ impl<'e> Vm<'e> {
23872499 let value = scope. get_mut_by_index ( index) . flatten_clone ( ) ;
23882500 self . stack . insert ( first, value) ;
23892501 }
2390-
2391- let mut new_scope;
2392- let use_scope = if capture_parent_scope {
2393- // Reuse parent scope.
2394- scope
2395- } else {
2396- // Create detached scope.
2397- new_scope = Scope :: new ( ) ;
2398- & mut new_scope
2399- } ;
2400-
2401- let value = self . call_stacked ( program, name_index, argc, first, use_scope, pos) ;
2502+ // Check if it is a built-in syntactic function.
2503+ let value =
2504+ if let Some ( value) = self . call_syntactic ( program, name, argc, first, scope, pos) ? {
2505+ value
2506+ } else {
2507+ // Detach the scope with a new one if not capturing the parent's.
2508+ let mut detached;
2509+ let scope = if !capture_parent_scope {
2510+ detached = Scope :: new ( ) ;
2511+ & mut detached
2512+ } else {
2513+ scope
2514+ } ;
2515+ self . call_stacked ( program, name_index, name, argc, first, scope, pos) ?
2516+ } ;
24022517 self . stack . truncate ( first) ;
2403- return value;
2518+ return Ok ( value) ;
24042519 }
24052520
24062521 let value = {
@@ -2459,6 +2574,7 @@ impl<'e> Vm<'e> {
24592574 name : & str ,
24602575 argc : usize ,
24612576 scope : & mut Scope ,
2577+ capture_parent_scope : bool ,
24622578 pos : Position ,
24632579 ) -> VmResult {
24642580 let first = self
@@ -2477,9 +2593,23 @@ impl<'e> Vm<'e> {
24772593 && program. function ( name_index, argc) . is_none ( ) ;
24782594
24792595 if !by_reference {
2480- let value = self . call_stacked ( program, name_index, argc, first, scope, pos) ;
2596+ // Check if it is a built-in syntactic function.
2597+ let value =
2598+ if let Some ( value) = self . call_syntactic ( program, name, argc, first, scope, pos) ? {
2599+ value
2600+ } else {
2601+ // Detach the scope with a new one if not capturing the parent's.
2602+ let mut detached;
2603+ let scope = if !capture_parent_scope {
2604+ detached = Scope :: new ( ) ;
2605+ & mut detached
2606+ } else {
2607+ scope
2608+ } ;
2609+ self . call_stacked ( program, name_index, name, argc, first, scope, pos) ?
2610+ } ;
24812611 self . stack . truncate ( first) ;
2482- return value;
2612+ return Ok ( value) ;
24832613 }
24842614
24852615 let value = {
@@ -3431,18 +3561,22 @@ impl<'e> Vm<'e> {
34313561 }
34323562 }
34333563
3434- let mut new_scope;
3435- let use_scope = if capture_parent_scope {
3436- // Reuse parent scope.
3437- & mut * scope
3564+ // Check if it is a built-in syntactic function.
3565+ let value = if let Some ( value) =
3566+ self . call_syntactic ( program, name, argc, first, scope, pos ( ) ) ?
3567+ {
3568+ value
34383569 } else {
3439- // Create detached scope.
3440- new_scope = Scope :: new ( ) ;
3441- & mut new_scope
3570+ // Detach the scope with a new one if not capturing the parent's.
3571+ let mut detached;
3572+ let scope = if !capture_parent_scope {
3573+ detached = Scope :: new ( ) ;
3574+ & mut detached
3575+ } else {
3576+ & mut * scope
3577+ } ;
3578+ self . call_stacked ( program, name_index, name, argc, first, scope, pos ( ) ) ?
34423579 } ;
3443-
3444- let value =
3445- self . call_stacked ( program, name_index, argc, first, use_scope, pos ( ) ) ?;
34463580 self . stack . truncate ( first) ;
34473581 self . stack . push ( value) ;
34483582 }
@@ -3454,6 +3588,9 @@ impl<'e> Vm<'e> {
34543588 | code:: tag:: CALL_THIS_REF
34553589 | code:: tag:: CALL_THIS_REF_CAPTURE => {
34563590 let name_index = u32:: from ( small ( 1 ) ?) ;
3591+ let name = program
3592+ . name ( name_index)
3593+ . ok_or_else ( || malformed ( format ! ( "no name {name_index}" ) ) ) ?;
34573594 let argc = code[ pc + 3 ] as usize ;
34583595 // `this` is a register, so this one carries no operand for
34593596 // the receiver and is two bytes shorter.
@@ -3479,6 +3616,7 @@ impl<'e> Vm<'e> {
34793616 let value = self . call_by_reference (
34803617 program,
34813618 name_index,
3619+ name,
34823620 argc,
34833621 receiver,
34843622 scope,
0 commit comments