• I have a nested while construct to find a value found in a source array to be within a destination array. When found want to break out from both loops. But it throws an error on the break statement in the outer loop. Could this be an error or do I miss something?

    I am using Espruino 1v99 on a ESP2866

    Here is the code:

    var oWifi = require('Wifi');
    oWifi.scan(function(aAp) {
      aAp.sort(function(a, b) {
        var r = a.rssi === b.rssi ? 0 : (a.rssi < b.rssi ? 1 : -1);
        return r;
      });
      console.log(aAp);
      var i=0, k=0, foundMy=false;
      while (i<aAp.length) {
        foundMy = false;
        while (k<aMyAp.length) {
          if (aAp[i].ssid === aMyAp[i].ssid) {
            foundMy = true;
            break;
          }
          k++;
        }
        if (foundMy) {
          break;  <--- Uncaught SyntaxError: BREAK statement outside of SWITCH, FOR or WHILE loop
        }
        i++;
      }
      if (foundMy) {
        oWifi.connect(aMyAp[k].ssid, {password: aMyAp[k].pwd}, function(err) {
          if (err===null) {
             console.log('Connection success to:', aMyAp[k].ssid);
          }
        });
      } else {
        console.log('no Ap found');
      }
    });
    
  • Mon 2018.10.01

    re: 'Could this be an error or do I miss something?'

    Hello @user94507, your post is timely. I just experienced the same error within a nested for loop only an hour ago. e.g. two for loops. Break in same position just after the nested inside loop. You have saved me the effort of creating this original post.

    1v99 on an authentic Pico

  • Give this a shot:

     var oWifi = require('Wifi');
    oWifi.scan(function(aAp) {
      aAp.sort(function(a, b) {
        var r = a.rssi === b.rssi ? 0 : (a.rssi < b.rssi ? 1 : -1);
        return r;
      });
      console.log(aAp);
      var i=0, k, foundMy;
      while (!foundMy && i<aAp.length) {
        k = 0; // <---- restart k IN outer loop... only once outside is not enough
        while (!foundMy && k<aMyAp.length) {
          if (aAp[i].ssid === aMyAp[k].ssid) { // <---- compare [i] w/ [k]
            foundMy = aMyAp[k];                //          ...and not [i] w/ [i] 
          }
          k++;
        }
        i++;
      }
      if (foundMy) {
        oWifi.connect(foundMy.ssid, {password: foundMy.pwd}, function(err) {
          if (err===null) {
             console.log('Connection success to:', foundMy.ssid);
          }
        });
      } else {
        console.log('no Ap found');
      }
    });
    

    ...there were obviously also some other issues... - see // <---- comments - were there?

    What is the sort helping with? ...do you have duplicate ssid in scan result and want only the one to match w/ highest rssi value?

    (Since labels are bad in general and worst in compiler free environment - as Espruino - in regard of nested control management, labels are not implemented in Espruino. Why though the simple, one-level break is not working... I don't know).

  • Actually I just tried this:

      while (true) {
        while (true) {
          if (true) {
            break;
          }
        }
        if (true) break;
      }
    

    And it breaks on 1v99 but works on cutting edge - so I'd just update your firmware. I will do a proper numbered release this week anyway hopefully.

    With the new firmware you also have the option of using Array.find, but Array.filter exists in the 1v99 build and might tidy this up nicely as well.

    Not tested, but you get the idea:

    var matches = aAp.filter(function(ap) {
      return aMyAp.filter(myAp=>ap.ssid==myAp.ssid).l­ength;
    });
    if (matches.length) // connect with matches[0]
    
  • Thanks for your tips, you are right there are some other issues. I came not across this yet because I got this compilation error which was irritating me. The mentioned error message does not go away, even with the corrected code. Of course I can remove the the breaks, but the code is not efficient because it does not stop looping when the correct record is found.

  • @user94507, including !foundMy in both while-loop conditions leaves for sure the loops at the moment the very first match is found... no need for the breaks, even though they work... --- because I cannot find the tool/context that produces this error... are you using some preprocessor/xcompiler/transpiler etc? Your code - even though logically broken - is JS syntactically absolute correct...

    @Gordon, neat, it's like a find all, where @user94507 was looking for a find first. With the built-in Array.filter() I'm sure that with the expected array sizes it's still orders faster, and has the additional benefit of saving Espruino variables (code space in RAM).

  • @allObjects ah ya! i have overseen this in your suggestion! Brilliant! The way around beak is perfect. Thank you.

    @Gordon I have tried using the function Array.filter() replacing the inner loop. This works although I must pass a parameter to this function and so the Web Ide warns me "don't use a function within a loop".
    By the way Array.find() is not implemented yet which would have been my favorite choice.

  • @user94507, this should work too - notice the switching of inner w/ outer loop.

    // findFirstInArrWForEach.js
    // @user94507 - 20181002
    
    function findFirstIn(arr,matcher) { 
      var r; arr.forEach(function(elt){ 
        if (!r && matcher(elt)) r = elt; });
      return r; }
    
    function findMyAp(aAp,aMyAp) {
      var myAp;
      findFirstIn(aAp,function(elt){
        myAp = myAp || findFirstIn(aMyAp,function(elt2){
          return elt.ssid == elt2.ssid; });
        return myAp; });
      return myAp; }
    
    var oWifi = require('Wifi'), myAp;
     
    oWifi.scan(function(aAp) {
        aAp.sort(function(a,b){return a.rssi===b.rssi?0:(a.rssi<b.rssi?1:-1);}­);
        if ((myAp = findMyAp(aAp,aMyAp))) {
          oWifi.connect(myAp.ssid, {password: myAp.pwd}, function(err) {
              if (err===null) {
                console.log('Connection success to:', myAp.ssid);
              } else {
                console.log('Connect error: ',err);
              }
            });
        } else {
          console.log('no Ap found');
        }
      });
    

    It still loops through all elements of the outer array (aMyAP[]), but stops comparing and looping through though the inner array (aAP[]) on first find (match).

    Both the matcher() functions return true, but truthy is enough, and therefore it would be sufficient to just return my2 ;

    If you do not like the looping through the first one and have even the optional telling where to start looping including handling of undefined and null arrays, you can use this findFirstIn(arr,mchr,strt) function (It was part of my survival kit w/ JS 1.2,..):

    findFirstIn(arr, mchr, strt, endx):

    • arr is the array to search in
    • mchr function taking array element as argument and return true on match, else false
    • strt is optional search start index, defaults to 0 when ommitted
    • endx is optional search end index exclusive, defaults to arr.length

    returns first element for which 'mchr(element)' return true, else undefined
    Note: does not help to find 'undefined' elements in array ;-)

    function findFirstIn(arr,mchr,strt,endx) {
      var i = ((strt) ? strt : 0)-1, m = ((arr) ? (endx) ? endx : arr.length : 0)-1;
      while (i<m) if (mchr(arr[++i])) return arr[i]; return undefined; }
    
  • And here is the test... (cannot stand code that has not been tested or at least has run once...).

    // findFirstInArrWForEachTest.js
    // @user94507 - 20181002
    
    var lg = false; // log to console
    var scanSetIdx = 1; // 1 finds, 0 does not find Ap in aMyAp
    function js(o) { return JSON.stringify(o); }
    
    function findFirstIn(arr,matcher) { 
      var r; arr.forEach(function(elt){ 
        if (lg) console.log("LX:",js(elt));
        if (!r && matcher(elt)) r = elt; });
      return r; }
    
    function findMyAp(aAp,aMyAp) {
      var myAp;
      findFirstIn(aAp,function(elt){
        myAp = myAp || findFirstIn(aMyAp,function(elt2){
          if (lg) console.log("LXX:",js(elt),js(elt2),elt.­ssid == elt2.ssid);
          return elt.ssid == elt2.ssid; });
        return myAp; });
      return myAp; }
    
    // mocking aMyAp, oWifi w/ aAp scan result and test/validation
    
    var aMyAp = // test data for myAps as provided before scanning for Aps
      [ { ssid:"sWW", pwd:"pWW" }
      , { ssid:"sXX", pwd:"pXX" }
      , { ssid:"sYY", pwd:"pYY" }
      ];
        
    var /* oWifi = require('Wifi'),*/  myAp;
    var oWifi =
      { aAp: // test data for aAp as scanned from oWifi
         [ [ { rssi:"rHB", ssid:"sNN" } // w/o myAp
           , { rssi:"rHC", ssid:"sQC" }
           , { rssi:"rUP", ssid:"sSS" }
           , { rssi:"rUQ", ssid:"sBQ" }
           ]
         , [ { rssi:"rAB", ssid:"sWW" } // w/ myAp
           , { rssi:"rAC", ssid:"sAC" }
           , { rssi:"rNP", ssid:"sXX" }
           , { rssi:"rNQ", ssid:"sPQ" }
           ]
         ]
       , scan: function(cb) {
           cb(this.aAp[scanSetIdx]);
         }
       , connect: function(ssid, options, cb) {
           var err = ((ssid == "sXX") && (options.password == "pXX"))
             ? null
             : "No matching ssid and password";
           cb(err);
         }
      };
     
    
    oWifi.scan(function(aAp) {
        if (lg) console.log("L1 ---(scanned):", aAp);
        aAp.sort(function(a,b){return a.rssi===b.rssi?0:(a.rssi<b.rssi?1:-1);}­);
        if (lg) console.log("L2 ---(sorted):", aAp);
        if ((myAp = findMyAp(aAp,aMyAp))) {
          if (lg) console.log("L3 ---(found):",js(myAp));
          oWifi.connect(myAp.ssid, {password: myAp.pwd}, function(err) {
              if (err===null) {
                console.log('Connection success to:', myAp.ssid);
              } else {
                console.log('Connect error: ',err);
              }
            });
        } else {
          console.log('no Ap found');
        }
      });
    

    Code executes immediately on upload... since it is in level 0... not recommended (by me, especially not when it contains some async / callback and communication stuff, like connect to AP / Wifi)... all level 0 code - code that is executed on uploade / on reception by the Espruino board should always all go into an appInit() method that is called from the onInit() method. But in this (test code) case, it works... at least my (1v3 HW Version) PICO.

    You can play with the scanSetIdx values 1 and 0, and of course with the 'test' data in mocked oWifi and in level 0 (aMyAp).

    If you want to track visually what is going on, set lg = true; to log in console:

    >
     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     1v99 (c) 2018 G.Williams
    >L1 ---(scanned): [
      {
        "rssi": "rAB",
        "ssid": "sWW"
       },
      {
        "rssi": "rAC",
        "ssid": "sAC"
       },
      {
        "rssi": "rNP",
        "ssid": "sXX"
       },
      {
        "rssi": "rNQ",
        "ssid": "sPQ"
       }
     ]
    L2 ---(sorted): [
      {
        "rssi": "rNQ",
        "ssid": "sPQ"
       },
      {
        "rssi": "rNP",
        "ssid": "sXX"
       },
      {
        "rssi": "rAC",
        "ssid": "sAC"
       },
      {
        "rssi": "rAB",
        "ssid": "sWW"
       }
     ]
    LX: {"rssi":"rNQ","ssid":"sPQ"}
    LX: {"ssid":"sWW","pwd":"pWW"}
    LXX: {"rssi":"rNQ","ssid":"sPQ"} {"ssid":"sWW","pwd":"pWW"} false
    LX: {"ssid":"sXX","pwd":"pXX"}
    LXX: {"rssi":"rNQ","ssid":"sPQ"} {"ssid":"sXX","pwd":"pXX"} false
    LX: {"ssid":"sYY","pwd":"pYY"}
    LXX: {"rssi":"rNQ","ssid":"sPQ"} {"ssid":"sYY","pwd":"pYY"} false
    LX: {"rssi":"rNP","ssid":"sXX"}
    LX: {"ssid":"sWW","pwd":"pWW"}
    LXX: {"rssi":"rNP","ssid":"sXX"} {"ssid":"sWW","pwd":"pWW"} false
    LX: {"ssid":"sXX","pwd":"pXX"}
    LXX: {"rssi":"rNP","ssid":"sXX"} {"ssid":"sXX","pwd":"pXX"} true
    LX: {"ssid":"sYY","pwd":"pYY"}
    LX: {"rssi":"rAC","ssid":"sAC"}
    LX: {"rssi":"rAB","ssid":"sWW"}
    L3 ---(found): {"ssid":"sXX","pwd":"pXX"}
    Connection success to: sXX
    =undefined
    >
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Uncaught SyntaxError: BREAK statement outside of SWITCH, FOR or WHILE loop

Posted by Avatar for fanThomas @fanThomas

Actions