コード例 #1
0
    def test_regression_parser(self):
        """Test the error cases. There are too many to make a test of each."""
        sys.stderr.write('\nRunning parser error tests: ')
        parser = lslparse.parser(lslloadlib.LoadLibrary())
        self.assertRaises(lslparse.EParseSyntax, parser.parse,
                          'f(){integer i;i>>=i;}')
        self.assertRaises(lslparse.EParseCantChangeState, parser.parse,
                          'f(){if(1)state default;else;}default{timer(){}}')
        self.assertRaises(lslparse.EParseCantChangeState, parser.parse,
                          'f(){if(1);else state default;}default{timer(){}}')
        self.assertRaises(
            lslparse.EParseCantChangeState, parser.parse,
            'f(){if(1)if(1)state default;else;else;}default{timer(){}}')

        # Test behaviour of void functions
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){<llDie(),0,0>;}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){[<llDie(),0,0>];}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){key a=llDie();}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){key a;a=llDie();}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){do;while(llDie());}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){for(;llDie(););}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){while(llDie());}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){if(llDie());}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){if(llDie());else;}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){[llDie()];}}', ('optimize', ))
        parser.parse('default{timer(){[llDie()];}}')
        parser.parse('default{timer(){llDie();}}')
        parser.parse('default{timer(){(llDie());}}')
        parser.parse('default{timer(){for(llDie();1;llDie());}}',
                     ('optimize', ))
        # 'return <void expr>' works in the same situations as state changes
        self.assertRaises(lslparse.EParseReturnShouldBeEmpty, parser.parse,
                          'default{timer(){return llDie();}}')
        self.assertRaises(lslparse.EParseReturnShouldBeEmpty, parser.parse,
                          'default{timer(){if(1)return llDie();else;}}')
        self.assertRaises(lslparse.EParseReturnShouldBeEmpty, parser.parse,
                          'default{timer(){if(1);else return llDie();}}')
        self.assertRaises(lslparse.EParseReturnShouldBeEmpty, parser.parse,
                          'default{timer(){return 1;}}')
        self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                          'default{timer(){if(1)return 1;}}')
コード例 #2
0
 def test_coverage_parser(self):
     """Cover the error cases. There are too many to make a test of each."""
     parser = lslparse.parser(
         lslloadlib.LoadLibrary(
             builtins='unit_tests/builtins-coverage-2.txt',
             fndata='unit_tests/builtins-coverage-2.txt'))
     self.assertRaises(lslparse.EParseNoConversion, parser.parse,
                       'f(){list L;(integer)L[0];}', ('lazylists', ))
     parser = lslparse.parser(lslloadlib.LoadLibrary())
     sys.stderr.write('\nRunning parser exception coverage tests: ')
     # Parse_unary_postfix_expression
     self.assertRaises(lslparse.EParseUEOF, parser.parse, u'f(){key x=')
     self.assertRaises(lslparse.EParseUndefined, parser.parse, 'f(){g();}')
     self.assertRaises(lslparse.EParseUndefined, parser.parse,
                       'integer g;f(){g();}')
     self.assertRaises(lslparse.EParseUndefined, parser.parse, 'f(){f=0;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){integer V; V[1] = 0;}', ('lazylists', ))
     self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
                       'f(){list V; V[1,1] = 0;}', ('lazylists', ))
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){list V; V[""] = 0;}', ('lazylists', ))
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){list V; V[1] = llDie();}', ('lazylists', ))
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s++;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;++s;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s=llDie();}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s+=(key)"";}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s-=s;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s*=2;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){vector v;v%=1.0;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){string s;s>>=s;}', ('extendedassignment', ))
     # Parse_unary_expression
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){-"";}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){!"";}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){~"";}')
     self.assertRaises(lslparse.EParseUndefined, parser.parse, 'f(){++f;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){(key)1;}')
     self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
                       'f(){list L;(integer)L[""];}', ('lazylists', ))
     # Parse_factor
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""*2;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){<1,1,1>%2;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){<1,1,1>/<1,1,1>;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){<1,1,1>/"";}')
     # Parse_term
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){llDie()+1;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""-1;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){[]+llDie();}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){(key)""+(key)"";}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""+(key)"";}')
     # Parse_shift
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){"">>1;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){1<<"";}')
     # Parse_inequality
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""<"";}')
     # Parse_comparison
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){llDie()==3;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""==3;}')
     # Parse_bitbool_factor
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""&3;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){3&"";}')
     # Parse_bitxor_term
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""^3;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){3^"";}')
     # Parse_bitbool_term
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""|3;}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){3|"";}')
     # Parse_expression
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){3||"";}')
     self.assertRaises(lslparse.EParseTypeMismatch, parser.parse,
                       'f(){""&&3;}')
     # Parse_optional_expression_list
     self.assertRaises(lslparse.EParseFunctionMismatch, parser.parse,
                       'f(){llSay(0);}')
     self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
                       'f(){@x;@x;}')
     self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
                       'f(){integer x;integer x;}')
     self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
                       'f(integer x, integer x){}')
     self.assertRaises(lslparse.EParseAlreadyDefined, parser.parse,
                       'default{timer(){}timer(){}}')
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(){state state;}}')
     self.assertRaises(lslparse.EParseUndefined, parser.parse,
                       'default{timer(){state undefined;}}')
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(){switch(1){case 1;}}}',
                       ('enableswitch', ))
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(){switch(1){default;}}}',
                       ('enableswitch', ))
     self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
                       'default{timer(){while(1){break 0;}}}',
                       ('breakcont', ))
     self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
                       'default{timer(){while(1){break 2;}}}',
                       ('breakcont', ))
     self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
                       'default{timer(){while(1){continue 0;}}}',
                       ('breakcont', ))
     self.assertRaises(lslparse.EParseInvalidBrkContArg, parser.parse,
                       'default{timer(){while(1){continue 2;}}}',
                       ('breakcont', ))
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'integer T=-TRUE;default{timer(){}}')
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'list L=[[]];default{timer(){}}')
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(integer i){}}')
     self.assertRaises(
         lslparse.EParseSyntax,
         parser.parse,
         'i = 0;',
     )
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(){}}state{timer(){}}')
     self.assertRaises(lslparse.EParseUndefined, parser.parse,
                       'default{timer(){jump undefined;}}')
     # BuildTempGlobalsTable coverage
     self.assertRaises(lslparse.EParseSyntax, parser.parse, ';')
     self.assertRaises(lslparse.EParseSyntax, parser.parse, 'f(;')
     self.assertRaises(lslparse.EParseSyntax, parser.parse, 'f();')
     self.assertRaises(lslparse.EParseSyntax, parser.parse, 'integer f=')
     self.assertRaises(lslparse.EParseUEOF, parser.parse, 'integer /*')
     self.assertRaises(lslparse.EParseSyntax, parser.parse,
                       'default{timer(){}}state e;')
