Papuascript JavaScript

Papuascript

A Function-oriented Dialect of JavaScript


Pages


Overview

Example Code

// this script alters a global called "module"
export module

// 'with' imports libraries
with (require 'fs') as fs
  [readFile, writeFile]

with (Math)
  [ sqrt
  , pow
  ]

// Assign to *local* variables with '='
one = 1
two = 'two'

// call a function by listing its arguments
console.log one two

// unless it has no arguments
bigTwo = two.toUpperCase()

// functions return the value of the last statement evaluated
diagonal = \a b ->
  cSquared = a*a + b*b
  sqrt cSquared
// this script alters a global called "module"
var readFile,writeFile,fs,sqrt,pow,one,two,bigTwo,diagonal,msg,steps,takeAStep,exp,e3,concatFiles;

// 'with' imports libraries
fs = require('fs');
readFile = owner.readFile; writeFile = owner.writeFile;

(function() { var owner = Math;
  sqrt = owner.sqrt;
  pow = owner.pow;
})();

// Assign to *local* variables with '='
one = 1;
two = 'two';

// call a function by listing its arguments
console.log(one, two);

// unless it has no arguments
bigTwo = two.toUpperCase();

// functions return the value of the last statement evaluated
diagonal = function (a, b) {
  var cSquared = a * a + b * b;
  return sqrt(cSquared); };
// if, switch, and try statements can be assigned as values
msg =
  if 5 < 6
    'impossible'
  else if sqrt 2 == 1.4
    'I told you it was rational!'
  else
    'Nothing to see here'


// var can be used to declare scope without setting a value
var steps

// Use := to update values in outer scope
steps = 0
takeAStep = \ ->
  console.log 'Taking another step...'
  steps := steps + 1

// including variables external to the script
module.exports := { exp: exp, fsConcat: concatFiles }

// Curry functions with @
exp = pow Math.E @
e3 = exp 3

// Use <- to clean up "continuation-passing" code,
// such as often occurs in event-based programming
concatFiles = \a b destination ->
  textA <- readFile a
  textB <- readFile b
  writeFile destination # textA + textB
// if, switch, and try statements can be assigned as values

if (5 < 6) {
  msg = 'impossible';
} else if (sqrt(2) === 1.4) {
  msg = 'I told you it was rational!';
} else {
  msg = 'Nothing to see here'; };


// var can be used to declare scope without setting a value
var steps;

// Use := to update values in outer scope
steps = 0;
takeAStep = function () {
  console.log('Taking another step...');
  steps = steps + 1; };

// including variables external to the script
module.exports = { exp: exp, fsConcat: concatFiles };

// Curry functions with @
exp = function (_p0) { return pow(Math.E, _p0); };
e3 = exp(3);

// Use <- to clean up "continuation-passing" code,
// such as often occurs in event-based programming
concatFiles = function (a, b, destination) {
  return readFile(a, function (textA) {
    return readFile(b, function (textB) {
      return writeFile(destination, (textA + textB)); }); }); };

Whitespace Rules

A block is interpreted either a continuation of the preceding, line, or as many separate lines, according to two rules:

In other words, if the line we're indenting from wants to end in a brace { in JavaScript, it will be. Otherwise it won't.

If, For, While, and Switch

if statements require indented blocks for each branch. The if-case construct can be more concise:

// A concise form for if-else-if statements
hour = new Date() .getHours()
message = if case
    hour < 4  -> 'Night owl'
    hour < 6  -> 'Up early'
    hour < 12 -> 'Good morning'
    default   -> 'Hello'
// A concise form for if-else-if statements
hour = new Date().getHours();

if (hour < 4) { message = 'Night owl';
} else if (hour < 6) { message = 'Up early';
} else if (hour < 12) { message = 'Good morning';
} else { message = 'Hello'; };

For loops have two special forms: for own and for index.

// hasOwnProperty() check 
x = { name: 'Bond', fullname: 'James Bond' }
for own k in x
    console.log (k + ':') x[k]

// can read value with key
for own k:v in x
    console.log v

