تولید و اجرای جاوا اسکریپت

برنامه های بلاکی اغلب جاوا اسکریپت را به عنوان زبان خروجی خود تولید می کنند، معمولاً برای اجرا در یک صفحه وب (احتمالاً همان یا یک WebView تعبیه شده). مانند هر مولد دیگری، اولین قدم شامل مولد جاوا اسکریپت است.

import {javascriptGenerator} from 'blockly/javascript';

برای تولید جاوا اسکریپت از فضای کاری، تماس بگیرید:

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

کد به دست آمده را می توان درست در صفحه وب مقصد اجرا کرد:

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

اساسا، قطعه بالا فقط کد را تولید می کند و آن را ارزیابی می کند. با این حال، چند اصلاح وجود دارد. یکی از اصلاحات این است که eval در یک try / catch پیچیده می‌شود تا خطاهای زمان اجرا قابل مشاهده باشند، به جای اینکه بی‌صدا از کار بیفتند. اصلاح دیگر این است که code به لیست کلمات رزرو شده اضافه می شود تا اگر کد کاربر حاوی متغیری به آن نام باشد، به جای برخورد به طور خودکار تغییر نام داده شود. هر متغیر محلی باید به این روش رزرو شود.

بلوک ها را برجسته کنید

برجسته کردن بلوک در حال اجرا در حین اجرای کد به کاربران کمک می کند تا رفتار برنامه خود را درک کنند. برجسته کردن ممکن است در سطح بیانیه به بیانیه با تنظیم STATEMENT_PREFIX قبل از تولید کد جاوا اسکریپت انجام شود:

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

برای علامت گذاری بلوک در فضای کاری، highlightBlock را تعریف کنید.

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

این منجر به عبارت highlightBlock('123'); قبل از هر عبارت به آن اضافه می شود، جایی که 123 شماره سریال بلوکی است که باید برجسته شود.

حلقه های بی نهایت

اگرچه کد حاصل تضمین شده است که همیشه از نظر نحوی صحیح است، ممکن است حاوی حلقه های بی نهایت باشد. از آنجایی که حل مشکل Halting خارج از محدوده 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);

مثال

در اینجا یک نسخه آزمایشی زنده از تولید و اجرای جاوا اسکریپت است.

JS-Interpreter

اگر در مورد اجرای صحیح بلوک های کاربر جدی هستید، پروژه JS-Interpreter راه حلی است. این پروژه جدا از Blockly است، اما به طور خاص برای Blockly نوشته شده است.

  • کد را با هر سرعتی اجرا کنید.
  • مکث/ازسرگیری/اجرای مرحله به مرحله.
  • بلوک ها را هنگام اجرا برجسته کنید.
  • به طور کامل از جاوا اسکریپت مرورگر جدا شده است.

مترجم را اجرا کنید

ابتدا JS-Interpreter را از GitHub دانلود کنید:

Download ZIP FileDownload TAR BallView On GitHub

سپس آن را به صفحه خود اضافه کنید:

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

ساده ترین روش فراخوانی آن، تولید جاوا اسکریپت، ایجاد مفسر و اجرای کد است:

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

مترجم را کنار بگذارید

برای اینکه کد را کندتر یا به شیوه ای کنترل شده تر اجرا کنید، تماس را با حلقه ای جایگزین کنید که مراحل آن run (در این مورد هر 10 میلی ثانیه یک مرحله):

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

توجه داشته باشید که هر مرحله یک خط یا یک بلوک نیست، بلکه یک واحد معنایی در جاوا اسکریپت است که ممکن است بسیار ظریف باشد.

یک 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-Interpreter، highlightBlock() باید بلافاصله در خارج از جعبه شنی اجرا شود، همانطور که کاربر از برنامه عبور می کند. برای انجام این کار، یک تابع wrapper 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-Interpreter

در اینجا یک نسخه آزمایشی زنده از تفسیر گام به گام جاوا اسکریپت وجود دارد. و این نسخه نمایشی شامل یک بلوک انتظار است، یک مثال خوب برای استفاده برای سایر رفتارهای ناهمزمان (به عنوان مثال، گفتار یا صدا، ورودی کاربر).