| // Generated by LiveScript 1.4.0 |
| (function(){ |
| var identifierRegex, tokenRegex; |
| identifierRegex = /[\$\w]+/; |
| function peek(tokens){ |
| var token; |
| token = tokens[0]; |
| if (token == null) { |
| throw new Error('Unexpected end of input.'); |
| } |
| return token; |
| } |
| function consumeIdent(tokens){ |
| var token; |
| token = peek(tokens); |
| if (!identifierRegex.test(token)) { |
| throw new Error("Expected text, got '" + token + "' instead."); |
| } |
| return tokens.shift(); |
| } |
| function consumeOp(tokens, op){ |
| var token; |
| token = peek(tokens); |
| if (token !== op) { |
| throw new Error("Expected '" + op + "', got '" + token + "' instead."); |
| } |
| return tokens.shift(); |
| } |
| function maybeConsumeOp(tokens, op){ |
| var token; |
| token = tokens[0]; |
| if (token === op) { |
| return tokens.shift(); |
| } else { |
| return null; |
| } |
| } |
| function consumeArray(tokens){ |
| var types; |
| consumeOp(tokens, '['); |
| if (peek(tokens) === ']') { |
| throw new Error("Must specify type of Array - eg. [Type], got [] instead."); |
| } |
| types = consumeTypes(tokens); |
| consumeOp(tokens, ']'); |
| return { |
| structure: 'array', |
| of: types |
| }; |
| } |
| function consumeTuple(tokens){ |
| var components; |
| components = []; |
| consumeOp(tokens, '('); |
| if (peek(tokens) === ')') { |
| throw new Error("Tuple must be of at least length 1 - eg. (Type), got () instead."); |
| } |
| for (;;) { |
| components.push(consumeTypes(tokens)); |
| maybeConsumeOp(tokens, ','); |
| if (')' === peek(tokens)) { |
| break; |
| } |
| } |
| consumeOp(tokens, ')'); |
| return { |
| structure: 'tuple', |
| of: components |
| }; |
| } |
| function consumeFields(tokens){ |
| var fields, subset, ref$, key, types; |
| fields = {}; |
| consumeOp(tokens, '{'); |
| subset = false; |
| for (;;) { |
| if (maybeConsumeOp(tokens, '...')) { |
| subset = true; |
| break; |
| } |
| ref$ = consumeField(tokens), key = ref$[0], types = ref$[1]; |
| fields[key] = types; |
| maybeConsumeOp(tokens, ','); |
| if ('}' === peek(tokens)) { |
| break; |
| } |
| } |
| consumeOp(tokens, '}'); |
| return { |
| structure: 'fields', |
| of: fields, |
| subset: subset |
| }; |
| } |
| function consumeField(tokens){ |
| var key, types; |
| key = consumeIdent(tokens); |
| consumeOp(tokens, ':'); |
| types = consumeTypes(tokens); |
| return [key, types]; |
| } |
| function maybeConsumeStructure(tokens){ |
| switch (tokens[0]) { |
| case '[': |
| return consumeArray(tokens); |
| case '(': |
| return consumeTuple(tokens); |
| case '{': |
| return consumeFields(tokens); |
| } |
| } |
| function consumeType(tokens){ |
| var token, wildcard, type, structure; |
| token = peek(tokens); |
| wildcard = token === '*'; |
| if (wildcard || identifierRegex.test(token)) { |
| type = wildcard |
| ? consumeOp(tokens, '*') |
| : consumeIdent(tokens); |
| structure = maybeConsumeStructure(tokens); |
| if (structure) { |
| return structure.type = type, structure; |
| } else { |
| return { |
| type: type |
| }; |
| } |
| } else { |
| structure = maybeConsumeStructure(tokens); |
| if (!structure) { |
| throw new Error("Unexpected character: " + token); |
| } |
| return structure; |
| } |
| } |
| function consumeTypes(tokens){ |
| var lookahead, types, typesSoFar, typeObj, type; |
| if ('::' === peek(tokens)) { |
| throw new Error("No comment before comment separator '::' found."); |
| } |
| lookahead = tokens[1]; |
| if (lookahead != null && lookahead === '::') { |
| tokens.shift(); |
| tokens.shift(); |
| } |
| types = []; |
| typesSoFar = {}; |
| if ('Maybe' === peek(tokens)) { |
| tokens.shift(); |
| types = [ |
| { |
| type: 'Undefined' |
| }, { |
| type: 'Null' |
| } |
| ]; |
| typesSoFar = { |
| Undefined: true, |
| Null: true |
| }; |
| } |
| for (;;) { |
| typeObj = consumeType(tokens), type = typeObj.type; |
| if (!typesSoFar[type]) { |
| types.push(typeObj); |
| } |
| typesSoFar[type] = true; |
| if (!maybeConsumeOp(tokens, '|')) { |
| break; |
| } |
| } |
| return types; |
| } |
| tokenRegex = RegExp('\\.\\.\\.|::|->|' + identifierRegex.source + '|\\S', 'g'); |
| module.exports = function(input){ |
| var tokens, e; |
| if (!input.length) { |
| throw new Error('No type specified.'); |
| } |
| tokens = input.match(tokenRegex) || []; |
| if (in$('->', tokens)) { |
| throw new Error("Function types are not supported.\ To validate that something is a function, you may use 'Function'."); |
| } |
| try { |
| return consumeTypes(tokens); |
| } catch (e$) { |
| e = e$; |
| throw new Error(e.message + " - Remaining tokens: " + JSON.stringify(tokens) + " - Initial input: '" + input + "'"); |
| } |
| }; |
| function in$(x, xs){ |
| var i = -1, l = xs.length >>> 0; |
| while (++i < l) if (x === xs[i]) return true; |
| return false; |
| } |
| }).call(this); |