def macro_expand(self, fn_symbol, ast_node, words_needed):
        r'''This macro expands to an set-output-bit.

        set-output-bit port_name bit#
        '''
        assert len(ast_node.args) == 2
        assert len(ast_node.args[1]) == 1, \
               "%s: incorrect number of arguments, expected 1, got %s" % \
                 (self.label, len(ast_node.args[1]))
        fn_symbol.side_effects = 1
        pin = ast_node.args[1][0]
        #print "toggle: pin", pin, pin.symbol_id, pin.label
        pin_number = \
          symbol_table.get_by_id(pin.symbol_id).word_word \
                      .get_value('pin_number')
        port_label, bit_number = output_pin.digital_pin_lookup[pin_number]
        #print "toggle: port_label", port_label, ", bit_number", bit_number
        ioreg_bit = ast.ast(kind='ioreg-bit',
                            label='io.pin' + port_label, int1=bit_number)
        new_args = (
            ast.ast.word('set-output-bit'),
            (ioreg_bit,),
        )
        return ast_node.macro_expand(fn_symbol, words_needed, new_args,
                                     kind='call')
    def prepare(self, fn_symbol, words_needed):
        r'''Called immediately after parsing, before writing to the database.

        Calls `prepare_args` on itself first, then prepare_<expect> on the
        word in the first arg.

        Also updates `fn_xref` and `symbol_table.symbol.side_effects` info so
        that these data will be known during the intermediate code generation
        phase that follows parsing.  See prepare_args_ function for more info.

        .. _prepare_args: ucc.database.ast-module.html#prepare_args
        '''
        if self.kind == 'call':
            self.prepare_args(fn_symbol, words_needed)
            if self.args and isinstance(self.args[0], ast) and \
               self.args[0].kind == 'word':
                word_obj = symbol_table.get(self.args[0].label).word_obj
                fn_xref.calls(fn_symbol.id, word_obj.ww.symbol.id)
                prepare_method = word_obj.get_method('prepare', self.expect)
                return prepare_method(fn_symbol, self, words_needed)
        if self.kind == 'word':
            sym = symbol_table.get_by_id(self.symbol_id)
            if sym.context is None:
                words_needed.add(sym.label)
                if self.expect == 'lvalue':
                    fn_xref.sets(fn_symbol.id, self.symbol_id)
                else:
                    fn_xref.uses(fn_symbol.id, self.symbol_id)
        if self.kind in ('ioreg', 'ioreg-bit'):
            fn_symbol.side_effects = 1
        return self
