יצירת JavaScript והרצה שלו

אפליקציות Blockly יוצרות בדרך כלל JavaScript כשפת הפלט שלהן, בדרך כלל כדי להריץ את הקוד בדף אינטרנט (יכול להיות שאותו דף או WebView מוטמע). כמו בכל מחולל, השלב הראשון הוא לכלול את מחולל JavaScript.

import {javascriptGenerator} from 'blockly/javascript';

כדי ליצור JavaScript מסביבת העבודה, קוראים ל-:

javascriptGenerator.addReservedWords('code');
var code = javascriptGenerator.workspaceToCode(workspace);

אפשר להריץ את הקוד שנוצר ישירות בדף האינטרנט של היעד:

try {
  eval(code);
} catch (e) {
  alert(e);
}

בעיקרון, קטע הקוד שלמעלה יוצר את הקוד ומעריך אותו. עם זאת, יש כמה שיפורים. שיפור אחד הוא שה-eval עטוף ב-try/catch כדי שכל שגיאות זמן הריצה יהיו גלויות, במקום להיכשל בשקט. שיפור נוסף הוא ש-code מתווסף לרשימת המילים המיוחדות, כך שאם הקוד של המשתמש מכיל משתנה בשם הזה, השם שלו ישתנה באופן אוטומטי במקום שיהיה התנגש. צריך להקצות משתנים מקומיים באופן הזה.

'הדגשת קטעים'

הדגשת הבלוק שפועל כרגע בזמן הרצת הקוד עוזרת למשתמשים להבין את ההתנהגות של התוכנית. אפשר להדגיש משפטים ספציפיים על ידי הגדרת STATEMENT_PREFIX לפני יצירת קוד ה-JavaScript:

javascriptGenerator.STATEMENT_PREFIX = 'highlightBlock(%1);\n';
javascriptGenerator.addReservedWords('highlightBlock');

מגדירים את highlightBlock כדי לסמן את הבלוק בסביבת העבודה.

function highlightBlock(id) {
  workspace.highlightBlock(id);
}

כתוצאה מכך, ההצהרה highlightBlock('123'); תתווסף לפני כל הצהרה, כאשר 123 הוא המספר הסידורי של הבלוק שרוצים להדגיש.

לולאות אינסופיות

הקוד שייווצר יהיה תמיד תקין מבחינה תחבירית, אבל הוא עשוי לכלול לולאות אינסופיות. מכיוון שפתרון בעיית ההפסקה חורג מהיקף Blockly (!), הגישה הטובה ביותר לטיפול במקרים כאלה היא לשמור על מונה ולהפחית אותו בכל פעם שמתבצעת חזרה. כדי לעשות זאת, צריך להגדיר את javascriptGenerator.INFINITE_LOOP_TRAP לקטע קוד שיתווסף לכל לולאה וכל פונקציה. דוגמה:

window.LoopTrap = 1000;
javascriptGenerator.INFINITE_LOOP_TRAP = 'if(--window.LoopTrap == 0) throw "Infinite loop.";\n';
var code = javascriptGenerator.workspaceToCode(workspace);

דוגמה

הדגמה חיה של יצירת JavaScript והרצה שלו.

JS-Interpreter

אם אתם רוצים להריץ את הבלוקס של המשתמש בצורה תקינה, הפרויקט JS-Interpreter הוא הפתרון בשבילכם. הפרויקט הזה נפרד מ-Blockly, אבל נכתב במיוחד עבור Blockly.

  • ביצוע קוד בכל מהירות.
  • השהיה/המשך/ביצוע מדורג.
  • הדגשת בלוקים בזמן ההפעלה שלהם.
  • מבודד לחלוטין מ-JavaScript של הדפדפן.

הרצת המתורגמן

קודם כול, מורידים את JS-Interpreter מ-GitHub:

הורדת קובץ ZIP הורדת קובץ TAR Ball צפייה ב-GitHub

לאחר מכן מוסיפים אותו לדף:

<script src="acorn_interpreter.js"></script>

הדרך הפשוטה ביותר להפעיל אותו היא ליצור את ה-JavaScript, ליצור את המתורגם ולהריץ את הקוד:

var code = javascriptGenerator.workspaceToCode(workspace);
var myInterpreter = new Interpreter(code);
myInterpreter.run();

איך להפעיל את התרגום הסימולטני

כדי להריץ את הקוד לאט יותר או בצורה מבוקרת יותר, מחליפים את הקריאה ל-run בלולאה שמבצעת שלבים (במקרה הזה שלב אחד כל 10 אלפיות השנייה):

function nextStep() {
  if (myInterpreter.step()) {
    setTimeout(nextStep, 10);
  }
}
nextStep();

חשוב לזכור שכל שלב הוא לא שורה או בלוק, אלא יחידה סמנטית ב-JavaScript, שיכולה להיות מאוד מפורטת.

הוספת ממשק API

JS-Interpreter הוא ארגז חול שמבודד לחלוטין מהדפדפן. כדי לבצע פעולות בעולם החיצון, צריך להוסיף ממשק API למפרש. תיאור מלא זמין במסמכי התיעוד של JS-Interpreter. אבל קודם כול, זהו ה-API שנחוץ כדי לתמוך בבלוק ההתראות ובבלוק ההנחיות:

function initApi(interpreter, globalObject) {
  // Add an API function for the alert() block.
  var wrapper = function(text) {
    return alert(arguments.length ? text : '');
  };
  interpreter.setProperty(globalObject, 'alert',
      interpreter.createNativeFunction(wrapper));

  // Add an API function for the prompt() block.
  wrapper = function(text) {
    return prompt(text);
  };
  interpreter.setProperty(globalObject, 'prompt',
      interpreter.createNativeFunction(wrapper));
}

לאחר מכן משנים את האתחול של המפרש כך שיעבירו את הפונקציה initApi:

var myInterpreter = new Interpreter(code, initApi);

הבלוק של ההתראה והבלוק של ההנחיה הם שני הבלוקים היחידים בקבוצת ברירת המחדל של הבלוקים שנדרש להם ממשק API מותאם אישית למתורגם.

מתבצע חיבור אל highlightBlock()

כשהקוד פועל במתורגם JS, הפונקציה highlightBlock() צריכה להתבצע באופן מיידי, מחוץ לארגז החול, כשהמשתמש עובר על התוכנית. כדי לעשות זאת, יוצרים פונקציית עטיפה highlightBlock() כדי לתעד את הארגומנט של הפונקציה, ומרשמים אותה כפונקציה מקומית.

function initApi(interpreter, globalObject) {
  // Add an API function for highlighting blocks.
  var wrapper = function(id) {
    return workspace.highlightBlock(id);
  };
  interpreter.setProperty(globalObject, 'highlightBlock',
      interpreter.createNativeFunction(wrapper));
}

באפליקציות מתוחכמות יותר, יכול להיות שתרצו לבצע שלבים שוב ושוב ללא השהיה עד שתגיעו לפקודת הדגשה, ואז להשהות. האסטרטגיה הזו מדמה ביצוע שורה אחר שורה. בדוגמה הבאה נעשה שימוש בגישה הזו.

דוגמה למתורגם JS

הדגמה חיה של פרשנות JavaScript שלב אחרי שלב. בדמו הזה מופיע גם בלוק המתנה, דוגמה טובה לשימוש בהתנהגות אסינכררונית אחרת (למשל, דיבור או אודיו, קלט של משתמש).