def resolve_aliases(env: Env, program: Node) -> Tuple[Node, Set[str], Set[str]]: """Resolve aliases to their targets in a YOLOL program.""" assert program.kind == 'program' logger.debug('resolving aliases') clone = program.clone() imported = set() exported = set() for alias, target in env.imports.items(): variables = clone.find( lambda node: node.kind == 'variable' and node.value == alias) for var in variables: var.value = target imported.add(target) for alias, target in env.exports.items(): var, index = env.var(alias) if type(var) == Number: num_prefix = '{}{}'.format(Number.PREFIX, index) num_variables = clone.find(lambda node: node.kind == 'variable' and node.value.startswith(num_prefix)) for var in num_variables: var.value = var.value.replace(num_prefix, target) # type: ignore exported.add(var.value) elif type(var) == Vector: vec_prefix = '{}{}'.format(Vector.PREFIX, index) vec_variables = clone.find(lambda node: node.kind == 'variable' and node.value.startswith(vec_prefix)) for var in vec_variables: var.value = var.value.replace(vec_prefix, target) # type: ignore exported.add(var.value) elif type(var) == Matrix: mat_prefix = '{}{}'.format(Matrix.PREFIX, index) mat_variables = clone.find(lambda node: node.kind == 'variable' and node.value.startswith(mat_prefix)) for var in mat_variables: var.value = var.value.replace(mat_prefix, target) # type: ignore exported.add(var.value) else: raise AssertionError('unexpected variable type: {}'.format( type(var))) return clone, imported, exported
def vexpr(self, env: Env, vexpr: Node) -> Tuple[Env, Vector]: """Transpile a vector expression to YOLOL.""" logger.debug('transpiling vector expression - {}'.format(vexpr)) if not is_vexpr(vexpr.kind): raise YovecError('expected vector expression, but got {}'.format( vexpr.kind)) elif vexpr.kind == 'vec_binary': env, lvec = self.vexpr(env, vexpr.children[0]) ops = vexpr.children[1::2] rvecs = vexpr.children[2::2] for op, rvec in zip(ops, rvecs): env, rvec = self.vexpr(env, rvec) lvec = lvec.vecbinary(op.kind, rvec) return env, lvec elif vexpr.kind == 'vec_map': op = vexpr.children[0] env, vec = self.vexpr(env, vexpr.children[1]) return env, vec.map(op.kind) elif vexpr.kind == 'vec_premap': op = vexpr.children[0] env, num = self.nexpr(env, vexpr.children[1]) env, vec = self.vexpr(env, vexpr.children[2]) return env, vec.premap(op.kind, num) elif vexpr.kind == 'vec_postmap': env, num = self.nexpr(env, vexpr.children[0]) op = vexpr.children[1] env, vec = self.vexpr(env, vexpr.children[2]) return env, vec.postmap(num, op.kind) elif vexpr.kind == 'vec_apply': op = vexpr.children[0] env, lvec = self.vexpr(env, vexpr.children[1]) for rvec in vexpr.children[1:]: env, rvec = self.vexpr(env, rvec) lvec = lvec.apply(op.kind, rvec) return env, lvec elif vexpr.kind == 'concat': env, lvec = self.vexpr(env, vexpr.children[0]) for rvec in vexpr.children[1:]: env, rvec = self.vexpr(env, rvec) lvec = lvec.concat(rvec) return env, lvec elif vexpr.kind == 'reverse': env, vec = self.vexpr(env, vexpr.children[0]) return env, vec.reverse() elif vexpr.kind == 'mat_row': env, mat = self.mexpr(env, vexpr.children[0]) row = vexpr.children[1].value try: return env, mat.row(int(row)) except ValueError: raise YovecError('invald row index: {}'.format(row)) elif vexpr.kind == 'mat_col': env, mat = self.mexpr(env, vexpr.children[0]) col = vexpr.children[1].value try: return env, mat.col(int(col)) except ValueError: raise YovecError('invald column index: {}'.format(col)) elif vexpr.kind == 'variable': ident = vexpr.value var, _ = env.var(ident) if type(var) != Vector: raise YovecError( 'expected variable {} to be vector, but got {}'.format( ident, var.class_name)) return env, var elif vexpr.kind == 'call': ident = vexpr.children[0].value macro = env.macro(ident) if macro.return_type != 'vector': raise YovecError( 'expected macro to return vector expression, but got {} expression' .format(macro.return_type)) args = vexpr.children[1].children return self.vexpr(env, macro.call(args)) elif vexpr.kind == 'vector': numums = [] for nexpr in vexpr.children: env, num = self.nexpr(env, nexpr) numums.append(num) return env, Vector(numums) else: raise AssertionError('vexpr fallthough: {}'.format(vexpr))
def mexpr(self, env: Env, mexpr: Node) -> Tuple[Env, Matrix]: """Transpile a matrix expression to YOLOL.""" logger.debug('transpiling matrix expression - {}'.format(mexpr)) if not is_mexpr(mexpr.kind): raise YovecError('expected matrix expression, but got {}'.format( mexpr.kind)) elif mexpr.kind == 'mat_binary': env, lmat = self.mexpr(env, mexpr.children[0]) ops = mexpr.children[1::2] rmats = mexpr.children[2::2] for op, rmat in zip(ops, rmats): env, rmat = self.mexpr(env, rmat) lmat = lmat.matbinary(op.kind, rmat) return env, lmat elif mexpr.kind == 'mat_map': op = mexpr.children[0] env, mat = self.mexpr(env, mexpr.children[1]) return env, mat.map(op.kind) elif mexpr.kind == 'mat_premap': op = mexpr.children[0] env, num = self.nexpr(env, mexpr.children[1]) env, mat = self.mexpr(env, mexpr.children[2]) return env, mat.premap(op.kind, num) elif mexpr.kind == 'mat_postmap': env, num = self.nexpr(env, mexpr.children[0]) op = mexpr.children[1] env, mat = self.mexpr(env, mexpr.children[2]) return env, mat.postmap(num, op.kind) elif mexpr.kind == 'mat_apply': op = mexpr.children[0] env, lmat = self.mexpr(env, mexpr.children[1]) for rmat in mexpr.children[1:]: env, rmat = self.mexpr(env, rmat) lmat = lmat.apply(op.kind, rmat) return env, lmat elif mexpr.kind == 'transpose': env, mat = self.mexpr(env, mexpr.children[0]) return env, mat.transpose() elif mexpr.kind == 'mat_mul': env, lmat = self.mexpr(env, mexpr.children[0]) env, rmat = self.mexpr(env, mexpr.children[1]) return env, lmat.matmul(rmat) elif mexpr.kind == 'variable': ident = mexpr.value var, _ = env.var(ident) if type(var) != Matrix: raise YovecError( 'expected variable {} to be matrix, but got {}'.format( ident, var.class_name)) return env, var elif mexpr.kind == 'call': ident = mexpr.children[0].value macro = env.macro(ident) if macro.return_type != 'matrix': raise YovecError( 'expected macro to return matrix expression, but got {} expression' .format(macro.return_type)) args = mexpr.children[1].children return self.mexpr(env, macro.call(args)) elif mexpr.kind == 'matrix': vecs = [] for vexpr in mexpr.children: env, vec = self.vexpr(env, vexpr) vecs.append(vec) return env, Matrix(vecs) else: raise AssertionError('mexpr fallthough: {}'.format(mexpr))
def nexpr(self, env: Env, nexpr: Node) -> Tuple[Env, Number]: """Transpile a number expression to YOLOL.""" logger.debug('transpiling number expression - {}'.format(nexpr)) if not is_nexpr(nexpr.kind): raise YovecError('expected number expression, but got {}'.format( nexpr.kind)) elif nexpr.kind == 'num_binary': env, lnum = self.nexpr(env, nexpr.children[0]) ops = nexpr.children[1::2] rnums = nexpr.children[2::2] for op, rnum in zip(ops, rnums): env, rnum = self.nexpr(env, rnum) lnum = lnum.binary(op.kind, rnum) return env, lnum elif nexpr.kind == 'num_unary': env, num = self.nexpr(env, nexpr.children[-1]) for op in reversed(nexpr.children[:-1]): num = num.unary(op.kind) return env, num elif nexpr.kind == 'reduce': op = nexpr.children[0] env, vec = self.vexpr(env, nexpr.children[1]) return env, vec.reduce(op.kind) elif nexpr.kind == 'dot': env, lvec = self.vexpr(env, nexpr.children[0]) env, rvec = self.vexpr(env, nexpr.children[1]) return env, lvec.dot(rvec) elif nexpr.kind == 'len': env, vec = self.vexpr(env, nexpr.children[0]) return env, vec.len() elif nexpr.kind == 'rows': env, mat = self.mexpr(env, nexpr.children[0]) return env, mat.rows() elif nexpr.kind == 'cols': env, mat = self.mexpr(env, nexpr.children[0]) return env, mat.cols() elif nexpr.kind == 'vec_elem': env, vec = self.vexpr(env, nexpr.children[0]) index = nexpr.children[1].value try: return env, vec.elem(int(index)) except ValueError: raise YovecError('invalid element index: {}'.format(index)) elif nexpr.kind == 'mat_elem': env, mat = self.mexpr(env, nexpr.children[0]) row = nexpr.children[1].value col = nexpr.children[2].value try: return env, mat.elem(int(row), int(col)) except ValueError: raise YovecError('invalid element indices: {}, {}'.format( row, col)) elif nexpr.kind == 'external': ident = nexpr.value _ = env.target(ident) return env, Number(ident) elif nexpr.kind == 'variable': ident = nexpr.value value, _ = env.var(ident) if type(value) != Number: raise YovecError( 'expected variable {} to be number, but got {}'.format( ident, value.class_name)) return env, value elif nexpr.kind == 'call': ident = nexpr.children[0].value macro = env.macro(ident) if macro.return_type != 'number': raise YovecError( 'expected macro to return number expression, but got {} expression' .format(macro.return_type)) args = nexpr.children[1].children return self.nexpr(env, macro.call(args)) elif nexpr.kind == 'number': try: return env, Number(int(nexpr.value)) except ValueError: return env, Number(float(nexpr.value)) else: raise AssertionError('nexpr fallthough: {}'.format(nexpr))