mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Implement function overriding syntax extension, fixing a bug on the way.
The funcoverride option allows defining multiple functions with the same name, each overriding the former. That's for compatibility with Firestorm, whose optimizer does that. While on it, fix a bug where defining a function whose name matches a library function was not reporting an error, and rename self.functions to self.funclibrary for clarity. It also brings consistency with other parts of the code and with the code documentation.
This commit is contained in:
parent
3839863a21
commit
921955f321
2 changed files with 39 additions and 15 deletions
|
@ -271,7 +271,7 @@ class parser(object):
|
||||||
try:
|
try:
|
||||||
return self.symtab[0][symbol] # Quick guess
|
return self.symtab[0][symbol] # Quick guess
|
||||||
except KeyError:
|
except KeyError:
|
||||||
if self.globalmode and symbol not in self.symtab[0] and symbol not in self.functions \
|
if self.globalmode and symbol not in self.symtab[0] \
|
||||||
or symbol not in self.globals:
|
or symbol not in self.globals:
|
||||||
return None # Disallow forwards in global var mode
|
return None # Disallow forwards in global var mode
|
||||||
return self.globals[symbol]
|
return self.globals[symbol]
|
||||||
|
@ -1965,6 +1965,7 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
func_def: optional_type IDENT '(' optional_param_list ')' code_block
|
func_def: optional_type IDENT '(' optional_param_list ')' code_block
|
||||||
optional_type: LAMBDA | TYPE
|
optional_type: LAMBDA | TYPE
|
||||||
"""
|
"""
|
||||||
|
assert self.scopeindex == 0
|
||||||
while self.tok[0] in ('TYPE','IDENT'):
|
while self.tok[0] in ('TYPE','IDENT'):
|
||||||
typ = None
|
typ = None
|
||||||
if self.tok[0] == 'TYPE':
|
if self.tok[0] == 'TYPE':
|
||||||
|
@ -1973,9 +1974,26 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
self.expect('IDENT')
|
self.expect('IDENT')
|
||||||
|
|
||||||
name = self.tok[1]
|
name = self.tok[1]
|
||||||
if name in self.symtab[self.scopeindex]:
|
|
||||||
raise EParseAlreadyDefined(self)
|
|
||||||
self.NextToken()
|
self.NextToken()
|
||||||
|
if name in self.symtab[0]:
|
||||||
|
# Duplicate identifier. That's an exception unless function
|
||||||
|
# override is in effect.
|
||||||
|
report = True
|
||||||
|
if self.funcoverride:
|
||||||
|
# Is it a function definition, and is the entry in the
|
||||||
|
# symbol table a function definition itself? And is it
|
||||||
|
# a user-defined function?
|
||||||
|
if self.tok[0] == '(' \
|
||||||
|
and self.symtab[0][name]['Kind'] == 'f' \
|
||||||
|
and 'Loc' in self.symtab[0][name]:
|
||||||
|
# Override it.
|
||||||
|
report = False
|
||||||
|
# Delete the previous definition.
|
||||||
|
self.tree[self.symtab[0][name]['Loc']] = \
|
||||||
|
{'nt':'LAMBDA', 't':None}
|
||||||
|
del self.symtab[0][name]
|
||||||
|
if report:
|
||||||
|
raise EParseAlreadyDefined(self)
|
||||||
|
|
||||||
if self.tok[0] in ('=', ';'):
|
if self.tok[0] in ('=', ';'):
|
||||||
# This is a variable definition
|
# This is a variable definition
|
||||||
|
@ -2134,7 +2152,7 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
states: state [state [...]]
|
states: state [state [...]]
|
||||||
state: (DEFAULT | STATE IDENT) balanced_braces_or_anything_else
|
state: (DEFAULT | STATE IDENT) balanced_braces_or_anything_else
|
||||||
"""
|
"""
|
||||||
ret = self.functions.copy() # The library functions go here too.
|
ret = self.funclibrary.copy() # The library functions go here too.
|
||||||
|
|
||||||
# If there's a syntax error, that's not our business. We just return
|
# If there's a syntax error, that's not our business. We just return
|
||||||
# what we have so far. Doing a proper parse will determine the exact
|
# what we have so far. Doing a proper parse will determine the exact
|
||||||
|
@ -2301,6 +2319,10 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
# Shrink names. Activates duplabels automatically.
|
# Shrink names. Activates duplabels automatically.
|
||||||
self.shrinknames = 'shrinknames' in options
|
self.shrinknames = 'shrinknames' in options
|
||||||
|
|
||||||
|
# Allow a duplicate function definition to override the former,
|
||||||
|
# rather than reporting a duplicate identifier error.
|
||||||
|
self.funcoverride = 'funcoverride' in options
|
||||||
|
|
||||||
# Symbol table:
|
# Symbol table:
|
||||||
# This is a list of all local and global symbol tables.
|
# This is a list of all local and global symbol tables.
|
||||||
# The first element (0) is the global scope. Each symbol table is a
|
# The first element (0) is the global scope. Each symbol table is a
|
||||||
|
@ -2309,13 +2331,15 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
# 'v' for variable, 'f' for function, 'l' for label, 's' for state,
|
# 'v' for variable, 'f' for function, 'l' for label, 's' for state,
|
||||||
# or 'e' for event.
|
# or 'e' for event.
|
||||||
# Variables have 'Scope', 'Type', 'Loc' (if global), 'Local' (if local).
|
# Variables have 'Scope', 'Type', 'Loc' (if global), 'Local' (if local).
|
||||||
# Functions have 'Type' and 'ParamTypes'; UDFs also have 'Loc' and'ParamNames'.
|
# Functions have 'Type' and 'ParamTypes'; UDFs also have 'Loc' and 'ParamNames'.
|
||||||
# Labels only have 'Scope'.
|
# Labels only have 'Scope'.
|
||||||
# States only have 'Loc'.
|
# States only have 'Loc'.
|
||||||
# Events have 'ParamTypes' and 'ParamNames'.
|
# Events have 'ParamTypes' and 'ParamNames'.
|
||||||
# Other modules may add information if they need.
|
# Other modules may add information if they need.
|
||||||
|
|
||||||
self.symtab = [{-1: None},]
|
# Incorporate the library into the initial symbol table.
|
||||||
|
self.symtab = [self.funclibrary.copy()]
|
||||||
|
self.symtab[0][-1] = None
|
||||||
self.scopeindex = 0
|
self.scopeindex = 0
|
||||||
|
|
||||||
# This is a small hack to prevent circular definitions in globals when
|
# This is a small hack to prevent circular definitions in globals when
|
||||||
|
@ -2363,9 +2387,6 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
# No longer needed. The data is already in self.symtab[0].
|
# No longer needed. The data is already in self.symtab[0].
|
||||||
del self.globals
|
del self.globals
|
||||||
|
|
||||||
# Insert library functions into symbol table
|
|
||||||
self.symtab[0].update(self.functions)
|
|
||||||
|
|
||||||
treesymtab = self.tree, self.symtab
|
treesymtab = self.tree, self.symtab
|
||||||
del self.tree
|
del self.tree
|
||||||
del self.symtab
|
del self.symtab
|
||||||
|
@ -2387,7 +2408,7 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
|
|
||||||
self.events = {}
|
self.events = {}
|
||||||
self.constants = {}
|
self.constants = {}
|
||||||
self.functions = {}
|
self.funclibrary = {}
|
||||||
|
|
||||||
# Library read code
|
# Library read code
|
||||||
|
|
||||||
|
@ -2449,12 +2470,12 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
# Library functions go to the functions table. If
|
# Library functions go to the functions table. If
|
||||||
# they are implemented in lslfuncs.*, they get a
|
# they are implemented in lslfuncs.*, they get a
|
||||||
# reference to the implementation; otherwise None.
|
# reference to the implementation; otherwise None.
|
||||||
if name in self.functions:
|
if name in self.funclibrary:
|
||||||
warning('Function already defined in bultins.txt, overwriting: ' + name)
|
warning('Function already defined in bultins.txt, overwriting: ' + name)
|
||||||
fn = getattr(lslfuncs, name, None)
|
fn = getattr(lslfuncs, name, None)
|
||||||
self.functions[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args}
|
self.funclibrary[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':args}
|
||||||
if fn is not None:
|
if fn is not None:
|
||||||
self.functions[name]['Fn'] = fn
|
self.funclibrary[name]['Fn'] = fn
|
||||||
elif match.group(4):
|
elif match.group(4):
|
||||||
# constant
|
# constant
|
||||||
name = match.group(5)
|
name = match.group(5)
|
||||||
|
@ -2544,7 +2565,7 @@ list lazy_list_set(list L, integer i, list v)
|
||||||
if line == '':
|
if line == '':
|
||||||
break
|
break
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if line and line[0] != '#' and line in self.functions:
|
if line and line[0] != '#' and line in self.funclibrary:
|
||||||
self.functions[line]['SEF'] = True
|
self.funclibrary[line]['SEF'] = True
|
||||||
finally:
|
finally:
|
||||||
f.close()
|
f.close()
|
||||||
|
|
3
main.py
3
main.py
|
@ -234,6 +234,9 @@ Optimizer options (+ means active by default, - means inactive by default):
|
||||||
Like lazylists, it's implemented for compatibility with
|
Like lazylists, it's implemented for compatibility with
|
||||||
Firestorm, but not recommended. Note that the operand to
|
Firestorm, but not recommended. Note that the operand to
|
||||||
switch() may be evaluated more than once.
|
switch() may be evaluated more than once.
|
||||||
|
funcoverride - Allow duplicate function definitions to override the
|
||||||
|
previous definition. For compatibility with Firestorm's
|
||||||
|
optimizer.
|
||||||
|
|
||||||
Optimization options
|
Optimization options
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue