shrub/lib/syntax/hoon.js
2015-10-08 15:23:03 -07:00

177 lines
4.3 KiB
JavaScript

CodeMirror.defineMode("hoon", function() {
glyph = /[+\-|$%:.#^~;=?!_,&\/<>%*]/
term = /^[$&|]|^[a-z]([a-z0-9\-]*[a-z0-9])?/
num = /-?-?^[0-9]([0-9.]*|[xwbv]?[0-9a-zA-Z.-~]*)/
res = {}
res.startState = function(){return {soblock: false, doqblock:false, inter:[], sail:false, space:true}}
var propOrVar = function(c){
if(c == '.')
return 'property'
return 'variable'
}
var nomQuote = function(stream,state){
reg = new RegExp('^[^'+state.inter[0]+'{\\\\]')
while(stream.match(reg) || stream.match(/\\./));
if(!stream.eat("{")) {
if(state.inter[0]){stream.eat(state.inter[0])}
state.inter.shift()
}
return 'string'
}
res.token = function(stream, state){
if(state.soqblock && stream.sol()){
if(stream.match(/\s*'''/)){
state.soqblock = false
}
else {
stream.skipToEnd()
}
return "string"
}
if(state.doqblock){
if(stream.match(/\s*"""/)){
state.doqblock = false
}
else {
stream.skipToEnd()
}
return "string"
}
if((state.inter.length) && stream.eat('}')){
return nomQuote(stream,state)
}
if(stream.sol())
state.space = true
if(state.sail){
if(stream.peek().match(/[^#./() ]/)||stream.eol()){
state.sail = false
if(stream.match(/:? /)){
// state.inter = ''
stream.skipToEnd()
return 'string'
}
if(stream.match(term))
state.sail = true
return;
if(stream.match(':'))
state.sail = true
return 'operator'
}
}
if(stream.match("'")){
if(stream.match("''")){
state.soqblock = true
return 'string'
}
while(stream.match(/^[^'\\]/) || stream.match(/\\./));
stream.eat("'")
return 'string'
}
if(stream.match('"')){
if(stream.match('""')){
state.doqblock = true
stream.skipToEnd()
return 'string'
}
state.inter.unshift('"')
return nomQuote(stream,state)
}
if(stream.match(' ;')){
if(stream.eat(' ')){
stream.skipToEnd()
return 'string'
}
if(!stream.match(glyph)){
state.sail = true
}
return 'builtin'
}
if(stream.match('::')){
stream.skipToEnd()
return 'comment'
}
if(stream.match('++ ') || stream.match('+- ')){
stream.match(term)
return 'header'
}
if(state.space && stream.match('--')){
if(stream.eat(glyph) || stream.eat(/[a-z0-9]/))
stream.backUp(3)
else return 'header'
}
if(stream.eat('%'))
if(stream.match(term) || stream.match(num))
return 'tag'
else stream.backUp(1)
if(state.space && stream.match('==')){
return 'tag'
}
if(stream.match(/^@[a-z]*[A-Z]?/))
return 'atom'
if(stream.match(num))
return 'number'
if(stream.eat(/[+\-]/)){
while(stream.eat(/[<>]/) && stream.eat(/[+\-]/));
return propOrVar(stream.peek())
}
if(stream.eat('`')){
state.space = true
return 'operator'
}
if(stream.sol() && stream.eatWhile(glyph)){
state.space = false
return 'builtin'
}
if(stream.eat(glyph)){
state.space = false
stream.backUp(2)
if(stream.eat(/[ ([{]/) || (stream.peek().match(/[^+\-<>]/)
&& stream.eat(glyph))){ // expression start
stream.eatWhile(glyph)
return 'builtin'
}
stream.next()
if(state.space && stream.eat('=')){
if(/[()]/.exec(stream.peek()))
return 'builtin'
return 'operator'
}
if(stream.eat(/[=:.^]/)){
state.space = true
return 'operator'
}
stream.next()
return 'builtin'
}
if(stream.match(term)){
if(state.space && stream.match('/'))
return 'tag'
state.space = false
return propOrVar(stream.peek())
}
if(stream.eat(/[ \[(]/)){
state.space = true
return
}
if(stream.eat(')') || stream.eat(']')){ // XX paren match
return
}
stream.next()
return "error"
}
res.lineComment = '::'
res.fold = "indent"
return res
});
CodeMirror.registerHelper("wordChars", "hoon", /[-\\w]/);
CodeMirror.defineMIME("text/x-hoon", "hoon");