Mammouth is a small language that compiles into PHP, inspired by CoffeeScript. It's compiled to PHP code/files that you can run on your PHP server.

Mammouth is created by Wael Amine Boutglay (wamalaka) with contributors.

Latest Version: 0.2.3

sudo npm install -g mammouth

Overview

Mammouth on the left, compiled PHP output on the right.

{{
number   = 42
opposite = true

square = (x) ->
 return(x * x)

$square()

list = [1, 2, 3, 4, 5]

if elvis
 alert("I knew it!") 

Hello->
 echo('Hello Mammouth')

$Hello()
}}
<?php 
$number = 42;
$opposite = true;

$square = function($x) { 
  return($x * $x);
};

$square();

$list = array(1, 2, 3, 4, 5);

if($elvis) {  
  alert('I knew it!');
}

function Hello() {  
  echo('Hello Mammouth');
};

Hello();
?>

Installation

The Mammouth compiler is written in JavaScript, using PEG.js. The command-line version of mammouth is available as a Node.js utility. The core compiler, however, does not depend on Node, and can be run in any JavaScript environment, or in the browser (see "Try Mammouth", above).

To install, first make sure you have a working copy of the latest stable version of Node.js, and npm (the Node Package Manager). You can then install Mammouth with npm:

npm install -g mammouth

