NYCJUG/2013-12-10/UsingAPLtoWriteBrowserCode

From J Wiki
Jump to: navigation, search

Using APL to Write Browser Code

Here’s an example of a simple browser page (at http://home.comcast.net/~paul.l.jackson/APL.js/Hosting.html) written in APL:

EgAPLHostingFilledIn.jpg

The source for this consists of the following files:

File Size Description
Hosting.html 3,216 Top-level HTML that implements page.
APL\NameSpaces.js 16,441 APL functions
Hosting\apl.js 155,324 Javascript implementation of APL interpreter
Hosting\aplHosting.js 491 Sets up APL workspace upon loading of page

The HTML below pulls in the definitions of the APL functions with these lines:

    thisAPL = apl.ws()
    thisAPL(_LIB_["Dates"] + _LIB_["Numbers"])

The Roman number handling is done by this JavaScript code that simply calls the APL to do the more complex work:

    if (isRoman) {
	  if (aRoman.value.trim().length == 0) {return false}
	  // NB. fromRoman needs its argument in quotes
     aNumber.value = callAPL("fromRoman " + quote(aRoman.value))
	 } else {
	  if (aNumber.value.trim().length == 0) {return false}
	  aRoman.value = callAPL("toRoman " + aNumber.value)
	 }

Here’s the complete source code for the top-level HTML that implements the site; an example of the APL definitions is given after this.

<!DOCTYPE html>
<html><head>
 <meta charset="UTF-8">
 <title>APL.js Hosting Compiled</title>
 <script type="text/javascript" src="APL/NameSpaces.js"></script>
 <script type="text/javascript" src="Hosting/aplHosting.js"></script>
 <script type="text/javascript" src="Hosting/apl.js"></script>
 <script type="text/javascript">
  function initAPL() {
   if (thisAPL == null) {
    thisAPL = apl.ws()
    thisAPL(_LIB_["Dates"] + _LIB_["Numbers"])
   }
  }

  function runMonth(anEvent, aYear, aMonth, anOutput) {
   if (anEvent == null || anEvent.keyCode == 13) {
    myArg = aYear.value + " " + aMonth.value
	 if (myArg.trim().length == 0) {return false}
	 myResult = callAPL("month " + myArg)
	 anOutput.value = myResult
    return false
   }
  }

  function runDay(anEvent, aYear, aMonth, aDay, anOutput) {
   if (anEvent == null || anEvent.keyCode == 13) {
    myArg = aYear.value + " " + aMonth.value + " " + aDay.value
	 if (myArg.trim().length == 0) {return false}
	 anOutput.value = callAPL("day " + myArg)
    return false
   }
  }

  function runRoman(anEvent, isRoman, aNumber, aRoman, anEnglish) {
   if (anEvent == null || anEvent.keyCode == 13) {
    if (isRoman) {
	  if (aRoman.value.trim().length == 0) {return false}
	  // NB. fromRoman needs its argument in quotes
     aNumber.value = callAPL("fromRoman " + quote(aRoman.value))
	 } else {
	  if (aNumber.value.trim().length == 0) {return false}
	  aRoman.value = callAPL("toRoman " + aNumber.value)
	 }
    anEnglish.value = callAPL("toEnglish " + aNumber.value)
    return false
   }
  }
 </script>
</head><body onload="handleLoad(formHosting.textYear); initAPL()">
 <form name="formHosting" action="">
  <table border="0" cellspacing="0" cellpadding="0">
   <tr>
    <td>Year </td>
    <td>Month</td>
    <td> Day</td>
   </tr><tr>
    <td><input type="Text" name="textYear" size="4" /></td>
    <td><center><input type="Text" name="textMonth" size="2"
     onkeypress="return runMonth(event, textYear, textMonth, textCalendar)" /></center></td>
    <td><center><input type="Text" name="textDay" size="2"
	 onfocus="runMonth(null, textYear, textMonth, textCalendar)"
     onkeypress="return runDay(event, textYear, textMonth, textDay, textDate)" /></center></td>
    <td> is a
     <input type="Text" name="textDate" size="10"
	 onfocus="return runDay(null, textYear, textMonth, textDay, textDate)"
	 readOnly=true /></td>
   </tr>
  </table>
  <br />
  <textarea name="textCalendar" rows="8" cols="20"
   onfocus="showOutput(textOutput)"></textarea><p />

  <table border="0" cellspacing="0" cellpadding="0">
   <tr>
    <td>An Integer</td>
    <td>Roman Numerals</td>
   </tr><tr>
    <td><input type="Text" name="textNumber" size="20"
     onkeypress="return runRoman(event, false, textNumber, textRoman, textEnglish)" /></td>
    <td><input type="Text" name="textRoman" size="20"
	 onfocus="runRoman(null, false, textNumber, textRoman, textEnglish)"
     onkeypress="return runRoman(event, true, textNumber, textRoman, textEnglish)" /></td>
   </tr>
  </table>
  <input type="Text" name="textEnglish" size="42"
   onfocus="runRoman(null, true, textNumber, textRoman, textEnglish)"
   readOnly=true /><p />
</body></html>

Example APL Code

Here’s an example of the APL code called in the above HTML, from “Namespaces.js”:

_LIB_["Numbers"] = "get_help← {\n (⍪'Functions for displaying numbers:'\n   '   toEnglish   converts an integer to words' \n   '   fromRoman   converts a positive integer to Roman Numerals'\n   '   toRoman     converts from Roman Numerals to a number')\n}\n\nDigits← {\n ⍝ Expand three digits for toEnglish\n Number← 28 9⍴ '_________one______two______three____four_____five_____six______seven____eight____nine_____ten______eleven___twelve___thirteen_fourteen_fifteen__sixteen__seventeeneighteen_ninteen__twenty__-thirty__-forty___-fifty___-sixty___-seventy_-eighty__-ninety__-'\n ∆← ''\n ({⍵← 0 100⊤ ⍵\n   ({∆← Number[⍵[0];], ' hundred '\n    } ⍣ (⍵[0]≠ 0)) ⍵\n   ⍵← ⍵[1]\n   ({∆← ∆, ,(Number[18 0+ 10 10⊤ ⍵;])[;(⍳8), (0≠ 10⊤ ⍵)⍴ 8]\n    } ⍣ (⍵> 19)) ⍵\n   ({∆← ∆, Number[⍵;]\n    } ⍣ (⍵< 20)) ⍵\n  } ⍣ (⍵≠ 0)) ⍵\n ∆~ '_'\n}\n\ntoEnglish← {\n ⍝ Convert a number into English\n Number← 5 9⍴ 'trillion_billion__million__thousand__________'\n ∆←  ({∆← 'zero'} ⍣ (⍵= 0)) ⍵←''⍴ ⍵\n ({∆← (⍵< 0)/ 'negative '\n   ⍵← (5⍴ 1000)⊤ |⍵\n   now← (⍵≠ 0)⍳ 1\n   {∆← ∆, (Digits ⍵) {⍺, (0≠ ⍴⍺)/ ⍵} ' ', Number[now;], ' '\n    now← now+ 1\n   } ¨ now↓ ⍵\n  } ⍣ (⍵≠ 0)) ⍵\n ∆~ '_'\n}\n\nfromRoman← {\n ⍝ Convert from Roman numerals\n ∆← ((14⍴1 5 10 50 100 500 1000), 5000 10000 50000 100000 500000 1000000)['ivxlcdmIVXLCDMⓋⓍⓁⒸⒹⓂ'⍳ ,⍵]  ⍝ NB. ()'s currently required\n ∆←∆ +.× ¯1+ 2× ∆≥ 1↓∆, 0\n}\n\ntoRoman← {\n ⍝ Convert a number to Roman numerals\n (⍵< 0)∨ ⍵> 3999 : 'domain error'\n ∆← 4 1 3 2 2 3 1 1 1 2 1 3 1 1 2 1 2 1 1 4 1 2\n ∆←∆/ 2 0 2 0 2 0 2 0 ¯1 2 ¯1 2 ¯1 0 2 ¯1 0 2 ¯1 0 ¯2 2\n ∆←,(10 4 ⍴∆)[(4⍴10)⊤⍵;]\n 'MDCLXVI'[(∆≠2)/∆+2×⌊0.25×⍳16] ⍝ ⓂⒹⒸⓁⓍⓋ\n}\n"