コード例 #3
0
def main(argv):
    """Main executable."""
    import os

    if hasattr(sys, "frozen") and sys.frozen in ("windows_exe", "console_exe"):
        lslopt.lslcommon.DataPath = (os.path.dirname(os.path.abspath(sys.executable)) + os.sep)
    else:
        # If it's good to append the basename to it, it's good to append the
        # auxiliary files' names to it, which should be located where this file is.
        lslopt.lslcommon.DataPath = __file__[:-len(os.path.basename(__file__))]

    # Default options
    options = {'extendedglobalexpr', 'extendedtypecast', 'extendedassignment', 'allowkeyconcat', 'allowmultistrings',
               'processpre', 'warntabs', 'optimize', 'optsigns', 'optfloats', 'constfold', 'dcr', 'errmissingdefault',
               'listlength', 'listadd'}

    assert not (options - validoptions), (u"Default options not present in"
                                          u" validoptions: '%s'"
                                          % (b"', '".join(options - validoptions)).decode('utf8'))

    try:
        opts, args = getopt.gnu_getopt(argv[1:], 'hO:o:p:P:HTyb:L:A:',
                                       ('optimizer-options=', 'help', 'version', 'output=', 'header',
                                        'timestamp', 'python-exceptions', 'prettify', 'bom', 'emap',
                                        'preproc=', 'precmd=', 'prearg=', 'prenodef', 'preshow',
                                        'avid=', 'avname=', 'assetid=', 'shortname=', 'builtins='
                                                                                      'libdata=', 'postarg='))
    except getopt.GetoptError as e:
        Usage(argv[0])
        werr(u"\nError: %s\n" % str(e).decode('utf8', 'replace'))
        return 1

    outfile = '-'
    avid = '00000000-0000-0000-0000-000000000000'
    avname = ''
    shortname = ''
    assetid = '00000000-0000-0000-0000-000000000000'
    preproc_command = 'cpp'
    preproc_user_preargs = []
    preproc_user_postargs = []
    preproc = 'none'
    predefines = True
    script_header = ''
    script_timestamp = ''
    preshow = False
    raise_exception = False
    prettify = False
    bom = False
    emap = False
    builtins = None
    libdata = None

    for opt, arg in opts:
        if opt in ('-O', '--optimizer-options'):
            optchanges = arg.lower().split(',')
            for chg in optchanges:
                if not chg:
                    continue
                if chg in ('clear', '+clear'):
                    options = set()
                    continue
                if chg == '-clear':
                    # ignore
                    continue
                chgfix = chg
                if chgfix[0] not in ('+', '-'):
                    chgfix = '+' + chgfix
                if chgfix[1:] not in validoptions:
                    Usage(argv[0], 'optimizer-options')
                    werr(u"\nError: Unrecognized"
                         u" optimizer option: %s\n" % chg.decode('utf8'))
                    return 1
                if chgfix[0] == '-':
                    options.discard(chgfix[1:])
                else:
                    options.add(chgfix[1:])
                del chgfix

        elif opt in ('-h', '--help'):
            Usage(argv[0])
            return 0

        elif opt == '--version':
            wout(u'LSL PyOptimizer version %s\n' % str2u(VERSION))
            return 0

        elif opt in ('-o', '--output'):
            outfile = arg

        elif opt in ('-b', '--builtins'):
            builtins = arg

        elif opt in ('-L', '--libdata'):
            libdata = arg

        elif opt in ('-y', '--python-exceptions'):
            raise_exception = True

        elif opt in ('-p', '--preproc'):
            preproc = arg.lower()
            supported = ('ext', 'mcpp', 'gcpp', 'none')
            if preproc not in supported:
                Usage(argv[0])
                werr(u"\nUnknown --preproc option: '%s'."
                     u" Only '%s' supported.\n"
                     % (preproc, str2u("', '".join(supported))))
                return 1

            if preproc == 'gcpp':
                preproc_command = 'cpp'

            elif preproc == 'mcpp':
                preproc_command = 'mcpp'

        elif opt == '--precmd':
            preproc_command = arg

        elif opt in ('-P', '--prearg'):
            preproc_user_preargs.append(arg)

        elif opt == '--prenodef':
            predefines = False

        elif opt == '--preshow':
            preshow = True

        elif opt in ('-H', '--header'):
            script_header = True

        elif opt in ('-T', '--timestamp'):
            script_timestamp = True

        elif opt == '--avid':
            avid = arg

        elif opt == '--avname':
            avname = arg

        elif opt == '--assetid':
            assetid = arg

        elif opt == '--shortname':
            shortname = arg

        elif opt == '--prettify':
            prettify = True

        elif opt == '--bom':
            bom = True

        elif opt == '--emap':
            emap = True

    del opts

    if prettify:
        options &= {'rsrclimit'}
        options.add('prettify')

    rsrclimit = False
    try:

        if 'rsrclimit' in options:
            rsrclimit = True
            import resource
            resource.setrlimit(resource.RLIMIT_CPU, (5, 8))
            resource.setrlimit(resource.RLIMIT_STACK, (0x60000, 0x80000))
            resource.setrlimit(resource.RLIMIT_DATA, (9001000, 12001000))
            resource.setrlimit(resource.RLIMIT_AS, (61001000, 81001000))

        if 'lso' in options:
            lslopt.lslcommon.LSO = True
            options.remove('lso')

        if 'expr' in options:
            lslopt.lslcommon.IsCalc = True
            options.remove('expr')

        if 'help' in options:
            Usage(argv[0], 'optimizer-options')
            return 0

        fname = args[0] if args else None
        if fname is None:
            Usage(argv[0])
            werr(u"\nError: Input file not specified. Use -"
                 u" if you want to use stdin.\n")
            return 1

        del args

        script = ''
        if fname == '-':
            script = sys.stdin.read()
        else:
            try:
                f = open(fname, 'r')
            except IOError as e:
                if e.errno == 2:
                    werr(u"Error: File not found: %s\n" % str2u(fname))
                    return 2
                raise
            try:
                script = f.read()
            finally:
                f.close()
                del f

        if script_header:
            script_header = ScriptHeader(script, avname)

        if script_timestamp:
            import time
            tmp = time.time()
            script_timestamp = time.strftime(
                b'// Generated on %Y-%m-%dT%H:%M:%S.{0:06d}Z\n'
                    .format(int(tmp % 1 * 1000000)), time.gmtime(tmp))
            del tmp

        if shortname == '':
            shortname = os.path.basename(fname)

        # Build preprocessor command line
        preproc_cmdline = [preproc_command] + preproc_user_preargs
        if preproc == 'gcpp':
            preproc_cmdline += [
                '-undef', '-x', 'c', '-std=c99', '-nostdinc',
                '-trigraphs', '-dN', '-fno-extended-identifiers',
            ]

        elif preproc == 'mcpp':
            preproc_cmdline += [
                '-e', 'UTF-8', '-I-', '-N', '-2', '-3', '-j',
                '-V199901L',
            ]

        if predefines:
            preproc_cmdline += [
                '-Dinteger(...)=((integer)(__VA_ARGS__))',
                '-Dfloat(...)=((float)(__VA_ARGS__))',
                '-Dstring(...)=((string)(__VA_ARGS__))',
                '-Dkey(...)=((key)(__VA_ARGS__))',
                '-Drotation(...)=((rotation)(__VA_ARGS__))',
                '-Dquaternion(...)=((quaternion)(__VA_ARGS__))',
                '-Dvector(...)=((vector)(__VA_ARGS__))',
                '-Dlist(...)=((list)(__VA_ARGS__))',
            ]
            preproc_cmdline.append('-D__AGENTKEY__="%s"' % avid)
            preproc_cmdline.append('-D__AGENTID__="%s"' % avid)
            preproc_cmdline.append('-D__AGENTIDRAW__=' + avid)
            preproc_cmdline.append('-D__AGENTNAME__="%s"' % avname)
            preproc_cmdline.append('-D__ASSETID__=' + assetid)
            preproc_cmdline.append('-D__SHORTFILE__="%s"' % shortname)
            preproc_cmdline.append('-D__OPTIMIZER__=LSL PyOptimizer')
            preproc_cmdline.append('-D__OPTIMIZER_VERSION__=' + VERSION)

        # Append user arguments at the end to allow them to override defaults
        preproc_cmdline += preproc_user_postargs

        if type(script) is unicode:
            script = script.encode('utf8')
        else:
            try:
                # Try converting the script to Unicode, to report any encoding
                # errors with accurate line information. At this point we don't
                # need the result.
                UniConvScript(script, options,
                              fname if fname != '-' else '<stdin>',
                              emap).to_unicode()
            except EParse as e:
                # We don't call ReportError to prevent problems due to
                # displaying invalid UTF-8
                werr(e.args[0] + u"\n")
                return 1

        if preproc != 'none':
            # At this point, for the external preprocessor to work we need the
            # script as a byte array, not as unicode, but it should be UTF-8.
            script = PreparePreproc(script.decode('utf8')).encode('utf8')
            if preproc == 'mcpp':
                # As a special treatment for mcpp, we force it to output its
                # macros so we can read if USE_xxx are defined. With GCC that
                # is achieved with -dN, but mcpp has no command line option.
                script += b'\n#pragma MCPP put_defines\n'

            # Invoke the external preprocessor
            import subprocess

            p = subprocess.Popen(preproc_cmdline, stdin=subprocess.PIPE,
                                 stdout=subprocess.PIPE)
            script = p.communicate(input=script)[0]
            status = p.wait()
            if status:
                return status
            del p, status

            # This method is very imperfect, in several senses. However, since
            # it's applied to the output of the preprocessor, all of the
            # concerns should be addressed:
            #    - \s includes \n, but \n should not be allowed.
            #    - Comments preceding the directive should not cause problems.
            #              e.g.: /* test */ #directive
            #    - #directive within a comment or string should be ignored.
            for x in re.findall(br'(?:(?<=\n)|^)\s*#\s*define\s+('
                                br'USE_SWITCHES'
                                br'|USE_LAZY_LISTS'
                                br')(?:$|[^A-Za-z0-9_])', script, re.S):
                if x == b'USE_SWITCHES':
                    options.add('enableswitch')
                elif x == b'USE_LAZY_LISTS':
                    options.add('lazylists')

        if not preshow:

            if emap:
                options.add('emap')

            lib = lslopt.lslloadlib.LoadLibrary(builtins, libdata)
            p = parser(lib)
            try:
                ts = p.parse(script, options,
                             fname if fname != '-' else '<stdin>')
            except EParse as e:
                ReportError(script, e)
                return 1
            del p, script

            opt = optimizer(lib)
            ts = opt.optimize(ts, options)
            del opt

            outs = outscript()
            script = script_header + script_timestamp + outs.output(ts, options)
            del outs, ts

        del script_header, script_timestamp

        if bom:
            if not script.startswith(b'\xEF\xBB\xBF'):
                script = b'\xEF\xBB\xBF' + script

        if outfile == '-':
            sys.stdout.write(script)
        else:
            outf = open(outfile, 'w')
            try:
                outf.write(script)
            finally:
                outf.close()
        return 0

    except Exception as e:
        if rsrclimit:
            # Raise the soft limits to hopefully prevent double exceptions
            resource.setrlimit(resource.RLIMIT_CPU, (8, 8))
            resource.setrlimit(resource.RLIMIT_STACK, (0x80000, 0x80000))
            resource.setrlimit(resource.RLIMIT_DATA, (12001000, 12001000))
            resource.setrlimit(resource.RLIMIT_AS, (81001000, 81001000))
        if raise_exception:
            raise
        werr(e.__class__.__name__ + ': ' + str(e) + '\n')
        return 1