def _generate_binop(self, node, ext_info): left_type = self.get_type(node.left) right_type = self.get_type(node.right) extra_code = ext_info.get('extra_code', '') if left_type.is_void or right_type.is_void: raise CompileError('Void type is not able to operate.') if left_type.is_number and right_type.is_number: op = self.generate_numeric_op(node.op, ext_info) if len(op) is 0: raise SyntaxNotSupportError("%s operation is not support yet." % node.op.__class__.__name__) left_name, extra_code = get_node_name_with_extra_code( self, node.left, extra_code) right_name, extra_code = get_node_name_with_extra_code( self, node.right, extra_code) return '$(( %s %s %s ))' % (left_name, op, right_name), extra_code elif (left_type.is_string or right_type.is_string) and isinstance( node.op, ast.Add): _ext_info = {'extra_code': extra_code} left = self.dispatch(node.left, _ext_info) right = self.dispatch(node.right, _ext_info) return left + right, _ext_info['extra_code'] else: raise SyntaxNotSupportError("%s operation is not support yet." % node.op.__class__.__name__)
def get_type(self, node): if isinstance(node, ast.BinOp): left_type = self.get_type(node.left) right_type = self.get_type(node.right) if isinstance(node.op, ast.Add): if left_type.is_number and right_type.is_number: return Type.NUMBER else: return Type.STRING elif left_type.is_number and right_type.is_number: return Type.NUMBER else: raise CompileError("Can not '%s' operator with string." % node.op.__class__.__name__) elif isinstance(node, ast.UnaryOp): if isinstance(operand, ast.Num): return Type.NUMBER else: raise SyntaxNotSupportError("Not support unary operator except number.") elif isinstance(node, ast.Num): return Type.NUMBER elif isinstance(node, ast.Str): return Type.STRING elif isinstance(node, ast.List): return Type.LIST elif isinstance(node, ast.Call): args_type = [self.get_type(arg) for arg in node.args] return self.get_function_return_type(node.func.id, args_type) elif isinstance(node, ast.Name): return self.variables[node.id].var_type
def generate(self): if self.node is None: self.node = ast.parse(self.code) if isinstance(self.node, ast.Module): for x in self.node.body: code_slice = self.dispatch(x) if code_slice is not None: self.code_buffer.append(code_slice) return '\n'.join(self.code_buffer) + '\n' elif isinstance(self.node, ast.FunctionDef): if self.function_info is None: raise FunctionIsNotAnalyzedError(self.node.name) if not len(self.node.decorator_list) == 0: raise SyntaxNotSupportError('Function decoration is not support yet.') arguments_list = [] for i, x in enumerate(self.node.args.args): if self.function_info.args_type[i].is_list: arguments_list.append('declare -a %s=("${!%i}")' % (self.dispatch(x), i + 1)) else: arguments_list.append('%s=$%i' % (self.dispatch(x), i + 1)) arguments_code = '\n'.join(arguments_list) for x in self.node.body: self.code_buffer.append(self.dispatch(x, {'func_name': self.node.name})) return 'function %s() {\n%s\n%s\n}' % (self.node.name, arguments_code, '\n'.join(self.code_buffer)) else: raise CompileError("code section must be function or module node")
def generate_list(self, node, ext_info): for x in node.elts: if isinstance(x, ast.List): raise SyntaxNotSupportError( "Multiple dimension array is not support in shellscript language." ) return '(%s)' % ' '.join([self.dispatch(x, ext_info) for x in node.elts])
def generate_aug_assign(self, node, ext_info): tmp_name = self.temp_variable.get_new_name() tmp_assign_code = '%s=%s' % (tmp_name, self.dispatch(node.value)) self.code_buffer.append(tmp_assign_code) target = self.dispatch(node.target) target_type = self.get_type(node.target) if target_type.is_number: op = self.generate_numeric_op(node.op, ext_info) return '%s=$(( $%s %s $%s ))' % (target, target, op, tmp_name) elif target_type.is_string: if isinstance(node.op, ast.Add): return '%s=%s$%s' % (target, target, tmp_name) else: raise SyntaxNotSupportError("%s operation is not support yet." % node.op.__class__.__name__)
def generate_compare_op(self, node, ext_info): left = self.dispatch(node.left, ext_info) right = self.dispatch(node.comparators[0], ext_info) op_node = node.ops[0] left_type = self.get_type(node.left) right_type = self.get_type(node.comparators[0]) op_code = None if left_type.is_number and right_type.is_number: op_code = number_compare_op_table.get(op_node.__class__) elif left_type.is_string and right_type.is_string: op_code = string_compare_op_table.get(op_node.__class__) if op_code is None: raise SyntaxNotSupportError( '%s and %s can not compare with `%s` operator' % (left_type, right_type, op_node.__class__.__name__)) return '%s %s %s' % (left, op_code, right)
def analysis_assign_node(self, variables, node): if len(node.targets) > 1: raise SyntaxNotSupportError('Tuple assignment is not support yet.') target = node.targets[0] variables.append(Variable(name=target.id, var_type=self.get_type(node.value)))
def dispatch(self, node, ext_info={}): from sherlock.codelib.generator.dispatcher import AST_NODE_DISPATCHER generator = AST_NODE_DISPATCHER.get(node.__class__) if generator is None: raise SyntaxNotSupportError("%s is not support yet." % node.__class__.__name__) return generator(self, node, ext_info)
def generate_unaryop(self, node, ext_info): if isinstance(node.op, ast.Not): return '! ' + self.dispatch(node.operand, ext_info) else: SyntaxNotSupportError("%s is not support yet" % node.op.__class__.__name__)
def generate_numeric_op(self, node, ext_info): op = NUMERIC_OP_TABLE.get(node.__class__) if op is None: SyntaxNotSupportError("%s is not support yet" % node.__class__.__name__) return op