def gen_fun(fun_id, fun_label, fun_kind):
    if fun_kind == 'function': far_size = 2
    else: far_size = 4
    prolog = assembler.block(fun_id, 'flash', fun_label)
    prolog.append_inst('push', 'r29')
    prolog.append_inst('push', 'r28')
    for id, kind, param_num \
     in crud.read_as_tuples('symbol_table', 'id', 'kind', 'int1',
                            context=fun_id,
                            order_by=('kind', 'desc', 'int1')):
        sym = symbol_table.get_by_id(id)
        far_size += 2
        sym.address = -far_size
        if fun_kind == 'task':
            sym.ram_size = 2
        if kind == 'parameter':
            prolog.append_inst('push', 'r%d' % (2 * param_num + 1))
            prolog.append_inst('push', 'r%d' % (2 * param_num))
    for id, name, next, next_conditional \
     in crud.read_as_tuples('blocks', 'id', 'name', 'next',
                            'next_conditional',
                            word_symbol_id=fun_id,
                            order_by=('id',)):
        asm_block = assembler.block(fun_id, 'flash', name)
        if next: asm_block.next_label(next)
        for what, should, this, be \
         in crud.read_as_tuples('triples',
                                block_id=id,
                                # FIX: finish...
                               ): pass
    def label(self, symbol_id, triple):
        r'''Attach 'symbol_id' as a "label" for 'triple'.

        A "label" is a symbol (variable) that the result of the `triple` must
        be stored into.  One triple may have multiple labels attached to it,
        meaning that the result must be stored into multiple places.
        '''
        self.labels[symbol_id] = triple
        if symbol_id in self.dirty_labels: self.dirty_labels.remove(symbol_id)
        if symbol_table.get_by_id(symbol_id).context is None:
            # This is a global variable!
            if symbol_id in self.sets_global:
                triple.add_hard_predecessor(self.sets_global[symbol_id])
            self.sets_global[symbol_id] = triple
            if symbol_id in self.uses_global:
                for t in self.uses_global[symbol_id]:
                    triple.add_soft_predecessor(t)
                del self.uses_global[symbol_id]
    def word(cls, symbol_id, syntax_position_info = (None, None, None, None),
             **kws):
        r'''Returns an ast node for the 'symbol_id' word.

        'symbol_id' may be either the integer id, or the label of the global
        word as a string.

        'kws' are simply passed to __init__ as attributes, along with the
        'kind' and the 'label' attributes.
        '''
        line_start, column_start, line_end, column_end = syntax_position_info
        if isinstance(symbol_id, (str, unicode)):
            symbol_id = symbol_table.get(symbol_id).id
        return cls(kind='word',
                   label=symbol_table.get_by_id(symbol_id).label,
                   symbol_id=symbol_id,
                   line_start=line_start, column_start=column_start,
                   line_end=line_end, column_end=column_end,
                   **kws)
    def compile(self):
        r'''Generates intermediate code for this AST node.
        '''
        if self.kind in ('approx', 'int', 'ratio'):
            return block.Current_block.gen_triple(
                     self.kind, self.int1, self.int2,
                     syntax_position_info= self.get_syntax_position_info())

        if self.kind == 'string':
            name = crud.gensym('strlit')
            sym = symbol_table.symbol.create(name, 'const')
            asm_block = assembler.block(self.word_symbol.id, 'flash', name)
            asm_block.append_inst('int16', str(len(self.str1)))
            asm_block.append_inst('bytes', repr(self.str1))
            asm_block.write()
            return block.Current_block.gen_triple(
                     'global', sym.id,
                     syntax_position_info=self.get_syntax_position_info())

        if self.kind == 'call':
            if self.args and isinstance(self.args[0], ast) and \
               self.args[0].kind == 'word':
                word_obj = symbol_table.get(self.args[0].label).word_obj
                compile_method = word_obj.get_method('compile', self.expect)
                return compile_method(self)
            else:
                raise AssertionError("call indirect not supported yet")

        if self.kind == 'word':
            sym = symbol_table.get_by_id(self.symbol_id)
            if sym.context is None:
                word_obj = symbol_table.get_by_id(self.symbol_id).word_obj
                compile_method = word_obj.get_method('compile', self.expect)
                ans = compile_method(self)
                return ans
            if sym.kind in ('parameter', 'var'):
                return block.Current_block.gen_triple('local', sym,
                         syntax_position_info=self.get_syntax_position_info())
            raise ValueError("%s.compile: unknown symbol.kind %r" % sym.kind)

        if self.kind in ('no-op', 'None'):
            return None

        if self.kind == 'label':
            block.new_label(self.label, self.word_symbol.id)
            return None

        if self.kind == 'jump':
            block.Current_block.unconditional_to(self.label)
            return None

        if self.kind == 'if-true':
            arg_triples = self.compile_args()
            block.Current_block.true_to(arg_triples[0], self.label)
            return None

        if self.kind == 'if-false':
            arg_triples = self.compile_args()
            block.Current_block.false_to(arg_triples[0], self.label)
            return None

        if self.kind == 'series':
            self.compile_args()
            return None

        if self.kind in ('ioreg', 'ioreg-bit'):
            if self.expect in ('value', 'condition'):
                return block.Current_block.gen_triple(
                         'input' if self.kind == 'ioreg' else 'input-bit',
                         string=self.label, int1=self.int1,
                         syntax_position_info=self.get_syntax_position_info())
            else:
                raise AssertionError("ast node[%s]: expect %s not supported "
                                     "for %s" %
                                       (self.id, self.expect, self.kind))

        raise AssertionError("ast node[%s]: unknown ast kind -- %s" %
                               (self.id, self.kind))