123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560 |
- // 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('haxe', function (config, parserConfig) {
- var indentUnit = config.indentUnit
- // Tokenizer
- function kw(type) {
- return { type: type, style: 'keyword' }
- }
- var A = kw('keyword a'),
- B = kw('keyword b'),
- C = kw('keyword c')
- var operator = kw('operator'),
- atom = { type: 'atom', style: 'atom' },
- attribute = { type: 'attribute', style: 'attribute' }
- var type = kw('typedef')
- var keywords = {
- if: A,
- while: A,
- else: B,
- do: B,
- try: B,
- return: C,
- break: C,
- continue: C,
- new: C,
- throw: C,
- var: kw('var'),
- inline: attribute,
- static: attribute,
- using: kw('import'),
- public: attribute,
- private: attribute,
- cast: kw('cast'),
- import: kw('import'),
- macro: kw('macro'),
- function: kw('function'),
- catch: kw('catch'),
- untyped: kw('untyped'),
- callback: kw('cb'),
- for: kw('for'),
- switch: kw('switch'),
- case: kw('case'),
- default: kw('default'),
- in: operator,
- never: kw('property_access'),
- trace: kw('trace'),
- class: type,
- abstract: type,
- enum: type,
- interface: type,
- typedef: type,
- extends: type,
- implements: type,
- dynamic: type,
- true: atom,
- false: atom,
- null: atom,
- }
- var isOperatorChar = /[+\-*&%=<>!?|]/
- function chain(stream, state, f) {
- state.tokenize = f
- return f(stream, state)
- }
- function toUnescaped(stream, end) {
- var escaped = false,
- next
- while ((next = stream.next()) != null) {
- if (next == end && !escaped) return true
- escaped = !escaped && next == '\\'
- }
- }
- // Used as scratch variables to communicate multiple values without
- // consing up tons of objects.
- var type, content
- function ret(tp, style, cont) {
- type = tp
- content = cont
- return style
- }
- function haxeTokenBase(stream, state) {
- var ch = stream.next()
- if (ch == '"' || ch == "'") {
- return chain(stream, state, haxeTokenString(ch))
- } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
- return ret(ch)
- } else if (ch == '0' && stream.eat(/x/i)) {
- stream.eatWhile(/[\da-f]/i)
- return ret('number', 'number')
- } else if (/\d/.test(ch) || (ch == '-' && stream.eat(/\d/))) {
- stream.match(/^\d*(?:\.\d*(?!\.))?(?:[eE][+\-]?\d+)?/)
- return ret('number', 'number')
- } else if (state.reAllowed && ch == '~' && stream.eat(/\//)) {
- toUnescaped(stream, '/')
- stream.eatWhile(/[gimsu]/)
- return ret('regexp', 'string-2')
- } else if (ch == '/') {
- if (stream.eat('*')) {
- return chain(stream, state, haxeTokenComment)
- } else if (stream.eat('/')) {
- stream.skipToEnd()
- return ret('comment', 'comment')
- } else {
- stream.eatWhile(isOperatorChar)
- return ret('operator', null, stream.current())
- }
- } else if (ch == '#') {
- stream.skipToEnd()
- return ret('conditional', 'meta')
- } else if (ch == '@') {
- stream.eat(/:/)
- stream.eatWhile(/[\w_]/)
- return ret('metadata', 'meta')
- } else if (isOperatorChar.test(ch)) {
- stream.eatWhile(isOperatorChar)
- return ret('operator', null, stream.current())
- } else {
- var word
- if (/[A-Z]/.test(ch)) {
- stream.eatWhile(/[\w_<>]/)
- word = stream.current()
- return ret('type', 'variable-3', word)
- } else {
- stream.eatWhile(/[\w_]/)
- var word = stream.current(),
- known = keywords.propertyIsEnumerable(word) && keywords[word]
- return known && state.kwAllowed ? ret(known.type, known.style, word) : ret('variable', 'variable', word)
- }
- }
- }
- function haxeTokenString(quote) {
- return function (stream, state) {
- if (toUnescaped(stream, quote)) state.tokenize = haxeTokenBase
- return ret('string', 'string')
- }
- }
- function haxeTokenComment(stream, state) {
- var maybeEnd = false,
- ch
- while ((ch = stream.next())) {
- if (ch == '/' && maybeEnd) {
- state.tokenize = haxeTokenBase
- break
- }
- maybeEnd = ch == '*'
- }
- return ret('comment', 'comment')
- }
- // Parser
- var atomicTypes = { atom: true, number: true, variable: true, string: true, regexp: true }
- function HaxeLexical(indented, column, type, align, prev, info) {
- this.indented = indented
- this.column = column
- this.type = type
- this.prev = prev
- this.info = info
- if (align != null) this.align = align
- }
- function inScope(state, varname) {
- for (var v = state.localVars; v; v = v.next) if (v.name == varname) return true
- }
- function parseHaxe(state, style, type, content, stream) {
- var cc = state.cc
- // Communicate our context to the combinators.
- // (Less wasteful than consing up a hundred closures on every call.)
- cx.state = state
- cx.stream = stream
- ;(cx.marked = null), (cx.cc = cc)
- if (!state.lexical.hasOwnProperty('align')) state.lexical.align = true
- while (true) {
- var combinator = cc.length ? cc.pop() : statement
- if (combinator(type, content)) {
- while (cc.length && cc[cc.length - 1].lex) cc.pop()()
- if (cx.marked) return cx.marked
- if (type == 'variable' && inScope(state, content)) return 'variable-2'
- if (type == 'variable' && imported(state, content)) return 'variable-3'
- return style
- }
- }
- }
- function imported(state, typename) {
- if (/[a-z]/.test(typename.charAt(0))) return false
- var len = state.importedtypes.length
- for (var i = 0; i < len; i++) if (state.importedtypes[i] == typename) return true
- }
- function registerimport(importname) {
- var state = cx.state
- for (var t = state.importedtypes; t; t = t.next) if (t.name == importname) return
- state.importedtypes = { name: importname, next: state.importedtypes }
- }
- // Combinator utils
- var cx = { state: null, column: null, marked: null, cc: null }
- function pass() {
- for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i])
- }
- function cont() {
- pass.apply(null, arguments)
- return true
- }
- function inList(name, list) {
- for (var v = list; v; v = v.next) if (v.name == name) return true
- return false
- }
- function register(varname) {
- var state = cx.state
- if (state.context) {
- cx.marked = 'def'
- if (inList(varname, state.localVars)) return
- state.localVars = { name: varname, next: state.localVars }
- } else if (state.globalVars) {
- if (inList(varname, state.globalVars)) return
- state.globalVars = { name: varname, next: state.globalVars }
- }
- }
- // Combinators
- var defaultVars = { name: 'this', next: null }
- function pushcontext() {
- if (!cx.state.context) cx.state.localVars = defaultVars
- cx.state.context = { prev: cx.state.context, vars: cx.state.localVars }
- }
- function popcontext() {
- cx.state.localVars = cx.state.context.vars
- cx.state.context = cx.state.context.prev
- }
- popcontext.lex = true
- function pushlex(type, info) {
- var result = function () {
- var state = cx.state
- state.lexical = new HaxeLexical(state.indented, cx.stream.column(), type, null, state.lexical, info)
- }
- result.lex = true
- return result
- }
- function poplex() {
- var state = cx.state
- if (state.lexical.prev) {
- if (state.lexical.type == ')') state.indented = state.lexical.indented
- state.lexical = state.lexical.prev
- }
- }
- poplex.lex = true
- function expect(wanted) {
- function f(type) {
- if (type == wanted) return cont()
- else if (wanted == ';') return pass()
- else return cont(f)
- }
- return f
- }
- function statement(type) {
- if (type == '@') return cont(metadef)
- if (type == 'var') return cont(pushlex('vardef'), vardef1, expect(';'), poplex)
- if (type == 'keyword a') return cont(pushlex('form'), expression, statement, poplex)
- if (type == 'keyword b') return cont(pushlex('form'), statement, poplex)
- if (type == '{') return cont(pushlex('}'), pushcontext, block, poplex, popcontext)
- if (type == ';') return cont()
- if (type == 'attribute') return cont(maybeattribute)
- if (type == 'function') return cont(functiondef)
- if (type == 'for') return cont(pushlex('form'), expect('('), pushlex(')'), forspec1, expect(')'), poplex, statement, poplex)
- if (type == 'variable') return cont(pushlex('stat'), maybelabel)
- if (type == 'switch') return cont(pushlex('form'), expression, pushlex('}', 'switch'), expect('{'), block, poplex, poplex)
- if (type == 'case') return cont(expression, expect(':'))
- if (type == 'default') return cont(expect(':'))
- if (type == 'catch') return cont(pushlex('form'), pushcontext, expect('('), funarg, expect(')'), statement, poplex, popcontext)
- if (type == 'import') return cont(importdef, expect(';'))
- if (type == 'typedef') return cont(typedef)
- return pass(pushlex('stat'), expression, expect(';'), poplex)
- }
- function expression(type) {
- if (atomicTypes.hasOwnProperty(type)) return cont(maybeoperator)
- if (type == 'type') return cont(maybeoperator)
- if (type == 'function') return cont(functiondef)
- if (type == 'keyword c') return cont(maybeexpression)
- if (type == '(') return cont(pushlex(')'), maybeexpression, expect(')'), poplex, maybeoperator)
- if (type == 'operator') return cont(expression)
- if (type == '[') return cont(pushlex(']'), commasep(maybeexpression, ']'), poplex, maybeoperator)
- if (type == '{') return cont(pushlex('}'), commasep(objprop, '}'), poplex, maybeoperator)
- return cont()
- }
- function maybeexpression(type) {
- if (type.match(/[;\}\)\],]/)) return pass()
- return pass(expression)
- }
- function maybeoperator(type, value) {
- if (type == 'operator' && /\+\+|--/.test(value)) return cont(maybeoperator)
- if (type == 'operator' || type == ':') return cont(expression)
- if (type == ';') return
- if (type == '(') return cont(pushlex(')'), commasep(expression, ')'), poplex, maybeoperator)
- if (type == '.') return cont(property, maybeoperator)
- if (type == '[') return cont(pushlex(']'), expression, expect(']'), poplex, maybeoperator)
- }
- function maybeattribute(type) {
- if (type == 'attribute') return cont(maybeattribute)
- if (type == 'function') return cont(functiondef)
- if (type == 'var') return cont(vardef1)
- }
- function metadef(type) {
- if (type == ':') return cont(metadef)
- if (type == 'variable') return cont(metadef)
- if (type == '(') return cont(pushlex(')'), commasep(metaargs, ')'), poplex, statement)
- }
- function metaargs(type) {
- if (type == 'variable') return cont()
- }
- function importdef(type, value) {
- if (type == 'variable' && /[A-Z]/.test(value.charAt(0))) {
- registerimport(value)
- return cont()
- } else if (type == 'variable' || type == 'property' || type == '.' || value == '*') return cont(importdef)
- }
- function typedef(type, value) {
- if (type == 'variable' && /[A-Z]/.test(value.charAt(0))) {
- registerimport(value)
- return cont()
- } else if (type == 'type' && /[A-Z]/.test(value.charAt(0))) {
- return cont()
- }
- }
- function maybelabel(type) {
- if (type == ':') return cont(poplex, statement)
- return pass(maybeoperator, expect(';'), poplex)
- }
- function property(type) {
- if (type == 'variable') {
- cx.marked = 'property'
- return cont()
- }
- }
- function objprop(type) {
- if (type == 'variable') cx.marked = 'property'
- if (atomicTypes.hasOwnProperty(type)) return cont(expect(':'), expression)
- }
- function commasep(what, end) {
- function proceed(type) {
- if (type == ',') return cont(what, proceed)
- if (type == end) return cont()
- return cont(expect(end))
- }
- return function (type) {
- if (type == end) return cont()
- else return pass(what, proceed)
- }
- }
- function block(type) {
- if (type == '}') return cont()
- return pass(statement, block)
- }
- function vardef1(type, value) {
- if (type == 'variable') {
- register(value)
- return cont(typeuse, vardef2)
- }
- return cont()
- }
- function vardef2(type, value) {
- if (value == '=') return cont(expression, vardef2)
- if (type == ',') return cont(vardef1)
- }
- function forspec1(type, value) {
- if (type == 'variable') {
- register(value)
- return cont(forin, expression)
- } else {
- return pass()
- }
- }
- function forin(_type, value) {
- if (value == 'in') return cont()
- }
- function functiondef(type, value) {
- //function names starting with upper-case letters are recognised as types, so cludging them together here.
- if (type == 'variable' || type == 'type') {
- register(value)
- return cont(functiondef)
- }
- if (value == 'new') return cont(functiondef)
- if (type == '(') return cont(pushlex(')'), pushcontext, commasep(funarg, ')'), poplex, typeuse, statement, popcontext)
- }
- function typeuse(type) {
- if (type == ':') return cont(typestring)
- }
- function typestring(type) {
- if (type == 'type') return cont()
- if (type == 'variable') return cont()
- if (type == '{') return cont(pushlex('}'), commasep(typeprop, '}'), poplex)
- }
- function typeprop(type) {
- if (type == 'variable') return cont(typeuse)
- }
- function funarg(type, value) {
- if (type == 'variable') {
- register(value)
- return cont(typeuse)
- }
- }
- // Interface
- return {
- startState: function (basecolumn) {
- var defaulttypes = ['Int', 'Float', 'String', 'Void', 'Std', 'Bool', 'Dynamic', 'Array']
- var state = {
- tokenize: haxeTokenBase,
- reAllowed: true,
- kwAllowed: true,
- cc: [],
- lexical: new HaxeLexical((basecolumn || 0) - indentUnit, 0, 'block', false),
- localVars: parserConfig.localVars,
- importedtypes: defaulttypes,
- context: parserConfig.localVars && { vars: parserConfig.localVars },
- indented: 0,
- }
- if (parserConfig.globalVars && typeof parserConfig.globalVars == 'object') state.globalVars = parserConfig.globalVars
- return state
- },
- token: function (stream, state) {
- if (stream.sol()) {
- if (!state.lexical.hasOwnProperty('align')) state.lexical.align = false
- state.indented = stream.indentation()
- }
- if (stream.eatSpace()) return null
- var style = state.tokenize(stream, state)
- if (type == 'comment') return style
- state.reAllowed = !!(type == 'operator' || type == 'keyword c' || type.match(/^[\[{}\(,;:]$/))
- state.kwAllowed = type != '.'
- return parseHaxe(state, style, type, content, stream)
- },
- indent: function (state, textAfter) {
- if (state.tokenize != haxeTokenBase) return 0
- var firstChar = textAfter && textAfter.charAt(0),
- lexical = state.lexical
- if (lexical.type == 'stat' && firstChar == '}') lexical = lexical.prev
- var type = lexical.type,
- closing = firstChar == type
- if (type == 'vardef') return lexical.indented + 4
- else if (type == 'form' && firstChar == '{') return lexical.indented
- else if (type == 'stat' || type == 'form') return lexical.indented + indentUnit
- else if (lexical.info == 'switch' && !closing) return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit)
- else if (lexical.align) return lexical.column + (closing ? 0 : 1)
- else return lexical.indented + (closing ? 0 : indentUnit)
- },
- electricChars: '{}',
- blockCommentStart: '/*',
- blockCommentEnd: '*/',
- lineComment: '//',
- }
- })
- CodeMirror.defineMIME('text/x-haxe', 'haxe')
- CodeMirror.defineMode('hxml', function () {
- return {
- startState: function () {
- return {
- define: false,
- inString: false,
- }
- },
- token: function (stream, state) {
- var ch = stream.peek()
- var sol = stream.sol()
- ///* comments */
- if (ch == '#') {
- stream.skipToEnd()
- return 'comment'
- }
- if (sol && ch == '-') {
- var style = 'variable-2'
- stream.eat(/-/)
- if (stream.peek() == '-') {
- stream.eat(/-/)
- style = 'keyword a'
- }
- if (stream.peek() == 'D') {
- stream.eat(/[D]/)
- style = 'keyword c'
- state.define = true
- }
- stream.eatWhile(/[A-Z]/i)
- return style
- }
- var ch = stream.peek()
- if (state.inString == false && ch == "'") {
- state.inString = true
- stream.next()
- }
- if (state.inString == true) {
- if (stream.skipTo("'")) {
- } else {
- stream.skipToEnd()
- }
- if (stream.peek() == "'") {
- stream.next()
- state.inString = false
- }
- return 'string'
- }
- stream.next()
- return null
- },
- lineComment: '#',
- }
- })
- CodeMirror.defineMIME('text/x-hxml', 'hxml')
- })
|