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.

We are now in the 2.0s versions, that provide more complex statements and expresion (eg. Classes, interfaces, type juggling...), in addition the an advanced context system, that allow for mammouth know were to put $ between different php identifier (eg. defined function and function stored in variable) and type.

Latest Version: 2.0.1

sudo npm install -g mammouth

Overview

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

{{
# Assignement
number   = 42
opposite = false

# Condition
number = (-42 if opposite else 13)

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

echo "I knew it!" if elvis?

### mammouth can detect difference
    between user-defined function
    and variable stored function ###
square = func (x) ->
 return x * x

square()

func Hello->
 echo 'Hello Mammouth'

Hello()
}}
<?php
// Assignement
$number   = 42;
$opposite = FALSE;

// Condition
$number = ($opposite ? -42 : 13);

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

echo isset($elvis) ? "I knew it!" : NULL;

/* mammouth can detect difference
   between user-defined function
   and variable stored function */
$square = function($x) {
  return $x * $x;
};

$square();

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

Hello();
?>

Installation

The Mammouth compiler is written in Javascript, using the Jison parser generator. 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. 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.

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

square()

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

cube()

func Hello->
 echo 'Hello Mammouth'

Hello()

# Functions may also have default values for arguments.
Say = func (text = "Hello World!") ->
 echo text

# You can also pass a variable by reference
foo = func (&var) ->
 var++
a = 5
foo(a) # after this a = 6

# Mammouth support also anonymous function
echo preg_replace_callback('~-([a-z])~', func (match)->
    return strtoupper(match[1])
, 'hello-world')
}}
<?php
$square = function($x) {
  return $x * $x;
};

$square();

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

$cube();

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

Hello();

$Say = function($text = "Hello World!") {
  echo $text;
};

$foo = function(&$var) {
  $var++;
};
$a = 5;
$foo($a);

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

Arrays Arrays are defined in mammouth just like array Javascript or list in python with [ and ]

{{
array1 = ["foo", "bar", "hello", "world"]

# A keyed array
array2 = [1: "a", "1": "b", 1.5: "c", true: "d"]
}}
<?php
$array1 = array("foo", "bar", "hello", "world");

$array2 = array(1 => "a", "1" => "b", 1.5 => "c", TRUE => "d");
?>

Constants Constants are defined in mammouth using the scientific keyword cte

{{
cte CONSTANT = 13
}}
<?php
const CONSTANT = 13;
?>

Type Casting Mammouth is very symbolic language so type casting is like: cte

{{
foo = bar => int
foo = bar => bool
foo = bar => float
foo = bar => binary
foo = bar => string
# etc...
}}
<?php
$foo = (int) $bar;
$foo = (bool) $bar;
$foo = (float) $bar;
$foo = (binary) $bar;
$foo = (string) $bar;
?>

Operators and Aliases Because the == operator frequently causes undesirable coercion, is intransitive, and has a different meaning than in other languages, CoffeeScript compiles == into ===, and != into !==. In addition, is compiles into ===, and isnt into !==.

You can use not as an alias for !.

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

MammouthPHP
is===
isnt!==
not!
and&&
or||
trueTRUE
falseFALSE
@, this$this
inno PHP equivalent
a ** b$a ** $b, pow($a, $b)
a.ba->b
a..b, a::ba::b
{{
# Execution operator
output = exec 'ls -al'

# Concatenation operator
text = 'sometext'<->'other text'
# mammouth + operator can join text
text = 'sometext'+'other text'

# You can use ? to check if a variable exist
myvar?

# You can unset or delete a variable using javascript
delete myvar

### All other PHP operators are sopported exclude Error Control Operators ###
}}
<?php
$output = `ls -al`;

$text = 'sometext'.'other text';
$text = mammouth("+", 'sometext', 'other text');

isset($myvar)

unset(myvar)
?>

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

Mammouth can compile if statements into PHP expressions, using the ternary operator when possible, and closure wrapping otherwise.

{{
mood = greatlyImproved if singing

if happy and knowsIt
  clapsHands()
  chaChaCha()
else
  showIt()

date = if friday then sue else jill
}}
<?php
$mood = $singing ? $greatlyImproved : NULL;

if($happy & $knowsIt) {
  $clapsHands();
  $chaChaCha();
} else {
  $showIt();
}

$date = $friday ? $sue : $jill;
?>

Loops and Comprehensions Mammouth support all PHP loops srtucture in addition to some comprehensions over array and object inspired from CoffeeScript.

{{
# The general simple for
for i = 1; i <= 10; i++
  echo i

# Let's do an array comprehension
projects = ['mammouth', 'locallydb', 'JISON', 'CoffeeScript']
for project in projects
  echo project

# Instead you can use "for each" not "foreach"
for each [1, 2, 3, 4] as value
  echo value**2

# You can also do an object comprehension
for each object as key => value
  echo "Key: $key; Value: $value<br />\n"

# Here a while example
i = 1
while i <= 11
  echo i++

# Or a do-while example
i = 0
do while i > 0
  echo i++
}}
<?php
for($i = 1; $i <= 10; $i++; ) {
  echo $i;
}

$projects = array('mammouth', 'locallydb', 'JISON', 'CoffeeScript');
for($_i = 0; $_i < count($projects); $_i++) {
  $project = $projects[$_i];
  echo $project;
}

foreach(array(1, 2, 3, 4) as $value) {
  echo pow($value, 2);
}

foreach($object as $value => key) {
  echo "Key: $key; Value: $value<br />\n";
}

$i = 1;
while($i <= 11) {
  echo $i++;
}

$i = 0;
do {
  echo $i++;
} while ($i > 0);
?>

