// Generated by LiveScript 1.2.0
(function(){
  var ref$, id, reject, parsedTypeCheck, types, tokenRegex, toString$ = {}.toString;
  ref$ = require('prelude-ls'), id = ref$.id, reject = ref$.reject;
  parsedTypeCheck = require('type-check').parsedTypeCheck;
  types = {
    '*': function(it){
      switch (toString$.call(it).slice(8, -1)) {
      case 'Array':
        return coerceType(it, {
          type: 'Array'
        });
      case 'Object':
        return coerceType(it, {
          type: 'Object'
        });
      default:
        return {
          type: 'Just',
          value: coerceTypes(it, [
            {
              type: 'Undefined'
            }, {
              type: 'Null'
            }, {
              type: 'Boolean'
            }, {
              type: 'Number'
            }, {
              type: 'Date'
            }, {
              type: 'RegExp'
            }, {
              type: 'Array'
            }, {
              type: 'Object'
            }, {
              type: 'String'
            }
          ], {
            explicit: true
          })
        };
      }
    },
    Undefined: function(it){
      if (it === 'undefined') {
        return {
          type: 'Just',
          value: void 8
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Null: function(it){
      if (it === 'null') {
        return {
          type: 'Just',
          value: null
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Boolean: function(it){
      if (it === 'true') {
        return {
          type: 'Just',
          value: true
        };
      } else if (it === 'false') {
        return {
          type: 'Just',
          value: false
        };
      } else {
        return {
          type: 'Nothing'
        };
      }
    },
    Number: function(it){
      return {
        type: 'Just',
        value: +it
      };
    },
    Int: function(it){
      return {
        type: 'Just',
        value: parseInt(it)
      };
    },
    Float: function(it){
      return {
        type: 'Just',
        value: parseFloat(it)
      };
    },
    Date: function(value, options){
      var that;
      if (that = /^\#(.*)\#$/.exec(value)) {
        return {
          type: 'Just',
          value: new Date(+that[1] || that[1])
        };
      } else if (options.explicit) {
        return {
          type: 'Nothing'
        };
      } else {
        return {
          type: 'Just',
          value: new Date(+value || value)
        };
      }
    },
    RegExp: function(value, options){
      var that;
      if (that = /^\/(.*)\/([gimy]*)$/.exec(value)) {
        return {
          type: 'Just',
          value: new RegExp(that[1], that[2])
        };
      } else if (options.explicit) {
        return {
          type: 'Nothing'
        };
      } else {
        return {
          type: 'Just',
          value: new RegExp(value)
        };
      }
    },
    Array: function(it){
      return coerceArray(it, {
        of: [{
          type: '*'
        }]
      });
    },
    Object: function(it){
      return coerceFields(it, {
        of: {}
      });
    },
    String: function(it){
      var that;
      if (that = it.match(/^'(.*)'$/)) {
        return {
          type: 'Just',
          value: that[1]
        };
      } else if (that = it.match(/^"(.*)"$/)) {
        return {
          type: 'Just',
          value: that[1]
        };
      } else {
        return {
          type: 'Just',
          value: it
        };
      }
    }
  };
  function coerceArray(node, type){
    var typeOf, element;
    if (toString$.call(node).slice(8, -1) !== 'Array') {
      return {
        type: 'Nothing'
      };
    }
    typeOf = type.of;
    return {
      type: 'Just',
      value: (function(){
        var i$, ref$, len$, results$ = [];
        for (i$ = 0, len$ = (ref$ = node).length; i$ < len$; ++i$) {
          element = ref$[i$];
          results$.push(coerceTypes(element, typeOf));
        }
        return results$;
      }())
    };
  }
  function coerceTuple(node, type){
    var i, types;
    if (toString$.call(node).slice(8, -1) !== 'Array') {
      return {
        type: 'Nothing'
      };
    }
    return {
      type: 'Just',
      value: (function(){
        var i$, ref$, len$, results$ = [];
        for (i$ = 0, len$ = (ref$ = type.of).length; i$ < len$; ++i$) {
          i = i$;
          types = ref$[i$];
          results$.push(coerceTypes(node[i], types));
        }
        return results$;
      }())
    };
  }
  function coerceFields(node, type){
    var typeOf, key, value;
    if (toString$.call(node).slice(8, -1) !== 'Object') {
      return {
        type: 'Nothing'
      };
    }
    typeOf = type.of;
    return {
      type: 'Just',
      value: (function(){
        var ref$, results$ = {};
        for (key in ref$ = node) {
          value = ref$[key];
          results$[key] = coerceTypes(value, typeOf[key] || [{
            type: '*'
          }]);
        }
        return results$;
      }())
    };
  }
  function coerceType(node, typeObj, options){
    var type, structure, coerceFunc;
    type = typeObj.type, structure = typeObj.structure;
    if (type) {
      coerceFunc = types[type];
      return coerceFunc(node, options);
    } else {
      switch (structure) {
      case 'array':
        return coerceArray(node, typeObj);
      case 'tuple':
        return coerceTuple(node, typeObj);
      case 'fields':
        return coerceFields(node, typeObj);
      }
    }
  }
  function coerceTypes(node, types, options){
    var i$, len$, type, ref$, valueType, value;
    options == null && (options = {});
    for (i$ = 0, len$ = types.length; i$ < len$; ++i$) {
      type = types[i$];
      ref$ = coerceType(node, type, options), valueType = ref$.type, value = ref$.value;
      if (valueType === 'Nothing') {
        continue;
      }
      if (parsedTypeCheck([type], value)) {
        return value;
      }
    }
    throw new Error("Value '" + node + "' does not type check against " + JSON.stringify(types) + ".");
  }
  function consumeOp(tokens, op){
    if (tokens[0] === op) {
      return tokens.shift();
    } else {
      throw new Error("Expected '" + op + "', but got " + tokens[0] + " instead.");
    }
  }
  function maybeConsumeOp(tokens, op){
    if (tokens[0] === op) {
      return tokens.shift();
    }
  }
  function consumeList(tokens, delimiters, hasDelimiters){
    var result;
    if (hasDelimiters) {
      consumeOp(tokens, delimiters[0]);
    }
    result = [];
    while (tokens.length && tokens[0] !== delimiters[1]) {
      result.push(consumeElement(tokens));
      maybeConsumeOp(tokens, ',');
    }
    if (hasDelimiters) {
      consumeOp(tokens, delimiters[1]);
    }
    return result;
  }
  function consumeArray(tokens, hasDelimiters){
    return consumeList(tokens, ['[', ']'], hasDelimiters);
  }
  function consumeTuple(tokens, hasDelimiters){
    return consumeList(tokens, ['(', ')'], hasDelimiters);
  }
  function consumeFields(tokens, hasDelimiters){
    var result, key;
    if (hasDelimiters) {
      consumeOp(tokens, '{');
    }
    result = {};
    while (tokens.length && (!hasDelimiters || tokens[0] !== '}')) {
      key = tokens.shift();
      consumeOp(tokens, ':');
      result[key] = consumeElement(tokens);
      maybeConsumeOp(tokens, ',');
    }
    if (hasDelimiters) {
      consumeOp(tokens, '}');
    }
    return result;
  }
  function consumeElement(tokens){
    switch (tokens[0]) {
    case '[':
      return consumeArray(tokens, true);
    case '(':
      return consumeTuple(tokens, true);
    case '{':
      return consumeFields(tokens, true);
    default:
      return tokens.shift();
    }
  }
  function consumeTopLevel(tokens, types){
    var structure, origTokens, result;
    structure = types[0].structure;
    if (types.length === 1 && structure) {
      origTokens = tokens.slice();
      result = structure === 'array'
        ? consumeArray(tokens, tokens[0] === '[')
        : structure === 'tuple'
          ? consumeTuple(tokens, tokens[0] === '(')
          : consumeFields(tokens, tokens[0] === '{');
      if (tokens.length) {
        return consumeElement(structure === 'array'
          ? ['['].concat(origTokens, [']'])
          : ['('].concat(origTokens, [')']));
      } else {
        return result;
      }
    } else {
      return consumeElement(tokens);
    }
  }
  tokenRegex = /("(?:[^"]|\\")*")|('(?:[^']|\\')*')|(#.*#)|(\/(?:\\\/|[^\/])*\/[gimy]*)|([\[\]\(\)}{:,])|([-\.\$\w]+)|\s*/;
  function coerce(types, string){
    var tokens, node;
    tokens = reject(function(it){
      return !it || /^\s+$/.test(it);
    }, string.split(tokenRegex));
    node = consumeTopLevel(tokens, types);
    if (!node) {
      throw new Error("Error parsing " + string);
    }
    return coerceTypes(node, types);
  }
  module.exports = coerce;
  /*
  function log
    console.log it; it
  */
}).call(this);
