smalltalk.js
138 lines
| 3.4 KiB
| application/javascript
|
JavascriptLexer
Matthias BUSSONNIER
|
r8053 | CodeMirror.defineMode('smalltalk', function(config, modeConfig) { | |
var specialChars = /[+\-/\\*~<>=@%|&?!.:;^]/; | |||
var keywords = /true|false|nil|self|super|thisContext/; | |||
var Context = function(tokenizer, parent) { | |||
this.next = tokenizer; | |||
this.parent = parent; | |||
}; | |||
var Token = function(name, context, eos) { | |||
this.name = name; | |||
this.context = context; | |||
this.eos = eos; | |||
}; | |||
var State = function() { | |||
this.context = new Context(next, null); | |||
this.expectVariable = true; | |||
this.indentation = 0; | |||
this.userIndentationDelta = 0; | |||
}; | |||
State.prototype.userIndent = function(indentation) { | |||
this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0; | |||
}; | |||
var next = function(stream, context, state) { | |||
var token = new Token(null, context, false); | |||
var aChar = stream.next(); | |||
if (aChar === '"') { | |||
token = nextComment(stream, new Context(nextComment, context)); | |||
} else if (aChar === '\'') { | |||
token = nextString(stream, new Context(nextString, context)); | |||
} else if (aChar === '#') { | |||
stream.eatWhile(/[^ .]/); | |||
token.name = 'string-2'; | |||
} else if (aChar === '$') { | |||
stream.eatWhile(/[^ ]/); | |||
token.name = 'string-2'; | |||
} else if (aChar === '|' && state.expectVariable) { | |||
token.context = new Context(nextTemporaries, context); | |||
} else if (/[\[\]{}()]/.test(aChar)) { | |||
token.name = 'bracket'; | |||
token.eos = /[\[{(]/.test(aChar); | |||
if (aChar === '[') { | |||
state.indentation++; | |||
} else if (aChar === ']') { | |||
state.indentation = Math.max(0, state.indentation - 1); | |||
} | |||
} else if (specialChars.test(aChar)) { | |||
stream.eatWhile(specialChars); | |||
token.name = 'operator'; | |||
token.eos = aChar !== ';'; // ; cascaded message expression | |||
} else if (/\d/.test(aChar)) { | |||
stream.eatWhile(/[\w\d]/); | |||
token.name = 'number' | |||
} else if (/[\w_]/.test(aChar)) { | |||
stream.eatWhile(/[\w\d_]/); | |||
token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null; | |||
} else { | |||
token.eos = state.expectVariable; | |||
} | |||
return token; | |||
}; | |||
var nextComment = function(stream, context) { | |||
stream.eatWhile(/[^"]/); | |||
return new Token('comment', stream.eat('"') ? context.parent : context, true); | |||
}; | |||
var nextString = function(stream, context) { | |||
stream.eatWhile(/[^']/); | |||
return new Token('string', stream.eat('\'') ? context.parent : context, false); | |||
}; | |||
var nextTemporaries = function(stream, context, state) { | |||
var token = new Token(null, context, false); | |||
var aChar = stream.next(); | |||
if (aChar === '|') { | |||
token.context = context.parent; | |||
token.eos = true; | |||
} else { | |||
stream.eatWhile(/[^|]/); | |||
token.name = 'variable'; | |||
} | |||
return token; | |||
} | |||
return { | |||
startState: function() { | |||
return new State; | |||
}, | |||
token: function(stream, state) { | |||
state.userIndent(stream.indentation()); | |||
if (stream.eatSpace()) { | |||
return null; | |||
} | |||
var token = state.context.next(stream, state.context, state); | |||
state.context = token.context; | |||
state.expectVariable = token.eos; | |||
state.lastToken = token; | |||
return token.name; | |||
}, | |||
blankLine: function(state) { | |||
state.userIndent(0); | |||
}, | |||
indent: function(state, textAfter) { | |||
var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta; | |||
return (state.indentation + i) * config.indentUnit; | |||
}, | |||
electricChars: ']' | |||
}; | |||
}); | |||
CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'}); |