// for use with arrays
nums = [1, 2, 3]
for index i in nums
    console.log nums[i]

for index i:n in nums
    console.log n
// hasOwnProperty() check
x = { name: 'Bond', fullname: 'James Bond' };
for (k in (_o1 = x)) { if (_o1.hasOwnProperty(k)) {
    console.log((k + ':'), x[k]); }}

// can read value with key
for (k in (_o2 = x)) { if (_o2.hasOwnProperty(k)) { v = _o2[k];
    console.log(v); }}

// for use with arrays
nums = [1, 2, 3];
for (_o3 = nums, i = 0, _len1 = _o3.length; i < _len1; i ++) {
    console.log(nums[i]); }

for (_o4 = nums, i = 0, _len2 = _o4.length; i < _len2; i ++) { n = _o4[i];
    console.log(n); }

Since assignments don't return a value, things like while (row = getRow()) will not work in Papuscript. Do this instead:

while row = getRow(), row
    process row
while(row = getRow(), row) {
    process(row); }

In switch statements, cases do not fall through. To match multiple values to the same block, list them separated by commas.

switch x
  case 1
      alert 'min'
  case 6
      alert 'max'
  case 2, 3, 4, 5
      alert 'middle'
  default
      throw new Error 'invalid roll'
switch (x) {
  case 1:
      alert('min'); break;
  case 6:
      alert('max'); break;
  case 2: case 3: case 4: case 5:
      alert('middle'); break;
  default:
      throw new Error('invalid roll');}

Other syntax

/* You can /* NEST */ comments */

// == becomes ===
bool = 1 == '1'

// undefined becomes "void 0"
nil = undefined

// one-liner
add = \a b -> a + b

// syntactic sugar for 'diagonalSafe = \a b ->'
diagonalSafe a b =
  if a <= 0 || b <= 0
      console.log 'Not a real rectangle!'
      return 0    // explicit return

  diagonal a b

// Ternary operator is different
// It's more readable with a symbol at the beginning
min = ?? a < b : a : b
/* You can NEST comments */

// == becomes ===
bool = 1 === '1';

// undefined becomes "void 0"
nil = void 0;

// one-liner
add = function (a, b) { return a + b; };

// syntactic sugar for 'diagonalSafe = \a b ->'
diagonalSafe = function diagonalSafe(a, b) {
  if (a <= 0 || b <= 0) {
      console.log('Not a real rectangle!');
      return 0; } // explicit return

  return diagonal(a, b); };

// Ternary operator is different
// It's more readable with a symbol at the beginning
min = a < b ? a : b;
// To chain methods without lots of parentheses
// put a space before the dot
str = myString.replace '\\' '\\\\' .replace '"' '\\"'

// # encloses rest of line in ()
console.log # diagonal 3 4

// You can use a function like an operator by surrounding it in backticks
eleven = 5 `add` 6

// numeric indices can be referenced like named members, with a dot
first = \ ->
  console.log arguments.0

// Symbol string: an alphanumeric name preceded by a colon
// useful when a string is semantic (such as the name of a method)
assignIfEmpty member value obj =
  if undefined == obj[member]
    obj[member] := value

assignIfEmpty :name 'MyModule' module

// A list of strings can be written thus:
colors = %{ red blue green }
// To chain methods without lots of parentheses
// put a space before the dot
str = myString.replace('\\', '\\\\').replace('"', '\\"');

// # encloses rest of line in ()
console.log(diagonal(3, 4));

// You can use a function like an operator by surrounding it in backticks
eleven = add(5, 6);

// numeric indices can be referenced like named members, with a dot
first = function () {
  return console.log(arguments[0]); };

// Symbol string: an alphanumeric name preceded by a colon
// useful when a string is semantic (such as the name of a method)
assignIfEmpty = function assignIfEmpty(member, value, obj) {
  if (void 0 === obj[member]) {
    obj[member] = value; }};

assignIfEmpty("name", 'MyModule', module);

// A list of strings can be written thus:
colors = ['red', 'blue', 'green'];

Project maintained by Rob Rosenbaum Theme by mattgraham, modified by Rob Rosenbaum