mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +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:
|
||||
return self.symtab[0][symbol] # Quick guess
|
||||
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:
|
||||
return None # Disallow forwards in global var mode
|
||||
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
|
||||
optional_type: LAMBDA | TYPE
|
||||
"""
|
||||
assert self.scopeindex == 0
|
||||
while self.tok[0] in ('TYPE','IDENT'):
|
||||
typ = None
|
||||
if self.tok[0] == 'TYPE':
|
||||
|
@ -1973,9 +1974,26 @@ list lazy_list_set(list L, integer i, list v)
|
|||
self.expect('IDENT')
|
||||
|
||||
name = self.tok[1]
|
||||
if name in self.symtab[self.scopeindex]:
|
||||
raise EParseAlreadyDefined(self)
|
||||
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 ('=', ';'):
|
||||
# This is a variable definition
|
||||
|
@ -2134,7 +2152,7 @@ list lazy_list_set(list L, integer i, list v)
|
|||
states: state [state [...]]
|
||||
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
|
||||
# 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.
|
||||
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:
|
||||
# This is a list of all local and global symbol tables.
|
||||
# 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,
|
||||
# or 'e' for event.
|
||||
# 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'.
|
||||
# States only have 'Loc'.
|
||||
# Events have 'ParamTypes' and 'ParamNames'.
|
||||
# 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
|
||||
|
||||
# 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].
|
||||
del self.globals
|
||||
|
||||
# Insert library functions into symbol table
|
||||
self.symtab[0].update(self.functions)
|
||||
|
||||
treesymtab = self.tree, self.symtab
|
||||
del self.tree
|
||||
del self.symtab
|
||||
|
@ -2387,7 +2408,7 @@ list lazy_list_set(list L, integer i, list v)
|
|||
|
||||
self.events = {}
|
||||
self.constants = {}
|
||||
self.functions = {}
|
||||
self.funclibrary = {}
|
||||
|
||||
# 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
|
||||
# they are implemented in lslfuncs.*, they get a
|
||||
# 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)
|
||||
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:
|
||||
self.functions[name]['Fn'] = fn
|
||||
self.funclibrary[name]['Fn'] = fn
|
||||
elif match.group(4):
|
||||
# constant
|
||||
name = match.group(5)
|
||||
|
@ -2544,7 +2565,7 @@ list lazy_list_set(list L, integer i, list v)
|
|||
if line == '':
|
||||
break
|
||||
line = line.strip()
|
||||
if line and line[0] != '#' and line in self.functions:
|
||||
self.functions[line]['SEF'] = True
|
||||
if line and line[0] != '#' and line in self.funclibrary:
|
||||
self.funclibrary[line]['SEF'] = True
|
||||
finally:
|
||||
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
|
||||
Firestorm, but not recommended. Note that the operand to
|
||||
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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue