scripts/CodeMirror/mode/swift/swift.js (view raw)
1// CodeMirror, copyright (c) by Marijn Haverbeke and others
2// Distributed under an MIT license: https://codemirror.net/LICENSE
3
4// Swift mode created by Michael Kaminsky https://github.com/mkaminsky11
5
6(function(mod) {
7 if (typeof exports == "object" && typeof module == "object")
8 mod(require("../../lib/codemirror"))
9 else if (typeof define == "function" && define.amd)
10 define(["../../lib/codemirror"], mod)
11 else
12 mod(CodeMirror)
13})(function(CodeMirror) {
14 "use strict"
15
16 function wordSet(words) {
17 var set = {}
18 for (var i = 0; i < words.length; i++) set[words[i]] = true
19 return set
20 }
21
22 var keywords = wordSet(["_","var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype",
23 "open","public","internal","fileprivate","private","deinit","init","new","override","self","subscript","super",
24 "convenience","dynamic","final","indirect","lazy","required","static","unowned","unowned(safe)","unowned(unsafe)","weak","as","is",
25 "break","case","continue","default","else","fallthrough","for","guard","if","in","repeat","switch","where","while",
26 "defer","return","inout","mutating","nonmutating","catch","do","rethrows","throw","throws","try","didSet","get","set","willSet",
27 "assignment","associativity","infix","left","none","operator","postfix","precedence","precedencegroup","prefix","right",
28 "Any","AnyObject","Type","dynamicType","Self","Protocol","__COLUMN__","__FILE__","__FUNCTION__","__LINE__"])
29 var definingKeywords = wordSet(["var","let","class","enum","extension","import","protocol","struct","func","typealias","associatedtype","for"])
30 var atoms = wordSet(["true","false","nil","self","super","_"])
31 var types = wordSet(["Array","Bool","Character","Dictionary","Double","Float","Int","Int8","Int16","Int32","Int64","Never","Optional","Set","String",
32 "UInt8","UInt16","UInt32","UInt64","Void"])
33 var operators = "+-/*%=|&<>~^?!"
34 var punc = ":;,.(){}[]"
35 var binary = /^\-?0b[01][01_]*/
36 var octal = /^\-?0o[0-7][0-7_]*/
37 var hexadecimal = /^\-?0x[\dA-Fa-f][\dA-Fa-f_]*(?:(?:\.[\dA-Fa-f][\dA-Fa-f_]*)?[Pp]\-?\d[\d_]*)?/
38 var decimal = /^\-?\d[\d_]*(?:\.\d[\d_]*)?(?:[Ee]\-?\d[\d_]*)?/
39 var identifier = /^\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1/
40 var property = /^\.(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
41 var instruction = /^\#[A-Za-z]+/
42 var attribute = /^@(?:\$\d+|(`?)[_A-Za-z][_A-Za-z$0-9]*\1)/
43 //var regexp = /^\/(?!\s)(?:\/\/)?(?:\\.|[^\/])+\//
44
45 function tokenBase(stream, state, prev) {
46 if (stream.sol()) state.indented = stream.indentation()
47 if (stream.eatSpace()) return null
48
49 var ch = stream.peek()
50 if (ch == "/") {
51 if (stream.match("//")) {
52 stream.skipToEnd()
53 return "comment"
54 }
55 if (stream.match("/*")) {
56 state.tokenize.push(tokenComment)
57 return tokenComment(stream, state)
58 }
59 }
60 if (stream.match(instruction)) return "builtin"
61 if (stream.match(attribute)) return "attribute"
62 if (stream.match(binary)) return "number"
63 if (stream.match(octal)) return "number"
64 if (stream.match(hexadecimal)) return "number"
65 if (stream.match(decimal)) return "number"
66 if (stream.match(property)) return "property"
67 if (operators.indexOf(ch) > -1) {
68 stream.next()
69 return "operator"
70 }
71 if (punc.indexOf(ch) > -1) {
72 stream.next()
73 stream.match("..")
74 return "punctuation"
75 }
76 var stringMatch
77 if (stringMatch = stream.match(/("""|"|')/)) {
78 var tokenize = tokenString.bind(null, stringMatch[0])
79 state.tokenize.push(tokenize)
80 return tokenize(stream, state)
81 }
82
83 if (stream.match(identifier)) {
84 var ident = stream.current()
85 if (types.hasOwnProperty(ident)) return "variable-2"
86 if (atoms.hasOwnProperty(ident)) return "atom"
87 if (keywords.hasOwnProperty(ident)) {
88 if (definingKeywords.hasOwnProperty(ident))
89 state.prev = "define"
90 return "keyword"
91 }
92 if (prev == "define") return "def"
93 return "variable"
94 }
95
96 stream.next()
97 return null
98 }
99
100 function tokenUntilClosingParen() {
101 var depth = 0
102 return function(stream, state, prev) {
103 var inner = tokenBase(stream, state, prev)
104 if (inner == "punctuation") {
105 if (stream.current() == "(") ++depth
106 else if (stream.current() == ")") {
107 if (depth == 0) {
108 stream.backUp(1)
109 state.tokenize.pop()
110 return state.tokenize[state.tokenize.length - 1](stream, state)
111 }
112 else --depth
113 }
114 }
115 return inner
116 }
117 }
118
119 function tokenString(openQuote, stream, state) {
120 var singleLine = openQuote.length == 1
121 var ch, escaped = false
122 while (ch = stream.peek()) {
123 if (escaped) {
124 stream.next()
125 if (ch == "(") {
126 state.tokenize.push(tokenUntilClosingParen())
127 return "string"
128 }
129 escaped = false
130 } else if (stream.match(openQuote)) {
131 state.tokenize.pop()
132 return "string"
133 } else {
134 stream.next()
135 escaped = ch == "\\"
136 }
137 }
138 if (singleLine) {
139 state.tokenize.pop()
140 }
141 return "string"
142 }
143
144 function tokenComment(stream, state) {
145 var ch
146 while (true) {
147 stream.match(/^[^/*]+/, true)
148 ch = stream.next()
149 if (!ch) break
150 if (ch === "/" && stream.eat("*")) {
151 state.tokenize.push(tokenComment)
152 } else if (ch === "*" && stream.eat("/")) {
153 state.tokenize.pop()
154 }
155 }
156 return "comment"
157 }
158
159 function Context(prev, align, indented) {
160 this.prev = prev
161 this.align = align
162 this.indented = indented
163 }
164
165 function pushContext(state, stream) {
166 var align = stream.match(/^\s*($|\/[\/\*])/, false) ? null : stream.column() + 1
167 state.context = new Context(state.context, align, state.indented)
168 }
169
170 function popContext(state) {
171 if (state.context) {
172 state.indented = state.context.indented
173 state.context = state.context.prev
174 }
175 }
176
177 CodeMirror.defineMode("swift", function(config) {
178 return {
179 startState: function() {
180 return {
181 prev: null,
182 context: null,
183 indented: 0,
184 tokenize: []
185 }
186 },
187
188 token: function(stream, state) {
189 var prev = state.prev
190 state.prev = null
191 var tokenize = state.tokenize[state.tokenize.length - 1] || tokenBase
192 var style = tokenize(stream, state, prev)
193 if (!style || style == "comment") state.prev = prev
194 else if (!state.prev) state.prev = style
195
196 if (style == "punctuation") {
197 var bracket = /[\(\[\{]|([\]\)\}])/.exec(stream.current())
198 if (bracket) (bracket[1] ? popContext : pushContext)(state, stream)
199 }
200
201 return style
202 },
203
204 indent: function(state, textAfter) {
205 var cx = state.context
206 if (!cx) return 0
207 var closing = /^[\]\}\)]/.test(textAfter)
208 if (cx.align != null) return cx.align - (closing ? 1 : 0)
209 return cx.indented + (closing ? 0 : config.indentUnit)
210 },
211
212 electricInput: /^\s*[\)\}\]]$/,
213
214 lineComment: "//",
215 blockCommentStart: "/*",
216 blockCommentEnd: "*/",
217 fold: "brace",
218 closeBrackets: "()[]{}''\"\"``"
219 }
220 })
221
222 CodeMirror.defineMIME("text/x-swift","swift")
223});