// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE ;(function (mod) { if (typeof exports == 'object' && typeof module == 'object') // CommonJS mod(require('../../lib/codemirror')) else if (typeof define == 'function' && define.amd) // AMD define(['../../lib/codemirror'], mod) // Plain browser env else mod(CodeMirror) })(function (CodeMirror) { 'use strict' CodeMirror.defineMode('haskell', function (_config, modeConfig) { function switchState(source, setState, f) { setState(f) return f(source, setState) } // These should all be Unicode extended, as per the Haskell 2010 report var smallRE = /[a-z_]/ var largeRE = /[A-Z]/ var digitRE = /\d/ var hexitRE = /[0-9A-Fa-f]/ var octitRE = /[0-7]/ var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/ var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/ var specialRE = /[(),;[\]`{}]/ var whiteCharRE = /[ \t\v\f]/ // newlines are handled in tokenizer function normal(source, setState) { if (source.eatWhile(whiteCharRE)) { return null } var ch = source.next() if (specialRE.test(ch)) { if (ch == '{' && source.eat('-')) { var t = 'comment' if (source.eat('#')) { t = 'meta' } return switchState(source, setState, ncomment(t, 1)) } return null } if (ch == "'") { if (source.eat('\\')) { source.next() // should handle other escapes here } else { source.next() } if (source.eat("'")) { return 'string' } return 'string error' } if (ch == '"') { return switchState(source, setState, stringLiteral) } if (largeRE.test(ch)) { source.eatWhile(idRE) if (source.eat('.')) { return 'qualifier' } return 'variable-2' } if (smallRE.test(ch)) { source.eatWhile(idRE) return 'variable' } if (digitRE.test(ch)) { if (ch == '0') { if (source.eat(/[xX]/)) { source.eatWhile(hexitRE) // should require at least 1 return 'integer' } if (source.eat(/[oO]/)) { source.eatWhile(octitRE) // should require at least 1 return 'number' } } source.eatWhile(digitRE) var t = 'number' if (source.match(/^\.\d+/)) { t = 'number' } if (source.eat(/[eE]/)) { t = 'number' source.eat(/[-+]/) source.eatWhile(digitRE) // should require at least 1 } return t } if (ch == '.' && source.eat('.')) return 'keyword' if (symbolRE.test(ch)) { if (ch == '-' && source.eat(/-/)) { source.eatWhile(/-/) if (!source.eat(symbolRE)) { source.skipToEnd() return 'comment' } } var t = 'variable' if (ch == ':') { t = 'variable-2' } source.eatWhile(symbolRE) return t } return 'error' } function ncomment(type, nest) { if (nest == 0) { return normal } return function (source, setState) { var currNest = nest while (!source.eol()) { var ch = source.next() if (ch == '{' && source.eat('-')) { ++currNest } else if (ch == '-' && source.eat('}')) { --currNest if (currNest == 0) { setState(normal) return type } } } setState(ncomment(type, currNest)) return type } } function stringLiteral(source, setState) { while (!source.eol()) { var ch = source.next() if (ch == '"') { setState(normal) return 'string' } if (ch == '\\') { if (source.eol() || source.eat(whiteCharRE)) { setState(stringGap) return 'string' } if (source.eat('&')) { } else { source.next() // should handle other escapes here } } } setState(normal) return 'string error' } function stringGap(source, setState) { if (source.eat('\\')) { return switchState(source, setState, stringLiteral) } source.next() setState(normal) return 'error' } var wellKnownWords = (function () { var wkw = {} function setType(t) { return function () { for (var i = 0; i < arguments.length; i++) wkw[arguments[i]] = t } } setType('keyword')( 'case', 'class', 'data', 'default', 'deriving', 'do', 'else', 'foreign', 'if', 'import', 'in', 'infix', 'infixl', 'infixr', 'instance', 'let', 'module', 'newtype', 'of', 'then', 'type', 'where', '_' ) setType('keyword')('..', ':', '::', '=', '\\', '<-', '->', '@', '~', '=>') setType('builtin')('!!', '$!', '$', '&&', '+', '++', '-', '.', '/', '/=', '<', '<*', '<=', '<$>', '<*>', '=<<', '==', '>', '>=', '>>', '>>=', '^', '^^', '||', '*', '*>', '**') setType('builtin')( 'Applicative', 'Bool', 'Bounded', 'Char', 'Double', 'EQ', 'Either', 'Enum', 'Eq', 'False', 'FilePath', 'Float', 'Floating', 'Fractional', 'Functor', 'GT', 'IO', 'IOError', 'Int', 'Integer', 'Integral', 'Just', 'LT', 'Left', 'Maybe', 'Monad', 'Nothing', 'Num', 'Ord', 'Ordering', 'Rational', 'Read', 'ReadS', 'Real', 'RealFloat', 'RealFrac', 'Right', 'Show', 'ShowS', 'String', 'True' ) setType('builtin')( 'abs', 'acos', 'acosh', 'all', 'and', 'any', 'appendFile', 'asTypeOf', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'break', 'catch', 'ceiling', 'compare', 'concat', 'concatMap', 'const', 'cos', 'cosh', 'curry', 'cycle', 'decodeFloat', 'div', 'divMod', 'drop', 'dropWhile', 'either', 'elem', 'encodeFloat', 'enumFrom', 'enumFromThen', 'enumFromThenTo', 'enumFromTo', 'error', 'even', 'exp', 'exponent', 'fail', 'filter', 'flip', 'floatDigits', 'floatRadix', 'floatRange', 'floor', 'fmap', 'foldl', 'foldl1', 'foldr', 'foldr1', 'fromEnum', 'fromInteger', 'fromIntegral', 'fromRational', 'fst', 'gcd', 'getChar', 'getContents', 'getLine', 'head', 'id', 'init', 'interact', 'ioError', 'isDenormalized', 'isIEEE', 'isInfinite', 'isNaN', 'isNegativeZero', 'iterate', 'last', 'lcm', 'length', 'lex', 'lines', 'log', 'logBase', 'lookup', 'map', 'mapM', 'mapM_', 'max', 'maxBound', 'maximum', 'maybe', 'min', 'minBound', 'minimum', 'mod', 'negate', 'not', 'notElem', 'null', 'odd', 'or', 'otherwise', 'pi', 'pred', 'print', 'product', 'properFraction', 'pure', 'putChar', 'putStr', 'putStrLn', 'quot', 'quotRem', 'read', 'readFile', 'readIO', 'readList', 'readLn', 'readParen', 'reads', 'readsPrec', 'realToFrac', 'recip', 'rem', 'repeat', 'replicate', 'return', 'reverse', 'round', 'scaleFloat', 'scanl', 'scanl1', 'scanr', 'scanr1', 'seq', 'sequence', 'sequence_', 'show', 'showChar', 'showList', 'showParen', 'showString', 'shows', 'showsPrec', 'significand', 'signum', 'sin', 'sinh', 'snd', 'span', 'splitAt', 'sqrt', 'subtract', 'succ', 'sum', 'tail', 'take', 'takeWhile', 'tan', 'tanh', 'toEnum', 'toInteger', 'toRational', 'truncate', 'uncurry', 'undefined', 'unlines', 'until', 'unwords', 'unzip', 'unzip3', 'userError', 'words', 'writeFile', 'zip', 'zip3', 'zipWith', 'zipWith3' ) var override = modeConfig.overrideKeywords if (override) for (var word in override) if (override.hasOwnProperty(word)) wkw[word] = override[word] return wkw })() return { startState: function () { return { f: normal } }, copyState: function (s) { return { f: s.f } }, token: function (stream, state) { var t = state.f(stream, function (s) { state.f = s }) var w = stream.current() return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t }, blockCommentStart: '{-', blockCommentEnd: '-}', lineComment: '--', } }) CodeMirror.defineMIME('text/x-haskell', 'haskell') })