syntaxdef perl {

# comment
/(?m)#.*$/ : {
    region {
        type=comment;
        index=prose;
        findlinks=true;
    }
}

# POD
/^(=(pod|head1|head2|item|over|back|cut|for|begin|end))\b/m : {
    context {
        /^(=(pod|head1|head2|item|over|back|for|begin|end))\b/m : {
          region ${1} { type=commentmeta; }
        }
        /^=cut\s*$/m : exit;
    }
    region ${1} { type=commentmeta; }
    region ${ALL} {
        index=prose;
        type=comment;
        findlinks=true;
    }
}

# here-docs, can be like <<EOF or << "EOF"
/<<((\w+).*?(^\2$)|\s+"([^"]*)".*?(^\4$))/sm : {
    region {
        type=string;
        findlinks=true;
    }region ${1} { type=commentmeta; }
}

# Ignore escaped quote marks (inside regular expressions, etc)
# this way, we don't consider them starts-of-strings
"\\\"" : {}
"\\'" : {}
"\\`" : {}

# string constants (can span lines)
"'" : {
    context {
        /\\./: ;
        "'" : exit;
    }
    region ${ALL} {
        type=string;
    }
}
"\"" : {
    context {
        /\\./: ;
        "\"" : exit;
    }
    region ${ALL} {
           type=string;
    }
}
"`" : {
    context {
        /\\./: ;
        "`" : exit;
    }
    region ${ALL} {
        type=string;
    }
}

#numbers
/(0(x|X)[0-9A-Fa-f]+(l|L)?)|([0-9]+(\.[0-9]*)?|\.[0-9]+)((e|E)(\+|-)?[0-9]+)?(f|F|l|L|d|D)?/ : {
    region {
        type=numeric;
    }
}

# weird inbuilt variables
/(\$(\^[NALECDFHIMORSTVWX]|[_\&`'+*.\/|,\";%=~^:?!@$<>()\[\]\-]))|@[+-_]|%!/ : {
    region {
        type=identifier;
    }
}

# variables/expressions
/[$%@&]+\w+(::\w+)*/ : {
    region {
        type=identifier;
    }
}

# method call
/->(\w+)/ : {
    region ${1} {
        type=identifier;
    }
}

# named param
/-(\w+)\s*=>/ : {
    region ${1} {
        type=identifier;
    }
}

#keywords (s m q[qxwr] tr handled in regex rule
/([xy]|a(bs|ccept|larm|nd|tan2)|b(in(d|mode)|less)|c(aller|h(dir|mod|o(mp|p|wn)|r(|oot))|lose(|dir)|mp|o(n(nect|tinue)|s)|rypt)|d(bm(close|open)|e(fined|lete)|ie|o|ump)|e(ach|ls(e|if)|nd(grent|hostent|netent|p(rotoent|went)|servent)|of|q|val|x(ec|i(sts|t)|p))|f(cntl|ileno|lock|or(|each|k|m(at|line)))|g([et]|et(c|gr(ent|gid|nam)|host(by(addr|name)|ent)|login|net(by(addr|name)|ent)|p(eername|grp|pid|r(iority|oto(byn(ame|umber)|ent))|w(ent|nam|uid))|s(erv(by(name|port)|ent)|ock(name|opt)))|lob|mtime|oto|rep)|hex|i(f|n(dex|t)|octl)|join|k(eys|ill)|l([cet]|ast|cfirst|ength|i(nk|sten)|o(cal(|time)|g)|stat)|m(ap|kdir|sg(ctl|get|rcv|snd)|y)|n([eo]|e(w|xt)|ot)|o(ct|pen(|dir)|rd?)|p(ack(|age)|ipe|o[ps]|r(intf?|ototype)|ush)|quotemeta|r(and|e(ad(|dir|lin[ek]|pipe)|cv|do|f|name|quire|set|turn|verse|winddir)|index|mdir)|s(calar|e(ek(|dir)|lect|m(ctl|get|op)|nd|t(grent|hostent|netent|p(grp|r(iority|otoent)|went)|s(ervent|ockopt)))|h(ift|m(ctl|get|read|write)|utdown)|in|leep|o(cket(|pair)|rt)|p(li(ce|t)|rintf)|qrt|rand|t(at|udy)|ub(|str)|y(mlink|s(call|open|read|seek|tem|write)))|t(ell(|dir)|i(ed?|mes?)|(runcate))|u(c(|first)|mask|n(def|l(ess|ink)|pack|shift|ti[el])|se|time)|v(alues|ec)|w(a(it(|pid)|ntarray|rn)|hile|rite)|xor)\b/ : {
    region {
        type=keyword;
    }
}

# quote operators see http://www.perldoc.com/perl5.8.0/pod/perlop.html#Quote-and-Quote-like-Operators
# q{} qq{} qx{} qw{}
# // m{}
# qr{}
# s{}{}
# tr{}{}
#
# TODO: only handle very simple // regular expressions. It is important
# to handle all of them, so that embedded quotes don't start strings.
# But the regex for this is too hard, we need paramaterized contexts, or
# custom contexts (implemented in java)
#
# This doesn't disambiguate between the divide-by operator and the start-of-regex,
# so only search for regex (containing newlines) of a certain length (to prevent stack-over-flows etc)
/
(
   (m|q[qxwr]?)? (\/
   (
     (\\\/|[^\/\n\r])*
     |
     (\\\/|[^\/]){0,100}
   )
   \/)
) | (
   (s|tr) (\/
   (\\\/|[^\/])*
   \/
   (\\\/|[^\/])*
   \/)
)
/x : {
    region ${2} {
        type=keyword;
    }
    region ${3} {
        type=string;
    }
    region ${6} {
        type=keyword;
    }
    region ${7} {
        type=string;
    }
}

# anything else is also a variable
/\w+/ : {
    region {
        type=identifier;
    }
}

}

