2024-04-14 02:40:21 -07:00
|
|
|
# (C) Copyright 2015-2024 Sei Lisa. All rights reserved.
|
2015-03-05 15:18:41 -07:00
|
|
|
#
|
|
|
|
# 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/>.
|
|
|
|
|
|
|
|
# Parser module. Converts the source into an abstract syntax tree,
|
|
|
|
# generating also the symbol table.
|
|
|
|
|
2014-08-06 13:49:57 -07:00
|
|
|
# TODO: Add info to be able to propagate error position to the source.
|
2014-07-31 15:33:20 -07:00
|
|
|
|
2019-01-15 12:27:02 -07:00
|
|
|
from lslopt.lslcommon import Key, Vector, Quaternion, types, nr
|
|
|
|
from lslopt import lslcommon, lslfuncs
|
|
|
|
from strutil import *
|
2019-01-18 15:41:45 -07:00
|
|
|
strutil_used
|
2017-10-20 07:26:05 -07:00
|
|
|
import re
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Note this module was basically written from bottom to top, which may help
|
|
|
|
# reading it.
|
|
|
|
|
2020-11-08 18:28:57 -07:00
|
|
|
WHITESPACE_CHARS = frozenset({' ', '\r', '\n', '\x0B', '\x0C'})
|
|
|
|
SINGLE_SYMBOLS = frozenset({'.', ';', '{', '}', ',', '=', '(', ')', '-', '+',
|
|
|
|
'*', '/', '%', '@', ':', '<', '>', '[', ']', '&', '|', '^', '~', '!'})
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
def isdigit(c):
|
|
|
|
return '0' <= c <= '9'
|
|
|
|
|
|
|
|
def isalpha_(c):
|
|
|
|
return c == '_' or 'A' <= c <= 'Z' or 'a' <= c <= 'z'
|
|
|
|
|
|
|
|
def isalphanum_(c):
|
|
|
|
return isalpha_(c) or isdigit(c)
|
|
|
|
|
|
|
|
def ishex(c):
|
|
|
|
return '0' <= c <= '9' or 'A' <= c <= 'F' or 'a' <= c <= 'f'
|
|
|
|
|
2017-10-01 15:40:59 -07:00
|
|
|
def GetErrLineCol(parser):
|
|
|
|
errorpos = parser.errorpos
|
2017-10-10 20:04:13 -07:00
|
|
|
# Find zero-based line number
|
2017-10-01 15:40:59 -07:00
|
|
|
lno = parser.script.count('\n', 0, errorpos)
|
2017-10-10 20:04:13 -07:00
|
|
|
# Find start of current line
|
2017-10-01 15:40:59 -07:00
|
|
|
lstart = parser.script.rfind('\n', 0, errorpos) + 1
|
2017-10-10 20:04:13 -07:00
|
|
|
# Find zero-based column number in characters
|
2020-11-08 18:28:57 -07:00
|
|
|
cno = len(any2u(parser.script[lstart:errorpos], 'utf8'))
|
2017-10-10 20:04:13 -07:00
|
|
|
# Find in #line directives list
|
|
|
|
i = len(parser.linedir)
|
|
|
|
filename = '<stdin>' # value to return if there's no #line before lno
|
|
|
|
while i:
|
|
|
|
i -= 1
|
|
|
|
line = parser.linedir[i]
|
|
|
|
# We wouldn't know where to report the error in this case:
|
|
|
|
assert lno != line[0], \
|
|
|
|
"Error position is in processed #line directive?!"
|
|
|
|
|
|
|
|
if line[0] < lno: # found the last #line directive before lno
|
|
|
|
# replace the value of lno
|
|
|
|
lno = lno - line[0] + line[1] - 2
|
|
|
|
filename = line[2]
|
|
|
|
break
|
|
|
|
|
|
|
|
return (lno + 1, cno + 1, filename)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParse(Exception):
|
|
|
|
def __init__(self, parser, msg):
|
2016-01-01 19:39:47 -07:00
|
|
|
self.errorpos = parser.errorpos
|
2017-10-10 20:04:13 -07:00
|
|
|
self.lno, self.cno, self.fname = GetErrLineCol(parser)
|
2019-02-04 09:51:15 -07:00
|
|
|
filename = self.fname
|
|
|
|
if parser.emap and filename == '<stdin>':
|
2019-02-04 09:20:12 -07:00
|
|
|
filename = parser.filename
|
|
|
|
|
2020-11-08 18:28:57 -07:00
|
|
|
filename = (str2u(filename, 'utf8')
|
2019-01-15 12:27:02 -07:00
|
|
|
.replace(u'\\', u'\\\\')
|
|
|
|
.replace(u'"', u'\\"')
|
2017-10-12 03:43:54 -07:00
|
|
|
)
|
2017-10-10 20:04:13 -07:00
|
|
|
|
2019-02-04 09:20:12 -07:00
|
|
|
if parser.emap:
|
|
|
|
msg = u'::ERROR::"%s":%d:%d: %s' % (
|
|
|
|
any2u(filename.lstrip('u')), self.lno, self.cno, msg)
|
|
|
|
elif parser.processpre and filename != '<stdin>':
|
|
|
|
msg = u"(Line %d char %d): ERROR in \"%s\": %s" % (
|
|
|
|
self.lno, self.cno, filename, msg)
|
2017-10-10 20:04:13 -07:00
|
|
|
else:
|
|
|
|
msg = u"(Line %d char %d): ERROR: %s" % (self.lno, self.cno, msg)
|
2014-07-25 17:43:44 -07:00
|
|
|
super(EParse, self).__init__(msg)
|
|
|
|
|
|
|
|
class EParseUEOF(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
parser.errorpos = len(parser.script)
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseUEOF, self).__init__(parser, u"Unexpected EOF")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseSyntax(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseSyntax, self).__init__(parser, u"Syntax error")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseAlreadyDefined(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseAlreadyDefined, self).__init__(parser,
|
|
|
|
u"Name previously declared within scope")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseUndefined(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseUndefined, self).__init__(parser,
|
|
|
|
u"Name not defined within scope")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseTypeMismatch(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseTypeMismatch, self).__init__(parser, u"Type mismatch")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseReturnShouldBeEmpty(EParse):
|
|
|
|
def __init__(self, parser):
|
2017-10-09 02:29:15 -07:00
|
|
|
# When the types don't match, the error es EParseTypeMismatch instead.
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseReturnShouldBeEmpty, self).__init__(parser,
|
|
|
|
u"Return statement type doesn't match function return type")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseReturnIsEmpty(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:34:34 -07:00
|
|
|
super(EParseReturnIsEmpty, self).__init__(parser,
|
2014-07-30 16:25:15 -07:00
|
|
|
u"Function returns a value but return statement doesn't")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# This error message may sound funny, for good reasons.
|
|
|
|
class EParseInvalidField(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseInvalidField, self).__init__(parser,
|
|
|
|
u"Use of vector or quaternion method on incorrect type")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseFunctionMismatch(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseFunctionMismatch, self).__init__(parser,
|
2015-03-12 19:28:51 -07:00
|
|
|
u"Function call mismatches type or number of arguments")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
class EParseDeclarationScope(EParse):
|
|
|
|
def __init__(self, parser):
|
2014-07-30 16:25:15 -07:00
|
|
|
super(EParseDeclarationScope, self).__init__(parser,
|
|
|
|
u"Declaration requires a new scope -- use { and }")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-08-01 14:51:24 -07:00
|
|
|
class EParseCantChangeState(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseCantChangeState, self).__init__(parser,
|
|
|
|
u"Global functions can't change state")
|
|
|
|
|
2014-08-02 19:50:18 -07:00
|
|
|
class EParseCodePathWithoutRet(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseCodePathWithoutRet, self).__init__(parser,
|
|
|
|
u"Not all code paths return a value")
|
|
|
|
|
2014-07-31 15:33:20 -07:00
|
|
|
class EParseDuplicateLabel(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseDuplicateLabel, self).__init__(parser,
|
2015-03-04 17:37:32 -07:00
|
|
|
u"Duplicate local label name. That won't allow the Mono script"
|
|
|
|
u" to be saved, and will not work as expected in LSO.")
|
|
|
|
|
|
|
|
class EParseInvalidCase(EParse):
|
|
|
|
def __init__(self, parser, kind):
|
|
|
|
super(EParseInvalidCase, self).__init__(parser,
|
|
|
|
u"'%s' used outside a 'switch' statement" % kind)
|
|
|
|
|
|
|
|
class EParseCaseNotAllowed(EParse):
|
|
|
|
def __init__(self, parser, kind):
|
|
|
|
super(EParseCaseNotAllowed, self).__init__(parser,
|
|
|
|
u"'%s' label only allowed at the main 'switch' block" % kind)
|
|
|
|
|
|
|
|
class EParseManyDefaults(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseManyDefaults, self).__init__(parser,
|
|
|
|
u"multiple 'default' labels inside 'switch' statement")
|
|
|
|
|
2016-05-06 17:38:54 -07:00
|
|
|
class EParseMissingDefault(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseMissingDefault, self).__init__(parser,
|
|
|
|
u"Missing 'default:' label inside 'switch' statement; disable"
|
|
|
|
u" option 'errmissingdefault' to disable this error.")
|
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
class EParseInvalidBreak(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseInvalidBreak, self).__init__(parser,
|
|
|
|
u"'break' used outside a loop or switch"
|
|
|
|
if parser.enableswitch and parser.breakcont
|
2017-04-28 18:33:45 -07:00
|
|
|
else u"'break' used outside a switch" if parser.enableswitch
|
2015-03-04 17:37:32 -07:00
|
|
|
else u"'break' used outside a loop")
|
|
|
|
|
|
|
|
class EParseInvalidCont(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseInvalidCont, self).__init__(parser,
|
|
|
|
u"'continue' used outside a loop")
|
2014-07-31 15:33:20 -07:00
|
|
|
|
2017-04-28 18:33:45 -07:00
|
|
|
class EParseInvalidBrkContArg(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseInvalidBrkContArg, self).__init__(parser,
|
|
|
|
u"Invalid argument to 'break' or 'continue'" if parser.breakcont
|
|
|
|
else u"Invalid argument to 'break'")
|
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
class EParseInvalidBackslash(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseInvalidBackslash, self).__init__(parser,
|
2016-06-27 13:38:19 -07:00
|
|
|
u"Preprocessor directive can't end in backslash."
|
|
|
|
u" Activate the preprocessor or put everything in the same line.")
|
2016-06-27 07:50:09 -07:00
|
|
|
|
2018-04-01 11:05:35 -07:00
|
|
|
class EParseInvalidLabelOpt(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseInvalidLabelOpt, self).__init__(parser,
|
|
|
|
u"When optimization is active, a label can't be the immediate"
|
|
|
|
u" child of a 'for', 'if', 'while' or 'do'. Disable optimization"
|
|
|
|
u" or rewrite the code in some other way.")
|
|
|
|
|
2018-12-22 07:44:14 -07:00
|
|
|
class EParseNoConversion(EParse):
|
|
|
|
def __init__(self, parser):
|
|
|
|
super(EParseNoConversion, self).__init__(parser,
|
|
|
|
u"There's no conversion function in the library for this type")
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
class EInternal(Exception):
|
|
|
|
"""This exception is a construct to allow a different function to cause an
|
2015-03-26 15:26:36 -07:00
|
|
|
immediate return of EOF from parser.GetToken().
|
2014-07-25 17:43:44 -07:00
|
|
|
"""
|
|
|
|
pass
|
|
|
|
|
|
|
|
class parser(object):
|
2020-11-08 18:06:37 -07:00
|
|
|
assignment_toks = frozenset({'=', '+=', '-=', '*=', '/=', '%='})
|
|
|
|
extassignment_toks = frozenset({'|=', '&=', '^=', '<<=', '>>='})
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2020-11-08 18:06:37 -07:00
|
|
|
double_toks = frozenset({'++', '--', '+=', '-=', '*=', '/=', '%=', '==',
|
|
|
|
'!=', '>=', '<=', '&&', '||', '<<', '>>'})
|
|
|
|
extdouble_toks = frozenset({'|=', '&=', '^='})
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# These are hardcoded because additions or modifications imply
|
|
|
|
# important changes to the code anyway.
|
2020-11-08 18:06:37 -07:00
|
|
|
base_keywords = frozenset({'default', 'state', 'event', 'jump', 'return',
|
|
|
|
'if', 'else', 'for', 'do', 'while', 'print', 'TRUE', 'FALSE'})
|
|
|
|
brkcont_keywords = frozenset({'break', 'continue'})
|
|
|
|
switch_keywords = frozenset({'switch', 'case', 'break', 'default'})
|
2017-10-20 07:26:05 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
PythonType2LSLToken = {int:'INTEGER_VALUE', float:'FLOAT_VALUE',
|
|
|
|
unicode:'STRING_VALUE', Key:'KEY_VALUE', Vector:'VECTOR_VALUE',
|
|
|
|
Quaternion:'ROTATION_VALUE', list:'LIST_VALUE'}
|
|
|
|
|
2018-12-22 07:44:14 -07:00
|
|
|
TypeToExtractionFunction = {}
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
# Utility function
|
|
|
|
def GenerateLabel(self):
|
|
|
|
while True:
|
2016-06-27 11:32:59 -07:00
|
|
|
self.labelcnt += 1
|
|
|
|
unique = 'J_autoGen%05d' % self.labelcnt
|
|
|
|
if unique not in self.locallabels:
|
2015-03-04 17:37:32 -07:00
|
|
|
break
|
|
|
|
self.locallabels.add(unique)
|
|
|
|
return unique
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
def PushScope(self):
|
|
|
|
"""Create a new symbol table / scope level"""
|
2018-12-29 09:55:07 -07:00
|
|
|
self.scopeindex = len(self.symtab)
|
|
|
|
self.symtab.append({}) # Add new symbol table
|
|
|
|
self.scopestack.append(self.scopeindex)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def PopScope(self):
|
|
|
|
"""Return to the previous scope level"""
|
2018-12-29 09:55:07 -07:00
|
|
|
assert self.scopeindex == self.scopestack[-1]
|
|
|
|
self.scopestack.pop()
|
|
|
|
self.scopeindex = self.scopestack[-1]
|
|
|
|
assert len(self.scopestack) > 0
|
2014-07-29 19:54:16 -07:00
|
|
|
|
|
|
|
def AddSymbol(self, kind, scope, name, **values):
|
|
|
|
values['Kind'] = kind
|
2018-12-29 09:55:07 -07:00
|
|
|
if kind in ('v', 'l'):
|
2014-07-29 19:54:16 -07:00
|
|
|
values['Scope'] = scope
|
|
|
|
self.symtab[scope][name] = values
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def FindSymbolPartial(self, symbol, MustBeLabel = False):
|
2014-07-29 19:54:16 -07:00
|
|
|
"""Find a symbol in all visible scopes in order, but not in the full
|
|
|
|
globals table (only globals seen so far are visible).
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
Labels have special scope rules: other identifiers with the same
|
|
|
|
name that are not labels are invisible to JUMP statements. Example:
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
default{timer(){ @x; {integer x; jump x;} }}
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
finds the label at the outer block. However:
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
default{timer(){ @x; integer x; }}
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
gives an identifier already defined error. On the other hand, labels
|
|
|
|
hide other types (but that's dealt with in the caller to this function):
|
|
|
|
|
|
|
|
default{timer(){ integer a; { @a; a++; } }}
|
|
|
|
|
|
|
|
gives an Name Not Defined error.
|
|
|
|
"""
|
2018-12-29 09:55:07 -07:00
|
|
|
scopelevel = len(self.scopestack)
|
|
|
|
while scopelevel:
|
|
|
|
scopelevel -= 1
|
|
|
|
symtab = self.symtab[self.scopestack[scopelevel]]
|
|
|
|
if symbol in symtab and (not MustBeLabel
|
|
|
|
or symtab[symbol]['Kind'] == 'l'):
|
2014-07-25 17:43:44 -07:00
|
|
|
return symtab[symbol]
|
|
|
|
return None
|
|
|
|
|
|
|
|
# No labels or states allowed here (but functions are)
|
2018-12-29 09:55:07 -07:00
|
|
|
def FindSymbolFull(self, symbol, globalonly=False):
|
2014-07-29 19:54:16 -07:00
|
|
|
"""Returns the symbol table entry for the given symbol."""
|
2018-12-29 09:55:07 -07:00
|
|
|
scopelevel = 1 if globalonly else len(self.scopestack)
|
|
|
|
while scopelevel: # Loop over all scopes in the stack
|
|
|
|
scopelevel -= 1
|
|
|
|
symtab = self.symtab[self.scopestack[scopelevel]]
|
2014-07-25 17:43:44 -07:00
|
|
|
if symbol in symtab:
|
|
|
|
# This can't happen, as functions can't be local
|
|
|
|
#if len(symtab[symbol]) > 3:
|
|
|
|
# return (symtab[symbol][1], symtab[symbol][3])
|
2014-07-29 19:54:16 -07:00
|
|
|
return symtab[symbol]
|
|
|
|
try:
|
2018-03-27 04:29:04 -07:00
|
|
|
return self.symtab[0][symbol] # Quick guess
|
2014-07-29 19:54:16 -07:00
|
|
|
except KeyError:
|
2018-12-29 09:55:07 -07:00
|
|
|
if (self.disallowglobalvars and symbol not in self.symtab[0]
|
|
|
|
or symbol not in self.globals
|
|
|
|
):
|
2018-03-27 04:29:04 -07:00
|
|
|
return None # Disallow forwards in global var mode
|
2014-07-29 19:54:16 -07:00
|
|
|
return self.globals[symbol]
|
2014-07-26 16:49:44 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
def ValidateField(self, typ, field):
|
|
|
|
if typ == 'vector' and field in ('x', 'y', 'z') \
|
|
|
|
or typ == 'rotation' and field in ('x', 'y', 'z', 's'):
|
|
|
|
return
|
|
|
|
raise EParseInvalidField(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
def autocastcheck(self, value, tgttype):
|
2018-03-30 17:02:36 -07:00
|
|
|
"""Check if automatic dynamic cast is possible. If explicit casts are
|
|
|
|
requested, insert one.
|
2014-07-25 17:43:44 -07:00
|
|
|
"""
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
tval = value.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if tval == tgttype:
|
2014-07-25 17:43:44 -07:00
|
|
|
return value
|
2014-07-29 19:54:16 -07:00
|
|
|
if tval in ('string', 'key') and tgttype in ('string', 'key') \
|
|
|
|
or tval == 'integer' and tgttype == 'float':
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.explicitcast:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CAST', t=tgttype, ch=[value])
|
2014-07-25 17:43:44 -07:00
|
|
|
return value
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
|
|
|
def ueof(self):
|
2014-08-05 19:11:57 -07:00
|
|
|
"""Check for unexpected EOF"""
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.pos >= self.length:
|
|
|
|
raise EParseUEOF(self)
|
|
|
|
|
|
|
|
def ceof(self):
|
2014-08-05 19:11:57 -07:00
|
|
|
"""Check for normal EOF"""
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.pos >= self.length:
|
2018-03-27 04:29:04 -07:00
|
|
|
raise EInternal() # force GetToken to return EOF
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2016-06-27 18:20:21 -07:00
|
|
|
def SetOpt(self, option, value):
|
|
|
|
# See parse() for meaning of options.
|
|
|
|
if option == 'extendedglobalexpr':
|
|
|
|
self.extendedglobalexpr = value
|
|
|
|
|
|
|
|
if option == 'extendedtypecast':
|
|
|
|
self.extendedtypecast = value
|
|
|
|
|
|
|
|
if option == 'extendedassignment':
|
|
|
|
self.extendedassignment = value
|
|
|
|
|
|
|
|
if option == 'explicitcast':
|
|
|
|
self.explicitcast = value
|
|
|
|
|
|
|
|
if option == 'allowkeyconcat':
|
|
|
|
self.allowkeyconcat = value
|
|
|
|
|
|
|
|
if option == 'allowmultistrings':
|
|
|
|
self.allowmultistrings = value
|
|
|
|
|
|
|
|
if option == 'processpre':
|
|
|
|
self.processpre = value
|
|
|
|
|
|
|
|
# TODO: Allow pure C-style string escapes. This is low-priority.
|
|
|
|
#if option == 'allowcescapes':
|
|
|
|
# self.allowcescapes = value
|
|
|
|
|
|
|
|
# Enable switch statements.
|
|
|
|
if option == 'enableswitch':
|
|
|
|
if not self.enableswitch and value:
|
|
|
|
self.keywords |= self.switch_keywords
|
|
|
|
elif self.enableswitch and not value:
|
2017-10-20 07:26:05 -07:00
|
|
|
self.keywords = self.base_keywords.copy()
|
2016-06-27 18:20:21 -07:00
|
|
|
if self.breakcont:
|
|
|
|
self.keywords |= self.brkcont_keywords
|
|
|
|
|
|
|
|
self.enableswitch = value
|
|
|
|
|
|
|
|
# Enable break/continue
|
|
|
|
if option == 'breakcont':
|
|
|
|
if not self.breakcont and value:
|
|
|
|
self.keywords |= self.brkcont_keywords
|
|
|
|
elif self.breakcont and not value:
|
2017-10-20 07:26:05 -07:00
|
|
|
self.keywords = self.base_keywords.copy()
|
2016-06-27 18:20:21 -07:00
|
|
|
if self.enableswitch:
|
|
|
|
self.keywords |= self.switch_keywords
|
|
|
|
|
|
|
|
self.breakcont = value
|
|
|
|
|
|
|
|
if option == 'errmissingdefault':
|
|
|
|
self.errmissingdefault = value
|
|
|
|
|
|
|
|
if option == 'lazylists':
|
|
|
|
self.lazylists = value
|
|
|
|
|
|
|
|
if option == 'duplabels':
|
|
|
|
self.duplabels = value
|
|
|
|
|
|
|
|
if option == 'shrinknames':
|
|
|
|
self.shrinknames = value
|
|
|
|
|
|
|
|
if option == 'funcoverride':
|
|
|
|
self.funcoverride = value
|
|
|
|
|
2019-01-05 18:20:34 -07:00
|
|
|
if option == 'inline':
|
|
|
|
self.enable_inline = value
|
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
def ProcessDirective(self, directive):
|
|
|
|
"""Process a given preprocessor directive during parsing."""
|
|
|
|
|
2016-06-27 09:50:31 -07:00
|
|
|
# Ignore directives on the first pass
|
|
|
|
if self.scanglobals:
|
|
|
|
return
|
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
if directive[len(directive)-1:] == '\\':
|
|
|
|
raise EParseInvalidBackslash(self)
|
|
|
|
|
2020-10-29 12:17:50 -07:00
|
|
|
# compile the RE lazily, to avoid penalizing programs not using it
|
2016-06-27 07:50:09 -07:00
|
|
|
if self.parse_directive_re is None:
|
|
|
|
self.parse_directive_re = re.compile(
|
|
|
|
r'^#\s*(?:'
|
2017-10-10 20:04:13 -07:00
|
|
|
r'(?:line)?\s+(\d+)(?:\s+("(?:\\.|[^"])*")(?:\s+\d+)*)?'
|
2016-06-27 07:50:09 -07:00
|
|
|
r'|'
|
2020-10-29 12:17:50 -07:00
|
|
|
r'(?:pragma)\s+(?:OPT)\s+([-+,a-z0-9_]+)'
|
|
|
|
r'|'
|
|
|
|
r'([a-z0-9_]+)(?:\s+(.*)?)' # others
|
2016-06-27 07:50:09 -07:00
|
|
|
r')\s*$'
|
2017-10-10 20:04:13 -07:00
|
|
|
, re.I
|
2016-06-27 07:50:09 -07:00
|
|
|
)
|
|
|
|
match = self.parse_directive_re.search(directive)
|
|
|
|
if match is not None:
|
|
|
|
# Something parsed
|
|
|
|
if match.group(1) is not None:
|
|
|
|
#line directive
|
|
|
|
if match.group(2) is not None:
|
|
|
|
# filename included
|
|
|
|
if match.group(2).find('\\') != -1:
|
|
|
|
# interpret escapes
|
|
|
|
from ast import literal_eval
|
|
|
|
filename = literal_eval(match.group(2))
|
|
|
|
else:
|
|
|
|
filename = match.group(2)[1:-1]
|
2017-10-10 20:04:13 -07:00
|
|
|
self.lastFILE = filename
|
|
|
|
else:
|
|
|
|
filename = self.lastFILE
|
|
|
|
|
|
|
|
# Referenced line number (in the #line directive)
|
|
|
|
reflinenum = int(match.group(1))
|
|
|
|
# Actual line number (where the #line directive itself is)
|
|
|
|
# FIXME: this is O(n^2); track line number instead of this hack
|
|
|
|
actlinenum = self.script.count('\n', 0, self.pos)
|
|
|
|
self.linedir.append((actlinenum, reflinenum, filename))
|
|
|
|
del actlinenum, reflinenum, filename
|
2020-10-29 12:17:50 -07:00
|
|
|
elif match.group(3): # '#pragma OPT <options>' found
|
|
|
|
opts = match.group(3).lower().split(',')
|
|
|
|
for opt in opts:
|
|
|
|
if opt != '':
|
|
|
|
if opt[0] == '-':
|
|
|
|
self.SetOpt(opt[1:], False)
|
|
|
|
elif opt[0] == '+':
|
|
|
|
self.SetOpt(opt[1:], True)
|
|
|
|
else:
|
|
|
|
self.SetOpt(opt, True)
|
|
|
|
elif match.group(4) == 'warning':
|
|
|
|
if match.group(5):
|
|
|
|
warning("Warning: #warning " + match.group(5))
|
|
|
|
else:
|
|
|
|
warning("Warning: #warning")
|
|
|
|
# else ignore
|
2016-06-27 07:50:09 -07:00
|
|
|
|
2019-01-17 12:26:46 -07:00
|
|
|
def GetToken(self):
|
2014-08-05 19:11:57 -07:00
|
|
|
"""Lexer"""
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
try:
|
|
|
|
while self.pos < self.length:
|
2020-10-29 12:17:50 -07:00
|
|
|
# In case of error, report it at the start of this token.
|
2016-01-01 19:39:47 -07:00
|
|
|
self.errorpos = self.pos
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
c = self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
|
2016-06-27 18:20:21 -07:00
|
|
|
# Process preprocessor directives
|
|
|
|
if self.processpre and self.linestart and c == '#':
|
2016-06-27 07:50:09 -07:00
|
|
|
# Preprocessor directive.
|
|
|
|
# Most are not supposed to reach us but some do:
|
|
|
|
# - gcpp generates lines in the output like:
|
|
|
|
# # 123 "file.lsl"
|
|
|
|
# - other preprocessors including Boost Wave and mcpp
|
|
|
|
# generate lines like:
|
|
|
|
# #line 123 "file.lsl"
|
|
|
|
# Firestorm comments these out and instead outputs
|
|
|
|
# //#line 123 "file.lsl"
|
|
|
|
# - #pragma directives
|
|
|
|
# - #define directives from mcpp's #pragma MCPP put_defines
|
|
|
|
# or from gcpp's -dN option, that we use to detect some
|
|
|
|
# definitions.
|
2014-07-27 17:13:08 -07:00
|
|
|
self.ceof()
|
|
|
|
while self.script[self.pos] != '\n':
|
|
|
|
self.pos += 1
|
2018-03-27 04:29:04 -07:00
|
|
|
self.ceof() # A preprocessor command at EOF is not unexpected EOF.
|
2014-07-27 17:13:08 -07:00
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
self.ProcessDirective(self.script[self.errorpos:self.pos])
|
|
|
|
|
2014-07-27 17:13:08 -07:00
|
|
|
self.pos += 1
|
|
|
|
self.ceof()
|
|
|
|
continue
|
|
|
|
|
2016-06-27 18:20:21 -07:00
|
|
|
# Process comments
|
2014-07-25 17:43:44 -07:00
|
|
|
if c == '/':
|
|
|
|
if self.script[self.pos:self.pos+1] == '/':
|
|
|
|
self.pos += 1
|
2021-10-17 11:07:33 -07:00
|
|
|
if self.enable_inline and self.script.startswith(
|
|
|
|
'pragma inline', self.pos
|
|
|
|
) and not isalphanum_(self.script[self.pos + 13:
|
|
|
|
self.pos + 14]
|
|
|
|
):
|
|
|
|
self.pos += 12 # len('pragma inline') - 1
|
|
|
|
while self.script[self.pos] != '\n':
|
|
|
|
self.pos += 1
|
|
|
|
# Check for normal EOF. Note: 'inline' is not
|
|
|
|
# inserted if the file ends before a newline.
|
|
|
|
self.ceof()
|
|
|
|
return ('IDENT', 'inline')
|
2014-07-25 17:43:44 -07:00
|
|
|
self.ceof()
|
|
|
|
while self.script[self.pos] != '\n':
|
|
|
|
self.pos += 1
|
2018-03-27 04:29:04 -07:00
|
|
|
self.ceof() # A single-line comment at EOF is not unexpected EOF.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
self.linestart = True
|
2014-07-25 17:43:44 -07:00
|
|
|
self.pos += 1
|
|
|
|
self.ceof()
|
|
|
|
continue
|
|
|
|
|
|
|
|
elif self.script[self.pos:self.pos+1] == '*':
|
|
|
|
self.pos += 2
|
2021-10-17 11:07:33 -07:00
|
|
|
if self.enable_inline and self.script.startswith(
|
|
|
|
'pragma inline*/', self.pos-1):
|
|
|
|
self.pos += 14 # len('pragma inline*/') - 1
|
|
|
|
return ('IDENT', 'inline')
|
2014-07-25 17:43:44 -07:00
|
|
|
while self.script[self.pos-1:self.pos+1] != '*/':
|
|
|
|
self.pos += 1
|
2018-03-27 04:29:04 -07:00
|
|
|
self.ueof() # An unterminated multiline comment *is* unexpected EOF.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
self.pos += 1
|
|
|
|
self.ceof()
|
|
|
|
continue
|
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
# self.linestart is related to the preprocessor, therefore we
|
|
|
|
# check the characters that are relevant for standard C.
|
2020-11-08 18:28:57 -07:00
|
|
|
if c not in WHITESPACE_CHARS:
|
2016-06-27 07:50:09 -07:00
|
|
|
self.linestart = False
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# Process strings
|
|
|
|
if c == '"' or c == 'L' and self.script[self.pos:self.pos+1] == '"':
|
|
|
|
strliteral = ''
|
|
|
|
if c == 'L':
|
|
|
|
self.pos += 1
|
|
|
|
strliteral = '"'
|
|
|
|
|
2018-03-27 04:29:04 -07:00
|
|
|
savepos = self.pos # we may need to backtrack
|
|
|
|
is_string = True # by default
|
2015-03-08 08:53:58 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
while self.script[self.pos:self.pos+1] != '"':
|
2015-03-08 08:53:58 -07:00
|
|
|
# per the grammar, on EOF, it's not considered a string
|
|
|
|
if self.pos >= self.length:
|
|
|
|
self.pos = savepos
|
|
|
|
is_string = False
|
|
|
|
break
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.script[self.pos] == '\\':
|
|
|
|
self.pos += 1
|
|
|
|
self.ueof()
|
|
|
|
if self.script[self.pos] == 'n':
|
|
|
|
strliteral += '\n'
|
|
|
|
elif self.script[self.pos] == 't':
|
|
|
|
strliteral += ' '
|
2015-03-08 08:53:58 -07:00
|
|
|
elif self.script[self.pos] == '\n':
|
|
|
|
# '\' followed by a newline; it's not a string.
|
|
|
|
self.pos = savepos
|
|
|
|
is_string = False
|
2016-06-27 07:50:09 -07:00
|
|
|
self.linestart = True
|
2015-03-08 08:53:58 -07:00
|
|
|
break
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
strliteral += self.script[self.pos]
|
|
|
|
else:
|
|
|
|
strliteral += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
|
2015-03-08 08:53:58 -07:00
|
|
|
if is_string:
|
|
|
|
self.pos += 1
|
2020-11-08 18:28:57 -07:00
|
|
|
return ('STRING_VALUE', lslfuncs.zstr(str2u(strliteral, 'utf8')))
|
2015-03-08 08:53:58 -07:00
|
|
|
# fall through (to consider the L or to ignore the ")
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if isalpha_(c):
|
|
|
|
# Identifier or reserved
|
|
|
|
|
|
|
|
ident = c
|
|
|
|
while isalphanum_(self.script[self.pos:self.pos+1]):
|
|
|
|
ident += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
|
|
|
|
# Got an identifier - check if it's a reserved word
|
|
|
|
if ident in self.keywords:
|
|
|
|
return (ident.upper(),)
|
2017-10-20 07:26:05 -07:00
|
|
|
if ident in types:
|
2014-07-25 17:43:44 -07:00
|
|
|
if ident == 'quaternion':
|
2018-03-27 04:29:04 -07:00
|
|
|
ident = 'rotation' # Normalize types
|
2014-07-25 17:43:44 -07:00
|
|
|
return ('TYPE',ident)
|
|
|
|
if ident in self.events:
|
|
|
|
return ('EVENT_NAME',ident)
|
|
|
|
if ident in self.constants:
|
|
|
|
value = self.constants[ident]
|
|
|
|
return (self.PythonType2LSLToken[type(value)], value)
|
|
|
|
|
|
|
|
return ('IDENT', ident)
|
|
|
|
|
|
|
|
# Process numbers: float, hex integer, dec integer
|
|
|
|
if c == '.' or isdigit(c):
|
|
|
|
|
|
|
|
number = ''
|
|
|
|
if c != '.':
|
|
|
|
# We have a digit, which means we have for sure either
|
|
|
|
# an integer or a float.
|
|
|
|
|
|
|
|
# Eat as many decimal digits as possible
|
|
|
|
number = c
|
|
|
|
while isdigit(self.script[self.pos:self.pos+1]):
|
|
|
|
number += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
|
|
|
|
if number == '0' and self.script[self.pos:self.pos+1] in ('x','X') \
|
|
|
|
and ishex(self.script[self.pos+1:self.pos+2]):
|
|
|
|
# We don't need the 0x prefix.
|
|
|
|
|
|
|
|
self.pos += 1
|
|
|
|
# Eat leading zeros to know the real length.
|
|
|
|
while self.script[self.pos:self.pos+1] == '0':
|
|
|
|
self.pos += 1
|
|
|
|
number = ''
|
|
|
|
|
|
|
|
while ishex(self.script[self.pos:self.pos+1]):
|
2018-03-27 04:29:04 -07:00
|
|
|
if len(number) < 9: # don't let it grow more than necessary
|
2014-07-25 17:43:44 -07:00
|
|
|
number += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
if number == '':
|
|
|
|
# We know there was at least a valid digit so it
|
|
|
|
# must've been all zeros.
|
|
|
|
number = '0'
|
|
|
|
if len(number) > 8:
|
|
|
|
number = -1
|
|
|
|
else:
|
|
|
|
number = lslfuncs.S32(int(number, 16))
|
|
|
|
return ('INTEGER_VALUE', number)
|
|
|
|
|
|
|
|
# Add the dot if present
|
|
|
|
if self.script[self.pos:self.pos+1] == '.':
|
|
|
|
number += '.'
|
|
|
|
self.pos += 1
|
|
|
|
else:
|
|
|
|
number = c
|
|
|
|
|
|
|
|
while isdigit(self.script[self.pos:self.pos+1]):
|
|
|
|
number += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
|
|
|
|
# At this point, number contains as many digits as there are before the dot,
|
|
|
|
# the dot if present, and as many digits as there are after the dot.
|
2018-03-27 04:29:04 -07:00
|
|
|
if number != '.': # A dot alone can't be a number so we rule it out here.
|
2014-07-25 17:43:44 -07:00
|
|
|
exp = ''
|
|
|
|
if self.script[self.pos:self.pos+1] in ('e','E'):
|
2018-03-27 04:29:04 -07:00
|
|
|
epos = self.pos # Temporary position tracker, made permanent only if the match succeeds
|
2014-07-25 17:43:44 -07:00
|
|
|
exp = self.script[epos]
|
|
|
|
epos += 1
|
|
|
|
if self.script[epos:epos+1] in ('+','-'):
|
|
|
|
exp += self.script[epos]
|
|
|
|
epos += 1
|
|
|
|
if isdigit(self.script[epos:epos+1]):
|
|
|
|
# Now we *do* have an exponent.
|
|
|
|
exp += self.script[epos]
|
|
|
|
epos += 1
|
|
|
|
while isdigit(self.script[epos:epos+1]):
|
|
|
|
exp += self.script[epos]
|
|
|
|
epos += 1
|
2018-03-27 04:29:04 -07:00
|
|
|
self.pos = epos # "Commit" the new position
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2018-03-27 04:29:04 -07:00
|
|
|
exp = '' # No cigar. Rollback and backtrack. Invalidate exp.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2018-03-27 04:29:04 -07:00
|
|
|
if exp != '' or '.' in number: # Float
|
2014-07-25 17:43:44 -07:00
|
|
|
if '.' in number:
|
|
|
|
# Eat the 'F' if present
|
|
|
|
if self.script[self.pos:self.pos+1] in ('f','F'):
|
|
|
|
# Python doesn't like the 'F' so don't return it
|
|
|
|
#exp += self.script[self.pos]
|
|
|
|
self.pos += 1
|
|
|
|
return ('FLOAT_VALUE', lslfuncs.F32(float(number + exp)))
|
|
|
|
|
|
|
|
if len(number) > 10 or len(number) == 10 and number > '4294967295':
|
|
|
|
number = -1
|
|
|
|
else:
|
|
|
|
number = lslfuncs.S32(int(number))
|
|
|
|
|
|
|
|
return ('INTEGER_VALUE', number)
|
|
|
|
|
2014-08-13 04:34:09 -07:00
|
|
|
if self.script[self.pos-1:self.pos+1] in self.double_toks \
|
|
|
|
or self.extendedassignment and self.script[self.pos-1:self.pos+1] in self.extdouble_toks:
|
2014-07-25 17:43:44 -07:00
|
|
|
self.pos += 1
|
|
|
|
if self.extendedassignment and self.script[self.pos-2:self.pos+1] in ('<<=', '>>='):
|
|
|
|
self.pos += 1
|
|
|
|
return (self.script[self.pos-3:self.pos],)
|
|
|
|
return (self.script[self.pos-2:self.pos],)
|
|
|
|
|
2020-11-08 18:28:57 -07:00
|
|
|
if c in SINGLE_SYMBOLS:
|
2014-07-25 17:43:44 -07:00
|
|
|
return (c,)
|
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
if c == '\n':
|
|
|
|
self.linestart = True
|
2015-03-09 05:20:37 -07:00
|
|
|
# We eat spacers AND any other character, so the following is not needed,
|
2014-07-25 17:43:44 -07:00
|
|
|
# although the lex file includes it (the lex file does not count() invalid characters
|
|
|
|
# for the purpose of error reporting).
|
|
|
|
#if c in ' \n\r\x0B':
|
|
|
|
# continue
|
|
|
|
|
|
|
|
except EInternal:
|
2018-03-27 04:29:04 -07:00
|
|
|
pass # clear the exception and fall through
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return ('EOF',)
|
|
|
|
|
2019-01-17 12:26:46 -07:00
|
|
|
def NextToken(self):
|
2014-07-25 17:43:44 -07:00
|
|
|
"""Calls GetToken and sets the internal token."""
|
2019-01-17 12:26:46 -07:00
|
|
|
self.tok = self.GetToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2015-03-08 17:07:55 -07:00
|
|
|
# Recursive-descendent parser. The result is an AST and a symbol table.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def expect(self, toktype):
|
|
|
|
"""Raise exception if the current token is not the given one."""
|
|
|
|
if self.tok[0] != toktype:
|
|
|
|
if self.tok[0] == 'EOF':
|
|
|
|
raise EParseUEOF(self)
|
|
|
|
raise EParseSyntax(self)
|
|
|
|
|
Only add a label and a jump for default and break when necessary.
Well, within reasonable limits.
For break, it's explained in the code. If the block is empty of actual code (code that generates output), then the break position is eliminated.
For default, if the default label is at the top of the block, the jump and the label are both eliminated. This check doesn't include verifying that there are other non-code-generating statements in between, so there's room for improvement (added corresponding TODO item).
This way, we're on par with FS, in case someone (ab)used the FS brokeness when the 'default' label was absent. All one has to do now is add the default label at the top, and the generated code will be the same as it was in FS when abusing that bug, with no extra burden.
Example: In FS, the code at the top acted as default and there was no jump for it:
default { timer() {
switch(1)
{
0;
case 1:
1;
}
}}
This generated roughly:
default { timer() {
{
if (1 == 1) jump CASE_1;
0;
@CASE_1;
1;
}
}}
In this system, it would trigger an error by default. To obtain the FS behaviour, the scripter can do instead:
default { timer() {
switch(1)
{
default:
0;
case 1:
1;
}
}}
Thanks to this optimization, the code will be the same as in FS. Without it, an extra default label and corresponding jump would be present.
2016-05-06 19:37:58 -07:00
|
|
|
def does_something(self, blk):
|
|
|
|
"""Tell if a list of nodes does something or is just empty statements
|
|
|
|
(a pure combination of ';' and '{}' and '@')
|
|
|
|
"""
|
|
|
|
for node in blk:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if '@' != node.nt != ';':
|
|
|
|
if node.nt == '{}':
|
|
|
|
if self.does_something(node.ch):
|
Only add a label and a jump for default and break when necessary.
Well, within reasonable limits.
For break, it's explained in the code. If the block is empty of actual code (code that generates output), then the break position is eliminated.
For default, if the default label is at the top of the block, the jump and the label are both eliminated. This check doesn't include verifying that there are other non-code-generating statements in between, so there's room for improvement (added corresponding TODO item).
This way, we're on par with FS, in case someone (ab)used the FS brokeness when the 'default' label was absent. All one has to do now is add the default label at the top, and the generated code will be the same as it was in FS when abusing that bug, with no extra burden.
Example: In FS, the code at the top acted as default and there was no jump for it:
default { timer() {
switch(1)
{
0;
case 1:
1;
}
}}
This generated roughly:
default { timer() {
{
if (1 == 1) jump CASE_1;
0;
@CASE_1;
1;
}
}}
In this system, it would trigger an error by default. To obtain the FS behaviour, the scripter can do instead:
default { timer() {
switch(1)
{
default:
0;
case 1:
1;
}
}}
Thanks to this optimization, the code will be the same as in FS. Without it, an extra default label and corresponding jump would be present.
2016-05-06 19:37:58 -07:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
def Parse_vector_rotation_tail(self):
|
|
|
|
"""(See Parse_unary_postfix_expression for context)
|
|
|
|
|
|
|
|
To our advantage, the precedence of the closing '>' in a vector or
|
|
|
|
rotation literal is that of an inequality. Our strategy will thus be
|
|
|
|
to perform the job of an inequality, calling the lower level 'shift'
|
|
|
|
rule and building the inequalities if they are not '>'. When we find a
|
|
|
|
'>', we check whether the next token makes sense as beginning an
|
|
|
|
inequality; if not, we finally close the vector or rotation.
|
|
|
|
|
|
|
|
But first, a quaternion _may_ have a full expression at the third
|
|
|
|
component, so we tentatively parse this position as an expression, and
|
2014-07-29 19:54:16 -07:00
|
|
|
backtrack if it causes an error.
|
2014-07-25 17:43:44 -07:00
|
|
|
"""
|
|
|
|
ret = []
|
|
|
|
pos = self.pos
|
|
|
|
errorpos = self.errorpos
|
|
|
|
tok = self.tok
|
2018-03-30 17:02:36 -07:00
|
|
|
component3 = False
|
2014-07-25 17:43:44 -07:00
|
|
|
try:
|
2018-03-30 17:02:36 -07:00
|
|
|
component3 = self.Parse_expression()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Checking here for '>' might parse a different grammar, because
|
|
|
|
# it might allow e.g. <1,2,3==3>; as a vector, which is not valid.
|
|
|
|
# Not too sure about that, but we're cautious and disable this
|
|
|
|
# just in case.
|
|
|
|
#if self.tok[0] == '>':
|
|
|
|
# return ret
|
|
|
|
|
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
2018-03-27 04:29:04 -07:00
|
|
|
except EParse: # The errors can be varied, e.g. <0,0,0>-v; raises EParseTypeMismatch
|
2014-07-25 17:43:44 -07:00
|
|
|
# Backtrack
|
|
|
|
self.pos = pos
|
|
|
|
self.errorpos = errorpos
|
|
|
|
self.tok = tok
|
|
|
|
|
2018-03-30 17:02:36 -07:00
|
|
|
# We do this here to prevent a type mismatch above
|
|
|
|
if component3 is not False:
|
|
|
|
ret.append(self.autocastcheck(component3, 'float'))
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# OK, here we are.
|
2018-03-27 04:29:04 -07:00
|
|
|
inequality = self.Parse_shift() # shift is the descendant of inequality
|
2014-07-25 17:43:44 -07:00
|
|
|
while self.tok[0] in ('<', '<=', '>=', '>'):
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
|
|
|
if op == '>':
|
|
|
|
# Check if the current token can be a part of a comparison.
|
|
|
|
# If not, it's a vector/quaternion terminator.
|
|
|
|
if self.tok[0] not in (
|
|
|
|
# List adapted from this section of the bison report:
|
|
|
|
#state 570
|
|
|
|
#
|
|
|
|
# 176 expression: expression '>' . expression
|
|
|
|
# 214 quaternion_initializer: '<' expression ',' expression ',' expression ',' expression '>' .
|
|
|
|
|
|
|
|
'IDENT', 'INTEGER_VALUE', 'FLOAT_VALUE', 'STRING_VALUE',
|
|
|
|
'KEY_VALUE', 'VECTOR_VALUE', 'ROTATION_VALUE', 'LIST_VALUE',
|
|
|
|
'TRUE', 'FALSE', '++', '--', 'PRINT', '!', '~', '(', '['
|
|
|
|
):
|
2018-03-30 17:02:36 -07:00
|
|
|
ret.append(self.autocastcheck(inequality, 'float'))
|
2014-07-25 17:43:44 -07:00
|
|
|
return ret
|
|
|
|
# This is basically a copy/paste of the Parse_inequality handler
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = inequality.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype not in ('integer', 'float'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_shift()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtype = rexpr.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if rtype not in ('integer', 'float'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype != rtype:
|
|
|
|
if rtype == 'float':
|
|
|
|
inequality = self.autocastcheck(inequality, rtype)
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.autocastcheck(rexpr, ltype)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
inequality = nr(nt=op, t='integer', ch=[inequality, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Reaching this means an operator or lower precedence happened,
|
|
|
|
# e.g. <1,1,1,2==2> (that's syntax error in ==)
|
|
|
|
raise EParseSyntax(self)
|
|
|
|
|
|
|
|
|
|
|
|
def Parse_unary_postfix_expression(self, AllowAssignment = True):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
2018-03-30 18:19:26 -07:00
|
|
|
unary_postfix_expression: TRUE | FALSE | LIST_VALUE
|
|
|
|
| INTEGER_VALUE | FLOAT_VALUE | '-' INTEGER_VALUE | '-' FLOAT_VALUE
|
2014-07-25 17:43:44 -07:00
|
|
|
| STRING_VALUE | KEY_VALUE | VECTOR_VALUE | ROTATION_VALUE
|
2018-03-30 18:19:26 -07:00
|
|
|
| vector_literal | rotation_literal | list_literal
|
2014-07-25 17:43:44 -07:00
|
|
|
| PRINT '(' expression ')' | IDENT '(' expression_list ')'
|
|
|
|
| lvalue '++' | lvalue '--' | assignment %if allowed
|
2015-03-12 22:38:35 -07:00
|
|
|
| IDENT '[' expression ']' '=' expression %if lazylists
|
|
|
|
| IDENT '[' expression ']' %if lazylists
|
2014-07-25 17:43:44 -07:00
|
|
|
| lvalue
|
|
|
|
vector_literal: '<' expression ',' expression ',' expression '>'
|
|
|
|
rotation_literal: '<' expression ',' expression ',' expression
|
|
|
|
',' expression '>'
|
|
|
|
list_literal: '[' optional_expression_list ']'
|
2015-03-12 22:38:35 -07:00
|
|
|
assignment: lvalue '=' expression | lvalue '+=' expression
|
2014-07-25 17:43:44 -07:00
|
|
|
| lvalue '-=' expression | lvalue '*=' expression
|
|
|
|
| lvalue '/=' expression | lvalue '%=' expression
|
2015-03-03 09:59:51 -07:00
|
|
|
| lvalue '|=' expression %if extendedassignment
|
|
|
|
| lvalue '&=' expression %if extendedassignment
|
|
|
|
| lvalue '<<=' expression %if extendedassignment
|
|
|
|
| lvalue '>>=' expression %if extendedassignment
|
2014-07-25 17:43:44 -07:00
|
|
|
lvalue: IDENT | IDENT '.' IDENT
|
|
|
|
"""
|
|
|
|
tok0 = self.tok[0]
|
|
|
|
val = self.tok[1] if len(self.tok) > 1 else None
|
2014-07-29 19:54:16 -07:00
|
|
|
CONST = 'CONST'
|
2016-01-02 17:20:05 -07:00
|
|
|
if tok0 == '-':
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
2016-01-02 17:20:05 -07:00
|
|
|
if self.tok[0] in ('INTEGER_VALUE', 'FLOAT_VALUE'):
|
|
|
|
val = self.tok[1]
|
|
|
|
self.NextToken()
|
2018-07-25 17:31:51 -07:00
|
|
|
return nr(nt=CONST, value=lslfuncs.neg(val),
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
t='integer' if type(val) == int else 'float')
|
2018-03-31 10:31:07 -07:00
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'INTEGER_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='integer', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'FLOAT_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='float', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'STRING_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
2014-07-25 18:44:48 -07:00
|
|
|
if self.allowmultistrings:
|
|
|
|
while self.tok[0] == 'STRING_VALUE':
|
|
|
|
val += self.tok[1]
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='string', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
# Key constants are not currently supported - use string
|
|
|
|
#if tok0 == 'KEY_VALUE':
|
2014-07-29 19:54:16 -07:00
|
|
|
# return [CONST, 'key', val]
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'VECTOR_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='vector', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'ROTATION_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='rotation', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'LIST_VALUE':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='list', value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 in ('TRUE', 'FALSE'):
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=CONST, t='integer', value=1 if tok0 == 'TRUE' else 0)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == '<':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
2019-01-01 12:03:02 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
self.allowVoid = False
|
2018-03-30 17:02:36 -07:00
|
|
|
val = [self.autocastcheck(self.Parse_expression(), 'float')]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
2018-03-30 17:02:36 -07:00
|
|
|
val.append(self.autocastcheck(self.Parse_expression(), 'float'))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
# It would be cute if it were this simple:
|
|
|
|
#val.append(self.Parse_expression())
|
|
|
|
#if self.tok[0] == '>':
|
|
|
|
# self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
# return ['VECTOR', 'vector'] + val
|
2014-07-25 17:43:44 -07:00
|
|
|
#self.expect(',')
|
|
|
|
#self.NextToken()
|
|
|
|
#val.append(self.Parse_inequality())
|
|
|
|
#self.expect('>')
|
|
|
|
#self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
#return ['ROTATION', 'rotation'] + val
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Alas, it isn't. The closing angle bracket of a vector '>'
|
|
|
|
# conflicts with the inequality operator '>' in unexpected ways.
|
2014-07-29 19:54:16 -07:00
|
|
|
# Example: <2,2,2> * 2 would trigger the problem with that code:
|
|
|
|
# the expression parser would try to parse the inequality 2 > *2,
|
2014-07-25 17:43:44 -07:00
|
|
|
# choking at the *. To make things worse, LSL admits things such as
|
|
|
|
# <2,2,2 > 2> (but not things like <2,2,2 == 2> because the == has
|
|
|
|
# lower precedence than the '>' and thus it forces termination of
|
|
|
|
# the vector constant). And to make things even worse, it also
|
|
|
|
# admits things such as <2,2,2 == 2, 2> because the comma is not in
|
|
|
|
# the precedence scale, so it's quite complex to handle.
|
|
|
|
|
|
|
|
# We defer it to a separate function.
|
|
|
|
val += self.Parse_vector_rotation_tail()
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if len(val) == 3:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='VECTOR', t='vector', ch=val)
|
|
|
|
return nr(nt='ROTATION', t='rotation', ch=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 == '[':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
2016-07-09 16:29:11 -07:00
|
|
|
val = self.Parse_optional_expression_list(False)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(']')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='LIST', t='list', ch=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'PRINT':
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
2019-01-01 12:03:02 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
self.allowVoid = True
|
2014-07-29 19:54:16 -07:00
|
|
|
expr = self.Parse_expression()
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if expr.t not in types:
|
|
|
|
raise (EParseTypeMismatch(self) if expr.t is None
|
|
|
|
else EParseUndefined(self))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2017-04-28 14:04:42 -07:00
|
|
|
# Syntactically, print returns the same type as the expression.
|
|
|
|
# However, compilation in Mono throws an exception, and even in
|
|
|
|
# LSO, it throws a bounds check error when the result is a string
|
|
|
|
# or key or list and the returned value is used.
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='PRINT', t=expr.t, ch=[expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 != 'IDENT':
|
|
|
|
if tok0 == 'EOF':
|
|
|
|
raise EParseUEOF(self)
|
|
|
|
raise EParseSyntax(self)
|
|
|
|
name = val
|
2017-10-09 02:29:15 -07:00
|
|
|
savepos = self.errorpos
|
2016-01-02 17:20:05 -07:00
|
|
|
self.NextToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Course of action decided here.
|
|
|
|
tok0 = self.tok[0]
|
|
|
|
if tok0 == '(':
|
|
|
|
# Function call
|
|
|
|
self.NextToken()
|
2015-03-13 08:20:54 -07:00
|
|
|
|
|
|
|
# Functions are looked up in the global scope only.
|
2018-12-29 09:55:07 -07:00
|
|
|
sym = self.FindSymbolFull(val, globalonly=True)
|
2015-03-13 08:20:54 -07:00
|
|
|
if sym is None:
|
2017-10-09 02:29:15 -07:00
|
|
|
self.errorpos = savepos
|
2015-03-13 08:20:54 -07:00
|
|
|
raise EParseUndefined(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
if sym['Kind'] != 'f':
|
2017-10-09 02:29:15 -07:00
|
|
|
self.errorpos = savepos
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseUndefined(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
args = self.Parse_optional_expression_list(sym['ParamTypes'])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='FNCALL', t=sym['Type'], name=name, ch=args)
|
2015-03-13 08:20:54 -07:00
|
|
|
|
|
|
|
sym = self.FindSymbolFull(val)
|
2024-05-25 11:48:30 -07:00
|
|
|
if sym is None or sym['Kind'] not in {'v', 'c'}:
|
2017-10-09 02:29:15 -07:00
|
|
|
self.errorpos = savepos
|
2015-03-13 08:20:54 -07:00
|
|
|
raise EParseUndefined(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = sym['Type']
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
lvalue = nr(nt='IDENT', t=typ, name=name, scope=sym['Scope'])
|
2015-03-12 22:38:35 -07:00
|
|
|
|
|
|
|
# Lazy lists
|
|
|
|
if self.lazylists and tok0 == '[':
|
|
|
|
self.NextToken()
|
|
|
|
if typ != 'list':
|
|
|
|
raise EParseTypeMismatch(self)
|
2016-07-09 16:29:11 -07:00
|
|
|
idxexpr = self.Parse_optional_expression_list(False)
|
2015-03-12 22:38:35 -07:00
|
|
|
self.expect(']')
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != '=' or not AllowAssignment:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='SUBIDX', t=None, ch=[lvalue] + idxexpr)
|
2015-03-12 22:38:35 -07:00
|
|
|
|
|
|
|
# Lazy list assignment
|
|
|
|
if len(idxexpr) != 1:
|
|
|
|
raise EParseFunctionMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if idxexpr[0].t != 'integer':
|
2015-03-12 22:38:35 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
idxexpr = idxexpr[0]
|
|
|
|
self.NextToken()
|
2019-01-01 12:03:02 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
self.allowVoid = True
|
2015-03-12 22:38:35 -07:00
|
|
|
expr = self.Parse_expression()
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtyp = expr.t
|
2015-03-12 22:38:35 -07:00
|
|
|
# Define aux function if it doesn't exist
|
|
|
|
# (leaves users room for writing their own replacement, e.g.
|
2019-01-01 12:03:02 -07:00
|
|
|
# one that uses something other than integer zero as filler)
|
2015-03-12 22:38:35 -07:00
|
|
|
if 'lazy_list_set' not in self.symtab[0]:
|
|
|
|
self.PushScope()
|
|
|
|
paramscope = self.scopeindex
|
2018-12-26 11:47:22 -07:00
|
|
|
self.PushScope()
|
|
|
|
blockscope = self.scopeindex
|
2015-03-12 22:38:35 -07:00
|
|
|
params = (['list', 'integer', 'list'],
|
|
|
|
['L', 'i', 'v'])
|
|
|
|
self.AddSymbol('f', 0, 'lazy_list_set', Loc=self.usedspots,
|
2019-01-01 14:29:12 -07:00
|
|
|
Type='list', ParamTypes=params[0], ParamNames=params[1],
|
|
|
|
Inline=False)
|
2024-05-25 11:48:30 -07:00
|
|
|
for typ, name in zip(*params):
|
|
|
|
self.AddSymbol('v', paramscope, name, Type=typ)
|
2018-03-27 04:29:04 -07:00
|
|
|
#self.PushScope() # no locals
|
2015-03-12 22:38:35 -07:00
|
|
|
|
|
|
|
# Add body (apologies for the wall of text)
|
|
|
|
# Generated from this source:
|
|
|
|
'''
|
|
|
|
list lazy_list_set(list L, integer i, list v)
|
|
|
|
{
|
|
|
|
while (llGetListLength(L) < i)
|
|
|
|
L = L + 0;
|
|
|
|
return llListReplaceList(L, v, i, i);
|
|
|
|
}
|
|
|
|
'''
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
self.tree[self.usedspots] = nr(
|
|
|
|
nt='FNDEF'
|
|
|
|
, t='list'
|
|
|
|
, name='lazy_list_set'
|
|
|
|
, ptypes=params[0]
|
|
|
|
, pnames=params[1]
|
|
|
|
, scope=0
|
|
|
|
, pscope=paramscope
|
|
|
|
, ch=[
|
|
|
|
nr(nt='{}'
|
|
|
|
, t=None
|
|
|
|
, LIR=True
|
2018-12-26 11:47:22 -07:00
|
|
|
, scope=blockscope
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
, ch=[
|
|
|
|
nr(nt='WHILE'
|
|
|
|
, t=None
|
|
|
|
, ch=[
|
|
|
|
nr(nt='<'
|
|
|
|
, t='integer'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='FNCALL'
|
|
|
|
, t='integer'
|
|
|
|
, name='llGetListLength'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='list'
|
|
|
|
, name='L'
|
|
|
|
, scope=paramscope
|
|
|
|
)
|
|
|
|
]
|
|
|
|
),
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='integer'
|
|
|
|
, name='i'
|
|
|
|
, scope=paramscope
|
|
|
|
)
|
|
|
|
]
|
|
|
|
),
|
|
|
|
nr(nt='EXPR'
|
|
|
|
, t='list'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='='
|
|
|
|
, t='list'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='list'
|
|
|
|
, name='L'
|
|
|
|
, scope=paramscope
|
|
|
|
),
|
|
|
|
nr(nt='+'
|
|
|
|
, t='list'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='list'
|
|
|
|
, name='L'
|
|
|
|
, scope=paramscope
|
|
|
|
),
|
|
|
|
nr(nt='CONST'
|
|
|
|
, t='integer'
|
|
|
|
, value=0
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
),
|
|
|
|
nr(nt='RETURN'
|
|
|
|
, t=None
|
|
|
|
, LIR=True
|
|
|
|
, ch=[
|
|
|
|
nr(nt='FNCALL'
|
|
|
|
, t='list'
|
|
|
|
, name='llListReplaceList'
|
|
|
|
, ch=[
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='list'
|
|
|
|
, name='L'
|
|
|
|
, scope=paramscope
|
|
|
|
),
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='list'
|
|
|
|
, name='v'
|
|
|
|
, scope=paramscope
|
|
|
|
),
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='integer'
|
|
|
|
, name='i'
|
|
|
|
, scope=paramscope
|
|
|
|
),
|
|
|
|
nr(nt='IDENT'
|
|
|
|
, t='integer'
|
|
|
|
, name='i'
|
|
|
|
, scope=paramscope
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
|
|
|
]
|
|
|
|
)
|
2015-03-12 22:38:35 -07:00
|
|
|
self.usedspots += 1
|
2018-12-26 11:47:22 -07:00
|
|
|
self.PopScope()
|
2015-03-12 22:38:35 -07:00
|
|
|
self.PopScope()
|
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if expr.t is None:
|
2015-03-12 22:38:35 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if expr.t != 'list':
|
|
|
|
expr = nr(nt='CAST', t='list', ch=[expr])
|
2015-03-12 22:38:35 -07:00
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='=', t='list', ch=[lvalue, nr(
|
|
|
|
nt='FNCALL', t='list', name='lazy_list_set', scope=0,
|
|
|
|
ch=[lvalue.copy(), idxexpr, expr]
|
|
|
|
)])
|
2015-03-12 22:38:35 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == '.':
|
2024-05-25 11:48:30 -07:00
|
|
|
if sym['Kind'] == 'c':
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
self.ValidateField(typ, self.tok[1])
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
lvalue = nr(nt='FLD', t='float', ch=[lvalue], fld=self.tok[1])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
tok0 = self.tok[0]
|
2014-08-07 15:52:23 -07:00
|
|
|
typ = 'float'
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 in ('++', '--'):
|
2024-05-25 11:48:30 -07:00
|
|
|
if sym['Kind'] == 'c':
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if lvalue.t not in ('integer', 'float'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='V++' if tok0 == '++' else 'V--', t=lvalue.t,
|
|
|
|
ch=[lvalue])
|
2014-08-13 04:34:09 -07:00
|
|
|
if AllowAssignment and (tok0 in self.assignment_toks
|
2015-03-12 22:38:35 -07:00
|
|
|
or self.extendedassignment
|
|
|
|
and tok0 in self.extassignment_toks):
|
2024-05-25 11:48:30 -07:00
|
|
|
if sym['Kind'] == 'c':
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
expr = self.Parse_expression()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtyp = expr.t
|
2014-07-25 17:43:44 -07:00
|
|
|
if typ in ('integer', 'float'):
|
|
|
|
# LSL admits integer *= float (go figger).
|
|
|
|
# It acts like: lhs = (integer)((float)lhs * rhs)
|
|
|
|
# That would trigger an error without this check.
|
|
|
|
if tok0 != '*=' or typ == 'float':
|
|
|
|
expr = self.autocastcheck(expr, typ)
|
|
|
|
rtyp = typ
|
2015-03-03 09:59:51 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# Lots of drama for checking types. This is pretty much like
|
|
|
|
# addition, subtraction, multiply, divide, etc. all in one go.
|
|
|
|
if tok0 == '=':
|
2015-06-15 19:16:59 -07:00
|
|
|
expr = self.autocastcheck(expr, typ)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='=', t=typ, ch=[lvalue, expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 == '+=':
|
|
|
|
if typ == 'float':
|
|
|
|
expr = self.autocastcheck(expr, typ)
|
|
|
|
if rtyp != typ != 'list' or typ == rtyp == 'key':
|
2015-06-15 19:16:59 -07:00
|
|
|
# key + key is the only disallowed combo of equal types
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
if self.explicitcast:
|
|
|
|
if typ == 'list' != rtyp:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
expr = nr(nt='CAST', t=typ, ch=[expr])
|
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 == '-=':
|
|
|
|
if typ == rtyp in ('integer', 'float', 'vector', 'rotation'):
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
|
|
|
if tok0 in ('*=', '/='):
|
2015-03-09 05:20:37 -07:00
|
|
|
# There is a special case that was dealt with before.
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == '*=' and typ == 'integer' and rtyp == 'float':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if (typ == rtyp or typ == 'vector') and rtyp in ('integer', 'float', 'rotation'):
|
|
|
|
if typ == 'vector' and rtyp == 'integer':
|
|
|
|
expr = self.autocastcheck(expr, 'float')
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
|
|
|
if tok0 == '%=':
|
|
|
|
if typ == rtyp in ('integer', 'vector'):
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-29 19:54:16 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Rest take integer operands only
|
|
|
|
|
|
|
|
if typ == rtyp == 'integer':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t=typ, ch=[lvalue, expr])
|
2014-07-29 19:54:16 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return lvalue
|
|
|
|
|
|
|
|
def Parse_unary_expression(self, AllowAssignment = True):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
unary_expression: '-' factor | '!' unary_expression | '~' unary_expression
|
|
|
|
# we expand lvalue here to facilitate parsing
|
|
|
|
| '++' IDENT | '++' IDENT '.' IDENT
|
|
|
|
| '--' IDENT | '--' IDENT '.' IDENT
|
|
|
|
| '(' TYPE ')' typecast_expression | '(' expression ')'
|
|
|
|
| unary_postfix_expression
|
|
|
|
%NORMAL RULES ONLY:
|
2018-03-30 18:19:26 -07:00
|
|
|
typecast_expression: '(' expression ')'
|
|
|
|
| unary_postfix_expression %except assignment
|
2014-07-25 17:43:44 -07:00
|
|
|
%EXTENDED RULES ONLY:
|
|
|
|
typecast_expression: unary_expression %except assignment
|
|
|
|
"""
|
|
|
|
tok0 = self.tok[0]
|
|
|
|
if tok0 == '-':
|
|
|
|
# Unary minus
|
|
|
|
self.NextToken()
|
|
|
|
value = self.Parse_factor()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if value.t not in ('integer', 'float', 'vector', 'rotation'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='NEG', t=value.t, ch=[value])
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 in ('!', '~'):
|
|
|
|
# Unary logic and bitwise NOT - applies to integers only
|
|
|
|
self.NextToken()
|
|
|
|
value = self.Parse_unary_expression()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if value.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=tok0, t='integer', ch=[value])
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 in ('++', '--'):
|
|
|
|
# Pre-increment / pre-decrement
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
name = self.tok[1]
|
2014-07-29 19:54:16 -07:00
|
|
|
sym = self.FindSymbolFull(name)
|
|
|
|
if sym is None or sym['Kind'] != 'v':
|
2014-07-25 17:43:44 -07:00
|
|
|
# Pretend it doesn't exist
|
|
|
|
raise EParseUndefined(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = sym['Type']
|
2014-07-25 17:43:44 -07:00
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='IDENT', t=typ, name=name, scope=sym['Scope'])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] == '.':
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
self.ValidateField(typ, self.tok[1])
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='FLD', t='float', ch=[ret], fld=self.tok[1])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
typ = ret.t
|
2014-07-25 17:43:44 -07:00
|
|
|
if typ not in ('integer', 'float'):
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='++V' if tok0 == '++' else '--V', t=typ, ch=[ret])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if tok0 == '(':
|
|
|
|
# Parenthesized expression or typecast
|
|
|
|
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != 'TYPE':
|
|
|
|
# Parenthesized expression
|
|
|
|
expr = self.Parse_expression()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2015-02-27 16:43:26 -07:00
|
|
|
return expr
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Typecast
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = self.tok[1]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
if self.extendedtypecast:
|
|
|
|
# Allow any unary expression (except assignment). The type cast
|
|
|
|
# acts as a prefix operator.
|
2015-06-22 21:35:27 -07:00
|
|
|
|
|
|
|
# Deal with the case of minus a constant integer or float.
|
|
|
|
# E.g. ~(integer)-2*3 should be parsed as (~(integer)-2)*3
|
|
|
|
# and not as ~(integer)(-(2*3))
|
|
|
|
# Note ~(integer)-a*3 is also parsed as ~(integer)(-a)*3
|
|
|
|
# which is bordering a violation of the POLA because of the
|
|
|
|
# priority of - with respect to *. But the syntax is quite
|
|
|
|
# explicit: what is typecast is always a unary expression,
|
|
|
|
# therefore processed first.
|
|
|
|
if self.tok[0] == '-':
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] == 'INTEGER_VALUE':
|
2018-07-25 17:31:51 -07:00
|
|
|
expr = nr(nt='CONST', t='integer',
|
|
|
|
value=lslfuncs.neg(self.tok[1]))
|
2015-06-22 21:35:27 -07:00
|
|
|
self.NextToken()
|
|
|
|
elif self.tok[0] == 'FLOAT_VALUE':
|
2018-07-25 17:31:51 -07:00
|
|
|
expr = nr(nt='CONST', t='float',
|
|
|
|
value=lslfuncs.neg(self.tok[1]))
|
2015-06-22 21:35:27 -07:00
|
|
|
self.NextToken()
|
|
|
|
else:
|
|
|
|
expr = self.Parse_unary_expression(AllowAssignment = False)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
expr = nr(nt='NEG', t=expr.t, ch=[expr])
|
2015-06-22 21:35:27 -07:00
|
|
|
else:
|
|
|
|
expr = self.Parse_unary_expression(AllowAssignment = False)
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
if self.tok[0] == '(':
|
|
|
|
self.NextToken()
|
|
|
|
expr = self.Parse_expression()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
|
|
|
else:
|
|
|
|
expr = self.Parse_unary_postfix_expression(AllowAssignment = False)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
basetype = expr.t
|
|
|
|
if self.lazylists and basetype is None and expr.nt == 'SUBIDX':
|
2018-12-22 07:44:14 -07:00
|
|
|
if typ not in self.TypeToExtractionFunction:
|
|
|
|
raise EParseNoConversion(self)
|
2015-03-12 22:38:35 -07:00
|
|
|
fn = self.TypeToExtractionFunction[typ]
|
2018-12-29 09:55:07 -07:00
|
|
|
sym = self.FindSymbolFull(fn, globalonly=True)
|
2018-12-22 07:44:14 -07:00
|
|
|
assert sym is not None
|
2015-03-12 22:38:35 -07:00
|
|
|
fnparamtypes = sym['ParamTypes']
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
subparamtypes = [x.t for x in expr.ch]
|
2015-03-12 22:38:35 -07:00
|
|
|
if fnparamtypes != subparamtypes:
|
|
|
|
raise EParseFunctionMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='FNCALL', t=sym['Type'], name=fn, scope=0,
|
|
|
|
ch=expr.ch)
|
2015-03-12 22:38:35 -07:00
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
if typ == 'list' and basetype in types \
|
2014-07-25 17:43:44 -07:00
|
|
|
or basetype in ('integer', 'float') and typ in ('integer', 'float', 'string') \
|
2017-10-20 07:26:05 -07:00
|
|
|
or basetype == 'string' and typ in types \
|
2014-07-25 17:43:44 -07:00
|
|
|
or basetype == 'key' and typ in ('string', 'key') \
|
|
|
|
or basetype == 'vector' and typ in ('string', 'vector') \
|
|
|
|
or basetype == 'rotation' and typ in ('string', 'rotation') \
|
|
|
|
or basetype == 'list' and typ == 'string':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CAST', t=typ, ch=[expr])
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
|
|
|
# Must be a postfix expression.
|
|
|
|
return self.Parse_unary_postfix_expression(AllowAssignment)
|
|
|
|
|
|
|
|
def Parse_factor(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
factor: unary_expression | factor '*' unary_expression
|
|
|
|
| factor '/' unary_expresssion | factor '%' unary_expression
|
|
|
|
"""
|
|
|
|
factor = self.Parse_unary_expression()
|
|
|
|
while self.tok[0] in ('*', '/', '%'):
|
|
|
|
op = self.tok[0]
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = factor.t
|
2014-07-25 17:43:44 -07:00
|
|
|
# Acceptable types for LHS
|
2014-07-29 19:54:16 -07:00
|
|
|
if op in ('*', '/') and ltype not in ('integer', 'float',
|
2014-07-25 17:43:44 -07:00
|
|
|
'vector', 'rotation') \
|
2014-07-29 19:54:16 -07:00
|
|
|
or op == '%' and ltype not in ('integer', 'vector'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_unary_expression()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtype = rexpr.t
|
2014-07-25 17:43:44 -07:00
|
|
|
# Mod is easier to check for
|
2014-07-29 19:54:16 -07:00
|
|
|
if op == '%' and ltype != rtype:
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
if op == '%' or ltype == rtype == 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
# Deal with the special cases first (it's easy)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
factor = nr(nt=op, t=ltype, ch=[factor, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
# Any integer must be promoted to float now
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype == 'integer':
|
|
|
|
ltype = 'float'
|
|
|
|
factor = self.autocastcheck(factor, ltype)
|
|
|
|
if rtype == 'integer':
|
|
|
|
rtype = 'float'
|
|
|
|
rexpr = self.autocastcheck(rexpr, rtype)
|
|
|
|
if ltype == 'float' and rtype in ('float', 'vector') \
|
|
|
|
or ltype == 'vector' and rtype in ('float', 'vector', 'rotation') \
|
|
|
|
or ltype == rtype == 'rotation':
|
|
|
|
if op == '/' and rtype == 'vector':
|
2014-07-25 17:43:44 -07:00
|
|
|
# Division by vector isn't valid
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
# The rest are valid
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype == 'float' and rtype == 'vector':
|
|
|
|
resulttype = rtype
|
|
|
|
elif ltype == rtype == 'vector':
|
2014-07-25 17:43:44 -07:00
|
|
|
resulttype = 'float'
|
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
resulttype = ltype
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
factor = nr(nt=op, t=resulttype, ch=[factor, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
|
|
|
return factor
|
|
|
|
|
|
|
|
def Parse_term(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
term: factor | term '+' factor | term '-' factor
|
|
|
|
"""
|
|
|
|
term = self.Parse_factor()
|
|
|
|
while self.tok[0] in ('+', '-'):
|
|
|
|
op = self.tok[0]
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = term.t
|
2017-10-20 07:26:05 -07:00
|
|
|
if op == '+' and ltype not in types \
|
2014-07-29 19:54:16 -07:00
|
|
|
or op == '-' and ltype not in ('integer', 'float',
|
2014-07-25 17:43:44 -07:00
|
|
|
'vector', 'rotation'):
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_factor()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtype = rexpr.t
|
2014-07-25 17:43:44 -07:00
|
|
|
# This is necessary, but the reason is subtle.
|
|
|
|
# The types must match in principle (except integer/float), so it
|
2014-07-29 19:54:16 -07:00
|
|
|
# doesn't seem necessary to check rtype. But there's the case
|
2014-07-25 17:43:44 -07:00
|
|
|
# where the first element is a list, where the types don't need to
|
|
|
|
# match but the second type must make sense.
|
2017-10-20 07:26:05 -07:00
|
|
|
if op == '+' and rtype not in types:
|
2014-07-29 19:54:16 -07:00
|
|
|
#or op == '-' and rtype not in ('integer', 'float',
|
2014-07-25 17:43:44 -07:00
|
|
|
# 'vector', 'rotation'):
|
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-25 19:41:09 -07:00
|
|
|
# Isolate the additions where the types match to make our life easier later
|
2014-07-29 19:54:16 -07:00
|
|
|
if op == '+' and (ltype == rtype or ltype == 'list' or rtype == 'list'):
|
|
|
|
if ltype == rtype == 'key':
|
2014-07-25 17:43:44 -07:00
|
|
|
# key + key is the only disallowed combo of equals
|
|
|
|
raise EParseTypeMismatch(self)
|
2015-09-03 21:26:01 -07:00
|
|
|
# Note that although list + nonlist is semantically the
|
|
|
|
# same as list + (list)nonlist, and similarly for
|
|
|
|
# nonlist + list, they don't compile to the same thing,
|
|
|
|
# so we don't act on self.explicitcast in this case.
|
2015-09-03 20:56:05 -07:00
|
|
|
if rtype == 'list':
|
|
|
|
ltype = rtype
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
term = nr(nt=op, t=ltype, ch=[term, rexpr])
|
2014-07-25 19:41:09 -07:00
|
|
|
elif self.allowkeyconcat and op == '+' \
|
2014-07-29 19:54:16 -07:00
|
|
|
and ltype in ('key', 'string') and rtype in ('key', 'string'):
|
2014-07-25 19:44:02 -07:00
|
|
|
# Allow string+key addition (but add explicit cast)
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype == 'key':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
term = nr(nt=op, t=rtype,
|
|
|
|
ch=[nr(nt='CAST', t=rtype, ch=[term]), rexpr])
|
2014-07-25 19:41:09 -07:00
|
|
|
else:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
term = nr(nt=op, t=ltype,
|
|
|
|
ch=[term, nr(nt='CAST', t=ltype, ch=[rexpr])])
|
2014-07-29 19:54:16 -07:00
|
|
|
elif ltype == 'key' or rtype == 'key':
|
2014-07-25 17:43:44 -07:00
|
|
|
# Only list + key or key + list is allowed, otherwise keys can't
|
|
|
|
# be added or subtracted with anything.
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype == 'float':
|
|
|
|
# Promote rexpr to float
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
term = nr(nt=op, t=ltype,
|
|
|
|
ch=[term, self.autocastcheck(rexpr, ltype)])
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
# Convert LHS to rtype if possible (note no keys get here)
|
|
|
|
term = nr(nt=op, t=rtype,
|
|
|
|
ch=[self.autocastcheck(term, rtype), rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return term
|
|
|
|
|
|
|
|
def Parse_shift(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
shift: term | shift '<<' term | shift '>>' term
|
|
|
|
"""
|
|
|
|
shift = self.Parse_term()
|
|
|
|
while self.tok[0] in ('<<', '>>'):
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if shift.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_term()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if rexpr.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
shift = nr(nt=op, t='integer', ch=[shift , rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return shift
|
|
|
|
|
|
|
|
def Parse_inequality(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
inequality: shift | inequality '<' shift | inequality '<=' shift
|
|
|
|
| inequality '>' shift | inequality '>=' shift
|
|
|
|
"""
|
|
|
|
inequality = self.Parse_shift()
|
|
|
|
while self.tok[0] in ('<', '<=', '>', '>='):
|
|
|
|
op = self.tok[0]
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = inequality.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype not in ('integer', 'float'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_shift()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtype = rexpr.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if rtype not in ('integer', 'float'):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype != rtype:
|
|
|
|
if rtype == 'float':
|
|
|
|
inequality = self.autocastcheck(inequality, rtype)
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.autocastcheck(rexpr, ltype)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
inequality = nr(nt=op, t='integer', ch=[inequality, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return inequality
|
|
|
|
|
|
|
|
def Parse_comparison(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
comparison: inequality | comparison '==' inequality
|
|
|
|
| comparison '!=' inequality
|
|
|
|
"""
|
|
|
|
comparison = self.Parse_inequality()
|
|
|
|
while self.tok[0] in ('==', '!='):
|
|
|
|
op = self.tok[0]
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = comparison.t
|
2017-10-20 07:26:05 -07:00
|
|
|
if ltype not in types:
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_inequality()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
rtype = rexpr.t
|
2014-07-29 19:54:16 -07:00
|
|
|
if ltype == 'float':
|
|
|
|
rexpr = self.autocastcheck(rexpr, ltype)
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
# For string & key, RHS (rtype) mandates the conversion
|
2014-07-25 17:43:44 -07:00
|
|
|
# (that's room for optimization: always compare strings)
|
2014-07-29 19:54:16 -07:00
|
|
|
comparison = self.autocastcheck(comparison, rtype)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
comparison = nr(nt=op, t='integer', ch=[comparison, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return comparison
|
|
|
|
|
|
|
|
def Parse_bitbool_factor(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
bitbool_factor: comparison | bitbool_factor '&' comparison
|
|
|
|
"""
|
|
|
|
bitbool_factor = self.Parse_comparison()
|
|
|
|
while self.tok[0] == '&':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if bitbool_factor.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_comparison()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if rexpr.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
bitbool_factor = nr(nt=op, t='integer', ch=[bitbool_factor, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return bitbool_factor
|
|
|
|
|
|
|
|
def Parse_bitxor_term(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
bitxor_term: bitbool_factor | bitxor_term '^' bitbool_factor
|
|
|
|
"""
|
|
|
|
bitxor_term = self.Parse_bitbool_factor()
|
|
|
|
while self.tok[0] == '^':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if bitxor_term.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_bitbool_factor()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if rexpr.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
bitxor_term = nr(nt=op, t='integer', ch=[bitxor_term, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return bitxor_term
|
|
|
|
|
|
|
|
def Parse_bitbool_term(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
bitbool_term: bitxor_term | bitbool_term '|' bitxor_term
|
|
|
|
"""
|
|
|
|
bitbool_term = self.Parse_bitxor_term()
|
|
|
|
while self.tok[0] == '|':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if bitbool_term.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_bitxor_term()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if rexpr.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
bitbool_term = nr(nt=op, t='integer', ch=[bitbool_term, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
return bitbool_term
|
|
|
|
|
|
|
|
def Parse_expression(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
expression: bitbool_term | expression '||' bitbool_term
|
|
|
|
| expression '&&' bitbool_term
|
|
|
|
|
|
|
|
Most operators with same priority, in general, are executed in
|
|
|
|
right-to-left order but calculated with precedence left-to-right.
|
|
|
|
That is, the tree is generated LTR but traversed RTL (in post-order).
|
|
|
|
|
|
|
|
E.g. a-b+c is calculated (in RPN notation) as: c, b, a, swap, -, +
|
|
|
|
i.e. c is evaluated first and a last, but the operation is still (a-b)+c
|
|
|
|
which is normal LTR.
|
|
|
|
|
|
|
|
At this point we're just constructing the tree, so we follow normal
|
|
|
|
precedence rules.
|
|
|
|
"""
|
|
|
|
expression = self.Parse_bitbool_term()
|
|
|
|
while self.tok[0] in ('&&', '||'):
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if expression.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
op = self.tok[0]
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
rexpr = self.Parse_bitbool_term()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if rexpr.t != 'integer':
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
expression = nr(nt=op, t='integer', ch=[expression, rexpr])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2019-01-01 12:03:02 -07:00
|
|
|
if not self.allowVoid and expression.t not in types:
|
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
return expression
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def Parse_optional_expression_list(self, expected_types = None):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
optional_expression_list: LAMBDA | expression_list
|
|
|
|
expression_list: expression | expression_list ',' expression
|
|
|
|
"""
|
2016-07-09 16:29:11 -07:00
|
|
|
# Recursive descendent parsers are nice, but not exempt of problems.
|
|
|
|
# We need to accept empty lists. This is a maze of which we get out
|
|
|
|
# with a dirty hack. Rather than attempt to parse as an expression and
|
|
|
|
# backtrack in case of error, we check the next token to see if it
|
|
|
|
# is one that closes the expression list.
|
|
|
|
# optional_expression_list is used by FOR loops (closed by ';' or ')'),
|
|
|
|
# list constants and lazy lists (closed by ']') and function arguments
|
|
|
|
# (closed by ')'). If it's not the right token, we'll err anyway upon
|
|
|
|
# return.
|
2014-07-25 17:43:44 -07:00
|
|
|
ret = []
|
|
|
|
idx = 0
|
|
|
|
if self.tok[0] not in (']', ')', ';'):
|
|
|
|
while True:
|
2019-01-01 12:03:02 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
self.allowVoid = True
|
2014-07-30 07:00:00 -07:00
|
|
|
expr = self.Parse_expression()
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
2018-04-09 09:42:31 -07:00
|
|
|
if expr.nt == 'SUBIDX' and expr.t is None:
|
|
|
|
# Don't accept an untyped lazy list in expression lists
|
|
|
|
raise EParseTypeMismatch(self)
|
2016-07-09 16:29:11 -07:00
|
|
|
if False is not expected_types is not None:
|
2014-07-25 17:43:44 -07:00
|
|
|
if idx >= len(expected_types):
|
|
|
|
raise EParseFunctionMismatch(self)
|
|
|
|
try:
|
2014-07-30 07:00:00 -07:00
|
|
|
expr = self.autocastcheck(expr, expected_types[idx]);
|
2014-07-25 17:43:44 -07:00
|
|
|
except EParseTypeMismatch:
|
|
|
|
raise EParseFunctionMismatch(self)
|
2018-04-09 09:42:31 -07:00
|
|
|
elif expected_types is False and self.optenabled:
|
|
|
|
# don't accept void expressions if optimization is on
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if expr.t not in types:
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseTypeMismatch(self)
|
|
|
|
idx += 1
|
2014-07-30 07:00:00 -07:00
|
|
|
ret.append(expr)
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] != ',':
|
|
|
|
break
|
|
|
|
self.NextToken()
|
2016-07-09 16:29:11 -07:00
|
|
|
if False is not expected_types is not None and idx != len(expected_types):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseFunctionMismatch(self)
|
|
|
|
return ret
|
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
def Parse_statement(self, ReturnType, AllowDecl = False, AllowStSw = False,
|
|
|
|
InsideSwitch = False, InsideLoop = False):
|
2014-07-25 17:43:44 -07:00
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
statement: ';' | single_statement | code_block
|
|
|
|
single_statement: if_statement | while_statement | do_statement
|
|
|
|
| for_statement | jump_statement | state_statement | label_statement
|
|
|
|
| return_statement | declaration_statement | expression ';'
|
2015-03-04 17:37:32 -07:00
|
|
|
| switch_statement %if enableswitch
|
|
|
|
| case_statement %if enableswitch and InsideSwitch
|
|
|
|
| break_statement %if enableswitch and InsideSwitch or breakcont and InsideLoop
|
|
|
|
| continue_statement %if breakcont and InsideLoop
|
2014-07-25 17:43:44 -07:00
|
|
|
if_statement: IF '(' expression ')' statement ELSE statement
|
|
|
|
| IF '(' expression ')' statement
|
|
|
|
while_statement: WHILE '(' expression ')' statement
|
|
|
|
do_statement: DO statement WHILE '(' expression ')' ';'
|
|
|
|
for_statement: FOR '(' optional_expression_list ';' expression ';'
|
|
|
|
optional_expression_list ')' statement
|
|
|
|
jump_statement: JUMP IDENT ';'
|
|
|
|
state_statement: STATE DEFAULT ';' | STATE IDENT ';'
|
|
|
|
label_statement: '@' IDENT ';'
|
|
|
|
return_statement: RETURN ';' | RETURN expression ';'
|
|
|
|
declaration_statement: TYPE lvalue ';' | TYPE lvalue '=' expression ';'
|
2015-03-04 17:37:32 -07:00
|
|
|
switch_statement: SWITCH '(' expression ')' code_block
|
2015-03-12 21:16:22 -07:00
|
|
|
case_statement: CASE expression ':' | CASE expression code_block
|
|
|
|
| DEFAULT ':' | DEFAULT code_block
|
2015-03-04 17:37:32 -07:00
|
|
|
break_statement: BREAK ';'
|
|
|
|
continue_statement: CONTINUE ';'
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
There's a restriction: a *single* statement can not be a declaration.
|
2015-03-04 17:37:32 -07:00
|
|
|
For example: if (1) integer x; is not allowed.
|
|
|
|
|
|
|
|
Note that SWITCH expects a code block because CASE is a full statement
|
|
|
|
for us, rather than a label. So for example this wouldn't work:
|
|
|
|
switch (expr) case expr: stmt; // works in C but not in this processor
|
|
|
|
but this works in both: switch (expr) { case expr: stmt; }
|
2014-07-25 17:43:44 -07:00
|
|
|
"""
|
|
|
|
tok0 = self.tok[0]
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == '{':
|
2015-03-04 17:37:32 -07:00
|
|
|
return self.Parse_code_block(ReturnType, AllowStSw = AllowStSw,
|
|
|
|
InsideSwitch = InsideSwitch, InsideLoop = InsideLoop)
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == ';':
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=';', t=None)
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == '@':
|
2018-04-09 09:42:31 -07:00
|
|
|
if not AllowDecl and self.optenabled:
|
2018-04-01 11:05:35 -07:00
|
|
|
raise EParseInvalidLabelOpt(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
name = self.tok[1]
|
2024-05-25 11:48:30 -07:00
|
|
|
if name in self.symtab[0] and self.symtab[0][name]['Kind'] == 'c':
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
if name in self.symtab[self.scopeindex]:
|
|
|
|
raise EParseAlreadyDefined(self)
|
2014-07-31 16:41:21 -07:00
|
|
|
# shrinknames *needs* all labels renamed, so they are out of the way
|
|
|
|
if self.duplabels or self.shrinknames:
|
|
|
|
# Duplicate labels allowed.
|
|
|
|
if name in self.locallabels or self.shrinknames:
|
|
|
|
# Generate a new unique name and attach it to the symbol.
|
2015-03-04 17:37:32 -07:00
|
|
|
unique = self.GenerateLabel()
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', self.scopeindex, name, NewName=unique,
|
|
|
|
ref=0)
|
2014-07-31 16:41:21 -07:00
|
|
|
else:
|
|
|
|
# Use the existing name. Faster and more readable.
|
|
|
|
unique = name
|
2015-03-04 17:37:32 -07:00
|
|
|
self.locallabels.add(name)
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', self.scopeindex, name, ref=0)
|
2014-07-31 16:41:21 -07:00
|
|
|
|
|
|
|
else:
|
|
|
|
# Duplicate labels disallowed.
|
|
|
|
# All labels go to a common pool local to the current function.
|
|
|
|
# Check if it's already there, and add it otherwise.
|
|
|
|
if name in self.locallabels:
|
|
|
|
raise EParseDuplicateLabel(self)
|
|
|
|
self.locallabels.add(name)
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', self.scopeindex, name, ref=0)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='@', t=None, name=name, scope=self.scopeindex)
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'JUMP':
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
name = self.tok[1]
|
2014-07-29 19:54:16 -07:00
|
|
|
sym = self.FindSymbolPartial(name, MustBeLabel=True)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
jumpnode = nr(nt='JUMP', t=None, name=name, scope=None)
|
2014-07-29 19:54:16 -07:00
|
|
|
if not sym or sym['Kind'] != 'l':
|
2014-07-25 17:43:44 -07:00
|
|
|
# It might still be a forward reference, so we add it to the
|
|
|
|
# list of things to look up when done
|
2018-12-29 09:55:07 -07:00
|
|
|
self.jump_lookups.append((name, self.scopestack[:],
|
|
|
|
self.errorpos, jumpnode))
|
2014-07-31 20:07:50 -07:00
|
|
|
else:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
jumpnode.scope = sym['Scope']
|
2018-05-16 23:12:33 -07:00
|
|
|
sym['ref'] += 1
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
return jumpnode
|
2017-08-09 07:41:36 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'STATE':
|
Fix EParseCantChangeState so that it is always properly reported.
Still somewhat messy, but still reported as soon as it can be detected.
If an ELSE token is detected at the top level, for example, the error position will be rewound to the state change and reported there.
This means that in this situation:
x()
{
if (1)
{
state default;
x(2);
}
else ;
}
default{timer(){}}
an error will be reported in x(2), because the ELSE hasn't been found at that point, therefore the state change statement isn't found to be at fault yet.
However, in this case:
x()
{
if (1)
state default;
else
x(2);
}
default{timer(){}}
the error WILL be reported at the state change statement.
This commit also changes the position where the exception is reported, to be at the STATE token. As an inconsequential side effect, EParseCantChangeState takes precedence over undefined identifiers, in case the state change is to an undefined state, but only in cases where it can be immediately detected.
2017-11-02 05:31:06 -07:00
|
|
|
if self.localevents is None:
|
|
|
|
if AllowStSw is False:
|
|
|
|
raise EParseCantChangeState(self)
|
|
|
|
if AllowStSw is None:
|
2019-04-30 19:03:58 -07:00
|
|
|
self.PruneBug.append((self.errorpos,
|
|
|
|
EParseCantChangeState))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] not in ('DEFAULT', 'IDENT'):
|
|
|
|
raise EParseSyntax(self)
|
2014-07-31 14:21:50 -07:00
|
|
|
# State Switch only searches for states in the global scope
|
2014-07-25 17:43:44 -07:00
|
|
|
name = self.tok[1] if self.tok[0] == 'IDENT' else 'default'
|
2024-05-25 11:04:33 -07:00
|
|
|
if (name not in self.symtab[0]
|
|
|
|
or self.symtab[0][name]['Kind'] != 's'
|
|
|
|
) and (name not in self.globals
|
|
|
|
or self.globals[name]['Kind'] != 's'
|
|
|
|
):
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseUndefined(self)
|
|
|
|
self.NextToken()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='STSW', t=None, name=name, scope=0)
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'RETURN':
|
2017-10-09 02:29:15 -07:00
|
|
|
savepos = self.errorpos
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] == ';':
|
|
|
|
value = None
|
|
|
|
else:
|
2017-10-09 02:29:15 -07:00
|
|
|
savepos = self.errorpos
|
2019-04-30 19:03:58 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
# Needed due to another LSL bug, see regr/void-in-return.lsl
|
|
|
|
self.allowVoid = True
|
2014-07-25 17:43:44 -07:00
|
|
|
value = self.Parse_expression()
|
2019-04-30 19:03:58 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
|
|
|
if ReturnType is None and value is not None:
|
2019-04-30 19:03:58 -07:00
|
|
|
# It follows the same rules as AllowStSw
|
|
|
|
if AllowStSw is False:
|
|
|
|
self.errorpos = savepos
|
|
|
|
raise EParseReturnShouldBeEmpty(self)
|
|
|
|
elif value.t is None:
|
|
|
|
if AllowStSw is None:
|
|
|
|
self.PruneBug.append((self.errorpos,
|
|
|
|
EParseReturnShouldBeEmpty))
|
|
|
|
self.PushScope()
|
|
|
|
scope = self.scopeindex
|
|
|
|
self.PopScope()
|
|
|
|
return nr(nt='{}', t=None, scope=scope,
|
|
|
|
ch=[nr(nt='EXPR', t=None, ch=[value]),
|
|
|
|
nr(nt='RETURN', t=None)])
|
|
|
|
else:
|
|
|
|
self.errorpos = savepos
|
|
|
|
raise EParseTypeMismatch(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
if ReturnType is not None and value is None:
|
2017-10-09 02:29:15 -07:00
|
|
|
self.errorpos = savepos
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseReturnIsEmpty(self)
|
|
|
|
if value is None:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='RETURN', t=None)
|
2014-08-02 19:50:18 -07:00
|
|
|
# Sets LastIsReturn flag too
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='RETURN', t=None, LIR=True,
|
|
|
|
ch=[self.autocastcheck(value, ReturnType)])
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-30 20:41:15 -07:00
|
|
|
if tok0 == 'IF':
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='IF', t=None, ch=[])
|
2014-08-02 19:50:18 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret.ch.append(self.Parse_expression())
|
2014-08-02 19:50:18 -07:00
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2019-04-30 19:03:58 -07:00
|
|
|
savePruneBug = self.PruneBug
|
|
|
|
self.PruneBug = []
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret.ch.append(self.Parse_statement(ReturnType, AllowStSw = None, InsideLoop = InsideLoop))
|
2014-08-02 19:50:18 -07:00
|
|
|
if self.tok[0] == 'ELSE':
|
2019-04-30 19:03:58 -07:00
|
|
|
if AllowStSw is False and self.PruneBug:
|
|
|
|
self.errorpos = self.PruneBug[0][0]
|
|
|
|
raise self.PruneBug[0][1](self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
LastIsReturn = getattr(ret.ch[1], 'LIR', False)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret.ch.append(self.Parse_statement(ReturnType,
|
|
|
|
AllowStSw = AllowStSw, InsideLoop = InsideLoop))
|
Fix EParseCantChangeState so that it is always properly reported.
Still somewhat messy, but still reported as soon as it can be detected.
If an ELSE token is detected at the top level, for example, the error position will be rewound to the state change and reported there.
This means that in this situation:
x()
{
if (1)
{
state default;
x(2);
}
else ;
}
default{timer(){}}
an error will be reported in x(2), because the ELSE hasn't been found at that point, therefore the state change statement isn't found to be at fault yet.
However, in this case:
x()
{
if (1)
state default;
else
x(2);
}
default{timer(){}}
the error WILL be reported at the state change statement.
This commit also changes the position where the exception is reported, to be at the STATE token. As an inconsequential side effect, EParseCantChangeState takes precedence over undefined identifiers, in case the state change is to an undefined state, but only in cases where it can be immediately detected.
2017-11-02 05:31:06 -07:00
|
|
|
if AllowStSw is None:
|
2019-04-30 19:03:58 -07:00
|
|
|
savePruneBug += self.PruneBug
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if LastIsReturn and getattr(ret.ch[2], 'LIR', False):
|
|
|
|
ret.LIR = True
|
2019-04-30 19:03:58 -07:00
|
|
|
self.PruneBug = savePruneBug
|
2014-08-02 19:50:18 -07:00
|
|
|
return ret
|
2014-07-29 19:54:16 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'WHILE':
|
|
|
|
self.NextToken()
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
|
|
|
# We may add braces - or not. The safe approach is to assume
|
|
|
|
# we always do and open a new scope for it. At worst it will be
|
2015-03-05 12:18:13 -07:00
|
|
|
# empty. At least it is not reflected as braces in the code if
|
|
|
|
# braces are not used.
|
2016-07-09 13:50:18 -07:00
|
|
|
#
|
|
|
|
# This is designed to deal with cases like:
|
|
|
|
# if (a) while (b) { ... break; }
|
|
|
|
#
|
|
|
|
# This works by adding braces around the while and the newly
|
|
|
|
# added label, like this:
|
|
|
|
# if (a) { while (b) { ... jump label; } @label; }
|
2015-03-04 17:37:32 -07:00
|
|
|
self.PushScope()
|
|
|
|
|
2018-05-16 23:12:33 -07:00
|
|
|
self.breakstack.append([self.GenerateLabel(), self.scopeindex,
|
|
|
|
0])
|
|
|
|
# Scope still unknown; if a block is opened, Parse_code_block()
|
|
|
|
# will fill it in.
|
|
|
|
self.continuestack.append([self.GenerateLabel(), None, 0])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
|
|
|
condition = self.Parse_expression()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2016-07-09 14:30:49 -07:00
|
|
|
# To fix a problem with a corner case (LSL allows defining a label
|
|
|
|
# in a single statement, at the same scope as the loop, breaking
|
|
|
|
# some of our logic), we check if the statement is a label. If so,
|
|
|
|
# we pop the scope to parse the statement and push it again.
|
|
|
|
# It won't cause scope problems in turn because we won't add any
|
|
|
|
# break or continue labels if no break or continue statement is
|
|
|
|
# present, which it can't because the statement is a label.
|
|
|
|
if self.breakcont and self.tok[0] == '@':
|
|
|
|
self.PopScope()
|
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
|
|
|
self.PushScope()
|
|
|
|
else:
|
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True, InsideLoop = True)
|
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='WHILE', t=None, ch=[condition, stmt])
|
2016-07-09 14:30:49 -07:00
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
2015-03-05 12:12:32 -07:00
|
|
|
last = self.continuestack.pop()
|
|
|
|
if last[2]:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
assert ret.ch[1].nt == '{}'
|
|
|
|
ret.ch[1].ch.append(nr(nt='@', t=None, name=last[0],
|
|
|
|
scope=last[1]))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-05 12:12:32 -07:00
|
|
|
|
|
|
|
last = self.breakstack.pop()
|
|
|
|
if last[2]:
|
2018-12-26 11:47:22 -07:00
|
|
|
assert last[1] is not None
|
|
|
|
ret = nr(nt='{}', t=None, scope=last[1], ch=[ret,
|
|
|
|
nr(nt='@', t=None, name=last[0], scope=last[1])])
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-04 17:37:32 -07:00
|
|
|
self.PopScope()
|
|
|
|
return ret
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'DO':
|
|
|
|
self.NextToken()
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
|
|
|
self.PushScope()
|
|
|
|
|
2018-05-16 23:12:33 -07:00
|
|
|
self.breakstack.append([self.GenerateLabel(), self.scopeindex,
|
|
|
|
0])
|
|
|
|
# Scope still unknown; if a block is opened, Parse_code_block()
|
|
|
|
# will fill it in.
|
|
|
|
self.continuestack.append([self.GenerateLabel(), None, 0])
|
2016-07-09 14:30:49 -07:00
|
|
|
if self.breakcont and self.tok[0] == '@':
|
|
|
|
self.PopScope()
|
2018-05-16 23:12:33 -07:00
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True,
|
|
|
|
InsideLoop = True)
|
2016-07-09 14:30:49 -07:00
|
|
|
self.PushScope()
|
|
|
|
else:
|
2018-05-16 23:12:33 -07:00
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True,
|
|
|
|
InsideLoop = True)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('WHILE')
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
|
|
|
condition = self.Parse_expression()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='DO', t=None, ch=[stmt, condition])
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
2015-03-05 12:12:32 -07:00
|
|
|
last = self.continuestack.pop()
|
|
|
|
if last[2]:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
assert ret.ch[0].nt == '{}'
|
|
|
|
ret.ch[0].ch.append(nr(nt='@', t=None, name=last[0],
|
|
|
|
scope=last[1]))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-05 12:12:32 -07:00
|
|
|
|
|
|
|
last = self.breakstack.pop()
|
|
|
|
if last[2]:
|
2018-12-26 11:47:22 -07:00
|
|
|
assert last[1] is not None
|
|
|
|
ret = nr(nt='{}', t=None, scope=last[1], ch=[ret,
|
|
|
|
nr(nt='@', t=None, name=last[0], scope=last[1])])
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-04 17:37:32 -07:00
|
|
|
self.PopScope()
|
|
|
|
return ret
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'FOR':
|
|
|
|
self.NextToken()
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
|
|
|
self.PushScope()
|
|
|
|
|
2018-05-16 23:12:33 -07:00
|
|
|
self.breakstack.append([self.GenerateLabel(), self.scopeindex,
|
|
|
|
0])
|
|
|
|
# Scope still unknown; if a block is opened, Parse_code_block()
|
|
|
|
# will fill it in.
|
|
|
|
self.continuestack.append([self.GenerateLabel(), None, 0])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
|
|
|
initializer = self.Parse_optional_expression_list()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
|
|
|
condition = self.Parse_expression()
|
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
|
|
|
iterator = self.Parse_optional_expression_list()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2016-07-09 14:30:49 -07:00
|
|
|
if self.breakcont and self.tok[0] == '@':
|
|
|
|
self.PopScope()
|
2018-05-16 23:12:33 -07:00
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True,
|
|
|
|
InsideLoop = True)
|
2016-07-09 14:30:49 -07:00
|
|
|
self.PushScope()
|
|
|
|
else:
|
2018-05-16 23:12:33 -07:00
|
|
|
stmt = self.Parse_statement(ReturnType, AllowStSw = True,
|
|
|
|
InsideLoop = True)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret = nr(nt='FOR', t=None,
|
|
|
|
ch=[nr(nt='EXPRLIST', t=None, ch=initializer),
|
2014-07-29 19:54:16 -07:00
|
|
|
condition,
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
nr(nt='EXPRLIST', t=None, ch=iterator),
|
|
|
|
stmt
|
|
|
|
])
|
2015-03-04 17:37:32 -07:00
|
|
|
if self.breakcont:
|
2015-03-05 12:12:32 -07:00
|
|
|
last = self.continuestack.pop()
|
|
|
|
if last[2]:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
assert ret.ch[3].nt == '{}'
|
|
|
|
ret.ch[3].ch.append(nr(nt='@', t=None, name=last[0],
|
|
|
|
scope=last[1]))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-05 12:12:32 -07:00
|
|
|
|
|
|
|
last = self.breakstack.pop()
|
|
|
|
if last[2]:
|
2018-12-26 11:47:22 -07:00
|
|
|
assert last[1] is not None
|
|
|
|
ret = nr(nt='{}', t=None, scope=last[1], ch=[ret,
|
|
|
|
nr(nt='@', t=None, name=last[0], scope=last[1])])
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', last[1], last[0], ref=last[2])
|
2015-03-04 17:37:32 -07:00
|
|
|
self.PopScope()
|
|
|
|
return ret
|
|
|
|
|
|
|
|
if tok0 == 'SWITCH':
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
|
|
|
expr = self.Parse_expression()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
|
|
|
brk = self.GenerateLabel()
|
2018-05-16 23:12:33 -07:00
|
|
|
# Scope is determined in Parse_code_block()
|
|
|
|
self.breakstack.append([brk, None, 0])
|
2015-03-04 17:37:32 -07:00
|
|
|
blk = self.Parse_code_block(ReturnType, AllowStSw = AllowStSw,
|
|
|
|
InsideSwitch = True, InsideLoop = InsideLoop)
|
2015-03-05 12:12:32 -07:00
|
|
|
blkscope = self.breakstack[-1][1]
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
# Replace the block
|
|
|
|
# switch (expr1) { case expr2: stmts1; break; default: stmts2; }
|
|
|
|
# is translated to:
|
|
|
|
# {
|
|
|
|
# if (expr1==expr2) jump label1;
|
|
|
|
# jump labeldef;
|
|
|
|
#
|
|
|
|
# @label1;
|
|
|
|
# stmts1;
|
|
|
|
# jump labelbrk;
|
|
|
|
# @labeldef;
|
|
|
|
# stmts2;
|
|
|
|
# @labelbrk;
|
|
|
|
# }
|
|
|
|
# The prelude is the ifs and the jumps.
|
|
|
|
# The block gets the cases replaced with labels,
|
|
|
|
# and the breaks replaced with jumps.
|
|
|
|
|
|
|
|
switchcaselist = []
|
|
|
|
switchcasedefault = None
|
|
|
|
# Since label scope rules prevent us from being able to jump inside
|
|
|
|
# a nested block, only one nesting level is considered.
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
assert blk.nt == '{}'
|
|
|
|
blk = blk.ch # Disregard the '{}' - we'll add it back later
|
2015-03-04 17:37:32 -07:00
|
|
|
for idx in xrange(len(blk)):
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if blk[idx].nt == 'CASE':
|
2015-03-04 17:37:32 -07:00
|
|
|
lbl = self.GenerateLabel()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
switchcaselist.append((lbl, blk[idx].ch[0]))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', blkscope, lbl, ref=0)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
blk[idx] = nr(nt='@', t=None, name=lbl, scope=blkscope)
|
|
|
|
elif blk[idx].nt == 'DEFAULTCASE':
|
2015-03-04 17:37:32 -07:00
|
|
|
if switchcasedefault is not None:
|
|
|
|
raise EParseManyDefaults(self)
|
|
|
|
lbl = self.GenerateLabel()
|
|
|
|
switchcasedefault = lbl
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', blkscope, lbl, ref=0)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
blk[idx] = nr(nt='@', name=lbl, scope=blkscope)
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
prelude = []
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ltype = expr.t
|
2015-03-04 17:37:32 -07:00
|
|
|
for case in switchcaselist:
|
|
|
|
rexpr = case[1]
|
|
|
|
lexpr = expr
|
|
|
|
if ltype == 'float':
|
|
|
|
rexpr = self.autocastcheck(rexpr, ltype)
|
|
|
|
else:
|
|
|
|
# For string & key, RHS (rtype) mandates the conversion
|
|
|
|
# (that's room for optimization: always compare strings)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
lexpr = self.autocastcheck(lexpr, rexpr.t)
|
|
|
|
prelude.append(nr(nt='IF', t=None, ch=[
|
|
|
|
nr(nt='==', t='integer', ch=[lexpr, rexpr]),
|
|
|
|
nr(nt='JUMP', t=None, name=case[0], scope=blkscope)
|
|
|
|
]))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.symtab[blkscope][case[0]]['ref'] += 1
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
if switchcasedefault is None:
|
2016-05-06 17:38:54 -07:00
|
|
|
if self.errmissingdefault:
|
|
|
|
raise EParseMissingDefault(self)
|
2016-05-07 18:55:55 -07:00
|
|
|
# Check if it's worth adding a break label. If there's no
|
|
|
|
# executable code, there's no point. However, this check is
|
|
|
|
# insufficient. It misses SEF expressions. For that reason,
|
|
|
|
# this is best left up to a later optimizer that knows about
|
|
|
|
# SEF. But we do a preliminary elimination here.
|
Only add a label and a jump for default and break when necessary.
Well, within reasonable limits.
For break, it's explained in the code. If the block is empty of actual code (code that generates output), then the break position is eliminated.
For default, if the default label is at the top of the block, the jump and the label are both eliminated. This check doesn't include verifying that there are other non-code-generating statements in between, so there's room for improvement (added corresponding TODO item).
This way, we're on par with FS, in case someone (ab)used the FS brokeness when the 'default' label was absent. All one has to do now is add the default label at the top, and the generated code will be the same as it was in FS when abusing that bug, with no extra burden.
Example: In FS, the code at the top acted as default and there was no jump for it:
default { timer() {
switch(1)
{
0;
case 1:
1;
}
}}
This generated roughly:
default { timer() {
{
if (1 == 1) jump CASE_1;
0;
@CASE_1;
1;
}
}}
In this system, it would trigger an error by default. To obtain the FS behaviour, the scripter can do instead:
default { timer() {
switch(1)
{
default:
0;
case 1:
1;
}
}}
Thanks to this optimization, the code will be the same as in FS. Without it, an extra default label and corresponding jump would be present.
2016-05-06 19:37:58 -07:00
|
|
|
if self.does_something(blk):
|
|
|
|
switchcasedefault = brk
|
|
|
|
else:
|
2016-05-07 18:55:55 -07:00
|
|
|
# Check if no code up to the default label does anything.
|
|
|
|
# If so, remove the label and don't generate the jump.
|
|
|
|
for i in xrange(len(blk)):
|
|
|
|
node = blk[i]
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if (node.nt == '@' and node.name == switchcasedefault
|
|
|
|
and node.scope == blkscope):
|
2016-05-07 18:55:55 -07:00
|
|
|
switchcasedefault = None
|
|
|
|
del blk[i]
|
|
|
|
break
|
|
|
|
if self.does_something([node]):
|
|
|
|
break
|
|
|
|
del i, node
|
Only add a label and a jump for default and break when necessary.
Well, within reasonable limits.
For break, it's explained in the code. If the block is empty of actual code (code that generates output), then the break position is eliminated.
For default, if the default label is at the top of the block, the jump and the label are both eliminated. This check doesn't include verifying that there are other non-code-generating statements in between, so there's room for improvement (added corresponding TODO item).
This way, we're on par with FS, in case someone (ab)used the FS brokeness when the 'default' label was absent. All one has to do now is add the default label at the top, and the generated code will be the same as it was in FS when abusing that bug, with no extra burden.
Example: In FS, the code at the top acted as default and there was no jump for it:
default { timer() {
switch(1)
{
0;
case 1:
1;
}
}}
This generated roughly:
default { timer() {
{
if (1 == 1) jump CASE_1;
0;
@CASE_1;
1;
}
}}
In this system, it would trigger an error by default. To obtain the FS behaviour, the scripter can do instead:
default { timer() {
switch(1)
{
default:
0;
case 1:
1;
}
}}
Thanks to this optimization, the code will be the same as in FS. Without it, an extra default label and corresponding jump would be present.
2016-05-06 19:37:58 -07:00
|
|
|
|
|
|
|
if switchcasedefault is not None:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
prelude.append(nr(nt='JUMP', t=None, name=switchcasedefault,
|
|
|
|
scope=blkscope))
|
2018-05-16 23:12:33 -07:00
|
|
|
if switchcasedefault == brk:
|
|
|
|
# add a reference to it in the break stack
|
|
|
|
self.breakstack[-1][2] += 1
|
|
|
|
else:
|
|
|
|
self.symtab[blkscope][switchcasedefault]['ref'] += 1
|
|
|
|
|
2015-03-05 12:12:32 -07:00
|
|
|
last = self.breakstack.pop()
|
|
|
|
if last[2]:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
blk.append(nr(nt='@', name=brk, scope=blkscope))
|
2018-05-16 23:12:33 -07:00
|
|
|
self.AddSymbol('l', blkscope, brk, ref=last[2])
|
2018-12-26 11:47:22 -07:00
|
|
|
return nr(nt='{}', t=None, scope=blkscope, ch=prelude + blk)
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
if tok0 == 'CASE':
|
|
|
|
if not InsideSwitch:
|
|
|
|
raise EParseInvalidCase(self, u"case")
|
2015-03-05 12:12:32 -07:00
|
|
|
if self.scopeindex != self.breakstack[-1][1]:
|
2015-03-04 17:37:32 -07:00
|
|
|
# If this block is nested and not the main switch block, this
|
2015-03-05 12:12:32 -07:00
|
|
|
# won't work. LSL label scope rules don't expose the nested
|
|
|
|
# labels. Nothing we can do about that.
|
2015-03-04 17:37:32 -07:00
|
|
|
raise EParseCaseNotAllowed(self, u"case")
|
|
|
|
self.NextToken()
|
|
|
|
expr = self.Parse_expression()
|
2015-03-12 21:16:22 -07:00
|
|
|
if self.tok[0] == ':':
|
|
|
|
self.NextToken()
|
|
|
|
elif self.tok[0] != '{':
|
|
|
|
raise EParseSyntax(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CASE', t=None, ch=[expr])
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
if tok0 == 'DEFAULT':
|
|
|
|
if self.enableswitch:
|
|
|
|
if not InsideSwitch:
|
|
|
|
raise EParseInvalidCase(self, u"default")
|
2015-03-05 12:12:32 -07:00
|
|
|
if self.scopeindex != self.breakstack[-1][1]:
|
2015-03-04 17:37:32 -07:00
|
|
|
# If this block is nested and not the main switch block, this
|
2015-03-05 12:12:32 -07:00
|
|
|
# won't work. Label scope rules don't expose the nested
|
|
|
|
# labels. Nothing we can do about that.
|
2015-03-04 17:37:32 -07:00
|
|
|
raise EParseCaseNotAllowed(self, u"default")
|
|
|
|
self.NextToken()
|
2015-03-12 21:16:22 -07:00
|
|
|
if self.tok[0] == ':':
|
|
|
|
self.NextToken()
|
|
|
|
elif self.tok[0] != '{':
|
|
|
|
raise EParseSyntax(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='DEFAULTCASE', t=None)
|
2015-03-04 17:37:32 -07:00
|
|
|
# else fall through to eventually fail
|
|
|
|
|
|
|
|
if tok0 == 'BREAK':
|
2015-03-05 12:12:32 -07:00
|
|
|
if not self.breakstack:
|
2015-03-04 17:37:32 -07:00
|
|
|
raise EParseInvalidBreak(self)
|
|
|
|
self.NextToken()
|
2015-03-05 12:12:32 -07:00
|
|
|
n = -1
|
|
|
|
if self.tok[0] == 'INTEGER_VALUE':
|
|
|
|
if self.tok[1] <= 0:
|
2017-04-28 18:33:45 -07:00
|
|
|
raise EParseInvalidBrkContArg(self)
|
2015-03-05 12:12:32 -07:00
|
|
|
n = -self.tok[1]
|
|
|
|
self.NextToken()
|
2015-03-04 17:37:32 -07:00
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
2015-03-05 12:12:32 -07:00
|
|
|
try:
|
2018-05-16 23:12:33 -07:00
|
|
|
self.breakstack[n][2] += 1
|
2015-03-05 12:12:32 -07:00
|
|
|
except IndexError:
|
2017-04-28 18:33:45 -07:00
|
|
|
raise EParseInvalidBrkContArg(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='JUMP', t=None, name=self.breakstack[n][0],
|
|
|
|
scope=self.breakstack[n][1])
|
2015-03-04 17:37:32 -07:00
|
|
|
|
|
|
|
if tok0 == 'CONTINUE':
|
2015-03-05 12:12:32 -07:00
|
|
|
if not self.continuestack:
|
2015-03-04 17:37:32 -07:00
|
|
|
raise EParseInvalidCont(self)
|
|
|
|
self.NextToken()
|
2015-03-05 12:12:32 -07:00
|
|
|
n = -1
|
|
|
|
if self.tok[0] == 'INTEGER_VALUE':
|
|
|
|
if self.tok[1] <= 0:
|
2017-04-28 18:33:45 -07:00
|
|
|
raise EParseInvalidBrkContArg(self)
|
2015-03-05 12:12:32 -07:00
|
|
|
n = -self.tok[1]
|
|
|
|
self.NextToken()
|
2015-03-04 17:37:32 -07:00
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
2015-03-05 12:12:32 -07:00
|
|
|
if n == -1 and self.continuestack[-1][1] is None:
|
|
|
|
# We're not inside a block - 'continue' is essentially a nop
|
|
|
|
# e.g. while (cond) continue; is the same as while (cond) ;
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt=';', t='None')
|
2015-03-05 12:12:32 -07:00
|
|
|
try:
|
|
|
|
if self.continuestack[n][1] is None:
|
|
|
|
# this can happen with e.g.:
|
|
|
|
# while (cond) while (cond) while (cond) continue 3;
|
|
|
|
# Transform to while(cond) while(cond) while(cond) break 2;
|
|
|
|
# which is equivalent since there are no {}.
|
2018-03-27 04:29:04 -07:00
|
|
|
n += 1 # e.g. -3 -> -2
|
2018-05-16 23:12:33 -07:00
|
|
|
self.breakstack[n][2] += 1 # add a reference to the break
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='JUMP', t=None, name=self.breakstack[n][0],
|
|
|
|
scope=self.breakstack[n][1])
|
2015-03-05 12:12:32 -07:00
|
|
|
except IndexError:
|
2017-04-28 18:33:45 -07:00
|
|
|
raise EParseInvalidBrkContArg(self)
|
2018-05-16 23:12:33 -07:00
|
|
|
self.continuestack[n][2] += 1
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='JUMP', t=None, name=self.continuestack[n][0],
|
|
|
|
scope=self.continuestack[n][1])
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok0 == 'TYPE':
|
|
|
|
if not AllowDecl:
|
|
|
|
raise EParseDeclarationScope(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = self.tok[1]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
name = self.tok[1]
|
2024-05-25 11:48:30 -07:00
|
|
|
if name in self.symtab[0] and self.symtab[0][name]['Kind'] == 'c':
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
if name in self.symtab[self.scopeindex]:
|
|
|
|
raise EParseAlreadyDefined(self)
|
|
|
|
self.NextToken()
|
|
|
|
value = None
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
decl = nr(nt='DECL', t=typ, name=name, scope=self.scopeindex)
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] == '=':
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
decl.ch = [self.autocastcheck(self.Parse_expression(), typ)]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
2015-03-26 18:12:32 -07:00
|
|
|
self.AddSymbol('v', self.scopeindex, name, Type=typ)
|
2014-07-29 19:54:16 -07:00
|
|
|
return decl
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# If none of the above, it must be an expression.
|
2019-01-01 12:03:02 -07:00
|
|
|
saveAllowVoid = self.allowVoid
|
|
|
|
self.allowVoid = True
|
2014-07-25 17:43:44 -07:00
|
|
|
value = self.Parse_expression()
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = saveAllowVoid
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(';')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='EXPR', t=value.t, ch=[value])
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
def Parse_code_block(self, ReturnType, AllowStSw = False, InsideSwitch = False,
|
|
|
|
InsideLoop = False):
|
2014-07-25 17:43:44 -07:00
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
code_block: '{' statements '}'
|
|
|
|
statements: LAMBDA | statements statement
|
|
|
|
|
|
|
|
It receives the return type to expect for return statements.
|
|
|
|
"""
|
|
|
|
self.expect('{')
|
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
self.PushScope()
|
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
# Kludge to find the scope of the break (for switch) /
|
|
|
|
# continue (for loops) labels.
|
2018-03-27 04:29:04 -07:00
|
|
|
if self.breakstack: # non-empty iff inside loop or switch
|
2015-03-05 12:12:32 -07:00
|
|
|
if InsideSwitch and self.breakstack[-1][1] is None:
|
|
|
|
self.breakstack[-1][1] = self.scopeindex
|
|
|
|
if InsideLoop and self.continuestack[-1][1] is None:
|
|
|
|
self.continuestack[-1][1] = self.scopeindex
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
body = []
|
2014-08-02 19:50:18 -07:00
|
|
|
LastIsReturn = False
|
2014-07-25 17:43:44 -07:00
|
|
|
while True:
|
|
|
|
if self.tok[0] == '}':
|
2020-10-11 07:31:49 -07:00
|
|
|
self.closebrace = self.errorpos
|
2014-07-25 17:43:44 -07:00
|
|
|
break
|
2015-03-04 17:37:32 -07:00
|
|
|
stmt = self.Parse_statement(ReturnType, AllowDecl = True,
|
|
|
|
AllowStSw = AllowStSw, InsideSwitch = InsideSwitch,
|
|
|
|
InsideLoop = InsideLoop)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
LastIsReturn = getattr(stmt, 'LIR', False)
|
2014-08-02 19:50:18 -07:00
|
|
|
body.append(stmt)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2018-12-26 11:47:22 -07:00
|
|
|
scope_braces = self.scopeindex
|
2014-07-25 17:43:44 -07:00
|
|
|
self.PopScope()
|
|
|
|
|
|
|
|
self.expect('}')
|
|
|
|
self.NextToken()
|
|
|
|
|
2018-12-26 11:47:22 -07:00
|
|
|
node = nr(nt='{}', t=None, scope=scope_braces, ch=body)
|
2014-08-02 19:50:18 -07:00
|
|
|
if LastIsReturn:
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
node.LIR = True
|
2014-08-02 19:50:18 -07:00
|
|
|
return node
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
def Parse_simple_expr(self, ForbidList=False):
|
2014-07-25 17:43:44 -07:00
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
simple_expr: simple_expr_except_list | list_simple_expr
|
|
|
|
simple_expr_except_list: STRING_VALUE | KEY_VALUE | VECTOR_VALUE
|
2022-10-31 09:20:25 -07:00
|
|
|
| ROTATION_VALUE | TRUE | FALSE | IDENT | number_value
|
2014-07-25 17:43:44 -07:00
|
|
|
| '<' simple_expr ',' simple_expr ',' simple_expr '>'
|
|
|
|
| '<' simple_expr ',' simple_expr ',' simple_expr ',' simple_expr '>'
|
|
|
|
number_value: FLOAT_VALUE | INTEGER_VALUE | '-' FLOAT_VALUE | '-' INTEGER_VALUE
|
|
|
|
list_simple_expr: '[' ']' | '[' list_simple_expr_items ']'
|
|
|
|
list_simple_expr_items: simple_expr_except_list
|
|
|
|
| list_simple_expr_items ',' simple_expr_except_list
|
|
|
|
"""
|
|
|
|
tok = self.tok
|
|
|
|
self.NextToken()
|
2018-03-27 04:29:04 -07:00
|
|
|
if tok[0] in ('TRUE', 'FALSE'): # TRUE and FALSE don't admit sign in globals
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CONST', t='integer', value=int(tok[0]=='TRUE'))
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok[0] in ('STRING_VALUE', 'KEY_VALUE', 'VECTOR_VALUE', 'ROTATION_VALUE', 'LIST_VALUE'):
|
2014-07-25 18:44:48 -07:00
|
|
|
val = tok[1]
|
|
|
|
if tok[0] == 'STRING_VALUE' and self.allowmultistrings:
|
|
|
|
while self.tok[0] == 'STRING_VALUE':
|
|
|
|
val += self.tok[1]
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CONST', t=lslcommon.PythonType2LSL[type(val)],
|
|
|
|
value=val)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok[0] == 'IDENT':
|
2014-07-29 19:54:16 -07:00
|
|
|
sym = self.FindSymbolPartial(tok[1])
|
2018-03-30 18:10:49 -07:00
|
|
|
# The parser accepts library function names here as valid variables
|
|
|
|
# (it chokes at RAIL in Mono, and at runtime in LSO for some types)
|
2024-05-25 11:48:30 -07:00
|
|
|
if sym is None or sym['Kind'] not in {'v', 'c'} and (sym['Kind'] !=
|
|
|
|
'f' or 'ParamNames' in sym): # only UDFs have ParamNames
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseUndefined(self)
|
2017-01-03 21:10:12 -07:00
|
|
|
typ = sym['Type']
|
|
|
|
if ForbidList and lslcommon.LSO and typ == 'key':
|
|
|
|
# This attempts to reproduce LSO's behaviour that a key global
|
|
|
|
# var inside a list global definition takes a string value
|
|
|
|
# (SCR-295).
|
|
|
|
typ = 'string'
|
2018-03-30 18:10:49 -07:00
|
|
|
return nr(nt='IDENT', t=typ, name=tok[1],
|
|
|
|
scope=sym['Scope'] if sym['Kind'] == 'v' else 0)
|
2014-07-25 17:43:44 -07:00
|
|
|
if tok[0] == '<':
|
|
|
|
value = [self.Parse_simple_expr()]
|
2014-07-29 19:54:16 -07:00
|
|
|
self.autocastcheck(value[0], 'float')
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
|
|
|
value.append(self.Parse_simple_expr())
|
2014-07-29 19:54:16 -07:00
|
|
|
self.autocastcheck(value[1], 'float')
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
|
|
|
value.append(self.Parse_simple_expr())
|
2014-07-29 19:54:16 -07:00
|
|
|
self.autocastcheck(value[2], 'float')
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] == '>':
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='VECTOR', t='vector', ch=value)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
|
|
|
value.append(self.Parse_simple_expr())
|
2014-07-29 19:54:16 -07:00
|
|
|
self.autocastcheck(value[3], 'float')
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('>')
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='ROTATION', t='rotation', ch=value)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
if tok[0] == '[' and not ForbidList:
|
2014-07-25 17:43:44 -07:00
|
|
|
value = []
|
|
|
|
if self.tok[0] == ']':
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='LIST', t='list', ch=value)
|
2014-07-25 17:43:44 -07:00
|
|
|
while True:
|
2014-07-29 19:54:16 -07:00
|
|
|
value.append(self.Parse_simple_expr(ForbidList=True))
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] == ']':
|
|
|
|
self.NextToken()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='LIST', t='list', ch=value)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect(',')
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
# Integer or Float constant expected
|
2014-07-25 17:43:44 -07:00
|
|
|
neg = False
|
|
|
|
if tok[0] == '-':
|
|
|
|
neg = True
|
|
|
|
tok = self.tok
|
|
|
|
self.NextToken()
|
|
|
|
if tok[0] not in ('INTEGER_VALUE', 'FLOAT_VALUE'):
|
|
|
|
raise EParseSyntax(self)
|
2014-07-29 19:54:16 -07:00
|
|
|
value = tok[1]
|
2015-02-11 20:23:47 -07:00
|
|
|
if neg and (tok[0] != 'INTEGER_VALUE' or value != -2147483648):
|
2014-07-29 19:54:16 -07:00
|
|
|
value = -value
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
return nr(nt='CONST',
|
|
|
|
t='float' if tok[0] == 'FLOAT_VALUE' else 'integer', value=value)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def Parse_optional_param_list(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
optional_param_list: LAMBDA | param_list
|
|
|
|
param_list: TYPE IDENT | param_list ',' TYPE IDENT
|
|
|
|
"""
|
2014-07-29 19:54:16 -07:00
|
|
|
types = []
|
|
|
|
names = []
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if self.tok[0] == 'TYPE':
|
|
|
|
while True:
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = self.tok[1]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
|
|
|
|
name = self.tok[1]
|
2024-05-25 11:48:30 -07:00
|
|
|
if (name in self.symtab[0]
|
|
|
|
and self.symtab[0][name]['Kind'] == 'c'
|
|
|
|
):
|
|
|
|
raise EParseSyntax(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
if name in self.symtab[self.scopeindex]:
|
|
|
|
raise EParseAlreadyDefined(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
types.append(typ)
|
|
|
|
names.append(name)
|
|
|
|
|
|
|
|
self.AddSymbol('v', self.scopeindex, name, Type=typ, Param=True)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != ',':
|
|
|
|
break
|
|
|
|
self.NextToken()
|
|
|
|
self.expect('TYPE')
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
return (types, names)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
def Parse_events(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
events: event | events event
|
|
|
|
event: EVENT_NAME '(' optional_parameter_list ')' code_block
|
|
|
|
"""
|
2018-03-27 04:29:04 -07:00
|
|
|
self.expect('EVENT_NAME') # mandatory
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
ret = []
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
while self.tok[0] == 'EVENT_NAME':
|
|
|
|
name = self.tok[1]
|
|
|
|
self.NextToken()
|
2014-08-01 08:57:55 -07:00
|
|
|
if name in self.localevents:
|
|
|
|
raise EParseAlreadyDefined(self)
|
|
|
|
self.localevents.add(name)
|
2014-07-25 17:43:44 -07:00
|
|
|
self.expect('(')
|
|
|
|
self.NextToken()
|
|
|
|
# Function parameters go to a dedicated symbol table.
|
|
|
|
self.PushScope()
|
|
|
|
params = self.Parse_optional_param_list()
|
2014-08-01 08:57:55 -07:00
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
# NOTE: Parse_events: This is a bit crude, as the error is given at the end of the param list.
|
|
|
|
# To do it correctly, we can pass the parameter list to Parse_optional_param_list().
|
2017-10-25 08:46:50 -07:00
|
|
|
if tuple(params[0]) != self.events[name]['pt']:
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseSyntax(self)
|
2014-07-31 15:33:20 -07:00
|
|
|
self.locallabels = set()
|
2014-07-29 19:54:16 -07:00
|
|
|
body = self.Parse_code_block(None)
|
2014-07-31 15:33:20 -07:00
|
|
|
del self.locallabels
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
ret.append(nr(nt='FNDEF', t=None, name=name, # no scope as these are reserved words
|
|
|
|
pscope=self.scopeindex, ptypes=params[0], pnames=params[1],
|
|
|
|
ch=[body]))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.PopScope()
|
|
|
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
def Parse_globals(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
globals: LAMBDA | globals var_def | globals func_def
|
|
|
|
var_def: TYPE IDENT ';' | TYPE IDENT '=' simple_expr ';'
|
|
|
|
func_def: optional_type IDENT '(' optional_param_list ')' code_block
|
|
|
|
optional_type: LAMBDA | TYPE
|
|
|
|
"""
|
2015-03-26 16:26:56 -07:00
|
|
|
assert self.scopeindex == 0
|
2014-07-25 17:43:44 -07:00
|
|
|
while self.tok[0] in ('TYPE','IDENT'):
|
|
|
|
typ = None
|
|
|
|
if self.tok[0] == 'TYPE':
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = self.tok[1]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.expect('IDENT')
|
|
|
|
|
|
|
|
name = self.tok[1]
|
|
|
|
self.NextToken()
|
2015-03-26 16:26:56 -07:00
|
|
|
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']] = \
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
nr(nt='LAMBDA', t=None)
|
2015-03-26 16:26:56 -07:00
|
|
|
del self.symtab[0][name]
|
|
|
|
if report:
|
|
|
|
raise EParseAlreadyDefined(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-30 19:47:19 -07:00
|
|
|
if self.tok[0] in ('=', ';'):
|
2014-07-25 17:43:44 -07:00
|
|
|
# This is a variable definition
|
2018-03-27 04:29:04 -07:00
|
|
|
if typ is None: # Typeless variables are not allowed
|
2014-07-25 17:43:44 -07:00
|
|
|
raise EParseSyntax(self)
|
|
|
|
|
|
|
|
if self.tok[0] == '=':
|
|
|
|
self.NextToken()
|
|
|
|
if self.extendedglobalexpr:
|
2018-03-27 04:29:04 -07:00
|
|
|
self.disallowglobalvars = True # Disallow forward globals.
|
2014-07-30 19:47:19 -07:00
|
|
|
# Mark backtracking position
|
|
|
|
pos = self.pos
|
|
|
|
errorpos = self.errorpos
|
|
|
|
tok = self.tok
|
|
|
|
try:
|
|
|
|
value = self.Parse_simple_expr()
|
|
|
|
self.expect(';')
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
value.Simple = True # Success - mark it as simple
|
2014-07-30 19:47:19 -07:00
|
|
|
except EParse:
|
|
|
|
# Backtrack
|
|
|
|
self.pos = pos
|
|
|
|
self.errorpos = errorpos
|
|
|
|
self.tok = tok
|
|
|
|
# Use advanced expression evaluation.
|
|
|
|
value = self.Parse_expression()
|
|
|
|
self.expect(';')
|
2018-03-27 04:29:04 -07:00
|
|
|
self.disallowglobalvars = False # Allow forward globals again.
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2014-07-30 19:47:19 -07:00
|
|
|
# Use LSL's dull global expression.
|
|
|
|
value = self.Parse_simple_expr()
|
|
|
|
self.expect(';')
|
2018-05-17 10:05:00 -07:00
|
|
|
value.Simple = True
|
2018-03-27 04:29:04 -07:00
|
|
|
else: # must be semicolon
|
2014-07-25 17:43:44 -07:00
|
|
|
value = None
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
assert self.scopeindex == 0
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
decl = nr(nt='DECL', t=typ, name=name, scope=0)
|
2014-07-25 17:43:44 -07:00
|
|
|
if value is not None:
|
2014-07-29 19:54:16 -07:00
|
|
|
value = self.autocastcheck(value, typ)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
decl.ch = [value]
|
2016-04-04 04:58:25 -07:00
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
self.AddSymbol('v', 0, name, Loc=len(self.tree), Type=typ)
|
|
|
|
self.tree.append(decl)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
elif self.tok[0] == '(':
|
|
|
|
# This is a function definition
|
|
|
|
self.NextToken()
|
2014-07-29 19:54:16 -07:00
|
|
|
self.PushScope()
|
2014-07-25 17:43:44 -07:00
|
|
|
params = self.Parse_optional_param_list()
|
|
|
|
self.expect(')')
|
|
|
|
self.NextToken()
|
2014-08-01 14:51:24 -07:00
|
|
|
self.localevents = None
|
2014-07-31 15:33:20 -07:00
|
|
|
self.locallabels = set()
|
2019-01-01 14:29:12 -07:00
|
|
|
force_inline = False
|
|
|
|
if (self.enable_inline and self.tok[0] == 'IDENT'
|
|
|
|
and self.tok[1] == 'inline'):
|
|
|
|
self.NextToken()
|
|
|
|
force_inline = True
|
2014-07-29 19:54:16 -07:00
|
|
|
body = self.Parse_code_block(typ)
|
2014-07-31 15:33:20 -07:00
|
|
|
del self.locallabels
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
if typ and not getattr(body, 'LIR', False): # is LastIsReturn flag set?
|
2020-10-11 07:31:49 -07:00
|
|
|
self.errorpos = self.closebrace
|
2014-08-02 19:50:18 -07:00
|
|
|
raise EParseCodePathWithoutRet(self)
|
2014-07-25 17:43:44 -07:00
|
|
|
paramscope = self.scopeindex
|
2014-07-29 19:54:16 -07:00
|
|
|
self.AddSymbol('f', 0, name, Loc=len(self.tree), Type=typ,
|
2019-01-01 14:29:12 -07:00
|
|
|
Inline=force_inline,
|
2014-07-29 19:54:16 -07:00
|
|
|
ParamTypes=params[0], ParamNames=params[1])
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
self.tree.append(nr(nt='FNDEF', t=typ, name=name, scope=0,
|
2019-01-01 14:29:12 -07:00
|
|
|
pscope=paramscope, ptypes=params[0], pnames=params[1],
|
|
|
|
ch=[body]))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.PopScope()
|
2014-07-29 19:54:16 -07:00
|
|
|
assert self.scopeindex == 0
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
raise EParseSyntax(self)
|
|
|
|
pass
|
|
|
|
|
|
|
|
def Parse_states(self):
|
|
|
|
"""Grammar parsed here:
|
|
|
|
|
|
|
|
states: LAMBDA | states state
|
|
|
|
state: state_header '{' events '}'
|
|
|
|
state_header: DEFAULT | STATE IDENT
|
|
|
|
|
|
|
|
(but we enforce DEFAULT to be the first token found, meaning there will
|
|
|
|
be at least one state and the first must be DEFAULT as in the original
|
|
|
|
grammar)
|
|
|
|
"""
|
|
|
|
self.expect('DEFAULT')
|
|
|
|
|
|
|
|
while True:
|
|
|
|
if self.tok[0] != 'DEFAULT' and self.tok[0] != 'STATE':
|
|
|
|
return
|
|
|
|
|
|
|
|
if self.tok[0] == 'DEFAULT':
|
2014-07-29 19:54:16 -07:00
|
|
|
name = 'default'
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != 'IDENT':
|
|
|
|
raise EParseSyntax(self)
|
|
|
|
name = self.tok[1]
|
|
|
|
|
|
|
|
if name in self.symtab[self.scopeindex]:
|
|
|
|
raise EParseAlreadyDefined(self)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
assert self.scopeindex == 0
|
|
|
|
self.AddSymbol('s', 0, name, Loc=len(self.tree))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
self.expect('{')
|
|
|
|
self.NextToken()
|
|
|
|
|
2014-08-01 08:57:55 -07:00
|
|
|
self.localevents = set()
|
2014-07-25 17:43:44 -07:00
|
|
|
events = self.Parse_events()
|
2014-08-01 08:57:55 -07:00
|
|
|
del self.localevents
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
self.expect('}')
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
self.tree.append(nr(nt='STDEF', t=None, name=name, scope=0,
|
|
|
|
ch=events))
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
def Parse_script(self):
|
|
|
|
"""Parses the whole LSL script
|
|
|
|
|
|
|
|
Grammar parsed here:
|
|
|
|
|
|
|
|
script: globals states EOF
|
|
|
|
"""
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
# We need a table of undefined jump references, to check later,
|
|
|
|
# as jumps are local, not global, and allow forward definitions.
|
|
|
|
# This avoids making one more pass, or making the first pass more
|
|
|
|
# detailed unnecessarily.
|
|
|
|
self.jump_lookups = []
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2015-03-26 18:12:32 -07:00
|
|
|
self.globalmode = True
|
2014-07-25 17:43:44 -07:00
|
|
|
self.Parse_globals()
|
2015-03-26 18:12:32 -07:00
|
|
|
self.globalmode = False
|
2014-07-25 17:43:44 -07:00
|
|
|
self.Parse_states()
|
|
|
|
self.expect('EOF')
|
|
|
|
|
2018-12-29 09:55:07 -07:00
|
|
|
assert len(self.scopestack) == 1 and self.scopestack[0] == 0
|
|
|
|
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
# Check the pending jump targets to assign them the scope of the label.
|
2014-07-25 17:43:44 -07:00
|
|
|
for tgt in self.jump_lookups:
|
2018-12-29 09:55:07 -07:00
|
|
|
self.scopestack = tgt[1]
|
|
|
|
self.scopeindex = self.scopestack[-1]
|
2014-07-31 20:07:50 -07:00
|
|
|
sym = self.FindSymbolPartial(tgt[0], MustBeLabel = True)
|
|
|
|
if sym is None:
|
2014-07-25 17:43:44 -07:00
|
|
|
self.errorpos = tgt[2]
|
|
|
|
raise EParseUndefined(self)
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
tgt[3].scope = sym['Scope']
|
2018-05-16 23:12:33 -07:00
|
|
|
sym['ref'] += 1
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2018-03-27 04:29:04 -07:00
|
|
|
del self.jump_lookups # Finished with it.
|
2018-12-29 09:55:07 -07:00
|
|
|
self.scopestack = [0]
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2016-12-14 18:42:12 -07:00
|
|
|
def Parse_single_expression(self):
|
|
|
|
"""Parse the script as an expression, Used by lslcalc.
|
|
|
|
|
|
|
|
Grammar parsed here:
|
|
|
|
|
|
|
|
script: expression EOF
|
|
|
|
"""
|
|
|
|
value = self.Parse_expression()
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
self.tree.append(nr(nt='EXPR', t=value.t, ch=[value]))
|
2016-12-14 20:12:02 -07:00
|
|
|
self.expect('EOF')
|
2016-12-14 18:42:12 -07:00
|
|
|
return
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
def BuildTempGlobalsTable(self):
|
|
|
|
"""Build an approximate globals table.
|
|
|
|
|
|
|
|
If the script syntax is correct, the globals table will be accurate.
|
|
|
|
If it is not, it may contain too many or too few symbols (normally the
|
|
|
|
latter). This globals table is not the normal globals in the symbol
|
2014-07-29 19:54:16 -07:00
|
|
|
table; it's just needed to resolve forward references. It's temporary.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
The grammar is approximately:
|
|
|
|
script: globals states
|
|
|
|
globals: [global [global [...]]]
|
|
|
|
global: [TYPE] IDENT '(' TYPE anytoken [',' TYPE anytoken [...]]
|
|
|
|
anytoken_except_comma balanced_braces_or_anything_else
|
|
|
|
| TYPE IDENT [anytoken_except_semicolon [...]] ';'
|
|
|
|
states: state [state [...]]
|
|
|
|
state: (DEFAULT | STATE IDENT) balanced_braces_or_anything_else
|
|
|
|
"""
|
2018-03-27 04:29:04 -07:00
|
|
|
ret = self.funclibrary.copy() # The library functions go here too.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# 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
|
|
|
|
# location and cause.
|
|
|
|
|
|
|
|
# Here we don't even care if it's duplicate - that will be caught
|
|
|
|
# when adding to the real symbol table.
|
|
|
|
|
|
|
|
# Scan globals
|
|
|
|
try:
|
|
|
|
while self.tok[0] not in ('DEFAULT', 'EOF'):
|
|
|
|
typ = None
|
|
|
|
if self.tok[0] == 'TYPE':
|
2014-07-29 19:54:16 -07:00
|
|
|
typ = self.tok[1]
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != 'IDENT':
|
|
|
|
return ret
|
|
|
|
name = self.tok[1]
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] == '(':
|
|
|
|
# Function call
|
|
|
|
self.NextToken()
|
|
|
|
params = []
|
|
|
|
if self.tok[0] != ')':
|
|
|
|
while True:
|
|
|
|
if self.tok[0] != 'TYPE':
|
|
|
|
return ret
|
2014-07-29 19:54:16 -07:00
|
|
|
params.append(self.tok[1])
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
2018-03-27 04:29:04 -07:00
|
|
|
self.NextToken() # not interested in parameter names
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] != ',':
|
|
|
|
break
|
|
|
|
self.NextToken()
|
|
|
|
self.NextToken()
|
2019-01-01 14:29:12 -07:00
|
|
|
if self.tok[0] == 'IDENT' and self.tok[1] == 'inline':
|
|
|
|
self.NextToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
if self.tok[0] != '{':
|
|
|
|
return ret
|
2018-03-27 04:29:04 -07:00
|
|
|
self.NextToken() # Enter the first brace
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
bracelevel = 1
|
|
|
|
while bracelevel and self.tok[0] != 'EOF':
|
|
|
|
if self.tok[0] == '{':
|
|
|
|
bracelevel += 1
|
|
|
|
elif self.tok[0] == '}':
|
|
|
|
bracelevel -= 1
|
|
|
|
self.NextToken()
|
2017-10-21 01:42:46 -07:00
|
|
|
ret[name] = {'Kind':'f', 'Type':typ, 'ParamTypes':params,
|
|
|
|
'uns':True}
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
elif typ is None:
|
2018-03-27 04:29:04 -07:00
|
|
|
return ret # A variable needs a type
|
2014-07-25 17:43:44 -07:00
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
# No location info but none is necessary for forward
|
|
|
|
# declarations.
|
|
|
|
ret[name] = {'Kind':'v','Type':typ,'Scope':0}
|
2018-03-27 04:29:04 -07:00
|
|
|
while self.tok[0] != ';': # Don't stop to analyze what's before the ending ';'
|
2015-02-10 21:43:13 -07:00
|
|
|
if self.tok[0] == 'EOF':
|
|
|
|
return ret
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
self.NextToken()
|
|
|
|
except EParseUEOF:
|
|
|
|
return ret
|
|
|
|
|
|
|
|
# Scan states
|
|
|
|
while True:
|
|
|
|
if self.tok[0] not in ('DEFAULT', 'STATE'):
|
2018-03-27 04:29:04 -07:00
|
|
|
return ret # includes EOF i.e. this is the normal return
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
if self.tok[0] == 'STATE':
|
|
|
|
self.NextToken()
|
|
|
|
if self.tok[0] != 'IDENT':
|
|
|
|
return ret
|
|
|
|
name = self.tok[1]
|
|
|
|
else:
|
2014-07-29 19:54:16 -07:00
|
|
|
name = 'default'
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
# No location info but none is necessary for forward declarations.
|
|
|
|
ret[name] = {'Kind':'s'}
|
2014-07-25 17:43:44 -07:00
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
if self.tok[0] != '{':
|
|
|
|
return ret
|
2018-03-27 04:29:04 -07:00
|
|
|
self.NextToken() # Enter the first brace
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
bracelevel = 1
|
|
|
|
while bracelevel and self.tok[0] != 'EOF':
|
|
|
|
if self.tok[0] == '{':
|
|
|
|
bracelevel += 1
|
|
|
|
elif self.tok[0] == '}':
|
|
|
|
bracelevel -= 1
|
|
|
|
self.NextToken()
|
|
|
|
|
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
def parse(self, script, options = (), filename = '<stdin>', lib = None):
|
|
|
|
"""Parse the given string with the given options.
|
|
|
|
|
|
|
|
If given, lib replaces the library passed in __init__.
|
|
|
|
|
|
|
|
filename is the filename of the current file, for error reporting.
|
|
|
|
'<stdin>' means errors in this file won't include a filename.
|
|
|
|
#line directives change the filename.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
This function also builds the temporary globals table.
|
|
|
|
"""
|
2015-03-15 11:19:57 -07:00
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
if lib is None:
|
|
|
|
lib = self.lib
|
2024-05-28 04:24:42 -07:00
|
|
|
self.events = lib[0].copy()
|
|
|
|
self.constants = lib[1].copy()
|
|
|
|
self.funclibrary = lib[2].copy()
|
2017-10-20 07:26:05 -07:00
|
|
|
|
2018-12-22 07:44:14 -07:00
|
|
|
self.TypeToExtractionFunction.clear()
|
|
|
|
for name in self.funclibrary:
|
|
|
|
fn = self.funclibrary[name]
|
|
|
|
if 'ListTo' in fn:
|
|
|
|
self.TypeToExtractionFunction[fn['ListTo']] = name
|
|
|
|
|
2017-10-10 20:04:13 -07:00
|
|
|
self.filename = filename
|
|
|
|
|
2020-11-08 18:28:57 -07:00
|
|
|
script = any2str(script, 'utf8')
|
2015-03-15 11:19:57 -07:00
|
|
|
|
2015-05-02 20:19:14 -07:00
|
|
|
self.script = script
|
2014-07-25 17:43:44 -07:00
|
|
|
self.length = len(script)
|
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
self.keywords = self.base_keywords.copy()
|
2016-06-27 11:33:47 -07:00
|
|
|
|
2016-06-27 11:32:59 -07:00
|
|
|
self.labelcnt = 0
|
|
|
|
|
|
|
|
# Options
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# Extended expressions in globals (needs support from the optimizer to work)
|
|
|
|
self.extendedglobalexpr = 'extendedglobalexpr' in options
|
|
|
|
|
|
|
|
# Extended typecast syntax (typecast as a regular unary operator)
|
|
|
|
self.extendedtypecast = 'extendedtypecast' in options
|
|
|
|
|
|
|
|
# Extended assignment operators: |= &= <<= >>=
|
|
|
|
self.extendedassignment = 'extendedassignment' in options
|
|
|
|
|
|
|
|
# Add explicit type casts when implicit (the output module takes care of
|
|
|
|
# the correctness of the output)
|
|
|
|
self.explicitcast = 'explicitcast' in options
|
|
|
|
|
2014-07-25 19:41:09 -07:00
|
|
|
# Allow string + key = string and key + string = string
|
|
|
|
self.allowkeyconcat = 'allowkeyconcat' in options
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-25 18:44:48 -07:00
|
|
|
# Allow C style string composition of strings: "blah" "blah" = "blahblah"
|
|
|
|
self.allowmultistrings = 'allowmultistrings' in options
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2016-06-27 18:20:21 -07:00
|
|
|
# Process preprocessor directives (especially #pragma and #line).
|
|
|
|
self.processpre = 'processpre' in options
|
2014-07-27 12:05:01 -07:00
|
|
|
|
2015-02-26 20:46:23 -07:00
|
|
|
# TODO: Allow pure C-style string escapes. This is low-priority.
|
2014-07-25 18:59:35 -07:00
|
|
|
#self.allowcescapes = 'allowcescapes' in options
|
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
# Enable switch statements.
|
|
|
|
self.enableswitch = 'enableswitch' in options
|
|
|
|
if self.enableswitch:
|
2016-06-27 11:33:47 -07:00
|
|
|
self.keywords |= self.switch_keywords
|
2014-07-25 19:57:58 -07:00
|
|
|
|
2016-05-06 11:15:46 -07:00
|
|
|
# Broken behaviour in the absence of a default: label in a switch stmt.
|
2016-05-06 17:38:54 -07:00
|
|
|
self.errmissingdefault = 'errmissingdefault' in options
|
2016-05-06 11:15:46 -07:00
|
|
|
|
2015-03-03 09:59:51 -07:00
|
|
|
# Allow brackets for assignment of list elements e.g. mylist[5]=4
|
|
|
|
self.lazylists = 'lazylists' in options
|
2014-07-25 19:57:58 -07:00
|
|
|
|
2015-03-03 16:40:07 -07:00
|
|
|
# This was once an idea, but it has been discarded because
|
|
|
|
# llListReplaceList requires the argument to be evaluated twice,
|
|
|
|
# so the function is unavoidable. Consider e.g. L[x++] = 3 expanded to
|
|
|
|
# L = llListReplaceList(L, [3], x++, x++).
|
|
|
|
# # Extend the list with integer zeros when lazylists is active and the
|
|
|
|
# # index is greater than the end of the list.
|
|
|
|
# self.lazylistcompat = 'lazylistcompat' in options
|
|
|
|
|
2015-03-04 17:37:32 -07:00
|
|
|
# Enable break/continue
|
|
|
|
self.breakcont = 'breakcont' in options
|
|
|
|
if self.breakcont:
|
2016-06-27 11:33:47 -07:00
|
|
|
self.keywords |= self.brkcont_keywords
|
2015-03-04 17:37:32 -07:00
|
|
|
|
2015-03-05 12:12:32 -07:00
|
|
|
# Stack to track the labels for break targets, their scope table index,
|
|
|
|
# and whether they are used.
|
2018-12-26 11:47:22 -07:00
|
|
|
# Elements are sublist with 0 = destination label name, 1 = scope for
|
|
|
|
# that label, and 2 = reference count of the label.
|
2015-03-05 12:12:32 -07:00
|
|
|
self.breakstack = []
|
|
|
|
# Stack to track the labels for continue targets, their scope index,
|
|
|
|
# and whether they are used.
|
|
|
|
self.continuestack = []
|
2014-12-13 05:12:02 -07:00
|
|
|
|
2014-07-31 15:33:20 -07:00
|
|
|
# Enable use of local labels with duplicate names
|
|
|
|
self.duplabels = 'duplabels' in options
|
|
|
|
|
2014-07-31 16:41:21 -07:00
|
|
|
# Shrink names. Activates duplabels automatically.
|
|
|
|
self.shrinknames = 'shrinknames' in options
|
|
|
|
|
2015-03-26 16:26:56 -07:00
|
|
|
# Allow a duplicate function definition to override the former,
|
|
|
|
# rather than reporting a duplicate identifier error.
|
|
|
|
self.funcoverride = 'funcoverride' in options
|
|
|
|
|
2015-03-26 18:12:32 -07:00
|
|
|
# This was an idea, but functions must return a type, and making the
|
|
|
|
# type suitable for the context is too much work.
|
|
|
|
# # Allow referencing undefined functions inside function definitions.
|
|
|
|
# self.allowundeffn = 'allowundeffn' in options
|
|
|
|
|
2017-11-19 11:48:35 -07:00
|
|
|
# Prettify a source file
|
|
|
|
self.prettify = 'prettify' in options
|
|
|
|
|
2018-04-01 11:05:35 -07:00
|
|
|
# We've decided to ditch support for optimization when the code
|
|
|
|
# includes a label as the immediate child of FOR, IF, DO or WHILE.
|
|
|
|
# If optimization is on, such a label will raise an error. That
|
|
|
|
# coding pattern is normally easy to work around anyway.
|
2018-04-09 09:42:31 -07:00
|
|
|
self.optenabled = 'optimize' in options
|
2018-04-01 11:05:35 -07:00
|
|
|
|
2019-01-01 14:29:12 -07:00
|
|
|
# Inline keyword
|
|
|
|
self.enable_inline = 'inline' in options
|
|
|
|
|
2019-02-04 09:20:12 -07:00
|
|
|
# Automated Processing friendly error messages
|
|
|
|
self.emap = 'emap' in options
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# 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
|
2018-12-29 09:55:07 -07:00
|
|
|
# dictionary of symbols, whose elements are in turn dictionaries of
|
|
|
|
# attributes. Each has a 'Kind', which can be:
|
2024-05-25 11:48:30 -07:00
|
|
|
# 'v' for variable, 'c' for constant, 'f' for function, 'l' for label,
|
|
|
|
# 's' for state, or 'e' for event. Some have a 'Loc' indicating the
|
|
|
|
# location (index) of the definition in the tree's root.
|
|
|
|
# Variables and constants have 'Scope' and 'Type' (a string).
|
2015-03-26 18:12:32 -07:00
|
|
|
# Global variables also have 'Loc'.
|
2018-12-29 09:55:07 -07:00
|
|
|
# Variables that are parameters also have 'Param'.
|
2024-05-25 11:48:30 -07:00
|
|
|
# Functions have 'Type' (return type, a string) and 'ParamTypes' (a
|
|
|
|
# list of strings).
|
|
|
|
# User-defined functions also have 'Loc' and 'ParamNames' (a list of
|
|
|
|
# strings).
|
2014-07-29 19:54:16 -07:00
|
|
|
# Labels only have 'Scope'.
|
|
|
|
# States only have 'Loc'.
|
2015-03-26 18:12:32 -07:00
|
|
|
# Events have 'ParamTypes' and 'ParamNames', just like UDFs.
|
2014-07-29 19:54:16 -07:00
|
|
|
# Other modules may add information if they need.
|
|
|
|
|
2015-03-26 16:26:56 -07:00
|
|
|
# Incorporate the library into the initial symbol table.
|
|
|
|
self.symtab = [self.funclibrary.copy()]
|
2018-12-29 09:55:07 -07:00
|
|
|
|
|
|
|
# Current scope index
|
2014-07-25 17:43:44 -07:00
|
|
|
self.scopeindex = 0
|
|
|
|
|
2018-12-29 09:55:07 -07:00
|
|
|
# Stack of scopes in which to look for a symbol as we parse
|
|
|
|
self.scopestack = [0]
|
|
|
|
|
2017-11-19 11:48:35 -07:00
|
|
|
if self.prettify:
|
2024-05-28 04:24:42 -07:00
|
|
|
# Add all constants to the blacklist
|
|
|
|
self.blacklist = list(u2str(i) for i in self.constants.keys())
|
2017-11-19 11:48:35 -07:00
|
|
|
# Remove TRUE and FALSE from keywords
|
|
|
|
self.keywords -= set(('TRUE', 'FALSE'))
|
|
|
|
|
2024-05-28 04:24:42 -07:00
|
|
|
# Some unit tests that reuse the parser object don't initialize the
|
|
|
|
# blacklist, so we don't rely on it being set.
|
|
|
|
if not hasattr(self, 'blacklist'):
|
|
|
|
self.blacklist = []
|
|
|
|
|
|
|
|
for name in self.blacklist:
|
|
|
|
# Add the blacklisted constants to the symbol table...
|
|
|
|
self.symtab[0][name] = {'Kind':'c', 'Scope':0, 'W':False,
|
|
|
|
'Type':lslcommon.PythonType2LSL[type(self.constants[name])]}
|
|
|
|
# ... and remove them from the list of substitutable constants.
|
|
|
|
del self.constants[name]
|
|
|
|
assert not self.prettify or len(self.constants) == 0
|
|
|
|
|
2017-10-10 20:04:13 -07:00
|
|
|
# Last preprocessor __FILE__. <stdin> means the current file.
|
|
|
|
self.lastFILE = '<stdin>'
|
|
|
|
|
|
|
|
# List of preprocessor #line directives.
|
|
|
|
self.linedir = []
|
|
|
|
|
2019-04-30 19:03:58 -07:00
|
|
|
# List of tuples (position, exception) where suspicious state change
|
|
|
|
# statements or returns with void expressions happen. These can only
|
|
|
|
# be detected when the 'else' is found.
|
|
|
|
self.PruneBug = []
|
Fix EParseCantChangeState so that it is always properly reported.
Still somewhat messy, but still reported as soon as it can be detected.
If an ELSE token is detected at the top level, for example, the error position will be rewound to the state change and reported there.
This means that in this situation:
x()
{
if (1)
{
state default;
x(2);
}
else ;
}
default{timer(){}}
an error will be reported in x(2), because the ELSE hasn't been found at that point, therefore the state change statement isn't found to be at fault yet.
However, in this case:
x()
{
if (1)
state default;
else
x(2);
}
default{timer(){}}
the error WILL be reported at the state change statement.
This commit also changes the position where the exception is reported, to be at the STATE token. As an inconsequential side effect, EParseCantChangeState takes precedence over undefined identifiers, in case the state change is to an undefined state, but only in cases where it can be immediately detected.
2017-11-02 05:31:06 -07:00
|
|
|
|
2014-07-27 09:42:55 -07:00
|
|
|
# This is a small hack to prevent circular definitions in globals when
|
|
|
|
# extended expressions are enabled. When false (default), forward
|
|
|
|
# globals are allowed; if true, only already seen globals are permitted.
|
2015-03-26 18:12:32 -07:00
|
|
|
self.disallowglobalvars = False
|
2014-07-27 09:42:55 -07:00
|
|
|
|
2019-01-01 14:44:54 -07:00
|
|
|
# Hack to determine where to allow void expressions.
|
2019-01-01 12:03:02 -07:00
|
|
|
self.allowVoid = False
|
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# Globals and labels can be referenced before they are defined. That
|
|
|
|
# includes states.
|
|
|
|
#
|
|
|
|
# Our first approach was going to be to build a list that keeps track of
|
|
|
|
# undefined references, to check them after parsing. But that has a big
|
|
|
|
# problem: expressions need to know the types of the arguments in order
|
|
|
|
# to give appropriate errors if they don't suit the operand, and in
|
|
|
|
# order to mark and check the types appropriately. But we don't know the
|
|
|
|
# types of the globals that haven't been found yet. Therefore, sticking
|
|
|
|
# to this approach would mean to scan the tree for every expression with
|
|
|
|
# a pending reference, fixing up every node upstream with the correct
|
|
|
|
# type with the possibility to find a type mismatch in a place for which
|
|
|
|
# we have no location info.
|
|
|
|
#
|
|
|
|
# For that reason, we change the strategy. We still don't want to do
|
|
|
|
# two full or almost full passes of the parser, nitpicking on every
|
|
|
|
# detail. But given LSL's structure, it's relatively easy to do a fast
|
|
|
|
# incomplete parsing pass, gathering globals with their types and
|
|
|
|
# function arguments. And that's what we do.
|
|
|
|
|
Fix EParseCantChangeState so that it is always properly reported.
Still somewhat messy, but still reported as soon as it can be detected.
If an ELSE token is detected at the top level, for example, the error position will be rewound to the state change and reported there.
This means that in this situation:
x()
{
if (1)
{
state default;
x(2);
}
else ;
}
default{timer(){}}
an error will be reported in x(2), because the ELSE hasn't been found at that point, therefore the state change statement isn't found to be at fault yet.
However, in this case:
x()
{
if (1)
state default;
else
x(2);
}
default{timer(){}}
the error WILL be reported at the state change statement.
This commit also changes the position where the exception is reported, to be at the STATE token. As an inconsequential side effect, EParseCantChangeState takes precedence over undefined identifiers, in case the state change is to an undefined state, but only in cases where it can be immediately detected.
2017-11-02 05:31:06 -07:00
|
|
|
self.scanglobals = True # Tell the lexer not to process directives
|
2016-01-01 19:39:47 -07:00
|
|
|
self.pos = self.errorpos = 0
|
2016-06-27 07:50:09 -07:00
|
|
|
self.linestart = True
|
2019-01-17 12:26:46 -07:00
|
|
|
self.tok = self.GetToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2016-12-20 16:22:49 -07:00
|
|
|
self.globals = self.BuildTempGlobalsTable() if not lslcommon.IsCalc \
|
2016-12-20 13:25:33 -07:00
|
|
|
else self.funclibrary.copy()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
|
|
|
# Restart
|
|
|
|
|
2016-06-27 09:50:31 -07:00
|
|
|
self.scanglobals = False
|
2016-01-01 19:39:47 -07:00
|
|
|
self.pos = self.errorpos = 0
|
2016-06-27 07:50:09 -07:00
|
|
|
self.linestart = True
|
2019-01-17 12:26:46 -07:00
|
|
|
self.tok = self.GetToken()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2015-03-03 09:59:51 -07:00
|
|
|
# Reserve spots at the beginning for functions we add
|
Change the AST node type from dict to object
That was long overdue. Obviously, this is a large commit.
The new nr (node record) class has built-in dump capabilities, rather than using print_node().
SEF always exists now, and is a boolean, rather than using the existence of SEF as the flag. This was changed for sanity. However, other flags like 'X' are still possibly absent, and in some cases the absence itself has meaning (in the case of 'X', its absence means that the node has not yet been analyzed).
Similarly, an event is distinguished from a UDF by checking for the existence of the 'scope' attribute. This trick works because events are not in the symbol table therefore they have no scope. But this should probably be changed in future to something more rational and faster.
A few minor bugfixes were applied while going through the code.
- Some tabs used as Unicode were written as byte strings. Add the u'\t' prefix.
- After simplifying a%1 -> a&0, fold again the node and return. It's not clear why it didn't return, and whether it depended on subsequent passes (e.g. after DCR) for possibly optimizing out the result. Now we're sure.
- A few places lacked a SEF declaration.
- Formatting changes to split lines that spilled the margin.
- Some comment changes.
- Expanded lazy_list_set definition while adapting it to object format. The plan was to re-compress it after done, but decided to leave it in expanded form.
- Added a few TODOs & FIXMEs, resisting the temptation to fix them in the same commit:
- TODO: ~-~-~-expr -> expr + -3.
- FIXME: Now that we have CompareTrees, we can easily check if expr + -expr cancels out and remove a TODO. Low-hanging fruit.
- TODO: Check what we can do when comparing non-SEF and non-CONST values in '>' (current code relies on converting '>' to '<' for applying more optimizations, but that may miss some opportunities).
- FIXME: Could remove one comparison in nt == '&&' or nt == '||'. Low-hanging fruit.
2018-03-27 15:19:08 -07:00
|
|
|
self.tree = [nr(nt='LAMBDA', t=None)]
|
2015-03-03 09:59:51 -07:00
|
|
|
self.usedspots = 0
|
2014-07-29 19:54:16 -07:00
|
|
|
|
2014-07-25 17:43:44 -07:00
|
|
|
# Start the parsing proper
|
2016-12-20 16:22:49 -07:00
|
|
|
if lslcommon.IsCalc:
|
2016-12-14 18:42:12 -07:00
|
|
|
self.Parse_single_expression()
|
|
|
|
else:
|
|
|
|
self.Parse_script()
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2014-07-31 16:41:21 -07:00
|
|
|
# No longer needed. The data is already in self.symtab[0].
|
|
|
|
del self.globals
|
2018-12-29 09:55:07 -07:00
|
|
|
del self.scopestack
|
2014-07-29 19:54:16 -07:00
|
|
|
|
2019-01-01 14:29:12 -07:00
|
|
|
if self.enable_inline:
|
2020-11-08 17:51:24 -07:00
|
|
|
from lslopt import lslinliner
|
2019-01-01 14:29:12 -07:00
|
|
|
lslinliner.inliner().inline(self.tree, self.symtab)
|
|
|
|
|
2014-07-29 19:54:16 -07:00
|
|
|
treesymtab = self.tree, self.symtab
|
|
|
|
del self.tree
|
|
|
|
del self.symtab
|
|
|
|
|
|
|
|
return treesymtab
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
def parsefile(self, filename, options = set(), lib = None):
|
|
|
|
"""Convenience function to parse a file rather than a string."""
|
2015-03-14 18:18:01 -07:00
|
|
|
f = open(filename, 'r')
|
2014-07-25 17:43:44 -07:00
|
|
|
try:
|
|
|
|
script = f.read()
|
|
|
|
finally:
|
|
|
|
f.close()
|
|
|
|
|
2019-02-04 09:20:12 -07:00
|
|
|
return self.parse(script, options, filename, lib)
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
def __init__(self, lib = None):
|
|
|
|
"""Initialization of library and lazy compilation.
|
2014-07-25 17:43:44 -07:00
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
lib is a tuple of three dictionaries: events, constants and functions,
|
|
|
|
in the format returned by lslloadlib.LoadLibrary().
|
|
|
|
"""
|
2017-04-28 14:43:15 -07:00
|
|
|
|
2016-06-27 07:50:09 -07:00
|
|
|
self.parse_directive_re = None
|
|
|
|
|
2017-10-20 07:26:05 -07:00
|
|
|
self.lib = lib if lib is not None else ({}, {}, {})
|