Passed
Push — master ( 3324e2...2ba76b )
by Ralf
13:44
created

julia.js ➔ tokenBase   F

Complexity

Conditions 37

Size

Total Lines 156
Code Lines 82

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 82
c 0
b 0
f 0
dl 0
loc 156
rs 0
cc 37

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like julia.js ➔ tokenBase often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: http://codemirror.net/LICENSE
3
4
(function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
    mod(require("../../lib/codemirror"));
7
  else if (typeof define == "function" && define.amd) // AMD
0 ignored issues
show
Bug introduced by
The variable define seems to be never declared. If this is a global, consider adding a /** global: define */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
    define(["../../lib/codemirror"], mod);
9
  else // Plain browser env
10
    mod(CodeMirror);
0 ignored issues
show
Bug introduced by
The variable CodeMirror seems to be never declared. If this is a global, consider adding a /** global: CodeMirror */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
11
})(function(CodeMirror) {
12
"use strict";
13
14
CodeMirror.defineMode("julia", function(_conf, parserConf) {
15
  var ERRORCLASS = 'error';
16
17
  function wordRegexp(words) {
18
    return new RegExp("^((" + words.join(")|(") + "))\\b");
19
  }
20
21
  var operators = parserConf.operators || /^\.?[|&^\\%*+\-<>!=\/]=?|\?|~|:|\$|\.[<>]|<<=?|>>>?=?|\.[<>=]=|->?|\/\/|\bin\b/;
22
  var delimiters = parserConf.delimiters || /^[;,()[\]{}]/;
23
  var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-z0-9\u00A1-\uFFFF]*!*/;
24
  var blockOpeners = ["begin", "function", "type", "immutable", "let", "macro", "for", "while", "quote", "if", "else", "elseif", "try", "finally", "catch", "do"];
25
  var blockClosers = ["end", "else", "elseif", "catch", "finally"];
26
  var keywordList = ['if', 'else', 'elseif', 'while', 'for', 'begin', 'let', 'end', 'do', 'try', 'catch', 'finally', 'return', 'break', 'continue', 'global', 'local', 'const', 'export', 'import', 'importall', 'using', 'function', 'macro', 'module', 'baremodule', 'type', 'immutable', 'quote', 'typealias', 'abstract', 'bitstype', 'ccall'];
27
  var builtinList = ['true', 'false', 'enumerate', 'open', 'close', 'nothing', 'NaN', 'Inf', 'print', 'println', 'Int', 'Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Int64', 'Uint64', 'Int128', 'Uint128', 'Bool', 'Char', 'Float16', 'Float32', 'Float64', 'Array', 'Vector', 'Matrix', 'String', 'UTF8String', 'ASCIIString', 'error', 'warn', 'info', '@printf'];
28
29
  //var stringPrefixes = new RegExp("^[br]?('|\")")
30
  var stringPrefixes = /^(`|'|"{3}|([br]?"))/;
31
  var keywords = wordRegexp(keywordList);
32
  var builtins = wordRegexp(builtinList);
33
  var openers = wordRegexp(blockOpeners);
34
  var closers = wordRegexp(blockClosers);
35
  var macro = /^@[_A-Za-z][_A-Za-z0-9]*/;
36
  var symbol = /^:[_A-Za-z][_A-Za-z0-9]*/;
37
  var indentInfo = null;
0 ignored issues
show
Unused Code introduced by
The variable indentInfo seems to be never used. Consider removing it.
Loading history...
38
39
  function in_array(state) {
40
    var ch = cur_scope(state);
41
    if(ch=="[" || ch=="{") {
42
      return true;
43
    }
44
    else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
45
      return false;
46
    }
47
  }
48
49
  function cur_scope(state) {
50
    if(state.scopes.length==0) {
0 ignored issues
show
Best Practice introduced by
Comparing state.scopes.length to 0 using the == operator is not safe. Consider using === instead.
Loading history...
51
      return null;
52
    }
53
    return state.scopes[state.scopes.length - 1];
54
  }
55
56
  // tokenizers
57
  function tokenBase(stream, state) {
58
    // Handle scope changes
59
    var leaving_expr = state.leaving_expr;
60
    if(stream.sol()) {
61
      leaving_expr = false;
62
    }
63
    state.leaving_expr = false;
64
    if(leaving_expr) {
65
      if(stream.match(/^'+/)) {
66
        return 'operator';
67
      }
68
69
    }
70
71
    if(stream.match(/^\.{2,3}/)) {
72
      return 'operator';
73
    }
74
75
    if (stream.eatSpace()) {
76
      return null;
77
    }
78
79
    var ch = stream.peek();
80
    // Handle Comments
81
    if (ch === '#') {
82
        stream.skipToEnd();
83
        return 'comment';
84
    }
85
    if(ch==='[') {
86
      state.scopes.push("[");
87
    }
88
89
    if(ch==='{') {
90
      state.scopes.push("{");
91
    }
92
93
    var scope=cur_scope(state);
94
95
    if(scope==='[' && ch===']') {
96
      state.scopes.pop();
97
      state.leaving_expr=true;
98
    }
99
100
    if(scope==='{' && ch==='}') {
101
      state.scopes.pop();
102
      state.leaving_expr=true;
103
    }
104
105
    if(ch===')') {
106
      state.leaving_expr = true;
107
    }
108
109
    var match;
110
    if(!in_array(state) && (match=stream.match(openers, false))) {
111
      state.scopes.push(match);
112
    }
113
114
    if(!in_array(state) && stream.match(closers, false)) {
115
      state.scopes.pop();
116
    }
117
118
    if(in_array(state)) {
119
      if(stream.match(/^end/)) {
120
        return 'number';
121
      }
122
123
    }
124
125
    if(stream.match(/^=>/)) {
126
      return 'operator';
127
    }
128
129
130
    // Handle Number Literals
131
    if (stream.match(/^[0-9\.]/, false)) {
132
      var imMatcher = RegExp(/^im\b/);
133
      var floatLiteral = false;
134
      // Floats
135
      if (stream.match(/^\d*\.(?!\.)\d+([ef][\+\-]?\d+)?/i)) { floatLiteral = true; }
136
      if (stream.match(/^\d+\.(?!\.)\d*/)) { floatLiteral = true; }
137
      if (stream.match(/^\.\d+/)) { floatLiteral = true; }
138
      if (floatLiteral) {
139
          // Float literals may be "imaginary"
140
          stream.match(imMatcher);
141
          state.leaving_expr = true;
142
          return 'number';
143
      }
144
      // Integers
145
      var intLiteral = false;
146
      // Hex
147
      if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
148
      // Binary
149
      if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
150
      // Octal
151
      if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
152
      // Decimal
153
      if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
154
          intLiteral = true;
155
      }
156
      // Zero by itself with no other piece of number.
157
      if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
158
      if (intLiteral) {
159
          // Integer literals may be "long"
160
          stream.match(imMatcher);
161
          state.leaving_expr = true;
162
          return 'number';
163
      }
164
    }
165
166
    if(stream.match(/^(::)|(<:)/)) {
167
      return 'operator';
168
    }
169
170
    // Handle symbols
171
    if(!leaving_expr && stream.match(symbol)) {
172
      return 'string';
173
    }
174
175
    // Handle operators and Delimiters
176
    if (stream.match(operators)) {
177
      return 'operator';
178
    }
179
180
181
    // Handle Strings
182
    if (stream.match(stringPrefixes)) {
183
      state.tokenize = tokenStringFactory(stream.current());
184
      return state.tokenize(stream, state);
185
    }
186
187
    if (stream.match(macro)) {
188
      return 'meta';
189
    }
190
191
192
    if (stream.match(delimiters)) {
193
      return null;
194
    }
195
196
    if (stream.match(keywords)) {
197
      return 'keyword';
198
    }
199
200
    if (stream.match(builtins)) {
201
      return 'builtin';
202
    }
203
204
205
    if (stream.match(identifiers)) {
206
      state.leaving_expr=true;
207
      return 'variable';
208
    }
209
    // Handle non-detected items
210
    stream.next();
211
    return ERRORCLASS;
212
  }
213
214 View Code Duplication
  function tokenStringFactory(delimiter) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
215
    while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
216
      delimiter = delimiter.substr(1);
217
    }
218
    var singleline = delimiter.length == 1;
0 ignored issues
show
Best Practice introduced by
Comparing delimiter.length to 1 using the == operator is not safe. Consider using === instead.
Loading history...
219
    var OUTCLASS = 'string';
220
221
    function tokenString(stream, state) {
222
      while (!stream.eol()) {
223
        stream.eatWhile(/[^'"\\]/);
224
        if (stream.eat('\\')) {
225
            stream.next();
226
            if (singleline && stream.eol()) {
227
              return OUTCLASS;
228
            }
229
        } else if (stream.match(delimiter)) {
230
            state.tokenize = tokenBase;
231
            return OUTCLASS;
232
        } else {
233
            stream.eat(/['"]/);
234
        }
235
      }
236
      if (singleline) {
237
        if (parserConf.singleLineStringErrors) {
238
            return ERRORCLASS;
239
        } else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
240
            state.tokenize = tokenBase;
241
        }
242
      }
243
      return OUTCLASS;
244
    }
245
    tokenString.isString = true;
246
    return tokenString;
247
  }
248
249
  function tokenLexer(stream, state) {
250
    indentInfo = null;
0 ignored issues
show
Unused Code introduced by
The variable indentInfo seems to be never used. Consider removing it.
Loading history...
251
    var style = state.tokenize(stream, state);
252
    var current = stream.current();
253
254
    // Handle '.' connected identifiers
255
    if (current === '.') {
256
      style = stream.match(identifiers, false) ? null : ERRORCLASS;
257
      if (style === null && state.lastStyle === 'meta') {
258
          // Apply 'meta' style to '.' connected identifiers when
259
          // appropriate.
260
        style = 'meta';
261
      }
262
      return style;
263
    }
264
265
    return style;
266
  }
267
268
  var external = {
269
    startState: function() {
270
      return {
271
        tokenize: tokenBase,
272
        scopes: [],
273
        leaving_expr: false
274
      };
275
    },
276
277
    token: function(stream, state) {
278
      var style = tokenLexer(stream, state);
279
      state.lastStyle = style;
280
      return style;
281
    },
282
283
    indent: function(state, textAfter) {
284
      var delta = 0;
285
      if(textAfter=="end" || textAfter=="]" || textAfter=="}" || textAfter=="else" || textAfter=="elseif" || textAfter=="catch" || textAfter=="finally") {
286
        delta = -1;
287
      }
288
      return (state.scopes.length + delta) * 4;
289
    },
290
291
    lineComment: "#",
292
    fold: "indent",
293
    electricChars: "edlsifyh]}"
294
  };
295
  return external;
296
});
297
298
299
CodeMirror.defineMIME("text/x-julia", "julia");
300
301
});
302