<!DOCTYPE html>
<html>

  <head>
    <link data-require="bootstrap@*" data-semver="3.3.2" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" />
    <script data-require="jquery@2.1.3" data-semver="2.1.3" src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
    <script data-require="angular.js@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular.js"></script>
    <script data-require="bootstrap@*" data-semver="3.3.2" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
    <script data-require="angular-animate@*" data-semver="1.4.0-beta.5" src="https://code.angularjs.org/1.4.0-beta.5/angular-animate.js"></script>
    <script data-require="mathjs@*" data-semver="0.27.0" src="http://cdnjs.cloudflare.com/ajax/libs/mathjs/0.27.0/math.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-app="myApp" ng-controller="MainCtrl as main">
    <p></p>
    <table class="exprs">
      <tbody>
        <tr class="animate-repeat" ng-repeat="expr in main.exprs">
          <td>
            <input ng-model="expr.key" class="badge-input" />
            <button class="btn btn-link btn-xs" ng-click="remove(expr)">x</button>
          </td>
          <td>
            <input ng-model="expr.expr" class="form-control input-sm" />
          </td>
          <td>{{expr.value}}</td>
        </tr>
        <tr>
          <td>
            <button class="btn btn-xs btn-primary add-button" ng-click="main.exprs.push({})">(+)</button>
          </td>
        </tr>
      </tbody>
    </table>
  </body>

</html>
// Code goes here

angular.module('myApp', ['ngAnimate'])
.controller('MainCtrl', function($scope, $parse) {
  var main = this;
  
  main.exprs = [
    { key: 'x', expr: '5' },
    { key: 'y', expr: 'range(0,x)' },
    { key: 'z', expr: 'round(log(y))' },
    { key: 't', expr: 'y[x-1]' }
  ];
  
  var locals = {};
  
  var ctx = math.create({
    matrix: 'array'       // Choose 'matrix' (default) or 'array'
  });
  
  function digest() {
    var newValues = {};
    main.exprs.forEach(function(v) {
      var getter = $parse(''+v.expr);
      try {
        v.value = newValues[v.key] = getter(ctx,locals);
      } catch(err) {
        v.value = newValues[v.key] = null;
      }
    });
    locals = newValues;
  }
  
  $scope.$watch('main.exprs', digest, true);
  $scope.$watch(function() { return locals; }, digest, true);
  
  
  $scope.remove = function(d) {
    var i = main.exprs.indexOf(d);
    if (i > -1) {
      main.exprs.splice(i,1);
    }
  }
  
});
/* Styles go here */

.exprs {
  width: 100%;
  text-align: center;
}

.exprs tr {
  height: 32px;
}

.exprs td {
  width: 33%;
  max-width: 300px;
  text-align: center;
  overflow-x: auto;
}

.badge-input {
  background-color: lightblue;
  border: none;
  border-radius: 10px;
  padding-left: 10px;
  width: auto;
}

.add-button {
  margin-left: 10px;
  background-color: lightblue;
  border-color: lightblue;
}

.animate-repeat {
}

.animate-repeat.ng-move,
.animate-repeat.ng-enter,
.animate-repeat.ng-leave {
  -webkit-transition:all linear 0.3s;
  transition:all linear 0.3s;
}

.animate-repeat.ng-leave.ng-leave-active,
.animate-repeat.ng-move,
.animate-repeat.ng-enter {
  opacity:0;
  max-height:0;
}

.animate-repeat.ng-leave,
.animate-repeat.ng-move.ng-move-active,
.animate-repeat.ng-enter.ng-enter-active {
  opacity:1;
  max-height:40px;
}