def run(top, prime_start_time = True, quiet = False):
    # The following gets a little confusing because we have two kinds of word
    # objects:
    #
    #   1.  ww objects       ("word_word", i.e., instances of the
    #                         ucc.word.word.word class)
    #   2.  word_obj objects (either subclasses or instances of the
    #                         ucclib.built_in.declaration.declaration class)
    #

    if prime_start_time:
        elapsed()       # prime the Start_time...
        compile_start_time = Start_time
    else:
        compile_start_time = Start_time
        if not quiet: print "top: %.2f" % elapsed()

    with crud.db_connection(top.packages[-1].package_dir):
        if not quiet: print "crud.db_connection: %.2f" % elapsed()

        types.init()
        if not quiet: print "types.init: %.2f" % elapsed()

        # Create symbols, word_objs and build the parsers for each package:
        #
        # {package_name: parser module}
        package_parsers = create_parsers(top)  # Also loads all of the word objs
        if not quiet: print "create parsers: %.2f" % elapsed()

        # word files => ast
        words_done = parse_needed_words(top, package_parsers, quiet)
        if not quiet: print "parse_needed_words: %.2f" % elapsed()

        # ast => intermediate code
        for word_label in words_done:
            with crud.db_transaction():
                symbol_table.get(word_label).word_obj.compile()
        if not quiet: print "generate intermediate code: %.2f" % elapsed()

        # intermediate code => optimized intermediate code
        optimize()
        if not quiet: print "optimize: %.2f" % elapsed()

        # intermediate code => assembler
        gen_assembler()
        if not quiet: print "gen_assembler: %.2f" % elapsed()

        # assembler => .hex files
        assemble_program(top.packages[-1].package_dir)
        if not quiet: print "assemble_program: %.2f" % elapsed()
    if not quiet: print "TOTAL: %.2f" % (Start_time - compile_start_time)
    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 delete_word_by_label(word_label):
    r'''Delete all ast nodes associated with word_label from the database.

    This does not report an error if the word is not in the database.
    '''
    sym = symbol_table.get(word_label, default=None)
    if sym is not None:
        delete_word_by_id(sym.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 macro_expand(self, fn_symbol, ast_node, words_needed):
        #print "repeat.macro_expand"
        _, count, body = ast_node.args
        loop_label = crud.gensym('repeat')
        if not count:
            #print "no count"
            new_args = (
              ast.ast(kind='label', label=loop_label, expect='statement'),
              body,
              ast.ast(kind='jump', label=loop_label, expect='statement'),
            )
        else:
            count = count[0]
            #print "count", count
            if count.kind == 'int':
                assert count.int1 >= 0, \
                       "repeat must not have negative repeat count"
                if count.int1 == 0:
                    return ast_node.macro_expand(fn_symbol, words_needed, (),
                                                 kind='no-op')
                if count.int1 == 1:
                    return ast_node.macro_expand(fn_symbol, words_needed, body,
                                                 kind='series')
                first_jmp = ()
            else:
                first_jmp = (
                    ast.ast(kind='jump', label=test, expect='statement'),
                )

            loop_var = crud.gensym('repeat_var')
            symbol_id = \
              symbol_table.symbol.create(loop_var, 'var', fn_symbol).id
            test = crud.gensym('repeat_test')
            new_args = (
              ast.ast(ast.ast.word(symbol_table.get('set').id),
                      (ast.ast.word(symbol_id),
                       count,
                      ),
                      kind='call',
                      expect='statement') \
                 .prepare(fn_symbol, words_needed),
            ) + first_jmp + (
              ast.ast(kind='label', label=loop_label, expect='statement'),
            ) + body + (
              ast.ast(ast.ast.word(symbol_table.get('set').id),
                      (ast.ast.word(symbol_id),
                       ast.ast(ast.ast.word(symbol_table.get('-').id),
                               ast.ast.word(symbol_id),
                               ast.ast(kind='int', int1=1),
                               kind='call',
                              ) \
                          .prepare(fn_symbol, words_needed),
                      ),
                      kind='call',
                      expect='statement') \
                 .prepare(fn_symbol, words_needed),
              ast.ast(kind='label', label=test, expect='statement'),
              ast.ast(ast.ast.word(symbol_id, expect='condition'),
                      kind='if-true',
                      label=loop_label,
                      expect='statement'),
            )

        return ast_node.macro_expand(fn_symbol, words_needed, new_args,
                                     kind='series')
    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))