contains behavior related to flow control

Mimics
Inactive cells
Active cells
Specs
Inactive cells (details)
inspect = "DefaultBehavior FlowControl"
kind = "DefaultBehavior FlowControl"
notice = "DefaultBehavior FlowControl"
Active cells (details)
(+args)

returns result of evaluating first argument

method(+args, 
  if(args length ==(1), 
    args [](0), 
    tuple(*(args))))
break(value nil)

breaks out of the enclosing context. if an argument is supplied, this will be returned as the result of the object breaking out of

cond(...)

takes zero or more arguments. each two arguments are paired, where the first one is the condition part, and the second is the then-part. if there's an uneven number of arguments, that part is the else-part. if no arguments are provided, or no conditions match and there is no else part, cond returns nil.

syntax(
  DefaultBehavior FlowControl cell(:cond) createNestedIfStatements(call arguments))
DefaultBehavior FlowControl cond
  • - should return nil for an empty statement [ show source ]
    cond should be nil 
    
    
  • - should evaluate and return the result of one statement [ show source ]
    cond(42 +(2)) should ==(44) 
    
    
  • - should evaluate a condition and not do it's then part if it's false [ show source ]
    Ground condTests = [] 
    cond(false, condTests <<(:ran)) should be nil 
    condTests should ==([]) 
    
    
  • - should do the then part for a true statement [ show source ]
    Ground condTests = [] 
    cond(true, condTests <<(:ran) 
      42) should ==(42) 
    condTests should ==([](:ran)) 
    
    
  • - should return the then part for a true statement [ show source ]
    cond(true, 42 +(4)) should ==(46) 
    
    
  • - should not execute conditions after the first true one [ show source ]
    Ground condTests = [] 
    cond(
      true, nil, 
      condTests <<(:cond) 
      false, nil 
      ) 
    condTests should ==([]) 
    
    
  • - should not execute more than one true condition [ show source ]
    Ground condTests = [] 
    cond(
      condTests <<(:one) 
      true, nil, 
      condTests <<(:two) 
      true, nil, 
      condTests <<(:three) 
      true, nil 
      ) 
    condTests should ==([](:one)) 
    
    
  • - should evaluate all conditions and return the else part if they are false [ show source ]
    cond(false, false, false, false, 42) should ==(42) 
    
    
continue()

breaks out of the enclosing context and continues from that point again.

do(...)

executes the arguments with the receiver as context and ground, and then returns the receiver.

macro(
  call arguments each(evaluateOn(cell("@"))) 
  cell("@"))
ensure([code], +[ensureBlocks])

will execute and return the value of the first argument. after the code has run, all the remaining blocks of code are guaranteed to run in order even if a non-local flow control happens inside the main code. if any code in the ensure blocks generate a new non-local flow control, the rest of the ensure blocks in that specific ensure invocation are not guaranteed to run.

DefaultBehavior FlowControl ensure
  • - should work with just main code [ show source ]
    ensure(10 +(10)) should ==(20) 
    
    
  • - should execute all the ensure code after the main code [ show source ]
    Ground ensureResults = [] 
    ensure(
      ensureResults <<(:mainCode), 
      ensureResults <<(:ensureBlock1), 
      ensureResults <<(:ensureBlock2)) 
    ensureResults should ==([](:mainCode, :ensureBlock1, :ensureBlock2)) 
    
    
  • - should execute nested ensure blocks [ show source ]
    Ground ensureResults = [] 
    ensure(
      ensure(
        ensure(
          ensureResults <<(:mainCode), 
          ensureResults <<(:ensureBlockInner)), 
        ensureResults <<(:ensureBlockOuter)), 
      ensureResults <<(:ensureBlockOutmost)) 
    ensureResults should ==([](:mainCode, :ensureBlockInner, :ensureBlockOuter, :ensureBlockOutmost)) 
    
    
  • - should return the result of the main code even though there are ensure blocks [ show source ]
    ensure(
      42, 
      43) should ==(42) 
    ensure(
      ensure(
        42, 
        44, 
        45), 
      43) should ==(42) 
    
    
  • - should execute the ensure code if a restart is invoked outside [ show source ]
    Ground ensureResults = [] 
    bind(restart(outside, fn), 
      ensure(
        invokeRestart(:outside), 
        ensureResults <<(:invoked))) 
    ensureResults should ==([](:invoked)) 
    
    
  • - should execute the ensure code if a condition is rescued outside [ show source ]
    Ground ensureResults = [] 
    bind(rescue(Condition, fn(c, nil)), 
      ensure(
        signal!(Condition), 
        ensureResults <<(:invoked))) 
    ensureResults should ==([](:invoked)) 
    
    
for(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "map", "flatMap") 
  )