(Leave off the -g if you don't wish to install globally.)

If you'd prefer to install the latest master version of Mammouth, you can clone the Mammouth source repository from GitHub, or download the source directly. To install the lastest master Mammouth compiler with npm:

npm install -g http://github.com/btwael/mammouth/tarball/master

Usage

Once installed, you should have access to the mammouth command, which can execute scripts, compile .mammouth files into .php, and provide an interactive REPL. The mammouth command takes the following options:

-c, --compile Compile a .mammouth script into a .php PHP file of the same name.
-o, --output [DIR] Write out all compiled PHP files into the specified directory. Use in conjunction with --compile.

Examples:

Language Reference

This reference is structured so that it can be read from top to bottom, if you like. Later sections use ideas and syntax previously introduced. Familiarity with JavaScript is assumed. In all of the following examples, the source Mammouth is provided on the left, and the direct compilation into PHP is on the right.

First, the basics: Mammouth uses significant whitespace to delimit blocks of code. You don't need to use semicolons ; to terminate expressions, ending the line will do just as well (although semicolons can still be used to fit multiple expressions onto a single line). Instead of using curly braces { } to surround blocks of code in functions, if-statements and switch, use indentation.

Functions Functions are defined by an optional list of parameters in parentheses, an arrow, and the function body. The empty function looks like this: ->

{{
square = (x) ->
 return(x * x)

$square()

cube = (x) ->
 return($square(x) * x)

$cube()

hello->
 echo("Hello")

hello()
}}
<?php
$square = function($x) { 
  return($x * $x);
};

$square();

$cube = function($x) { 
  return($square($x) * $x);

$cube();

function hello($x) {  
  echo('Hello');
}

hello();
?>

Functions may also have default values for arguments.

{{
Say = (text = "Hello World!") ->
 echo(text)
}}
<?php
Say = function($text = "Hello World!") { 
  echo($text);
};
?>

You can pass a variable by reference to a function so the function can modify the variable. The syntax is as follows: (a is 6 after the function call)

{{
foo = (&var) ->
 var++
a = 5
foo(a)
}}
<?php
foo = function(&$var) { 
  $var++;
};
a = 5;
foo(a);
?>

Anonymous functions Mammouth support anonymous functions like in example: ->

{{
echo preg_replace_callback('~-([a-z])~', (match)->
    return strtoupper(match[1])
, 'hello-world')
}}
<?php
echo preg_replace_callback('~-([a-z])~', function($match) {	
	return strtoupper($match[1]);
}, 'hello-world');
?>

Arrays The Mammouth literals for arrays look very similar to their JavaScript cousins.

{{
song = ["do", "re", "mi", "fa", "so"]
colors = [
  'chars': 'grey',
  'keywords': 'blue',
  'joins': 'gray',
  'functions': 'violet',
  'constants': 'red',
  12: 'hello',
  var1
]
}}
<?php
$song = array('do', 're', 'mi', 'fa', 'so');
$colors = array('chars' => 'grey', 'keywords' => 'blue', 'joins' => 'gray', 'functions' => 'violet', 'constants' => 'red', 12 => 'hello', $var1);
?>

Slices string and array This new feature allow to slice arrays and strings like in Python

{{
a = ['wael', 'mammouth', 'PHP', 'Coffee']
a[0:1]  // return ['wael']
a[1:3]  // return ['mammouth', 'PHP']
a[1:]   // return ['mammouth', 'PHP', 'coffee']
a[:3]   // return ['wael', 'mammouth', 'PHP']

s = 'I love this project'
s[0:1] // return 'I'
s[2:4] // return 'love'
s[2:]  // return 'love this project'
s[:7]  // return 'I love'
}}
<?php
function _m_len($var) {if(gettype($var)=='string') {return strlen($var);} elseif(gettype($var)=='array') {return count($var);}}
function _m_slice($var, $start, $end) {if(gettype($var)=='string') {return substr($var, $start, $end);} elseif(gettype($var)=='array') {return array_slice($var, $start, $end);}}

$a = array('wael', 'mammouth', 'PHP', 'Coffee');
_m_slice($a, 0, 1);
_m_slice($a, 1, 3);
_m_slice($a, 1, _m_len($a));
_m_slice($a, 0, 3);

$s = 'I love this project';
_m_slice($s, 0, 1);
_m_slice($s, 2, 4);
_m_slice($s, 2, _m_len($s));
_m_slice($s, 0, 7);
?>

The Existential Operator Check for the existence of a variable with ?

{{
if(speed?)
  echo speed
}}
<?php
if(isset($speed)) {
	echo $speed;
}
?>

If/else If/else statements can be written without the use of parentheses and curly brackets. As with functions and other block expressions, conditionals are delimited by indentation.

{{
if happy and knowsIt
  clapsHands()
  chaChaCha()
else
  showIt()
}}
<?php
if($happy && $knowsIt) {  
  clapsHands();
  chaChaCha();
} else {  
  showIt();
}
?>

For Loops For statements can be written without the use of parentheses and curly brackets as with functions and other block expressions. Here are two examples of for usage:

{{
for i = 0; i < 10; i++
  echo(i)

for contact of contacts
  echo(contact)
}}
<?php
for($i = 0; $i < 10; $i++) {  
  echo($i);
}
for($_i = 0; $_i < count($contacts); $_i++) { 
  $contact = $contacts[$_i];
  echo($contact);
}
?>

Operators and Aliases For logic, and compiles to &&, and or into ||.

Instead of a newline or semicolon, then can be used to separate conditions from expressions, in if/else and switch/when statements.

All other PHP operators are supported by Mammouth like +=, ?+, >>=, ^, ~...

Concatenation Operator In PHP, we use . to join two strings in one. In mammouth, you can use whitespace to join strings:

{{
hello = "hello"
word = "word"
echo(hello " " word)
}}
<?php
$hello = 'hello';
$word = 'word';
echo($hello.' '.$word);
?>

Classes

{{
class NiceUser ->
 const type = 'nice'
 public name
 private pass
 variableC = 12
 public showType ->
  echo(this.type)
 private ChangeType(Type) ->
  this.type = Type
}}
<?php
class NiceUser {	
	const $type = 'nice';
	public $name;
	private $pass;
	var $variableC = 12;
	public function showType() {
		echo($this->type);
	}
	private function ChangeType($Type) {
		$this->type = $Type;  	
	}
}
?>


Mammouth don't support static yet.

Namespaces Declaring a namespace is as simple as using the namespace keyword. A namespace name should obey the same rules as other identifiers in mammouth. Therefore, a namespace must start with a letter or underscore, followed by any number of letters, numbers, or underscores.

{{
namespace User ->
 class NiceUser ->
  const type = 'nice'
  public name
  private pass
  variableC = 12
  public showType ->
   echo(this.type)
  private ChangeType(Type) ->
   this.type = Type
}}
<?php
namespace User {
	class NiceUser {	
		const $type = 'nice';
		public $name;
		private $pass;
		var $variableC = 12;
		public function showType() {
			echo($this->type);
		}
		private function ChangeType($Type) {
			$this->type = $Type;  	
		}
	}
}
?>


If you want to declare a sub-namespace you can use backslash(mammouth namespace separator).

{{
namespace MyProject\Database

class Connection ->
}}
<?php
namespace MyProject\Database;

class Connection {

}
?>


You can have as many sub-namespaces as you want.

{{
namespace MyProject\Blog\Auth\Handler\Social

class Twitter ->
}}
<?php
namespace MyProject\Blog\Auth\Handler\Social;

class Twitter {

}
?>

Heredoc strings You can use a multi-line string using the syntax of mammouth heredocs.

{{
str = `Example of a string
spanning multiple lines
using heredoc syntax.`

echo(`My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41`)
}}
<?php
$str = <<<EOD
Example of a string
spanning multiple lines
using heredoc syntax.
EOD;

echo(<<<EOT
My name is "$name". I am printing some $foo->foo.
Now, I am printing some {$foo->bar[1]}.
This should print a capital 'A': \x41
EOT);
?>

Switch/Case/Else Switch statements in PHP are a bit awkward. You need to remember to break at the end of every case statement to avoid accidentally falling through to the default case. Mammouth switch statements have automatic breaks at the end of each case. The format is: switch condition, case clauses, else the default case.

{{
switch day
  case "Mon" then
    go(work)
  case "Tue" then
    go(relax)
  case "Thu"
    go(iceFishing)
  case "Fri"
    if day == bingoDay
      go(bingo)
      go(dancing)
  case "Sun" then
    go(church)
  else
    go(work)
}}
<?php
switch($day) {
  case 'Mon': 
    go($work);
    break;
  case 'Tue': 
    go($relax);
    break;
  case 'Thu': 
    go($iceFishing);
    break;
  case 'Fri': 
    if($day == $bingoDay) { 
      go($bingo);
      go($dancing);
    }
    break;
  case 'Sun': 
    go($church);
    break;
  default:  
    go($work);
}
?>

Embedded PHP Hopefully, you'll never need to use it, but if you ever need to intersperse snippets of PHP within your Mammouth, you can use ``PHP code`` to pass it straight through.

{{
try
m = ``function($name) {
    echo $name;
}``
}}
<?php
$m = function($name) {
    echo $name;
}
?>

Try/Catch/Finally Try/catch statements are just about the same as CoffeeScript.

{{
try
  allHellBreaksLoose()
  catsAndDogsLivingTogether()
catch error
  print(error.getMessage())
finally
  cleanUp()
}}
<?php
try {
  allHellBreaksLoose();
  catsAndDogsLivingTogether();
} catch(Exception $error) {
  print($error->getMessage());
} finally {
  cleanUp();
}
?>

Comments Comments in Mammouth are just about the same as JavaScript or CoffeeScript.

{{
number   = 42 // This is a comment
number   = 42 # This is a comment
/*
This is a 
multi-lines comment 
*/
###
This is a 
multi-lines comment 
###
}}
<?php
$number = 42;
?>

Resources

Change Log

0.2.3 JAN 15, 2014 -[ADD] break, continue, echo, include, include_once... statements without ( and )
-[ADD] Anonymous functions
-[ADD] key-based (associative) arrays
-[ADD] Use ? as isset
-[ADD] Simplified array_push notation
-[ADD] Dynamically created fields
-[ADD] Embedding raw PHP feature
-[ADD] CoffeeScript-likes comments style
-[FIX] Scope Resolution Operator (::)
-[FIX] Fix proprety access
-[FIX] New line after EOT and EOD
-[FIX] Installer
-[DEV] Create tests-tools by @korpirkor

0.2.2 JAN 05, 2014 ADD: Scope Resolution Operator (::)

0.2.0 Oct 26, 2013 ADD: slice string and array like in Python with syntax a[start:end]
ADD: Code comments feature like in Javascript
ADD: HEX character (\code) support into string
ADD: null value feature using 'NULL' or 'None' like in PHP or Python
FIX: Statements into statement
FIX: For statement bug and some reserved word in variables problem

0.1.9 Sep 17, 2013 Fix: variables starting with reserved words

0.1.8 Aug 13, 2013 ADD: namespaces and sub-namespaces support
ADD: class support

0.1.7 Jul 17, 2013 Use whitespace as concatenation operator

0.1.6 Jul 17, 2013 ADD: try/catch/finally
ADD: Inner functions
ALLOW: Empty block

0.1.4 Jul 14, 2013 FIX:For loops counter

0.1.3 Jul 14, 2013 FIX:v0.1.2 changes

0.1.2 Jul 14, 2013 FIX:Passing args in function declaration.
ADD:using HEX char in heredoc.

0.1.1 Jul 13, 2013 Fix For loops.

0.1.0 Jul 12, 2013 Initial Mammouth release.