From 828a8411f505564cc232fbde2103a98028230d4c Mon Sep 17 00:00:00 2001 From: Ben Davies Date: Sat, 9 Mar 2019 12:47:08 -0400 Subject: [PATCH] Document control flow in the JS nutshell --- doc/Language/js-nutshell.pod6 | 256 ++++++++++++++++++++++++++++++++-- 1 file changed, 246 insertions(+), 10 deletions(-) diff --git a/doc/Language/js-nutshell.pod6 b/doc/Language/js-nutshell.pod6 index 29296e226..828e7ff9c 100644 --- a/doc/Language/js-nutshell.pod6 +++ b/doc/Language/js-nutshell.pod6 @@ -337,7 +337,7 @@ multi sub infix:<||=>($a, $b) is equiv(&infix:<+=>) { $a || $b } my $foo = 0; $foo ||= 1; -say $foo; # 1 +say $foo; # OUTPUT: 1 =end code Operators can be defined as C, C, or C. The @@ -356,28 +356,264 @@ us to override any native operator we want: multi sub prefix:<++>($a) is default { $a - 1 } my $foo = 1; -say ++$foo; # 0 +say ++$foo; # OUTPUT: 0 =end code -=head2 Conditionals +=head2 Control flow -=comment TODO +=head3 if/else -# TBD +You should be familiar with how C/C looks in JavaScript: -=head2 Control flow +=begin code :lang +let diceRoll = Math.ceil(Math.random() * 6) + Math.ceil(Math.random() * 6); +if (diceRoll === 2) { + console.log('Snake eyes!'); +} else if (diceRoll === 16) { + console.log('Boxcars!'); +} else { + console.log(`Rolled ${diceRoll}.`); +} +=end code -=comment TODO +In Perl 6, C/C works largely the same, with a few key differences. +One, parentheses are not required. Two, C is written as C. +Three, the if clause may be written I a statement: -# TBD +=begin code +my Int $dice-roll = ceiling rand * 12 + ceiling rand * 12; +if $dice-roll == 2 { + say 'Snake eyes!'; +} elsif $dice-roll == 16 { + say 'Boxcars!'; +} else { + say "Rolled $dice-roll."; +} +=end code -=head2 Functions +Alternatively, though less efficient, this could be written to use C after +statements: + +=begin code +my Int $dice-roll = ceiling rand * 12 + ceiling rand * 12; +say 'Snake eyes!' if $dice-roll == 2; +say 'Boxcars!' if $dice-roll == 16; +say "Rolled $dice-roll." if $dice-roll !~~ 2 | 16; +=end code + +Perl 6 also has C, which is like C, but if the condition given is +true, no code past the C block within the block it's in is executed: + +=begin code +{ + when True { + say 'In when block!'; # OUTPUT: In when block! + } + say 'This will never be output!'; +} +=end code + +Additionally, Perl 6 has C, C, and C, which are like +C, C, and C respectively, but instead of checking whether +their condition is true, they check if it's defined. + +=head3 switch + +Switch statements are a way of checking for equality between a given value and +a list of values and run some code if one matches. C statements define +each value to compare to. C, if included, acts as a fallback for when +the given value matches no cases. After matching a case, C is typically +used to prevent the code from the cases that follow the one matched from being +executed, though rarely this is intentionally omitted. + +=begin code :lang +const ranklist = [2, 3, 4, 5, 6, 7, 8, 9, 'Jack', 'Queen', 'King', 'Ace']; +const ranks = Array.from(Array(3), () => ranklist[Math.floor(Math.random() * ranks.length)]); +let score = 0; + +for (let rank of ranks) { + switch (rank) { + case 'Jack': + case 'Queen': + case 'King': + score += 10; + break; + case 'Ace'; + score += (score <= 11) ? 10 : 1; + break; + default: + score += rank; + break; + } +} +=end code + +In Perl 6, C can be used like switch statements. There is no equivalent +to C since C blocks are most commonly used like C +statements. One major difference between C and C is that a value +passed to a C statement will only match cases that are exactly equal to +the value; C values are smart matched (C<~~>) against the C values. + +=begin code +my @ranklist = [2, 3, 4, 5, 6, 7, 8, 9, 'Jack', 'Queen', 'King', 'Ace']; +my @ranks = @ranklist.pick: 3; +my Int $score = 0; + +for @ranks -> $rank { + # The when blocks implicitly return the last statement they contain. + $score += do given $rank { + when 'Jack' | 'Queen' | 'King' { 10 } + when 'Ace' { $score <= 11 ?? 10 !! 1 } + default { $_ } + }; +} +=end code + +If there are multiple C blocks that match the value passed to C +and you wish to run more than one of them, use C. C may be +used to exit both the C block it's in and the given block, preventing any +following statements from being executed: + +=begin code +given Int { + when Int { say 'Int is Int'; proceed } + when Numeric { say 'Int is Numeric'; proceed } + when Any { say 'Int is Any'; succeed } + when Mu { say 'Int is Mu' } # Won't output +} + +# OUTPUT: +# Int is Int +# Int is Numeric +# Int is Any +=end code + +=head3 for, while, and do/while + +There are three different types of for loops in JavaScript: + +=begin code :lang +// C-style for loops +const letters = {}; +for (let ord = 0x61; ord <= 0x7A; ord++) { + let letter = String.fromCharCode(ord); + letters[letter] = letter.toUpperCase(); +} + +// for..in loops (typically used on objects) +for (let letter in letters) { + console.log(letters[letter]); + # OUTPUT: + # A + # B + # C + # etc. +} + +// for..of loops (typically used on arrays, maps, and sets) +for (let letter of Object.values(letters)) { + console.log(letter); + # OUTPUT: + # A + # B + # C + # etc. +} +=end code + +Perl 6 C loops most closely resemble C loops, since they work on +anything as long as it's iterable. C-style loops are possible to write using +C, but this is discouraged since they're better written as C loops +using ranges. Like C statements, C may follow a statement, with the +current iteration being accessible using the C<$_> variable (known as "it"). +Methods on C<$_> may be called without specifying the variable: + +=begin code +my Str %letters{Str}; +%letters{$_} = .uc for 'a'..'z'; +.say for %letters.values; +# OUTPUT: +# A +# B +# C +# etc. +=end code + +C loops work identically between JavaScript and Perl 6. Perl 6 also has +C loops, where instead of iterating until the given condition is false, +they iterate until the condition is true. + +C loops are known as C loops in Perl 6. Likewise with +C, C loops also exist and loop until the given condition +is false. + +To write infinite loops in Perl 6, use C rather than C or C. + +In JavaScript, C is used to skip to the next iteration in a loop, and +C is used to exit a loop early: + +=begin code :lang +let primes = new Set(); +let i = 2; + +do { + let isPrime = true; + for (let prime of primes) { + if (i % prime == 0) { + isPrime = false; + break; + } + } + if (!isPrime) continue; + primes.add(i); +} while (++i < 20); + +console.log(primes); # OUTPUT: Set { 2, 3, 5, 7, 11, 13, 17, 19 } +=end code + +In Perl 6, these are known as C and C respectively. There is also +C, which repeats the current iteration without evaluating the loop's +condition again. + +C/C/C statements may be followed by a label defined before an +outer loop to make the statement work on the loop the label refers to, rather +than the loop the statement is in: + +=begin code +my %primes is SetHash; +my Int $i = 2; + +OUTSIDE: +repeat { + next OUTSIDE if $i %% $_ for %primes.keys; + %primes{$i}++; +} while ++$i < 20; + +say %primes; # OUTPUT: SetHash(11 13 17 19 2 3 5 7) +=end code + +=head3 do + +C is not currently a feature in JavaScript, however a proposal has been made +to L. +C expressions evaluate a block and return the result: + +=begin code +constant VERSION = v2.0.0; +constant VERSION_NUMBER = do { + my @digits = VERSION.Str.comb(/\d+/); + :16(sprintf "%02x%02x%04x", |@digits) +}; +say VERSION_NUMBER; # OUTPUT: 33554432 +=end code + +=head2 Types =comment TODO # TBD -=head2 Types +=head2 Functions =comment TODO