mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +00:00
First baby steps towards dual Python2+3 compatibility
This commit is contained in:
parent
789eb85bfe
commit
fe2dd9a721
17 changed files with 319 additions and 175 deletions
|
@ -34,12 +34,13 @@
|
||||||
# The JSON functions have been separated to their own module.
|
# The JSON functions have been separated to their own module.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from lslcommon import *
|
from lslopt.lslcommon import *
|
||||||
import lslcommon
|
from lslopt import lslcommon
|
||||||
from ctypes import c_float
|
from ctypes import c_float
|
||||||
import math
|
import math
|
||||||
import hashlib
|
import hashlib
|
||||||
from base64 import b64encode, b64decode
|
from base64 import b64encode, b64decode
|
||||||
|
from strutil import *
|
||||||
|
|
||||||
|
|
||||||
# Regular expressions used along the code. They are needed mainly because
|
# Regular expressions used along the code. They are needed mainly because
|
||||||
|
@ -58,18 +59,49 @@ from base64 import b64encode, b64decode
|
||||||
# as is (vector)"<1,inf,info>". The 1st gives <0,0,0>, the others <1,inf,inf>.
|
# as is (vector)"<1,inf,info>". The 1st gives <0,0,0>, the others <1,inf,inf>.
|
||||||
# The lookahead (?!i) is essential for parsing them that way without extra code.
|
# The lookahead (?!i) is essential for parsing them that way without extra code.
|
||||||
# Note that '|' in REs is order-sensitive.
|
# Note that '|' in REs is order-sensitive.
|
||||||
float_re = re.compile(ur'^\s*[+-]?(?:0(x)(?:[0-9a-f]+(?:\.[0-9a-f]*)?|\.[0-9a-f]+)(?:p[+-]?[0-9]+)?'
|
float_re = re.compile(str2u(r'''
|
||||||
ur'|(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:e[+-]?[0-9]+)?|inf|(nan))',
|
^\s*[+-]?(?:
|
||||||
re.I)
|
0(x)(?: # Hex float or hex int (captures the 'x')
|
||||||
vfloat_re = re.compile(ur'^\s*[+-]?(?:0(x)(?:[0-9a-f]+(?:\.[0-9a-f]*)?|\.[0-9a-f]+)(?:p[+-]?[0-9]+)?'
|
[0-9a-f]+(?:\.[0-9a-f]*)?
|
||||||
ur'|(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+)(?:e[+-]?[0-9]+)?|infinity|inf(?!i)|(nan))',
|
|\.[0-9a-f]+ # Hex digits
|
||||||
|
)(?:
|
||||||
|
p[+-]?[0-9]+ # Hex float exponent
|
||||||
|
)? # (optional)
|
||||||
|
|(?: # Decimal float or decimal int
|
||||||
|
[0-9]+(?:\.[0-9]*)?
|
||||||
|
|\.[0-9]+ # Decimal digits
|
||||||
|
)(?:
|
||||||
|
e[+-]?[0-9]+ # Decimal float exponent
|
||||||
|
)? # (optional)
|
||||||
|
|inf # Infinity
|
||||||
|
|(nan) # NaN (captured)
|
||||||
|
)
|
||||||
|
'''), re.I | re.X)
|
||||||
|
vfloat_re = re.compile(str2u(r'''
|
||||||
|
^\s*[+-]?(?:
|
||||||
|
0(x)(?: # Hex float or hex int (captures the 'x')
|
||||||
|
[0-9a-f]+(?:\.[0-9a-f]*)?
|
||||||
|
|\.[0-9a-f]+ # Hex digits
|
||||||
|
)(?:
|
||||||
|
p[+-]?[0-9]+ # Hex float exponent
|
||||||
|
)? # (optional)
|
||||||
|
|(?: # Decimal float or decimal int
|
||||||
|
[0-9]+(?:\.[0-9]*)?
|
||||||
|
|\.[0-9]+ # Decimal digits
|
||||||
|
)(?:
|
||||||
|
e[+-]?[0-9]+ # Decimal float exponent
|
||||||
|
)? # (optional)
|
||||||
|
|infinity|inf(?!i) # Infinity (the only difference with the above)
|
||||||
|
|(nan) # NaN (captured)
|
||||||
|
)
|
||||||
|
'''), re.I | re.X)
|
||||||
|
|
||||||
|
int_re = re.compile(str2u(r'^0(x)[0-9a-f]+|^\s*[+-]?[0-9]+'), re.I)
|
||||||
|
|
||||||
|
key_re = re.compile(str2u(r'^[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}$'),
|
||||||
re.I)
|
re.I)
|
||||||
|
|
||||||
int_re = re.compile(ur'^0(x)[0-9a-f]+|^\s*[+-]?[0-9]+', re.I)
|
b64_re = re.compile(str2u(r'^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2,3})?'))
|
||||||
|
|
||||||
key_re = re.compile(ur'^[0-9a-f]{8}(?:-[0-9a-f]{4}){4}[0-9a-f]{8}$', re.I)
|
|
||||||
|
|
||||||
b64_re = re.compile(ur'^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2,3})?')
|
|
||||||
|
|
||||||
ZERO_VECTOR = Vector((0.0, 0.0, 0.0))
|
ZERO_VECTOR = Vector((0.0, 0.0, 0.0))
|
||||||
ZERO_ROTATION = Quaternion((0.0, 0.0, 0.0, 1.0))
|
ZERO_ROTATION = Quaternion((0.0, 0.0, 0.0, 1.0))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
# Classes, functions and variables for use of all modules.
|
# Classes, functions and variables for use of all modules.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
from strutil import *
|
||||||
|
|
||||||
_exclusions = frozenset(('nt','t','name','value','ch', 'X','SEF'))
|
_exclusions = frozenset(('nt','t','name','value','ch', 'X','SEF'))
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
# Dead Code Removal optimization
|
# Dead Code Removal optimization
|
||||||
|
|
||||||
import lslfuncs
|
from lslopt import lslfuncs
|
||||||
from lslcommon import nr
|
from lslopt.lslcommon import nr
|
||||||
|
|
||||||
class deadcode(object):
|
class deadcode(object):
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
# Extra functions that have predictable return values for certain arguments.
|
# Extra functions that have predictable return values for certain arguments.
|
||||||
|
|
||||||
from lslcommon import Key, Vector #, Quaternion
|
from lslopt.lslcommon import Key, Vector #, Quaternion
|
||||||
from lslbasefuncs import ELSLCantCompute, fi,ff,fs,fk,v2f,q2f,fl, \
|
from lslopt.lslbasefuncs import ELSLCantCompute, fi,ff,fs,fk,v2f,q2f,fl, \
|
||||||
NULL_KEY, ZERO_VECTOR, ZERO_ROTATION, \
|
NULL_KEY, ZERO_VECTOR, ZERO_ROTATION, \
|
||||||
TOUCH_INVALID_TEXCOORD, cond
|
TOUCH_INVALID_TEXCOORD, cond
|
||||||
ff, q2f # keep pyflakes happy as these are not used
|
ff, q2f # keep pyflakes happy as these are not used
|
||||||
|
|
|
@ -17,12 +17,12 @@
|
||||||
|
|
||||||
# Constant folding and simplification of expressions and statements.
|
# Constant folding and simplification of expressions and statements.
|
||||||
|
|
||||||
import lslcommon
|
from lslopt import lslcommon
|
||||||
from lslcommon import Vector, Quaternion, warning, nr
|
from lslopt.lslcommon import Vector, Quaternion, warning, nr
|
||||||
import lslfuncs
|
from lslopt import lslfuncs
|
||||||
from lslfuncs import ZERO_VECTOR, ZERO_ROTATION
|
from lslopt.lslfuncs import ZERO_VECTOR, ZERO_ROTATION
|
||||||
import math
|
import math
|
||||||
from lslfuncopt import OptimizeFunc, OptimizeArgs, FuncOptSetup
|
from lslopt.lslfuncopt import OptimizeFunc, OptimizeArgs, FuncOptSetup
|
||||||
|
|
||||||
# TODO: Remove special handling of @ within IF,WHILE,FOR,DO
|
# TODO: Remove special handling of @ within IF,WHILE,FOR,DO
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
# Optimize calls to LSL library functions and parameters where possible
|
# Optimize calls to LSL library functions and parameters where possible
|
||||||
# This is dependent on the LSL function library.
|
# This is dependent on the LSL function library.
|
||||||
|
|
||||||
import lslcommon
|
from lslopt import lslcommon
|
||||||
from lslcommon import Key, Vector, Quaternion, nr
|
from lslopt.lslcommon import Key, Vector, Quaternion, nr
|
||||||
import lslfuncs
|
from lslopt import lslfuncs
|
||||||
|
|
||||||
def OptimizeArgs(node, sym):
|
def OptimizeArgs(node, sym):
|
||||||
"""Transform function arguments to shorter equivalents where possible."""
|
"""Transform function arguments to shorter equivalents where possible."""
|
||||||
|
|
|
@ -17,6 +17,6 @@
|
||||||
|
|
||||||
# Put all LSL functions together in one single module
|
# Put all LSL functions together in one single module
|
||||||
|
|
||||||
from lslbasefuncs import *
|
from lslopt.lslbasefuncs import *
|
||||||
from lsljson import *
|
from lslopt.lsljson import *
|
||||||
from lslextrafuncs import *
|
from lslopt.lslextrafuncs import *
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
import math
|
import math
|
||||||
from lslcommon import *
|
from lslopt.lslcommon import *
|
||||||
from lslbasefuncs import llStringTrim, fs, fl, InternalTypecast
|
from lslopt.lslbasefuncs import llStringTrim, fs, fl, InternalTypecast
|
||||||
|
|
||||||
# INCOMPATIBILITY NOTE: The JSON functions in SL have very weird behaviour
|
# INCOMPATIBILITY NOTE: The JSON functions in SL have very weird behaviour
|
||||||
# in corner cases. Despite our best efforts, that behaviour is not replicated
|
# in corner cases. Despite our best efforts, that behaviour is not replicated
|
||||||
|
@ -44,8 +44,8 @@ JSON_DELETE = u'\uFDD8'
|
||||||
JSON_APPEND = -1
|
JSON_APPEND = -1
|
||||||
|
|
||||||
jsonesc_re = re.compile(u'[\x08\x09\x0A\x0C\x0D"/\\\\]')
|
jsonesc_re = re.compile(u'[\x08\x09\x0A\x0C\x0D"/\\\\]')
|
||||||
jsonesc_dict = {u'\x08':ur'\b', u'\x09':ur'\t', u'\x0A':ur'\n', u'\x0C':ur'\f',
|
jsonesc_dict = {u'\x08':u'\\b', u'\x09':u'\\t', u'\x0A':u'\\n', u'\x0C':u'\\f',
|
||||||
u'\x0D':ur'\r', u'"':ur'\"', u'/':ur'\/', u'\\':ur'\\'}
|
u'\x0D':u'\\r', u'"':u'\\"', u'/':u'\\/', u'\\':u'\\\\'}
|
||||||
jsonunesc_dict = {u'b':u'\x08', u't':u'\x09', u'n':u'\x0A', u'f':u'\x0C', u'r':u'\x0D'}
|
jsonunesc_dict = {u'b':u'\x08', u't':u'\x09', u'n':u'\x0A', u'f':u'\x0C', u'r':u'\x0D'}
|
||||||
|
|
||||||
# LSL JSON numbers differ from standard JSON numbers in many respects:
|
# LSL JSON numbers differ from standard JSON numbers in many respects:
|
||||||
|
@ -72,18 +72,37 @@ jsonunesc_dict = {u'b':u'\x08', u't':u'\x09', u'n':u'\x0A', u'f':u'\x0C', u'r':u
|
||||||
# elements when appropriate.
|
# elements when appropriate.
|
||||||
|
|
||||||
# Real JSON number parser:
|
# Real JSON number parser:
|
||||||
#jsonnum_re = re.compile(ur'-?(?:[1-9][0-9]*|0)(?:\.[0-9]+)?(?:[Ee][+-]?[0-9]+)?')
|
#jsonnum_re = re.compile(str2u(
|
||||||
|
# r'-?(?:[1-9][0-9]*|0)(?:\.[0-9]+)?(?:[Ee][+-]?[0-9]+)?'
|
||||||
|
# ))
|
||||||
|
|
||||||
# BUG-6466 active:
|
# BUG-6466 active:
|
||||||
jsonnumbug_re = re.compile(ur'-?(?:[0-9]*([Ee])-?[0-9]*\.?[0-9]*|(?=[0-9Ee.])[0-9]*(\.?[0-9]*(?:[Ee]-?)?[0-9]*))')
|
jsonnumbug_re = re.compile(str2u(r'''
|
||||||
|
-?(?:
|
||||||
|
[0-9]*([Ee])-?[0-9]*\.?[0-9]*
|
||||||
|
|(?=[0-9Ee.])[0-9]*(\.?[0-9]*(?:[Ee]-?)?[0-9]*)
|
||||||
|
)
|
||||||
|
'''), re.X)
|
||||||
# BUG-6466 fixed:
|
# BUG-6466 fixed:
|
||||||
# The new RE is just a modified version of the crap, allowing + exponents and
|
# The new RE is just a modified version of the crap, allowing + exponents and
|
||||||
# disallowing zeros, sometimes even when legal (e.g. 0e0)
|
# disallowing zeros, sometimes even when legal (e.g. 0e0)
|
||||||
#jsonnum_re = re.compile(ur'-?(?:(?=[1-9]|\.(?:[^e]|$)|0(?:[^0-9e]|$))[0-9]*([Ee])[+-]?[0-9]*\.?[0-9]*|(?=[1-9]|\.(?:[^e]|$)|0(?:[^0-9e]|$))[0-9]*(\.?[0-9]*(?:[Ee][+-]?)?[0-9]*))')
|
#jsonnum_re = re.compile(str2u(r'''
|
||||||
|
# -?(?:
|
||||||
|
# (?=[1-9]|\.(?:[^e]|$)
|
||||||
|
# |0(?:[^0-9e]|$))[0-9]*([Ee])[+-]?[0-9]*\.?[0-9]*
|
||||||
|
# |(?=[1-9]|\.(?:[^e]|$)
|
||||||
|
# |0(?:[^0-9e]|$))[0-9]*(\.?[0-9]*(?:[Ee][+-]?)?[0-9]*)
|
||||||
|
# )
|
||||||
|
# '''), re.X)
|
||||||
# They've fixed BUG-6657 by bringing BUG-6466 back to life.
|
# They've fixed BUG-6657 by bringing BUG-6466 back to life.
|
||||||
jsonnum_re = re.compile(ur'-?(?:[0-9]*([Ee])-?[0-9]*\.?[0-9]*|(?=[0-9Ee.])[0-9]*(\.?[0-9]*(?:[Ee]-?)?[0-9]*))')
|
jsonnum_re = re.compile(str2u(r'''
|
||||||
|
-?(?:
|
||||||
|
[0-9]*([Ee])-?[0-9]*\.?[0-9]*
|
||||||
|
|(?=[0-9Ee.])[0-9]*(\.?[0-9]*(?:[Ee]-?)?[0-9]*)
|
||||||
|
)
|
||||||
|
'''), re.X)
|
||||||
|
|
||||||
jsonstring_re = re.compile(ur'"(?:[^"\\]|\\.)*"')
|
jsonstring_re = re.compile(str2u(r'"(?:[^"\\]|\\.)*"'))
|
||||||
|
|
||||||
# This might need some explanation. The ] and - are included in the first
|
# This might need some explanation. The ] and - are included in the first
|
||||||
# set, the ] in the first after the ^ and the - in the last positions of
|
# set, the ] in the first after the ^ and the - in the last positions of
|
||||||
|
@ -91,7 +110,7 @@ jsonstring_re = re.compile(ur'"(?:[^"\\]|\\.)*"')
|
||||||
# though it confuses things. The set comprises any character not in
|
# though it confuses things. The set comprises any character not in
|
||||||
# -{}[],:"0123456789
|
# -{}[],:"0123456789
|
||||||
# The second set comprises zero or more characters not in ,:]}
|
# The second set comprises zero or more characters not in ,:]}
|
||||||
#word_re = re.compile(ur'[^][{}0-9",:-][^]},:]*')
|
#word_re = re.compile(str2u(r'[^][{}0-9",:-][^]},:]*'))
|
||||||
# Screw that, we're using just a fallback.
|
# Screw that, we're using just a fallback.
|
||||||
jsoncatchall_re = re.compile(u'(.*?)[\x09\x0A\x0B\x0C\x0D ]*(?:[]},]|$)')
|
jsoncatchall_re = re.compile(u'(.*?)[\x09\x0A\x0B\x0C\x0D ]*(?:[]},]|$)')
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
|
|
||||||
# Optimizations that have a negative effect on other stages.
|
# Optimizations that have a negative effect on other stages.
|
||||||
|
|
||||||
import lslcommon
|
from lslopt import lslcommon
|
||||||
from lslcommon import nr
|
from lslopt.lslcommon import nr
|
||||||
#from lslcommon import Vector, Quaternion
|
#from lslcommon import Vector, Quaternion
|
||||||
#import lslfuncs
|
#import lslfuncs
|
||||||
#from lslfuncs import ZERO_VECTOR, ZERO_ROTATION
|
#from lslfuncs import ZERO_VECTOR, ZERO_ROTATION
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
# Load the builtins and function properties.
|
# Load the builtins and function properties.
|
||||||
|
|
||||||
import sys, re
|
import sys, re
|
||||||
from lslcommon import types, warning, Vector, Quaternion
|
from lslopt.lslcommon import types, warning, Vector, Quaternion
|
||||||
import lslcommon, lslfuncs
|
from lslopt import lslcommon, lslfuncs
|
||||||
|
|
||||||
def LoadLibrary(builtins = None, fndata = None):
|
def LoadLibrary(builtins = None, fndata = None):
|
||||||
"""Load builtins.txt and fndata.txt (or the given filenames) and return
|
"""Load builtins.txt and fndata.txt (or the given filenames) and return
|
||||||
|
@ -40,21 +40,21 @@ def LoadLibrary(builtins = None, fndata = None):
|
||||||
# Library read code
|
# Library read code
|
||||||
|
|
||||||
parse_lin_re = re.compile(
|
parse_lin_re = re.compile(
|
||||||
r'^\s*([a-z]+)\s+'
|
br'^\s*([a-z]+)\s+'
|
||||||
r'([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*('
|
br'([a-zA-Z_][a-zA-Z0-9_]*)\s*\(\s*('
|
||||||
r'[a-z]+\s+[a-zA-Z_][a-zA-Z0-9_]*'
|
br'[a-z]+\s+[a-zA-Z_][a-zA-Z0-9_]*'
|
||||||
r'(?:\s*,\s*[a-z]+\s+[a-zA-Z_][a-zA-Z0-9_]*)*'
|
br'(?:\s*,\s*[a-z]+\s+[a-zA-Z_][a-zA-Z0-9_]*)*'
|
||||||
r')?\s*\)\s*$'
|
br')?\s*\)\s*$'
|
||||||
r'|'
|
br'|'
|
||||||
r'^\s*const\s+([a-z]+)'
|
br'^\s*const\s+([a-z]+)'
|
||||||
r'\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*?)\s*$'
|
br'\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(.*?)\s*$'
|
||||||
r'|'
|
br'|'
|
||||||
r'^\s*(?:#.*|//.*)?$')
|
br'^\s*(?:#.*|//.*)?$')
|
||||||
parse_arg_re = re.compile(r'^\s*([a-z]+)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*$')
|
parse_arg_re = re.compile(br'^\s*([a-z]+)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*$')
|
||||||
parse_fp_re = re.compile(r'^\s*(-?(?=[0-9]|\.[0-9])[0-9]*'
|
parse_fp_re = re.compile(br'^\s*(-?(?=[0-9]|\.[0-9])[0-9]*'
|
||||||
r'((?:\.[0-9]*)?(?:[Ee][+-]?[0-9]+)?))\s*$')
|
br'((?:\.[0-9]*)?(?:[Ee][+-]?[0-9]+)?))\s*$')
|
||||||
parse_int_re = re.compile(r'^\s*(-?0x[0-9A-Fa-f]+|-?[0-9]+)\s*$')
|
parse_int_re = re.compile(br'^\s*(-?0x[0-9A-Fa-f]+|-?[0-9]+)\s*$')
|
||||||
parse_str_re = re.compile(ur'^"((?:[^"\\]|\\.)*)"$')
|
parse_str_re = re.compile(u'^"((?:[^"\\\\]|\\\\.)*)"$')
|
||||||
|
|
||||||
f = open(builtins, 'rb')
|
f = open(builtins, 'rb')
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -17,13 +17,13 @@
|
||||||
|
|
||||||
# Optimizer class that wraps and calls the other parts.
|
# Optimizer class that wraps and calls the other parts.
|
||||||
|
|
||||||
import lslfuncs
|
from lslopt import lslfuncs
|
||||||
|
|
||||||
from lslcommon import nr
|
from lslopt.lslcommon import nr
|
||||||
from lslfoldconst import foldconst
|
from lslopt.lslfoldconst import foldconst
|
||||||
from lslrenamer import renamer
|
from lslopt.lslrenamer import renamer
|
||||||
from lsldeadcode import deadcode
|
from lslopt.lsldeadcode import deadcode
|
||||||
from lsllastpass import lastpass
|
from lslopt.lsllastpass import lastpass
|
||||||
|
|
||||||
class optimizer(foldconst, renamer, deadcode, lastpass):
|
class optimizer(foldconst, renamer, deadcode, lastpass):
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
# Convert an abstract syntax tree + symbol table back to a script as text.
|
# Convert an abstract syntax tree + symbol table back to a script as text.
|
||||||
|
|
||||||
import lslfuncs
|
from lslopt import lslfuncs
|
||||||
import lslcommon
|
from lslopt import lslcommon
|
||||||
from lslcommon import Key, Vector, Quaternion, warning
|
from lslopt.lslcommon import Key, Vector, Quaternion, warning
|
||||||
from math import copysign
|
from math import copysign
|
||||||
|
|
||||||
debugScopes = False
|
debugScopes = False
|
||||||
|
|
|
@ -20,8 +20,9 @@
|
||||||
|
|
||||||
# TODO: Add info to be able to propagate error position to the source.
|
# TODO: Add info to be able to propagate error position to the source.
|
||||||
|
|
||||||
from lslcommon import Key, Vector, Quaternion, types, nr
|
from lslopt.lslcommon import Key, Vector, Quaternion, types, nr
|
||||||
import lslcommon, lslfuncs
|
from lslopt import lslcommon, lslfuncs
|
||||||
|
from strutil import *
|
||||||
import re
|
import re
|
||||||
|
|
||||||
# Note this module was basically written from bottom to top, which may help
|
# Note this module was basically written from bottom to top, which may help
|
||||||
|
@ -70,8 +71,8 @@ class EParse(Exception):
|
||||||
self.errorpos = parser.errorpos
|
self.errorpos = parser.errorpos
|
||||||
self.lno, self.cno, self.fname = GetErrLineCol(parser)
|
self.lno, self.cno, self.fname = GetErrLineCol(parser)
|
||||||
filename = (self.fname.decode('utf8', 'replace')
|
filename = (self.fname.decode('utf8', 'replace')
|
||||||
.replace(u'\\', ur'\\')
|
.replace(u'\\', u'\\\\')
|
||||||
.replace(u'"', ur'\"')
|
.replace(u'"', u'\\"')
|
||||||
)
|
)
|
||||||
|
|
||||||
if parser.processpre and filename != '<stdin>':
|
if parser.processpre and filename != '<stdin>':
|
||||||
|
|
89
main.py
89
main.py
|
@ -31,6 +31,7 @@ from lslopt.lsloptimizer import optimizer
|
||||||
import sys, os, getopt, re
|
import sys, os, getopt, re
|
||||||
import lslopt.lslcommon
|
import lslopt.lslcommon
|
||||||
import lslopt.lslloadlib
|
import lslopt.lslloadlib
|
||||||
|
from strutil import *
|
||||||
|
|
||||||
|
|
||||||
VERSION = '0.3.0beta'
|
VERSION = '0.3.0beta'
|
||||||
|
@ -44,7 +45,7 @@ def ReportError(script, e):
|
||||||
# When the encoding of stderr is unknown (e.g. when redirected to a file),
|
# When the encoding of stderr is unknown (e.g. when redirected to a file),
|
||||||
# output will be encoded in UTF-8; otherwise the terminal's encoding will
|
# output will be encoded in UTF-8; otherwise the terminal's encoding will
|
||||||
# be used.
|
# be used.
|
||||||
enc = sys.stderr.encoding or 'utf8'
|
enc = getattr(sys.stderr, 'encoding', 'utf8')
|
||||||
|
|
||||||
# Synchronize the UTF-8 encoded line with the output line in the
|
# Synchronize the UTF-8 encoded line with the output line in the
|
||||||
# terminal's encoding. We need to compensate for the fact that the
|
# terminal's encoding. We need to compensate for the fact that the
|
||||||
|
@ -58,15 +59,15 @@ def ReportError(script, e):
|
||||||
|
|
||||||
# Write the whole line in the target encoding.
|
# Write the whole line in the target encoding.
|
||||||
err_line = script[linestart:lineend] + b'\n'
|
err_line = script[linestart:lineend] + b'\n'
|
||||||
sys.stderr.write(err_line.decode('utf8').encode(enc, 'backslashreplace'))
|
werr(err_line.decode('utf8'))
|
||||||
sys.stderr.write(u" " * cno + u"^\n")
|
werr(" " * cno + "^\n")
|
||||||
sys.stderr.write(e.args[0] + u"\n")
|
werr(e.args[0] + u"\n")
|
||||||
|
|
||||||
class UniConvScript(object):
|
class UniConvScript(object):
|
||||||
"""Converts the script to Unicode, setting the properties required by
|
"""Converts the script to Unicode, setting the properties required by
|
||||||
EParse to report a meaningful error position.
|
EParse to report a meaningful error position.
|
||||||
"""
|
"""
|
||||||
def __init__(self, script, options = (), filename = '<stdin>'):
|
def __init__(self, script, options = (), filename = b'<stdin>'):
|
||||||
self.linedir = []
|
self.linedir = []
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
# We don't interpret #line here. In case of an encode error,
|
# We don't interpret #line here. In case of an encode error,
|
||||||
|
@ -118,29 +119,29 @@ def PreparePreproc(script):
|
||||||
# least surprise seems to suggest to accept valid LSL strings as LSL
|
# least surprise seems to suggest to accept valid LSL strings as LSL
|
||||||
# instead of reproducing that C quirk. This also matches what FS is doing
|
# instead of reproducing that C quirk. This also matches what FS is doing
|
||||||
# currently, so it's good for compatibility.
|
# currently, so it's good for compatibility.
|
||||||
tok = re.compile(
|
tok = re.compile(str2u(
|
||||||
ur'(?:'
|
r'(?:'
|
||||||
ur'/(?:\?\?/\n|\\\n)*\*.*?\*(?:\?\?/\n|\\\n)*/'
|
r'/(?:\?\?/\n|\\\n)*\*.*?\*(?:\?\?/\n|\\\n)*/'
|
||||||
ur'|/(?:\?\?/\n|\\\n)*/(?:\?\?/\n|\\\n|[^\n])*\n'
|
r'|/(?:\?\?/\n|\\\n)*/(?:\?\?/\n|\\\n|[^\n])*\n'
|
||||||
ur'|[^"]'
|
r'|[^"]'
|
||||||
ur')+'
|
r')+'
|
||||||
ur'|"'
|
r'|"'
|
||||||
, re.S)
|
), re.S)
|
||||||
# RE used inside strings.
|
# RE used inside strings.
|
||||||
tok2 = re.compile(
|
tok2 = re.compile(str2u(
|
||||||
ur'(?:'
|
r'(?:'
|
||||||
ur"\?\?[='()!<>-]" # valid trigraph except ??/ (backslash)
|
r"\?\?[='()!<>-]" # valid trigraph except ??/ (backslash)
|
||||||
ur"|(?:\?\?/|\\)(?:\?\?[/='()!<>-]|[^\n])"
|
r"|(?:\?\?/|\\)(?:\?\?[/='()!<>-]|[^\n])"
|
||||||
# backslash trigraph or actual backslash,
|
# backslash trigraph or actual backslash,
|
||||||
# followed by any trigraph or non-newline
|
# followed by any trigraph or non-newline
|
||||||
ur'|(?!\?\?/\n|\\\n|"|\n).'
|
r'|(?!\?\?/\n|\\\n|"|\n).'
|
||||||
# any character that doesn't start a trigraph/
|
# any character that doesn't start a trigraph/
|
||||||
# backslash escape followed by a newline
|
# backslash escape followed by a newline
|
||||||
# or is a newline or double quote, as we're
|
# or is a newline or double quote, as we're
|
||||||
# interested in all those individually.
|
# interested in all those individually.
|
||||||
ur')+' # as many of those as possible
|
r')+' # as many of those as possible
|
||||||
ur'|\?\?/\n|\\\n|\n|"' # or any of those individually
|
r'|\?\?/\n|\\\n|\n|"' # or any of those individually
|
||||||
)
|
))
|
||||||
|
|
||||||
pos = 0
|
pos = 0
|
||||||
match = tok.search(script, pos)
|
match = tok.search(script, pos)
|
||||||
|
@ -155,24 +156,24 @@ def PreparePreproc(script):
|
||||||
matched2 = match2.group(0)
|
matched2 = match2.group(0)
|
||||||
pos += len(matched2)
|
pos += len(matched2)
|
||||||
|
|
||||||
if matched2 == u'\\\n' or matched2 == u'??/\n':
|
if matched2 == b'\\\n' or matched2 == b'??/\n':
|
||||||
nlines += 1
|
nlines += 1
|
||||||
col = 0
|
col = 0
|
||||||
match2 = tok2.search(script, pos)
|
match2 = tok2.search(script, pos)
|
||||||
continue
|
continue
|
||||||
if matched2 == u'"':
|
if matched2 == b'"':
|
||||||
if nlines:
|
if nlines:
|
||||||
if script[pos:pos+1] == u'\n':
|
if script[pos:pos+1] == b'\n':
|
||||||
col = -1 # don't add spaces if not necessary
|
col = -1 # don't add spaces if not necessary
|
||||||
# col misses the quote added here, so add 1
|
# col misses the quote added here, so add 1
|
||||||
s += u'"' + u'\n'*nlines + u' '*(col+1)
|
s += b'"' + b'\n'*nlines + b' '*(col+1)
|
||||||
else:
|
else:
|
||||||
s += u'"'
|
s += b'"'
|
||||||
break
|
break
|
||||||
if matched2 == u'\n':
|
if matched2 == b'\n':
|
||||||
nlines += 1
|
nlines += 1
|
||||||
col = 0
|
col = 0
|
||||||
s += u'\\n'
|
s += b'\\n'
|
||||||
else:
|
else:
|
||||||
col += len(matched2)
|
col += len(matched2)
|
||||||
s += matched2
|
s += matched2
|
||||||
|
@ -186,20 +187,20 @@ def PreparePreproc(script):
|
||||||
|
|
||||||
def ScriptHeader(script, avname):
|
def ScriptHeader(script, avname):
|
||||||
if avname:
|
if avname:
|
||||||
avname = ' - ' + avname
|
avname = b' - ' + avname
|
||||||
return ('//start_unprocessed_text\n/*'
|
return (b'//start_unprocessed_text\n/*'
|
||||||
# + re.sub(r'([*/])(?=[*|/])', r'\1|', script) # FS's algorithm
|
# + re.sub(r'([*/])(?=[*|/])', r'\1|', script) # FS's algorithm
|
||||||
# HACK: This won't break strings containing ** or /* or // like URLs,
|
# HACK: This won't break strings containing ** or /* or // like URLs,
|
||||||
# while still being compatible with FS.
|
# while still being compatible with FS.
|
||||||
+ re.sub(r'([*/]\||\*(?=/))', r'\1|', script)
|
+ re.sub(br'([*/]\||\*(?=/))', br'\1|', script)
|
||||||
+ '*/\n//end_unprocessed_text\n//nfo_preprocessor_version 0\n'
|
+ b'*/\n//end_unprocessed_text\n//nfo_preprocessor_version 0\n'
|
||||||
'//program_version LSL PyOptimizer v' + VERSION + avname
|
b'//program_version LSL PyOptimizer v' + str2b(VERSION)
|
||||||
+ '\n//mono\n\n')
|
+ str2b(avname) + b'\n//mono\n\n')
|
||||||
|
|
||||||
def Usage(progname, about = None):
|
def Usage(progname, about = None):
|
||||||
if about is None:
|
if about is None:
|
||||||
sys.stderr.write(
|
werr(
|
||||||
ur"""LSL optimizer v{version}
|
u"""LSL optimizer v{version}
|
||||||
|
|
||||||
(C) Copyright 2015-2019 Sei Lisa. All rights reserved.
|
(C) Copyright 2015-2019 Sei Lisa. All rights reserved.
|
||||||
|
|
||||||
|
@ -253,12 +254,12 @@ Preprocessor modes:
|
||||||
|
|
||||||
Normally, running the preprocessor needs the option 'processpre' active, to
|
Normally, running the preprocessor needs the option 'processpre' active, to
|
||||||
make the output readable by the optimizer. This option is active by default.
|
make the output readable by the optimizer. This option is active by default.
|
||||||
""".format(progname=progname, version=VERSION))
|
""".format(progname=str2u(progname), version=str2u(VERSION)))
|
||||||
return
|
return
|
||||||
|
|
||||||
if about == 'optimizer-options':
|
if about == 'optimizer-options':
|
||||||
sys.stderr.write(
|
werr(
|
||||||
ur"""
|
u"""
|
||||||
Optimizer control options.
|
Optimizer control options.
|
||||||
+ means active by default, - means inactive by default.
|
+ means active by default, - means inactive by default.
|
||||||
Case insensitive.
|
Case insensitive.
|
||||||
|
@ -363,7 +364,7 @@ For example:
|
||||||
{progname} -O -DCR,+BreakCont scriptname.lsl
|
{progname} -O -DCR,+BreakCont scriptname.lsl
|
||||||
would turn off dead code removal (which is active by default) and turn on the
|
would turn off dead code removal (which is active by default) and turn on the
|
||||||
break/continue syntax extension (which is inactive by default).
|
break/continue syntax extension (which is inactive by default).
|
||||||
""".format(progname=progname))
|
""".format(progname=str2u(progname)))
|
||||||
return
|
return
|
||||||
|
|
||||||
validoptions = frozenset(('extendedglobalexpr','breakcont','extendedtypecast',
|
validoptions = frozenset(('extendedglobalexpr','breakcont','extendedtypecast',
|
||||||
|
@ -405,7 +406,7 @@ def main(argv):
|
||||||
'libdata='))
|
'libdata='))
|
||||||
except getopt.GetoptError as e:
|
except getopt.GetoptError as e:
|
||||||
Usage(argv[0])
|
Usage(argv[0])
|
||||||
sys.stderr.write(u"\nError: %s\n" % str(e).decode('utf8', 'replace'))
|
werr(u"\nError: %s\n" % str(e).decode('utf8', 'replace'))
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
outfile = '-'
|
outfile = '-'
|
||||||
|
@ -462,7 +463,7 @@ def main(argv):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
elif opt == '--version':
|
elif opt == '--version':
|
||||||
sys.stdout.write('LSL PyOptimizer version %s\n' % VERSION)
|
wout(u'LSL PyOptimizer version %s\n' % str2u(VERSION))
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
elif opt in ('-o', '--output'):
|
elif opt in ('-o', '--output'):
|
||||||
|
@ -558,7 +559,7 @@ def main(argv):
|
||||||
fname = args[0] if args else None
|
fname = args[0] if args else None
|
||||||
if fname is None:
|
if fname is None:
|
||||||
Usage(argv[0])
|
Usage(argv[0])
|
||||||
sys.stderr.write(u"\nError: Input file not specified. Use -"
|
werr(u"\nError: Input file not specified. Use -"
|
||||||
u" if you want to use stdin.\n")
|
u" if you want to use stdin.\n")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@ -644,7 +645,7 @@ def main(argv):
|
||||||
except EParse as e:
|
except EParse as e:
|
||||||
# We don't call ReportError to prevent problems due to
|
# We don't call ReportError to prevent problems due to
|
||||||
# displaying invalid UTF-8
|
# displaying invalid UTF-8
|
||||||
sys.stderr.write(e.args[0] + u"\n")
|
werr(e.args[0] + u"\n")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
if preproc != 'none':
|
if preproc != 'none':
|
||||||
|
|
128
run-tests.py
128
run-tests.py
|
@ -56,9 +56,13 @@ try:
|
||||||
import difflib
|
import difflib
|
||||||
except ImportError:
|
except ImportError:
|
||||||
difflib = None
|
difflib = None
|
||||||
import StringIO as StringStream
|
if sys.hexversion < 0x3000000:
|
||||||
|
from StringIO import StringIO as StringStream
|
||||||
|
else:
|
||||||
|
from io import BytesIO as StringStream
|
||||||
from lslopt import lslcommon,lslfuncs,lslparse,lsloutput,lslloadlib
|
from lslopt import lslcommon,lslfuncs,lslparse,lsloutput,lslloadlib
|
||||||
from lslopt.lslcommon import nr
|
from lslopt.lslcommon import nr
|
||||||
|
from strutil import *
|
||||||
|
|
||||||
class EArgError(Exception):
|
class EArgError(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -89,25 +93,25 @@ def parseArgs(s):
|
||||||
State = Space
|
State = Space
|
||||||
p = 0
|
p = 0
|
||||||
Len = len(s)
|
Len = len(s)
|
||||||
arg = ''
|
arg = b''
|
||||||
|
|
||||||
while p < Len:
|
while p < Len:
|
||||||
c = s[p]
|
c = s[p:p+1]
|
||||||
p += 1
|
p += 1
|
||||||
if State in (Space, Normal):
|
if State in (Space, Normal):
|
||||||
if c == '\\':
|
if c == b'\\':
|
||||||
State = NBackslash if State == Normal else SBackslash
|
State = NBackslash if State == Normal else SBackslash
|
||||||
elif c == '"':
|
elif c == b'"':
|
||||||
State = DQuote
|
State = DQuote
|
||||||
elif c == "'":
|
elif c == b"'":
|
||||||
State = SQuote
|
State = SQuote
|
||||||
elif c in (' ', '\t'):
|
elif c in (b' ', b'\t'):
|
||||||
if State == Normal:
|
if State == Normal:
|
||||||
State = Space
|
State = Space
|
||||||
args.append(arg)
|
args.append(arg)
|
||||||
arg = ''
|
arg = b''
|
||||||
# else remain in the 'Space' state
|
# else remain in the 'Space' state
|
||||||
elif c == '\n':
|
elif c == b'\n':
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
State = Normal
|
State = Normal
|
||||||
|
@ -118,20 +122,20 @@ def parseArgs(s):
|
||||||
else Space if State == SBackslash
|
else Space if State == SBackslash
|
||||||
else Normal)
|
else Normal)
|
||||||
else:
|
else:
|
||||||
if State == DQBackslash and c not in ('"', '`', '$', '\\'):
|
if State == DQBackslash and c not in (b'"', b'`', b'$', b'\\'):
|
||||||
arg += '\\'
|
arg += b'\\'
|
||||||
arg += c
|
arg += c
|
||||||
State = DQuote if State == DQBackslash else Normal
|
State = DQuote if State == DQBackslash else Normal
|
||||||
elif State == DQuote:
|
elif State == DQuote:
|
||||||
if c == '\\':
|
if c == b'\\':
|
||||||
State = DQBackslash
|
State = DQBackslash
|
||||||
# ` and $ are not interpreted by this parser.
|
# ` and $ are not interpreted by this parser.
|
||||||
elif c == '"':
|
elif c == b'"':
|
||||||
State = Normal
|
State = Normal
|
||||||
else:
|
else:
|
||||||
arg += c
|
arg += c
|
||||||
elif State == SQuote:
|
elif State == SQuote:
|
||||||
if c == "'":
|
if c == b"'":
|
||||||
State = Normal
|
State = Normal
|
||||||
else:
|
else:
|
||||||
arg += c
|
arg += c
|
||||||
|
@ -185,7 +189,7 @@ def parseArgs(s):
|
||||||
def tryRead(fn):
|
def tryRead(fn):
|
||||||
result = None
|
result = None
|
||||||
try:
|
try:
|
||||||
f = open(fn, 'r')
|
f = open(fn, 'rb')
|
||||||
try:
|
try:
|
||||||
result = f.read()
|
result = f.read()
|
||||||
finally:
|
finally:
|
||||||
|
@ -197,12 +201,9 @@ def tryRead(fn):
|
||||||
|
|
||||||
# In StringIO, mixing unicode and str causes problems with non-ASCII chars.
|
# In StringIO, mixing unicode and str causes problems with non-ASCII chars.
|
||||||
# Avoid it by overriding the write method, to always encode unicode as UTF-8.
|
# Avoid it by overriding the write method, to always encode unicode as UTF-8.
|
||||||
class StrUTF8IO(StringStream.StringIO):
|
class StrUTF8IO(StringStream):
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
if type(s) == unicode:
|
StringStream.write(self, any2b(s))
|
||||||
StringStream.StringIO.write(self, s.encode('utf8'))
|
|
||||||
else:
|
|
||||||
StringStream.StringIO.write(self, s)
|
|
||||||
|
|
||||||
def invokeMain(argv, stdin = None):
|
def invokeMain(argv, stdin = None):
|
||||||
"""Invoke main.main, substituting stdin, stdout, stderr.
|
"""Invoke main.main, substituting stdin, stdout, stderr.
|
||||||
|
@ -218,7 +219,7 @@ def invokeMain(argv, stdin = None):
|
||||||
stdout_output = None
|
stdout_output = None
|
||||||
stderr_output = None
|
stderr_output = None
|
||||||
try:
|
try:
|
||||||
sys.stdin = StringStream.StringIO(stdin)
|
sys.stdin = StringStream(stdin)
|
||||||
sys.stdout = StrUTF8IO()
|
sys.stdout = StrUTF8IO()
|
||||||
sys.stderr = StrUTF8IO()
|
sys.stderr = StrUTF8IO()
|
||||||
sys.stdin.encoding = 'utf8'
|
sys.stdin.encoding = 'utf8'
|
||||||
|
@ -314,8 +315,10 @@ class UnitTestRegression(UnitTestCase):
|
||||||
stdout_output = False
|
stdout_output = False
|
||||||
stderr_output = False
|
stderr_output = False
|
||||||
try:
|
try:
|
||||||
sys.stdout = StringStream.StringIO()
|
sys.stdout = StringStream()
|
||||||
sys.stderr = StringStream.StringIO()
|
sys.stdout.encoding = 'utf8'
|
||||||
|
sys.stderr = StringStream()
|
||||||
|
sys.stderr.encoding = 'utf8'
|
||||||
errs = json.run_tests()
|
errs = json.run_tests()
|
||||||
stdout_output = sys.stdout.getvalue()
|
stdout_output = sys.stdout.getvalue()
|
||||||
stderr_output = sys.stderr.getvalue()
|
stderr_output = sys.stderr.getvalue()
|
||||||
|
@ -439,7 +442,8 @@ class UnitTestCoverage(UnitTestCase):
|
||||||
self.assertEqual(repr(lslfuncs.q2f(lslcommon.Quaternion((1,0,0,0)))),
|
self.assertEqual(repr(lslfuncs.q2f(lslcommon.Quaternion((1,0,0,0)))),
|
||||||
'Quaternion((1.0, 0.0, 0.0, 0.0))')
|
'Quaternion((1.0, 0.0, 0.0, 0.0))')
|
||||||
# Key repr coverage
|
# Key repr coverage
|
||||||
self.assertEqual(repr(lslcommon.Key(u'')), "Key(u'')")
|
self.assertEqual(repr(lslcommon.Key(u'')), "Key(u'')"
|
||||||
|
if str != unicode else "Key('')")
|
||||||
|
|
||||||
# string + key coverage
|
# string + key coverage
|
||||||
self.assertEqual(lslfuncs.add(u'a', lslcommon.Key(u'b')), u'ab')
|
self.assertEqual(lslfuncs.add(u'a', lslcommon.Key(u'b')), u'ab')
|
||||||
|
@ -684,8 +688,8 @@ def generateScriptTests():
|
||||||
def makeTestFunction(fbase, suite):
|
def makeTestFunction(fbase, suite):
|
||||||
def TestFunction(self):
|
def TestFunction(self):
|
||||||
stdin = tryRead(fbase + '.lsl') or ''
|
stdin = tryRead(fbase + '.lsl') or ''
|
||||||
expected_stdout = tryRead(fbase + '.out') or ''
|
expected_stdout = tryRead(fbase + '.out') or b''
|
||||||
expected_stderr = tryRead(fbase + '.err') or ''
|
expected_stderr = tryRead(fbase + '.err') or b''
|
||||||
runargs = (parseArgs(tryRead(fbase + '.run'))
|
runargs = (parseArgs(tryRead(fbase + '.run'))
|
||||||
or (['main.py', '-y', '-'] if suite != 'Expr'
|
or (['main.py', '-y', '-'] if suite != 'Expr'
|
||||||
else ['main.py',
|
else ['main.py',
|
||||||
|
@ -694,18 +698,18 @@ def generateScriptTests():
|
||||||
',addstrings,expr',
|
',addstrings,expr',
|
||||||
'-y',
|
'-y',
|
||||||
'-']))
|
'-']))
|
||||||
sys.stderr.write("\nRunning test %s: " % fbase)
|
werr(u"\nRunning test %s: " % any2u(fbase))
|
||||||
actual_stdout, actual_stderr = invokeMain(runargs, stdin)
|
actual_stdout, actual_stderr = invokeMain(runargs, stdin)
|
||||||
actual_stdout = (actual_stdout.replace('\r','\r\n')
|
actual_stdout = (actual_stdout.replace(b'\r',b'\r\n')
|
||||||
.replace('\r\n\n','\n')
|
.replace(b'\r\n\n',b'\n')
|
||||||
.replace('\r\n','\n'))
|
.replace(b'\r\n',b'\n'))
|
||||||
|
|
||||||
actual_stderr = (actual_stderr.replace('\r','\r\n')
|
actual_stderr = (actual_stderr.replace(b'\r',b'\r\n')
|
||||||
.replace('\r\n\n','\n')
|
.replace(b'\r\n\n',b'\n')
|
||||||
.replace('\r\n','\n'))
|
.replace(b'\r\n',b'\n'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if expected_stderr.startswith('REGEX\n'):
|
if expected_stderr.startswith(b'REGEX\n'):
|
||||||
self.assertIsNotNone(
|
self.assertIsNotNone(
|
||||||
re.search(expected_stderr[6:],
|
re.search(expected_stderr[6:],
|
||||||
actual_stderr.decode('utf8')
|
actual_stderr.decode('utf8')
|
||||||
|
@ -714,66 +718,67 @@ def generateScriptTests():
|
||||||
else:
|
else:
|
||||||
self.assertTrue(expected_stderr == actual_stderr)
|
self.assertTrue(expected_stderr == actual_stderr)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
sys.stderr.write('Failed'
|
werr(u'Failed'
|
||||||
'\n************ expected stderr:\n')
|
u'\n************ expected stderr:\n')
|
||||||
sys.stderr.write(expected_stderr)
|
werr(expected_stderr)
|
||||||
sys.stderr.write('\n************ actual stderr:\n')
|
werr(u'\n************ actual stderr:\n')
|
||||||
sys.stderr.write(actual_stderr)
|
werr(actual_stderr)
|
||||||
if difflib and expected_stderr and actual_stderr:
|
if difflib and expected_stderr and actual_stderr:
|
||||||
sys.stderr.write('\n************ diff:\n'
|
sys.stderr.write(u'\n************ diff:\n'
|
||||||
+ '\n'.join(difflib.unified_diff(
|
+ u'\n'.join(difflib.unified_diff(
|
||||||
expected_stderr.split('\n'),
|
b2u(expected_stderr).split(u'\n'),
|
||||||
actual_stderr.split('\n'),
|
b2u(actual_stderr).split(u'\n'),
|
||||||
'expected', 'actual', lineterm=''
|
'expected', 'actual', lineterm=''
|
||||||
)))
|
)))
|
||||||
sys.stderr.write('\n************ ')
|
werr(u'\n************ ')
|
||||||
raise
|
raise
|
||||||
try:
|
try:
|
||||||
if expected_stdout.startswith('REGEX\n'):
|
if expected_stdout.startswith(b'REGEX\n'):
|
||||||
self.assertIsNotNone(re.search(expected_stdout[6:],
|
self.assertIsNotNone(re.search(expected_stdout[6:],
|
||||||
actual_stdout))
|
actual_stdout))
|
||||||
else:
|
else:
|
||||||
self.assertTrue(expected_stdout == actual_stdout)
|
self.assertTrue(expected_stdout == actual_stdout)
|
||||||
except AssertionError:
|
except AssertionError:
|
||||||
sys.stderr.write('Failed'
|
werr(u'Failed'
|
||||||
'\n************ expected stdout:\n')
|
u'\n************ expected stdout:\n')
|
||||||
sys.stderr.write(expected_stdout)
|
werr(expected_stdout)
|
||||||
sys.stderr.write('\n************ actual stdout:\n')
|
werr(u'\n************ actual stdout:\n')
|
||||||
sys.stderr.write(actual_stdout)
|
werr(actual_stdout)
|
||||||
if difflib and expected_stdout and actual_stdout:
|
if difflib and expected_stdout and actual_stdout:
|
||||||
sys.stderr.write('\n************ diff:\n'
|
werr(u'\n************ diff:\n'
|
||||||
+ '\n'.join(difflib.unified_diff(
|
+ u'\n'.join(difflib.unified_diff(
|
||||||
expected_stdout.split('\n'),
|
b2u(expected_stdout).split('\n'),
|
||||||
actual_stdout.split('\n'),
|
b2u(actual_stdout).split('\n'),
|
||||||
'expected', 'actual', lineterm=''
|
'expected', 'actual', lineterm=''
|
||||||
)))
|
)))
|
||||||
sys.stderr.write('\n************ ')
|
sys.stderr.write(u'\n************ ')
|
||||||
raise
|
raise
|
||||||
return TestFunction
|
return TestFunction
|
||||||
TestFunction = makeTestFunction(fbase, testsuite)
|
TestFunction = makeTestFunction(fbase, testsuite)
|
||||||
# __doc__ is used by Eric
|
# __doc__ is used by Eric
|
||||||
line = ''
|
line = b''
|
||||||
try:
|
try:
|
||||||
f = open(fbase + '.lsl')
|
f = open(fbase + '.lsl', 'rb')
|
||||||
try:
|
try:
|
||||||
line = f.readline()
|
line = f.readline()
|
||||||
if line.endswith('\r\n'):
|
if line.endswith(b'\r\n'):
|
||||||
line = line[:-2]
|
line = line[:-2]
|
||||||
elif line[-1:] in ('\r', '\n'):
|
elif line[-1:] in (b'\r', b'\n'):
|
||||||
line = line[:-1]
|
line = line[:-1]
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
except IOError as e:
|
except IOError as e:
|
||||||
if e.errno != 2:
|
if e.errno != 2:
|
||||||
raise
|
raise
|
||||||
TestFunction.__doc__ = line[3:] if line.startswith('// ') else None
|
TestFunction.__doc__ = (b2u(line[3:]) if line.startswith(b'// ')
|
||||||
|
else None)
|
||||||
|
|
||||||
TestFunction.__name__ = ('test_' + testsuite + '__'
|
TestFunction.__name__ = ('test_' + testsuite + '__'
|
||||||
+ os.path.basename(fbase).replace('-','_'))
|
+ os.path.basename(fbase).replace('-','_'))
|
||||||
fail = tryRead(fbase + '.fail')
|
fail = tryRead(fbase + '.fail')
|
||||||
if fail is not None:
|
if fail is not None:
|
||||||
if fail:
|
if fail:
|
||||||
TestFunction.__doc__ = fail
|
TestFunction.__doc__ = b2u(fail)
|
||||||
TestFunction = unittest.expectedFailure(TestFunction)
|
TestFunction = unittest.expectedFailure(TestFunction)
|
||||||
else:
|
else:
|
||||||
skip = tryRead(fbase + '.skp')
|
skip = tryRead(fbase + '.skp')
|
||||||
|
@ -786,3 +791,4 @@ def generateScriptTests():
|
||||||
generateScriptTests()
|
generateScriptTests()
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(argv = sys.argv)
|
unittest.main(argv = sys.argv)
|
||||||
|
#UnitTestRegression().test_Regression__multiline_string()
|
||||||
|
|
85
strutil.py
Normal file
85
strutil.py
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
# (C) Copyright 2015-2019 Sei Lisa. All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is part of LSL PyOptimizer.
|
||||||
|
#
|
||||||
|
# LSL PyOptimizer is free software: you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License as
|
||||||
|
# published by the Free Software Foundation, either version 3 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# LSL PyOptimizer is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with LSL PyOptimizer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
# String <-> Bytes conversion and output utilities
|
||||||
|
|
||||||
|
import sys
|
||||||
|
if sys.hexversion >= 0x3000000:
|
||||||
|
unicode = str
|
||||||
|
unichr = chr
|
||||||
|
def str2u(s, enc=None):
|
||||||
|
"""Convert a native Python3 str to Unicode. This is a NOP."""
|
||||||
|
return s
|
||||||
|
|
||||||
|
def str2b(s, enc=None):
|
||||||
|
"""Convert a native Python3 str to bytes, with the given encoding."""
|
||||||
|
return s.encode(enc if type(enc) == str
|
||||||
|
else getattr(enc, 'encoding', 'utf8'),
|
||||||
|
'backslashreplace')
|
||||||
|
|
||||||
|
def u2str(s, enc=None):
|
||||||
|
"""Convert a Unicode string to native Python 3 str. This is a NOP."""
|
||||||
|
return s
|
||||||
|
|
||||||
|
def b2str(s, enc=None):
|
||||||
|
"""Convert a Bytes string to native Python 3 str."""
|
||||||
|
return s.decode(getattr(enc, 'encoding', enc) or 'utf8',
|
||||||
|
'backslashreplace')
|
||||||
|
|
||||||
|
else:
|
||||||
|
def str2u(s, enc=None):
|
||||||
|
"""Convert a native Python2 str to Unicode."""
|
||||||
|
return s.decode(getattr(enc, 'encoding', enc) or 'utf8',
|
||||||
|
'backslashreplace')
|
||||||
|
|
||||||
|
def str2b(s, enc=None):
|
||||||
|
"""Convert a native Python2 str to bytes. This is a NOP."""
|
||||||
|
return s
|
||||||
|
|
||||||
|
def u2str(s, enc=None):
|
||||||
|
"""Convert a Unicode string to native Python 2 str."""
|
||||||
|
return s.encode(enc if type(enc) == str
|
||||||
|
else getattr(enc, 'encoding', 'utf8'),
|
||||||
|
'backslashreplace')
|
||||||
|
|
||||||
|
def b2str(s, enc=None):
|
||||||
|
"""Convert a Bytes string to native Python 2 str. This is a NOP."""
|
||||||
|
return s
|
||||||
|
|
||||||
|
def b2u(s, enc=None):
|
||||||
|
"""Bytes to Unicode"""
|
||||||
|
return str2u(b2str(s, enc), enc)
|
||||||
|
|
||||||
|
def u2b(s, enc=None):
|
||||||
|
"""Unicode to Bytes"""
|
||||||
|
return u2str(str2b(s, enc), enc)
|
||||||
|
|
||||||
|
def any2b(s, enc=None):
|
||||||
|
"""Bytes or Unicode to Bytes"""
|
||||||
|
return s if type(s) == bytes else u2b(s, enc)
|
||||||
|
|
||||||
|
def any2u(s, enc=None):
|
||||||
|
"""Bytes or Unicode to Unicode"""
|
||||||
|
return s if type(s) == unicode else b2u(s, enc)
|
||||||
|
|
||||||
|
def werr(s):
|
||||||
|
"""Write any string to stderr"""
|
||||||
|
sys.stderr.write(any2u(s, sys.stderr))
|
||||||
|
|
||||||
|
def wout(s):
|
||||||
|
"""Write any string to stdout"""
|
||||||
|
sys.stdout.write(any2u(s, sys.stdout))
|
|
@ -1,4 +1,5 @@
|
||||||
import sys
|
import sys
|
||||||
|
from strutil import *
|
||||||
from lslopt.lslfuncs import *
|
from lslopt.lslfuncs import *
|
||||||
|
|
||||||
tests = 0
|
tests = 0
|
||||||
|
@ -7,7 +8,6 @@ errors = 0
|
||||||
# Begin JSON tests from http://wiki.secondlife.com/wiki/Json_usage_in_LSL/TestScript
|
# Begin JSON tests from http://wiki.secondlife.com/wiki/Json_usage_in_LSL/TestScript
|
||||||
def verify(msg, result, expected):
|
def verify(msg, result, expected):
|
||||||
global tests
|
global tests
|
||||||
werr = sys.stderr.write
|
|
||||||
tests += 1
|
tests += 1
|
||||||
if expected != result:
|
if expected != result:
|
||||||
global errors
|
global errors
|
||||||
|
@ -356,7 +356,6 @@ def test_jira_fixes():
|
||||||
maint3081();
|
maint3081();
|
||||||
|
|
||||||
def run_tests():
|
def run_tests():
|
||||||
werr = sys.stderr.write
|
|
||||||
# JSON tests from the wiki
|
# JSON tests from the wiki
|
||||||
test_types();
|
test_types();
|
||||||
test_get_value();
|
test_get_value();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue