from tab import StackTabber2 from mode import Fundamental from lex import Grammar, PatternRule, RegionRule, PatternMatchRule from mode.sh import ShGrammar from mode.xml import XMLGrammar from mode.pipe import Pipe from method.shell import Interact from method import Method, arg import default import urllib2 import os import re from subprocess import Popen, PIPE, STDOUT chr1 = '[a-zA-Z_]' chr2 = '[a-zA-Z_0-9]' word = chr1 + chr2 + '*' class NestedCommentGrammar(Grammar): pass NestedCommentGrammar.rules = [ RegionRule('comment', r'/\*', NestedCommentGrammar, r'\*/'), PatternRule('data', r'(?:[^\*]|\*(?!/))+'), ] class StringGrammar(Grammar): rules = [ PatternRule('escaped', r"\\u[0-9A-Fa-f]{4}|\\[0-7]{1,3}|\\[btnfr\"'\\]"), PatternRule('data', r'[^\\"]+'), ] class SubTypeGrammar(Grammar): pass SubTypeGrammar.rules = [ RegionRule('sub', r'\[', SubTypeGrammar, r'\]'), #PatternRule('scala.type', '(?:[a-zA-Z0-9_.]+| *=> *)+'), PatternRule('scala.type', '[A-Z][a-zA-Z0-9_.]*'), PatternRule('spaces', ' +'), PatternRule('scala.annotation', '@[a-zA-Z_][a-zA-Z0-9_]*'), ] class ScalaGrammar(Grammar): rules = [ PatternRule('scala.comment', '//.*$'), RegionRule('scala.comment', r'/\*', NestedCommentGrammar, r'\*/'), RegionRule('scala.script', r'#!.+$', ShGrammar, r'!#'), #PatternMatchRule('x', r'(? *)+)', # 'delimiter', 'scala.type'), #PatternMatchRule('x', r'(? *)+)', # 'delimiter', 'spaces', 'scala.type'), PatternMatchRule('x', r'(?<=[a-zA-Z0-9_ ])(:)([a-zA-Z0-9_]+)', 'delimiter', 'scala.type'), PatternMatchRule('x', r'(?<=[a-zA-Z0-9_ ])(:)( +)([a-zA-Z0-9_]+)', 'delimiter', 'spaces', 'scala.type'), #PatternMatchRule('x', r'(extends|with|new)( +)([a-zA-Z0-9_.]+)', # 'scala.reserved', 'spaces', 'scala.type'), #PatternMatchRule('x', r'(with)( +)([a-zA-Z0-9_.]+)', # 'scala.reserved', 'spaces', 'scala.type'), #PatternMatchRule('x', r'(new)( +)([a-zA-Z0-9_.]+)', # 'scala.reserved', 'spaces', 'scala.type'), PatternRule('scala.def', '(?<=(?|:|/|\+|-|\*|=)'), RegionRule('sub', r'(?<=:)\(', SubTypeGrammar, r'\)'), PatternRule('delimiter', r'(?:;|{|}|\(|\)|,|\.|<(?![a-zA-Z_])|>|:|/|\+|-|\*|=)'), RegionRule('sub', r'\[', SubTypeGrammar, r'\]'), RegionRule('scala.inline', r'(?:^| )(?=<[a-zA-Z_])', XMLGrammar, '^[ \t]*$'), PatternRule('spaces', r'(?:\t| )+'), PatternRule('eol', r'\n'), #PatternRule('scala.def', '(?<=(? 1: self.pkg = '.'.join(toks[:-1]) + '.' else: self.pkg = None return self._abbrev(line[:-1]) def _parse_method(self, line): return self._abbrev(line[:-1]).replace("(", " (") prims = { 'B': 'byte', 'C': 'char', 'D': 'double', 'F': 'float', 'I': 'int', 'J': 'long', 'S': 'short', 'V': 'void', 'Z': 'bool', } def _parse_args(self, line): args = [] i = 0 arr = "" while i < len(line): if line[i] in self.prims: args.append(self.prims[line[i]] + arr) arr = "" elif line[i] == "[": arr += "[]" elif line[i] == "L": j = i + 1 while line[j] != ';': j += 1 args.append(self._abbrev(line[i + 1:j]) + arr) arr = "" i = j else: raise Exception("huh? saw %r (%r)" % (line[i:], line)) i += 1 return args typs = { 'InterfaceMethod': 'iface ', 'Method': 'method', } field_re = re.compile('^Field\s+([^:]+):(.+)$') long_re = re.compile('^long\s+(\d+)[lL]$') double_re = re.compile('^double\s+([\d.]+)[dD]$') sig_re = re.compile('^(\w+)\s+([^:]+):\(([^)]*)\)(.+)$') def _parse_sig(self, line): if line.startswith('class'): _, name = line.split() return "class " + self._abbrev(name) elif line.startswith('String'): return 'string "%s"' % line[7:] elif line.startswith('Field'): m = self.field_re.match(line) if not m: raise Exception("failed to match (1) %r" % line) name = self._abbrev(m.group(1)) result = self._parse_args(m.group(2))[0] #return "field %s -> %s" % (name, result) return "field %s %s" % (result, name) elif line.startswith('long'): return 'long %s' % line[5:] elif line.startswith('int'): return 'int %s' % line[4:] elif line.startswith('double'): return 'double %s' % line[7:] else: m = self.sig_re.match(line) if not m: raise Exception("failed to match (3) %r" % line) typ = self.typs[m.group(1)] name = self._abbrev(m.group(2)) args = self._parse_args(m.group(3)) result = self._parse_args(m.group(4))[0] #return "%s %s (%s) -> %s" % (typ, name, ', '.join(args), result) return "%s %s %s (%s)" % (typ, result, name, ', '.join(args)) def _parse_instruction(self, line): if '//' in line: real, x = line.split('//') sig = self._parse_sig(x.strip()) else: real, sig = line, None toks = real.split() n = toks[0][:-1] ins = toks[1] rest = [t[:-1] for t in toks[2:]] args = " ".join(rest) if sig: #return "%4s %-22s -- %s" % (n, ins + " " + args, sig) return "%4s %-22s --%s" % (n, ins + " " + args, sig) else: return "%4s %-22s" % (n, ins + " " + args) def _execute(self, w, **vargs): clsname = vargs['classname'] cp = '.:target/scala-2.9.1.final/classes' #FIXME argv = ['javap', '-classpath', cp, '-c', '-private', clsname] p = Popen(argv, stdout=PIPE, stderr=STDOUT) lines = p.stdout.readlines() obj = None methods = [] curr = None instructions = [] for i, line in enumerate(lines): line = line.strip() if i == 0: continue elif i == 1: obj = self._parse_obj(line) elif line == "Code:": continue elif line == "" or line == "}": if curr: methods.append((curr, instructions)) curr = None instructions = [] elif self.ins_re.match(line): instructions.append(self._parse_instruction(line)) else: import sys curr = self._parse_method(line) outlines = [] if self.pkg: outlines.append('package ' + self.pkg[:-1]) outlines.append('') outlines.append(str(obj) + " {") for method, instructions in methods: if instructions: outlines.append(" " + method + " {") for ins in instructions: outlines.append(" " + ins) outlines.append(" }") else: outlines.append(" " + method + " {}") outlines.append("}") output = "\n".join(outlines) name = "*Javap:%s*" % clsname w.application.data_buffer(name, output, modename='javap', switch_to=True) # white is for delimiters, operators, numbers default = ('default', 'default') # magenta is for keywords/builtins lo_magenta = ('magenta202', 'default') hi_magenta = ('magenta414', 'default') # red is for comments lo_red = ('red300', 'default') hi_red = ('red511', 'default') # orange is for macro definitions, headers and constants hi_orange = ('yellow531', 'default') lo_orange = ('yellow520', 'default') # yellow is for parts of macros hi_yellow = ('yellow551', 'default') lo_yellow = ('yellow330', 'default') # green is for strings and characters lo_green = ('green030', 'default') hi_green = ('green050', 'default') # cyan is for types lo_cyan = ('cyan033', 'default') hi_cyan = ('cyan155', 'default') # blue is definitions, functions and some macros lo_blue = ('blue113', 'default') hi_blue = ('blue225', 'default') class Scala(Fundamental): name = 'Scala' extensions = ['.scala'] tabwidth = 2 tabbercls = ScalaTabber grammar = ScalaGrammar commentc = '//' #actions = [ScalaStart, ScalaDocBrowse, ScalaDocLookup, ScalaGetType, ScalaGotoDefinition] actions = [ScalaStart, ScalaDecompile] opentokens = ('delimiter', 'sub.start', 'sub.sub.start', 'sub.sub.sub.start') opentags = {'(': ')', '[': ']', '{': '}'} closetokens = ('delimiter', 'sub.end', 'sub.sub.end', 'sub.sub.sub.end') closetags = {')': '(', ']': '[', '}': '{'} config = { 'scala.api': 'http://www.scala-lang.org/api/current/allclasses.html', 'scala.api-base': 'http://www.scala-lang.org/api/current', 'scala.type-abbrev': True, } colors = { 'scala.script.start': hi_red, 'scala.script.end': hi_red, 'scala.annotation': lo_orange, 'scala.pseudo': hi_magenta, 'scala.reserved': hi_cyan, 'scala.integer': default, 'scala.float': default, 'scala.bareword': default, 'scala.symbol': hi_orange, 'scala.class': hi_yellow, 'scala.object': hi_yellow, 'scala.trait': hi_yellow, 'scala.type': hi_magenta, 'scala.def': hi_blue, 'scala.def': hi_blue, } _bindings = { #'scala-get-type': ('M-,',), #'scala-goto-definition': ('C-c ,',), 'close-paren': (')',), 'close-brace': ('}',), 'close-bracket': (']',), } class ScalaPipe(Pipe): name = 'scalapipe' grammar = ScalaGrammar def install(*args): Scala.install(*args) ScalaPipe.install(*args)