DefaultBehavior FlowControl for
  • - should handle a simple iteration [ show source ]
    for(x <-([](1, 2, 3)), x) should ==([](1, 2, 3)) 
    for(x <-(1 ..(10)), x) should ==([](1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 
    for(x <-(set(:a, :b, :c)), x) sort should ==([](:a, :b, :c)) 
    
    
  • - should be possible to do something advanced in the output part [ show source ]
    for(x <-(1 ..(10)), x *(2)) should ==([](2, 4, 6, 8, 10, 12, 14, 16, 18, 20)) 
    mex = method(f, f +(f) +(f)) 
    for(x <-(1 ...(5)), mex(x)) should ==([](3, 6, 9, 12)) 
    
    
  • - should be possible to combine two or more iterations [ show source ]
    for(x <-([](1, 2, 3)), y <-([](15, 16, 17)), [](x, y)) should ==([]([](1, 15), [](1, 16), [](1, 17), [](2, 15), [](2, 16), [](2, 17), [](3, 15), [](3, 16), [](3, 17))) 
    
    
  • - should be possible to filter output [ show source ]
    for(x <-(1 ..(100)), x <(5), x) should ==([](1, 2, 3, 4)) 
    for(x <-(1 ..(10)), (x %(2)) ==(0), x) should ==([](2, 4, 6, 8, 10)) 
    
    
  • - should be possible to do midlevel assignment [ show source ]
    for(x <-(1 ..(20)), y = x *(2), y <(10), [](x, y)) should ==([]([](1, 2), [](2, 4), [](3, 6), [](4, 8))) 
    
    
  • - should be possible to combine these parts into a larger comprehension [ show source ]
    for(x <-(0 ..(10)), x *(x) >(3), 2 *(x)) should ==([](4, 6, 8, 10, 12, 14, 16, 18, 20)) 
    for(x <-(1 ..(6)), y <-(x ..(6)), z <-(y ..(6)), (x **(2) +(y **(2))) ==(z **(2)), [](x, y, z)) should ==([]([](3, 4, 5))) 
    
    
for:dict(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "map:dict", "flatMap:dict") 
  )
DefaultBehavior FlowControl for:dict
  • - should handle a simple iteration [ show source ]
    for:dict(x <-([](1, 2, 3)), x =>(x *(x))) should ==(dict(1 =>(1), 2 =>(4), 3 =>(9))) 
    for:dict(x <-([](1, 2, 3, 1, 2, 3)), x =>(x *(x))) should ==(dict(1 =>(1), 2 =>(4), 3 =>(9))) 
    for:dict(x <-(1 ..(10)), x) should ==(dict(1 =>(nil), 2 =>(nil), 3 =>(nil), 4 =>(nil), 5 =>(nil), 6 =>(nil), 7 =>(nil), 8 =>(nil), 9 =>(nil), 10 =>(nil))) 
    for:dict(x <-(set(:a, :b, :c)), x =>(x asText)) should ==(dict(a: "a", b: "b", c: "c")) 
    
    
  • - should handle more than one generator [ show source ]
    for:dict(x <-([](1, 2, 3)), y <-([](10, 11, 12)), x *(y) =>([](x, y))) should ==({}(10 =>([](1, 10)), 11 =>([](1, 11)), 12 =>([](1, 12)), 20 =>([](2, 10)), 22 =>([](2, 11)), 24 =>([](2, 12)), 30 =>([](3, 10)), 33 =>([](3, 11)), 36 =>([](3, 12)))) 
    
    
for:set(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "map:set", "flatMap:set") 
  )
DefaultBehavior FlowControl for:set
  • - should handle a simple iteration [ show source ]
    for:set(x <-([](1, 2, 3)), x) should ==(set(1, 2, 3)) 
    for:set(x <-([](1, 2, 3, 1, 2, 3)), x) should ==(set(1, 2, 3)) 
    for:set(x <-(1 ..(10)), x) should ==(set(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) 
    for:set(x <-(set(:a, :b, :c)), x) should ==(set(:a, :b, :c)) 
    
    
  • - should be possible to do something advanced in the output part [ show source ]
    for:set(x <-(1 ..(10)), x *(2)) should ==(set(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)) 
    mex = method(f, f +(f) +(f)) 
    for:set(x <-(1 ...(5)), mex(x)) should ==(set(3, 6, 9, 12)) 
    
    
  • - should be possible to combine two or more iterations [ show source ]
    for:set(x <-([](1, 2, 3)), y <-([](15, 16, 17)), [](x, y)) should ==(set([](1, 15), [](1, 16), [](1, 17), [](2, 15), [](2, 16), [](2, 17), [](3, 15), [](3, 16), [](3, 17))) 
    
    
  • - should be possible to filter output [ show source ]
    for:set(x <-(1 ..(100)), x <(5), x) should ==(set(1, 2, 3, 4)) 
    for:set(x <-(1 ..(10)), (x %(2)) ==(0), x) should ==(set(2, 4, 6, 8, 10)) 
    
    
  • - should be possible to do midlevel assignment [ show source ]
    for:set(x <-(1 ..(20)), y = x *(2), y <(10), [](x, y)) should ==(set([](1, 2), [](2, 4), [](3, 6), [](4, 8))) 
    
    
  • - should be possible to combine these parts into a larger comprehension [ show source ]
    for:set(x <-(0 ..(10)), x *(x) >(3), 2 *(x)) should ==(set(4, 6, 8, 10, 12, 14, 16, 18, 20)) 
    for:set(x <-(1 ..(6)), y <-(x ..(6)), z <-(y ..(6)), (x **(2) +(y **(2))) ==(z **(2)), [](x, y, z)) should ==(set([](3, 4, 5))) 
    
    
if(condition, [then] nil, [else] nil)

evaluates the first arguments, and then evaluates the second argument if the result was true, otherwise the last argument. returns the result of the call, or the result if it's not true.

let([code], +[placesAndValues])

takes zero or more place and value pairs and one code argument, establishes a new lexical scope and binds the places to the values given. if the place is a simple name, it will just be created as a new binding in the lexical scope. if it is a place specification, that place will be temporarily changed - but guaranteed to be changed back after the lexical scope is finished. the let-form returns the final result of the code argument.

DefaultBehavior FlowControl let
  • - should take a code argument, apply that on the current ground and return the result [ show source ]
    let(40 +(2)) should ==(42) 
    
    
  • - should establish a new lexical scope inside [ show source ]
    let(non_existing_let_binding = 42) 
    cell?(:non_existing_let_binding) should be false 
    
    
  • - should take zero or more name-value pairs [ show source ]
    let(42) 
    let(x, 42, x) 
    let(
      x, 42, 
      y, 43, 
      x +(y)) 
    
    
  • - should bind a simple name to a value [ show source ]
    let(probably_not_existing_name, 42, 
      probably_not_existing_name *(2)) should ==(84) 
    
    
  • - should shadow an existing name [ show source ]
    wow_this_is_a_test = 42 
    let(wow_this_is_a_test, 43, wow_this_is_a_test) should ==(43) 
    wow_this_is_a_test should ==(42) 
    
    
  • - should rebind a place specification during the time of the code running [ show source ]
    Text fluxie = Origin mimic 
    Text fluxie wowsie = 13 
    let(
      Text fluxie wowsie, 14, 
      "foo" fluxie wowsie) should ==(14) 
    Text fluxie wowsie should ==(13) 
    
    
  • - should unbind places even if a non-local transfer happens [ show source ]
    Text fluxie2 = Origin mimic 
    Text fluxie2 wowsie = 13 
    bind(rescue(Condition Error, fn(c, nil)), 
      let(
        Text fluxie2 wowsie, 14, 
        "foo" fluxie2 wowsie should ==(14) 
        error!("non-local yay!"))) 
    Text fluxie2 wowsie should ==(13) 
    
    
  • - should bind a new place temporarily, and then remove it [ show source ]
    X = Origin mimic 
    let(X testOfLetMethod, method(42), 
      X testOfLetMethod should ==(42) 
      ) 
    X cellNames should not include(:testOfLetMethod) 
    
    
  • - should bind a new place with cell temporarily, and then remove it [ show source ]
    X = Origin mimic 
    let(X cell(:testOfLetMethod2), method(42), 
      X testOfLetMethod2 should ==(42) 
      ) 
    X cellNames should not include(:testOfLetMethod2) 
    
    
loop(+[body])

loops forever - executing it's argument over and over until interrupted in some way.

p:for(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "p:map", "p:flatMap") 
  )
p:for:dict(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "p:map:dict", "p:flatMap:dict") 
  )
p:for:set(...)

nil

syntax(
  DefaultBehavior FlowControl cell(:for) transform(call arguments, "p:map:set", "p:flatMap:set") 
  )
return(value nil)

returns from the enclosing method/macro. if an argument is supplied, this will be returned as the result of the method/macro breaking out of.

unless(condition, [then] nil, [else] nil)

evaluates the first arguments, and then evaluates the second argument if the result was false, otherwise the last argument. returns the result of the call, or the result if it's true.

until([condition] nil, +[body])

until the first argument evaluates to something true, loops and evaluates the next argument

while([condition] nil, +[body])

while the first argument evaluates to something true, loops and evaluates the next argument

with(...)

takes any number of keyword arguments, followed by an optional code argument. will first create a new mimic of the receiver, then evaluate all the keyword arguments in order and set cells corresponding to the names of these keyword arguments to the evaluated arguments. if a code argument is supplied, it will be evaluated in the context of the newly created object, using something similar to 'do'. returns the created object.

macro(
  newObject = mimic 
  call arguments each(arg, 
    if(arg keyword?, 
      Reflector other:cell(newObject, arg name asText [](0 ..(0 -(2)))) = arg next evaluateOn(call ground), 
      newObject doMessage(arg))) 
  newObject)