Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
1295 lines (1160 sloc) 38.6 KB
import tokenizer
import chartparser
import grammar
import optable
import base
import binon
doc = path("doc:/compiler")
# It is expected these classes are here.
SyntaxError = chartparser.SyntaxError
SyntaxErrorExpected = chartparser.SyntaxErrorExpected
# TODO: You could shave away 300ms by serializing the preprocessed grammar here.
language = grammar.read_file(dir ++ "../lever-A.grammar")
# language.new_parser = chartparser.preprocess(
# language.grammar,
# language.table.nonterminal("file"))
# We allow the indentation to slip out on these tokens:
# The slip-out keywords are represented by the grammar itself from now on.
# slips = set([
# language.table.keyword(","),
# language.table.keyword(")"),
# language.table.keyword("}"),
# language.table.keyword("]") ])
main = ():
code = read_file("sample.lc", "sample.lc")
binon.write_file("sample.lc.cb", code)
# this = module("sample", base)
# exec(code, this)
# compile_file("sample.lc.cb", "sample.lc")
compile_file = (cb_path, lc_path):
source = path(lc_path).relpath(cb_path.dirname).to_string()
code = read_file(lc_path, source)
binon.write_file(cb_path, code)
read_file = (path, source=null):
result = language.read_file(path, source)
return read_parse_tree(result, source)
read_string = (string, source=null):
result = language.read_string(string)
return read_parse_tree(result, source)
#tokens = tokenizer.read_string(string, language.table.keywords)
#return read_tokens(tokens, source)
read_parse_tree = (result, source=null):
# parser = language.new_parser()
# indent = chartparser.IndentParser(tokens[0].start);
# indent = language.table.terminal("indent")
# dedent = language.table.terminal("dedent")
# newline = language.table.terminal("newline")
# for token in tokens
# indent.step(parser, token.start, source)
# terminal = language.table.terminal(token.name)
# if not parser.expecting(terminal) and terminal in slips
# indent.slip(parser, token.start, source)
# if not parser.expecting(terminal)
# raise chartparser.SyntaxErrorExpected(parser.expect, token.start, source)
# parser.step(terminal, token, token.start, token.stop)
# indent.finish(parser, token.stop)
# if not parser.accepted
# raise chartparser.SyntaxErrorExpected(parser.expect, token.stop, source, true)
# argl = []
# post = (rule, args, start, stop):
# cell = rule.annotation(actions, args, argl)
# if isinstance(cell, Cell)
# return Origin(cell, 0, start, stop)
# return cell
post = (name, args, loc):
cell = getattr(actions, name)(args...)
if isinstance(cell, Cell)
return Origin(cell, 0, loc.start, loc.stop)
return cell
consttab = ConstantTable()
functions = []
# blank_lhs = (x): # Not used often in this grammar.
# return null
rootdef = object();
body = result.traverse(post) #, blank_lhs)
scope = Scope(null, 0, 0, 0, [])
origin = null
context = Context([rootdef])
for funcdef in context.closures
context.scope = scope = funcdef.scope
context.block = entry = context.new_block()
context.is_generator = false
if scope.parent
Prog(funcdef.body).visit(context, true)
context.op('return', context.op("getglob", "null"))
else
val = Prog(funcdef.body).visit(context)
context.op('return', val)
if context.is_generator
scope.flags |= 2
functions.append(dump(
scope.flags, scope.argc, scope.topc, scope.localv,
entry, consttab, funcdef.origin))
code = {
"functions": functions,
"constants": consttab.constants,
"sources": [source],
"version": 0
}
return code
actions = object();
lookup = (symbol):
return Getvar(symbol)
int = (token):
return Code("constant", parse_int(token, 10))
hex = (token):
return Code("constant", parse_int(token, 16))
float = (token):
return Code("constant", parse_float(token))
string = (string):
return Code("constant", string)
list = (args=[]):
return Code("list", args...)
dict = (pairs=[]):
return CodeGroup("setitem",
Code("call", Getvar("dict")), pairs)
record = (pairs):
return CodeGroup("setattr",
Code("call", Getvar("object")), pairs)
scopegrabber = (expr, block):
return ScopeGrab(expr, block)
call = (callee, args=[]):
return Code("call", callee, args...)
callv = (callee, args):
return Code("callv", callee, args...)
getitem = (base, indexer):
return Code("getitem", base, indexer)
setitem = (base, indexer, expr):
return CodeM("setitem",
[base, indexer, expr],
[2, 0, 1])
getattr = (base, name):
return Code("getattr", base, name)
getattr_or_null = (base, name):
return Code("call",
Code("getglob", "getattr_or"),
base,
Code("constant", name))
setattr = (base, name, expr):
return CodeM("setattr",
[base, name, expr],
[2, 0, 1])
setattr_default = (base, name, expr):
bind_base = Let(base)
cond = Code("call",
Getvar("=="), Getvar("null"),
actions.getattr_or_null(bind_base, name))
body = [Code("setattr", bind_base, name, expr)]
conds = [[cond, body]]
return bind_base(Cond(conds, null))
prefix = (op, rhs):
return CodeM("call",
[Getvar(op ++ "expr"), rhs],
[1, 0])
binary = (lhs, op, rhs):
return CodeM("call",
[Getvar(op), lhs, rhs],
[1, 2, 0])
exponent = (base, exponent):
return Code("call", Getvar("pow"),
base, exponent)
slice_incr = (start, stop, step=null):
if not start
start = Code("getglob", "null")
if not stop
stop = Code("getglob", "null")
if not step
step = Code("constant", 1)
return Code("call", Code("getglob", "slice"), start, stop, step)
slice_decr = (start, stop, step=null):
if not start
start = Code("getglob", "null")
if not stop
stop = Code("getglob", "null")
if not step
step = Code("constant", -1)
else
step = Code("call", Getvar("-expr"), step)
return Code("call", Code("getglob", "slice"), start, stop, step)
%"in" = (lhs, rhs):
return CodeM("contains", [rhs, lhs], [1, 0])
%"not_in" = (lhs, rhs):
return Code("not", CodeM("contains", [rhs, lhs], [1, 0]))
%"not" = (item):
return Code("not", item)
local_assign = (name, statement):
return Setvar("local", name, statement)
upvalue_assign = (name, statement):
return Setvar("upvalue", name, statement)
op_assign = (slot, op, statement):
bind = Let(slot.base)
return bind(
slot.setslot(bind, Code("call",
Getvar(op), slot.getslot(bind), statement)))
unpack_assign = (names, statement):
bind = Let(Code("iter", statement))
prog = []
for name in names
prog.append(Setvar("local", name,
Code("call", Code("getattr", bind, "next"))))
prog.append(bind)
return bind(Prog(prog))
lookup_slot = (name):
return object();
base = null
getslot = (base):
return Getvar(name)
setslot = (base, expr):
return Setvar("auto", name, expr)
attr_slot = (base, name):
return object();
base = base
getslot = (base):
return Code("getattr", base, name)
setslot = (base, expr):
return CodeM("setattr",
[base, name, expr],
[2, 0, 1])
item_slot = (base, indexer):
return object();
base = base
getslot = (base):
return Code("getitem", base, indexer)
setslot = (base, expr):
return CodeM("setitem",
[base, indexer, expr],
[2, 0, 1])
%"return" = (expr=Code("getglob", "null")):
return Code("return", expr)
%"yield" = (expr=Code("getglob", "null")):
return Code("yield", expr)
%"raise" = (expr):
return Code("raise", expr)
%"break" = ():
return Jumper((context):
loop = context.loop
while loop.type == "finally"
loop.body.visit(context, true)
loop = loop.parent
return loop.brk
)
%"continue" = ():
return Jumper((context):
loop = context.loop
while loop.type == "finally"
loop.body.visit(context, true)
loop = loop.parent
return loop.cont
)
%"try" = (body, excepts=[], finally_body=null):
if finally_body
finally_body = Prog(finally_body)
return Try(body, excepts, finally_body)
%"except" = (expr, symbol, body):
return [expr, symbol, body]
%"finally" = (body):
return body
%"while" = (cond, body):
return While(cond, body)
%"for" = (bind, iterator, body):
bind_fn = (context, value):
setvar(context, "local", bind, value)
return For(bind_fn, iterator, body)
%"for_unpack" = (binds, iterator, body):
bind_fn = (context, value):
it = context.op("iter", value)
for bind in binds
setvar(context, "local", bind,
context.op("call", context.op("getattr", it, "next")))
return For(bind_fn, iterator, body)
%"if" = (cond, body=[], otherwise=done()):
otherwise.conds.insert(0, [cond, body])
return Cond(otherwise.conds, otherwise.body)
%"elif" = (cond, body=[], otherwise=done()):
otherwise.conds.insert(0, [cond, body])
return otherwise
%"else" = (body=[]):
return object();
conds = []
body = body
%"done" = ():
return object();
conds = []
body = null
%"assert" = (cond, body=Code("constant", "")):
if isinstance(body, base.list)
body = Prog(body)
return Cond([[Code("not", cond),
[Code("assert", body)]]], null)
%"or" = (a, b):
return Or(a, b)
%"and" = (a, b):
return And(a, b)
%"import" = (names):
import_fn = Getvar("import")
proc = []
for name in names
const = Code("constant", name)
module = Code("call", import_fn, const)
proc.append(Setvar("local", name, module))
return Prog(proc)
from_import = (module_name, names):
proc = []
for name in names
it = Code("call", Getvar("import"), Code("constant", module_name))
proc.append(
Setvar("local", name,
Code("getattr", it, name)))
return Prog(proc)
from_import_all = (module_name):
return Code("loglob", Code("call",
Getvar("import"),
Code("constant", module_name)))
%"class" = (header, block=[]):
grabber = Code("call", Getvar("object"))
return Setvar("local", header.name,
Code("call", Getvar("class"),
ScopeGrab(grabber, block),
header.base,
Code("constant", header.name)))
class_header = (name, base = Getvar("object")):
return object();
name = name
base = base
function = (bindings=blank_bindings(), body=[]):
return Closure(bindings, body)
with_variadic = (bindings, vararg):
bindings.variadic = vararg
return bindings
only_variadic = (vararg):
return object();
variadic = vararg
args = []
opts = []
blank_bindings = ():
return object();
variadic = null
args = []
opts = []
optional = (var, expr):
return object();
var = var
expr = expr
mandatory = (var):
return object();
variadic = null
args = [var]
opts = []
first_optional = (opt):
return object();
variadic = null
args = []
opts = [opt]
append_optional = (bindings, opt):
bindings.opts.append(opt)
return bindings
append_mandatory = (bindings, var):
bindings.args.append(var)
return bindings
first = (item):
return [item]
append = (items, item):
items.append(item)
return items
str_join = (item, rest...):
out = [item]
for item in rest
out.append(item)
return "".join(out)
class Context
+init = (self, closures):
self.closures = closures
self.scope = null
self.block = null
self.origin = null
self.loop_stack = []
self.loop = null
self.exc = null
self.is_generator = false
self.finally_exc = null
push_finally = (self, body):
self.loop = object();
type = "finally"
parent = self.loop
body = body
push_loop = (self, cont, brk):
self.loop_stack.append(self.loop)
self.loop = object();
type = "loop"
parent = self.loop
cont = cont
brk = brk
pop_loop = (self):
self.loop = self.loop_stack.pop()
pop_finally = (self):
self.loop = self.loop.parent
new_block = (self):
succ = set()
if self.exc
for x in self.exc.trace()
succ.add(x.block)
return Block([], succ, self.exc)
op = (self, name, args...):
if name == 'yield'
self.is_generator = true
if self.finally_exc and name == 'raise' # Ensure finally through raise.
self.finally_exc.visit(self, true)
if name == 'return'
loop = self.loop # Ensures that escape through return won't skip
while loop # any finally blocks.
if loop.type == "finally"
loop.body.visit(self, true)
loop = loop.parent
return self.block.op(self.origin, name, args...)
class Scope
+init = (self, parent, flags, argc, topc, localv):
self.parent = parent
self.flags = flags
self.argc = argc
self.topc = topc
self.localv = localv
self.depthc = 1
# This ended up being not very clean. But afterwards not sure why.
# It may be because the localv will obtain ObjectScope -object here.
object_scope = (self, context, val, parent=self):
index = self.localv.length
context.op("setloc", index, val)
scope = ObjectScope(parent, Slot(self, index), [])
self.localv.append(scope)
return scope
getslot = (self, name):
return Slot(self, self.localv.index(name))
class Slot
+init = (self, scope, index):
self.scope = scope
self.index = index
get = (self, context):
depth = -1
scope = context.scope
while scope != self.scope
depth += scope.depthc
scope = scope.parent
if depth < 0
return context.op("getloc", self.index)
else
return context.op("getupv", depth, self.index)
set = (self, context, value):
depth = -1
scope = context.scope
while scope != self.scope
depth += scope.depthc
scope = scope.parent
if depth < 0
return context.op("setloc", self.index, value)
else
return context.op("setupv", depth, self.index, value)
class ObjectScope
+init = (self, parent, slot, localv):
self.parent = parent
self.slot = slot
self.localv = localv
self.depthc = 0
object_scope = (self, context, val, parent=self):
return self.parent.object_scope(context, val, parent)
getslot = (self, name):
return AttrSlot(self.slot, name)
class AttrSlot
+init = (self, slot, name):
self.slot = slot
self.name = name
get = (self, context):
obj = self.slot.get(context)
return context.op("getattr", obj, self.name)
set = (self, context, value):
obj = self.slot.get(context)
return context.op("setattr", obj, self.name, value)
class Cell
+init = (self, visit):
self.visit = visit
class Origin
+init = (self, cell, location_id, start, stop):
self.cell = cell
self.location_id = location_id
self.start = start
self.stop = stop
visit = (self, context, noret=false):
origin = context.origin
context.origin = self
retval = self.cell.visit(context, noret)
context.origin = origin
return retval
class Closure extends Cell
+init = (self, bindings, body):
self.bindings = bindings
self.body = body
visit = (self, context, noret=false):
flags = 0
localv = []
header = []
argc = self.bindings.args.length
topc = self.bindings.args.length + self.bindings.opts.length
for var in self.bindings.args
localv.append(var)
for opt in self.bindings.opts
localv.append(opt.var)
cond = Cond([[
Code("isnull", Getvar(opt.var)), [
Setvar("local", opt.var, opt.expr)
]]], null)
header.append(cond)
if self.bindings.variadic
localv.append(self.bindings.variadic)
flags |= 1
handle = Function(context.closures.length)
context.closures.append(object();
origin = context.origin
body = header ++ self.body
scope = Scope(context.scope, flags, argc, topc, localv)
)
return context.op("func", handle)
class Code extends Cell
+init = (self, name, args...):
self.name = name
self.args = args
visit = (self, context, noret=false):
args = []
for arg in self.args
if isinstance(arg, Cell) or isinstance(arg, Origin)
arg = arg.visit(context)
args.append(arg)
return context.op(self.name, args...)
class CodeM extends Cell
+init = (self, name, args, order):
self.name = name
self.args = args
self.order = order
visit = (self, context, noret=false):
args = []
for arg in self.args
args.append(null)
for i in self.order
arg = self.args[i]
if isinstance(arg, Cell) or isinstance(arg, Origin)
arg = arg.visit(context)
args[i] = arg
return context.op(self.name, args...)
class CodeGroup extends Cell
+init = (self, name, prefix, groups):
self.name = name
self.prefix = prefix
self.groups = groups
visit = (self, context, noret=false):
prefix = self.prefix.visit(context)
for seq in self.groups
argv = [prefix]
for item in seq
if isinstance(item, [Cell, Origin])
argv.append(item.visit(context))
else # Used at constructing the record() -object.
argv.append(item)
context.op(self.name, argv...)
return prefix
class Prog extends Cell
+init = (self, exprs):
self.exprs = exprs
visit = (self, context, noret=false):
last = null
for expr in self.exprs
if last
last.visit(context, true)
last = expr
if last
return last.visit(context, noret)
else
return context.op("getglob", "null")
class Jumper extends Cell
+init = (self, blockfn):
self.blockfn = blockfn
visit = (self, context, noret=false):
label = self.blockfn(context)
return context.op("jump", label)
class ScopeGrab extends Cell
+init = (self, expr, body):
self.expr = expr
self.body = body
visit = (self, context, noret=false):
this = self.expr.visit(context)
parent = context.scope
context.scope = parent.object_scope(context, this)
for expr in self.body
expr.visit(context, true)
context.scope = parent
return this
class For extends Cell
+init = (self, bind, iterator, body):
self.bind = bind
self.iterator = iterator
self.body = body
visit = (self, context, noret=false):
exit = context.new_block()
result = context.op("getglob", "null")
iter = self.iterator.visit(context)
iter = context.op("iter", iter)
repeat = label_this_point(context, context.block)
context.push_loop(repeat, exit)
context.block = repeat
value = context.op("next", iter, exit)
self.bind(context, value) # setvar(context, "local", self.bind, value)
val = Prog(self.body).visit(context)
if val and val.has_result
context.op("move", result, val)
context.op("jump", repeat)
context.block = exit
context.pop_loop()
return result
class While extends Cell
+init = (self, cond, body):
self.cond = cond
self.body = body
visit = (self, context, noret=false):
result = context.op("getglob", "null")
cont = label_this_point(context, context.block)
exit = context.new_block()
byes = context.new_block()
context.push_loop(cont, exit)
context.block = cont
cond = self.cond.visit(context)
context.op('cond', cond, byes, exit)
context.block = byes
val = Prog(self.body).visit(context)
if val and val.has_result
context.op("move", result, val)
context.op("jump", cont)
context.block = exit
context.pop_loop()
return result
class Or extends Cell
+init = (self, lhs, rhs):
self.lhs = lhs
self.rhs = rhs
visit = (self, context, noret=false):
exit = context.new_block()
other = context.new_block()
lhs = self.lhs.visit(context)
context.op("cond", lhs, exit, other)
context.block = other
rhs = self.rhs.visit(context)
context.op('move', lhs, rhs)
context.op('jump', exit)
context.block = exit
return lhs
class And extends Cell
+init = (self, lhs, rhs):
self.lhs = lhs
self.rhs = rhs
visit = (self, context, noret=false):
exit = context.new_block()
other = context.new_block()
lhs = self.lhs.visit(context)
context.op("cond", lhs, other, exit)
context.block = other
rhs = self.rhs.visit(context)
context.op("move", lhs, rhs)
context.op("jump", exit)
context.block = exit
return lhs
class Cond extends Cell
+init = (self, cond, otherwise):
self.cond = cond
self.otherwise = otherwise
visit = (self, context, noret=false):
exit = context.new_block()
result = context.op("getglob", "null")
branch = null
for cell in self.cond
cond = cell[0]
body = cell[1]
if branch
context.block = bno = context.new_block()
blabel = branch.blabel
bcond = branch.bcond
byes = branch.byes
blabel.op(context.origin, "cond", bcond, byes, bno)
cond = cond.visit(context)
label = context.block
context.block = byes = context.new_block()
val = Prog(body).visit(context)
if val and val.has_result
context.op("move", result, val)
context.op("jump", exit)
branch = object();
blabel = label
bcond = cond
byes = byes
if self.otherwise
context.block = bno = context.new_block()
blabel = branch.blabel
bcond = branch.bcond
byes = branch.byes
blabel.op(context.origin, "cond", bcond, byes, bno)
val = Prog(self.otherwise).visit(context)
if val and val.has_result
context.op("move", result, val)
context.op("jump", exit)
label1 = context.block
else
blabel = branch.blabel
bcond = branch.bcond
byes = branch.byes
blabel.op(context.origin, "cond", bcond, byes, exit)
context.block = exit
return result
label_this_point = (context, block):
if block.length == 0
return block
label = context.new_block()
block.op(context.origin, 'jump', label)
return label
class Try extends Cell
+init = (self, body, excepts, finally_body):
self.body = body
self.excepts = excepts
self.finally_body = finally_body
visit = (self, context, noret=false):
result = context.op("getglob", "null")
exit = context.new_block()
context.exc = exc = Exc(context.new_block(), context.exc)
# populating try block
try_block = context.new_block()
if self.finally_body
context.push_finally(self.finally_body)
context.op("jump", try_block)
context.block = try_block
val = Prog(self.body).visit(context)
if val and val.has_result
context.op("move", result, val)
context.op("jump", exit)
# populating exception block
context.exc = exc.parent
context.block = exc.block
ins = context.op('getglob', "isinstance")
finally_exc_parent = context.finally_exc
context.finally_exc = self.finally_body
for exl in self.excepts
expr = exl[0]
name = exl[1]
body = exl[2]
this = context.new_block()
next = context.new_block()
which = expr.visit(context)
cond = context.op('call', ins, exc, which)
context.op('cond', cond, this, next)
context.block = this
setvar(context, 'local', name, exc)
val = Prog(body).visit(context)
if val and val.has_result
context.op('move', result, val)
context.op('jump', exit)
context.block = next
context.op('raise', exc)
context.finally_exc = finally_exc_parent
# done
context.block = exit
if self.finally_body
self.finally_body.visit(context, true)
context.pop_finally()
return result
class Getvar extends Cell
+init = (self, name):
self.name = name
visit = (self, context, noret=false):
slot = scope_lookup(context.scope, "auto", self.name)
if slot
return slot.get(context)
return context.op("getglob", self.name)
class Setvar extends Cell
+init = (self, flavor, name, value):
self.flavor = flavor # local, auto, upvalue
self.name = name
self.value = value
visit = (self, context, noret=false):
value = self.value.visit(context)
return setvar(context, self.flavor, self.name, value)
class Let extends Cell
+init = (self, value):
self.value = value
self.reg = null
+call = (self, body):
return LetBody(self, body)
visit = (self, context, noret=false):
assert self.reg
if self.value
"Let.value == null"
else
"Let not bound"
return self.reg
class LetBody extends Cell
+init = (self, binding, body):
self.binding = binding
self.body = body
visit = (self, context, noret=false):
if self.binding.value
self.binding.reg = self.binding.value.visit(context)
result = self.body.visit(context, noret)
self.binding.reg = null # avoid reuse.
return result
setvar = (context, flavor, name, value):
slot = scope_lookup(context.scope, flavor, name)
if slot
return slot.set(context, value)
return context.op("setglob", name, value)
scope_lookup = (scope, flavor, name):
# The lookup doesn't write into the rootscope.
if scope and scope.parent
if name in scope.localv and flavor != "upvalue"
return scope.getslot(name)
if flavor == "local"
scope.localv.append(name)
return scope.getslot(name)
while scope.parent.parent
if name in scope.parent.localv
return scope.parent.getslot(name)
scope = scope.parent
return null
dump = (flags, argc, topc, localv, entry_block, consttab, origin):
blocks = reverse_postorder(entry_block)
tmpc = allocate_tmp(blocks)
block = []
for bb in blocks
bb.label = block.length
for op in bb
if isinstance(op, Exc)
continue
block.extend(encode_op(op, consttab))
exceptions = find_exception_ranges(blocks, block.length)
block = []
sourcemap = SourcemapBuilder(origin)
for bb in blocks
for op in bb
if isinstance(op, Exc)
continue
codes = list(encode_op(op, consttab))
block.extend(codes)
sourcemap.add(codes.length, op.loc)
localc = localv.length
code = []
for value in block
code.extend([value >> 8, value & 255])
varnames = []
for item in localv
if isinstance(item, ObjectScope)
varnames.append("{object scope}")
elif isinstance(item, str)
varnames.append(item)
else
assert false, "What is this localv?"
return {
"flags": flags,
"regc": tmpc,
"argc": argc,
"topc": topc,
"localc": localc,
"code": Uint8Array(code),
"sourcemap": Uint8Array(sourcemap.get()),
"exceptions": exceptions,
"varnames": varnames
}
# Blocks are ordered into reverse postorder because
# it makes easier to do the following analysis on them.
reverse_postorder = (entry):
seq = postorder_visit([], entry)
seq.reverse()
return seq
postorder_visit = (sequence, block):
if block.visited
return sequence
block.visited = true
for succ in block.succ
postorder_visit(sequence, succ)
sequence.append(block)
return sequence
# Virtualizable frame takes a performance hit if we pass it large
# array of indices.
# To avoid that we will reuse indices with live range analysis.
allocate_tmp = (blocks):
tmpc = 0
index = 0
base = 0
for block in blocks
block.base = base
block.index = index
block.depends = set()
block.iterstop_in = set()
block.except_in = set()
index += 1
base += block.length
done = false
while not done
done = true
for block in reversed(blocks)
N = block.depends.length
for succ in block.succ
block.depends.update(succ.depends)
for op in reversed(block.contents)
block.depends.discard(op)
for use in op.uses()
block.depends.add(use)
M = block.depends.length
if N != M
done = false
live_ranges = dict()
for block in blocks
for op in block.depends
plot_range(live_ranges, op, block.base)
for succ in block.succ
#assert succ.index >= 0
for op in succ.depends
plot_range(live_ranges, op, block.base + block.length)
i = 0
for op in block
plot_range(live_ranges, op, block.base+i)
for use in op.uses()
plot_range(live_ranges, use, block.base+i+1)
i += 1
starts = []
stops = []
avail = []
for block in live_ranges.items()
op = block[0]
rg = block[1]
starts.append([rg[0], rg[1], op])
starts.sort((a, b):
a[0] < b[0]
)
for x in starts
current = x[0]
stop = x[1]
op = x[2]
if avail.length > 0
op.index = avail.pop()
else
op.index = tmpc
tmpc += 1
stops.append([stop, op])
stops.sort((a, b):
a[0] < b[0]
)
while stops.length > 0 and stops[0][0] < current
exp = stops.pop(0)[1]
#assert exp.index not in avail
avail.append(exp.index)
return tmpc
plot_range = (ranges, key, pos):
if key not in ranges
ranges[key] = [pos, pos]
else
x = ranges[key]
start = x[0]
stop = x[1]
ranges[key] = [min(start, pos), max(stop, pos)]
find_exception_ranges = (blocks, finish):
exceptions = []
starts = []
stack = []
for block in blocks
if block.exc
new_stack = block.exc.trace()
else
new_stack = []
L = stack.length - 1
while L >= 0 and (L >= new_stack.length or stack[L] != new_stack[L])
exc = stack.pop()
exceptions.append([starts.pop(), block.label, exc.block.label, exc.index])
L -= 1
stack = new_stack
while starts.length < stack.length
starts.append(block.label)
for exc in reversed(stack)
exceptions.append([starts.pop(), finish, exc.block.label, exc.index])
return exceptions
# improve this one ?
encode_op = (op, consttab):
# assert len(op.args) >= len(op.pattern), op.opname
# assert op.variadic or len(op.args) == len(op.pattern), op.opname
out = []
oplen = op.args.length + int(op.has_result)
out.append(op.opcode << 8 | oplen)
if op.has_result
out.append(op.index)
i = 0
for arg in op.args
if i < op.pattern.length
vt = op.pattern[i]
else
vt = op.variadic
out.append(as_arg(op, vt, arg, consttab))
i += 1
return out
check_args = (op):
i = 0
for arg in op.args
if i < op.pattern.length
vt = op.pattern[i]
else
vt = op.variadic
i += 1
if vt == 'index' and isinstance(arg, int)
continue
if vt == 'vreg' and isinstance(arg, Op) or isinstance(arg, Exc)
continue
if vt == 'block'
if isinstance(arg, int) and arg == 0
continue
if isinstance(arg, Block)
continue
if vt == 'function' and isinstance(arg, Function)
continue
if vt == 'string' and isinstance(arg, str)
continue
if vt == 'constant'
continue
print(op, op.pattern, op.args)
print("exc", i-1, vt, arg)
raise Exception("bad argument to op")
as_arg = (op, vt, arg, consttab):
if vt == 'index'
# assert isinstance(arg, int)
return arg
if vt == 'vreg'
# assert isinstance(arg, (Op, Exc)), (op.opname, op.loc, arg)
# assert arg.has_result, (arg.opname, arg.loc, arg)
return arg.index
if vt == 'block'
if isinstance(arg, int) and arg == 0
return 0
# assert isinstance(arg, Block)
return arg.label
if vt == 'function'
# assert isinstance(arg, Function)
return arg.index
if vt == 'string'
# assert isinstance(arg, unicode), (op.opname, op.loc, type(arg))
return consttab[arg]
if vt == 'constant'
return consttab[arg]
# assert False, "as_arg {} ?".format(arg)
class Exc
+init = (self, block, parent=null):
self.block = block
self.parent = parent
#assert block.length == 0, "exc block must be fresh"
block.append(self)
self.has_result = true
self.index = null
self.opname = "exc"
uses = (self):
return set()
+iter = (self):
return iter([])
trace = (self):
seq = []
while self
seq.append(self)
self = self.parent
seq.reverse()
return seq
class Function
+init = (self, index):
self.index = index
class Block
+init = (self, contents, succ, exc):
self.label = 0
self.contents = contents
self.succ = succ
self.visited = false # for reverse_postorder()
self.exc = exc
+getitem = (self, index):
return self.contents[index]
+iter = (self):
return iter(self.contents)
length = property();
get = (self):
return self.contents.length
append = (self, op):
self.contents.append(op)
for succ in op
if isinstance(succ, Block)
self.succ.add(succ)
op = (self, loc, opname, args...):
op = Op(loc, opname, args)
self.append(op)
return op
class Op
+init = (self, loc, opname, args):
assert isinstance(opname, str), [loc.start, opname, args]
self.index = null
self.loc = loc
self.opname = opname
self.args = args
op = optable.enc[opname]
self.opcode = op[0]
self.has_result = op[1]
self.pattern = op[2]
self.variadic = op[3]
check_args(self)
uses = (self):
uses = set()
for arg in self.args
if isinstance(arg, Op) or isinstance(arg, Exc)
uses.add(arg)
return uses
+iter = (self):
return iter(self.args)
class ConstantTable
+init = (self):
self.table = {}
self.constants = []
+getitem = (self, const):
try
return self.table[const]
except KeyError as _
self.constants.append(const)
self.table[const] = self.table.length
return self.table[const]
# If this code was where it is used, it'd look complicated.
class SourcemapBuilder
+init = (self, origin):
self.buf = []
self.count = 0
self.entry = []
if origin
self.add(0, origin)
self.buf = self.get(true)
add = (self, count, origin):
entry = [0, 0, 0, 0, 0]
if origin
entry = [origin.location_id,
origin.start.col,
origin.start.lno,
origin.stop.col,
origin.stop.lno]
if entry != self.entry
self.buf = self.get()
self.entry = entry
self.count = count
else
self.count += count
get = (self, force=false):
if self.count > 0 or force
raw_entry = enc_vlq(self.count)
for value in self.entry
raw_entry.extend(enc_vlq(value))
return self.buf ++ raw_entry
return self.buf
enc_vlq = (v):
out = [v & 0x7F]
while v >= 0x80
v >>= 7
out.append(0x80 | v & 0x7F)
out.reverse()
return out