You can use also continue or break sush as in PHP.

Declare structure In this new Mammouth version you can use the structure declare

{{
# you can use this
declare ticks=1 ->
  somethingh = other
  # entire script here

# or you can use this
declare ticks=1
# entire script here
}}
<?php
declare($ticks = 1) {
  $somethingh = $other;
}

declare($ticks = 1);
?>

require, include, once...

{{
require 'somefile.php'
include 'other.php'

# or once
require once 'afile.php'
include once 'aother.php'
}}
<?php
require 'somefile.php'
include 'other.php'

require_once 'afile.php'
include_once 'aother.php'
?>

switch and try

{{
# A switch example
switch day
 when "Mon"
  go(work)
 when "Tue"
  go(relax)
 when "Thu"
  go(iceFishing)
 else
  walloooo()

# A Try example
try
  echo inverse(5)<->"\n"
  echo inverse(0)<->"\n"
catch e
  echo 'Exception reçue : '<->e.getMessage()<->"\n"
finally
  value = false
}}
<?php
switch ($day) {
  case "Mon": {
    $go($work);
    break;
  }
  case "Tue": {
    $go($relax);
    break;
  }
  case "Thu": {
    $go($iceFishing);
    break;
  }
  default: {
    $walloooo();
  }
}

try {
  echo $inverse(5)."\n";
  echo $inverse(0)."\n";
} catch(Exception $e) {
  echo 'Exception reçue : '.$e->getMessage()."\n";
} finally {
  $value = FALSE;
}
?>

Section and goto

{{
goto a
echo 'Foo'
 
a:
echo 'Bar'
}}
<?php
goto a;
echo 'Foo';
 
a:
echo 'Bar';
?>

Classes, interfaces, inheritance...

{{
# A simple example
class A
  # Mammouth support property Visibility
  private vari = true
  protected cte CONST = "yes"
  func foo() ->
    if this?
        echo '$this is defined ('
        echo get_class(this)
        echo ")\n"
    else 
        echo "\$this is not defined.\n"
  # you can also use final and static
  final public static func fii ->
    return true

a = new A()
a.foo()
A..foo() # you can also use A::foo()

# an example about Inheritance
class foo
  public func printItem(string) ->
    echo 'Foo: '<->string<->PHP_EOL
  public func printPHP ->
    echo 'Mammouth is great.'<->PHP_

class bar extends foo
  public func printItem(string) ->
    echo 'Bar: '<->string<->PHP_EOL

# Abstract class example
abstract class AbstractClass
  abstract protected func getValue()
  abstract protected func prefixValue(prefix)

  public func printOut ->
    echo this.getValue() <-> "\n"

class ConcreteClass1 extends AbstractClass
  protected func getValue ->
    return "ConcreteClass1"

  public func prefixValue(prefix) ->
    return "{$prefix}ConcreteClass1"

# Interface example
interface iTemplate
  public func setVariable(name, var)
  public func getHtml(template)

# Implement the interface
class Template implements iTemplate
  private vars = []

  public func setVariable(name, var) ->
    this.vars[name] = var

  public func getHtml(template) ->
    for each this.vars as name => value
      template = '{$name}: {$value}'
    return template

# Cloning objects/classes
variable = clone a
}}
<?php
class A {
  private $vari = TRUE;
  protected const CONST = "yes";
  function foo() {
    if(isset($this)) {
      echo '$this is defined (';
      echo get_class($this);
      echo ")\n";
    } else {
      echo "\$this is not defined.\n";
    }
  }
  final public static function fii() {
    return TRUE;
  }
}

$a = new A();
$a->foo();
A::foo();

class foo {
  public function printItem($string) {
    echo 'Foo: '.$string.$PHP_EOL;
  }
  public function printPHP() {
    echo 'Mammouth is great.'.$PHP_;
  }
}

class bar extends foo {
  public function printItem($string) {
    echo 'Bar: '.$string.$PHP_EOL;
  }
}

abstract class AbstractClass {
  abstract protected function getValue();
  abstract protected function prefixValue($prefix);
  public function printOut() {
    echo $this->getValue()."\n";
  }
}

class ConcreteClass1 extends AbstractClass {
  protected function getValue() {
    return "ConcreteClass1";
  }
  public function prefixValue($prefix) {
    return "{$prefix}ConcreteClass1";
  }
}

interface iTemplate {
  public function setVariable($name, $var);
  public function getHtml($template);
}

class Template implements iTemplate {
  private $vars = array();
  public function setVariable($name, $var) {
    $this->vars[$name] = $var;
  }
  public function getHtml($template) {
    foreach($this->vars as $value => $name) {
      $template = '{$name}: {$value}';
    }
    return $template;
  }
}

$variable = clone $a;
?>

Namespaces

{{
namespace my # Defining a namespace
# code go here
namespace my\name # Defining a sub-namespace
# code go here

namespace AnotherProject ->
  cte CONNECT_OK = 1
  class Connection
    cte host = "12"
  func connect() ->
    return 'you are connected'

a = AnotherProject\connect()
echo AnotherProject\Connection::start()
}}
<?php
namespace my;

namespace my\name;

namespace AnotherProject {
  const CONNECT_OK = 1;
  class Connection {
    const host = "12";
  }
  function connect() {
    return 'you are connected';
  }
}

$a = AnotherProject\connect();
echo AnotherProject\Connection::start();
?>

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.`
}}
<?php
$str = <<<EOT
Example of a string
spanning multiple lines
using heredoc syntax.
EOT;
?>

Change Log

2.0.0 Aug 15, 2014 Rewriting the project using JISON, support many php structure, better context system, in short large changes

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.