1.1 --- a/compiler/transformer.py Mon Jan 08 00:13:18 2018 +0100
1.2 +++ b/compiler/transformer.py Mon Jan 08 00:30:23 2018 +0100
1.3 @@ -719,7 +719,7 @@
1.4 # varargslist:
1.5 # (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] | '**' NAME)
1.6 # | fpdef ['=' test] (',' fpdef ['=' test])* [',']
1.7 - # fpdef: NAME | '(' fplist ')'
1.8 + # fpdef: NAME | '.' NAME | '(' fplist ')'
1.9 # fplist: fpdef (',' fpdef)* [',']
1.10 names = []
1.11 defaults = []
1.12 @@ -748,7 +748,7 @@
1.13
1.14 break
1.15
1.16 - # fpdef: NAME | '(' fplist ')'
1.17 + # fpdef: NAME | '.' NAME | '(' fplist ')'
1.18 names.append(self.com_fpdef(node))
1.19
1.20 i = i + 1
1.21 @@ -766,9 +766,11 @@
1.22 return names, defaults, flags
1.23
1.24 def com_fpdef(self, node):
1.25 - # fpdef: NAME | '(' fplist ')'
1.26 + # fpdef: NAME | '.' NAME | '(' fplist ')'
1.27 if node[1][0] == token["LPAR"]:
1.28 return self.com_fplist(node[2])
1.29 + elif node[1][0] == token["DOT"]:
1.30 + return node[1][1] + node[2][1]
1.31 return node[1][1]
1.32
1.33 def com_fplist(self, node):
2.1 --- a/importer.py Mon Jan 08 00:13:18 2018 +0100
2.2 +++ b/importer.py Mon Jan 08 00:30:23 2018 +0100
2.3 @@ -4,7 +4,7 @@
2.4 Import logic.
2.5
2.6 Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013,
2.7 - 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
2.8 + 2014, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
2.9
2.10 This program is free software; you can redistribute it and/or modify it under
2.11 the terms of the GNU General Public License as published by the Free Software
2.12 @@ -79,6 +79,7 @@
2.13 self.objects = {}
2.14 self.classes = {}
2.15 self.function_parameters = {}
2.16 + self.function_attr_initialisers = {}
2.17 self.function_defaults = {}
2.18 self.function_locals = {}
2.19
3.1 --- a/inspector.py Mon Jan 08 00:13:18 2018 +0100
3.2 +++ b/inspector.py Mon Jan 08 00:30:23 2018 +0100
3.3 @@ -4,7 +4,7 @@
3.4 Inspect and obtain module structure.
3.5
3.6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,
3.7 - 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
3.8 + 2014, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
3.9
3.10 This program is free software; you can redistribute it and/or modify it under
3.11 the terms of the GNU General Public License as published by the Free Software
3.12 @@ -591,11 +591,31 @@
3.13 if is_method and argnames and argnames[0] == "self":
3.14 del argnames[0]
3.15
3.16 + # Convert .name entries in the parameters, provided this is a method.
3.17 +
3.18 + l = []
3.19 + attr_initialisers = []
3.20 +
3.21 + for argname in argnames:
3.22 + if argname[0] == ".":
3.23 + if not is_method:
3.24 + raise InspectError("Attribute initialisers are only allowed amongst method parameters.", function_name, n)
3.25 +
3.26 + argname = argname[1:]
3.27 + attr_initialisers.append(argname)
3.28 +
3.29 + l.append(argname)
3.30 +
3.31 + argnames = l
3.32 +
3.33 # Copy and propagate the parameters.
3.34
3.35 self.importer.function_parameters[function_name] = \
3.36 self.function_parameters[function_name] = argnames[:]
3.37
3.38 + self.importer.function_attr_initialisers[function_name] = \
3.39 + self.function_attr_initialisers[function_name] = attr_initialisers
3.40 +
3.41 # Define all arguments/parameters in the local namespace.
3.42
3.43 locals = \
3.44 @@ -652,8 +672,15 @@
3.45 # Track attribute usage within the namespace.
3.46
3.47 path = self.get_namespace_path()
3.48 + self.start_tracking(locals)
3.49
3.50 - self.start_tracking(locals)
3.51 + # Establish attributes for .name entries, provided this is a method.
3.52 +
3.53 + for argname in attr_initialisers:
3.54 + self.process_assignment_node(
3.55 + compiler.ast.AssAttr(compiler.ast.Name("self"), argname, "OP_ASSIGN"),
3.56 + compiler.ast.Name(argname))
3.57 +
3.58 self.process_structure_node(n.code)
3.59 returns_value = self.stop_tracking()
3.60
4.1 --- a/modules.py Mon Jan 08 00:13:18 2018 +0100
4.2 +++ b/modules.py Mon Jan 08 00:30:23 2018 +0100
4.3 @@ -4,7 +4,7 @@
4.4 Module abstractions.
4.5
4.6 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013,
4.7 - 2014, 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
4.8 + 2014, 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
4.9
4.10 This program is free software; you can redistribute it and/or modify it under
4.11 the terms of the GNU General Public License as published by the Free Software
4.12 @@ -63,6 +63,7 @@
4.13 # Function details.
4.14
4.15 self.function_parameters = {}
4.16 + self.function_attr_initialisers = {}
4.17 self.function_defaults = {}
4.18 self.function_locals = {}
4.19 self.scope_globals = {}
4.20 @@ -391,6 +392,7 @@
4.21 self._get_initialised_names(f)
4.22 self._get_aliased_names(f)
4.23 self._get_function_parameters(f)
4.24 + self._get_function_attr_initialisers(f)
4.25 self._get_function_defaults(f)
4.26 self._get_function_locals(f)
4.27 self.from_lines(f, self.scope_globals) # "scope globals:"
4.28 @@ -510,6 +512,15 @@
4.29 self.function_parameters[function] = names != "{}" and names.split(", ") or []
4.30 line = f.readline().rstrip()
4.31
4.32 + def _get_function_attr_initialisers(self, f):
4.33 + f.readline() # "function attribute initialisers:"
4.34 + line = f.readline().rstrip()
4.35 + while line:
4.36 + function, names = self._get_fields(line)
4.37 + self.importer.function_attr_initialisers[function] = \
4.38 + self.function_attr_initialisers[function] = names != "{}" and names.split(", ") or []
4.39 + line = f.readline().rstrip()
4.40 +
4.41 def _get_function_defaults(self, f):
4.42 f.readline() # "function default parameters:"
4.43 line = f.readline().rstrip()
4.44 @@ -782,6 +793,17 @@
4.45 print >>f, function, "{}"
4.46
4.47 print >>f
4.48 + print >>f, "function attribute initialisers:"
4.49 + functions = self.function_attr_initialisers.keys()
4.50 + functions.sort()
4.51 + for function in functions:
4.52 + parameters = self.function_attr_initialisers[function]
4.53 + if parameters:
4.54 + print >>f, function, ", ".join(parameters)
4.55 + else:
4.56 + print >>f, function, "{}"
4.57 +
4.58 + print >>f
4.59 print >>f, "function default parameters:"
4.60 functions = self.function_defaults.keys()
4.61 functions.sort()
5.1 --- a/pyparser/data/Grammar-Lichen Mon Jan 08 00:13:18 2018 +0100
5.2 +++ b/pyparser/data/Grammar-Lichen Mon Jan 08 00:30:23 2018 +0100
5.3 @@ -11,10 +11,13 @@
5.4
5.5 funcdef: 'def' NAME parameters ':' suite
5.6 parameters: '(' [varargslist] ')'
5.7 +# NOTE: Remove * and ** support.
5.8 varargslist: ((fpdef ['=' test] ',')*
5.9 ('*' NAME [',' '**' NAME] | '**' NAME) |
5.10 fpdef ['=' test] (',' fpdef ['=' test])* [','])
5.11 -fpdef: NAME | '(' fplist ')'
5.12 +# NOTE: Replace with flat parameter lists?
5.13 +# Supporting .name for attribute assignment convenience.
5.14 +fpdef: NAME | '.' NAME | '(' fplist ')'
5.15 fplist: fpdef (',' fpdef)* [',']
5.16
5.17 stmt: simple_stmt | compound_stmt
6.1 --- a/translator.py Mon Jan 08 00:13:18 2018 +0100
6.2 +++ b/translator.py Mon Jan 08 00:30:23 2018 +0100
6.3 @@ -3,7 +3,7 @@
6.4 """
6.5 Translate programs.
6.6
6.7 -Copyright (C) 2015, 2016, 2017, 2018 Paul Boddie <paul@boddie.org.uk>
6.8 +Copyright (C) 2015, 2016, 2017 Paul Boddie <paul@boddie.org.uk>
6.9
6.10 This program is free software; you can redistribute it and/or modify it under
6.11 the terms of the GNU General Public License as published by the Free Software
6.12 @@ -854,6 +854,15 @@
6.13 if self.in_method():
6.14 self.generate_guard("self")
6.15
6.16 + # Make assignments for .name entries in the parameters, provided this is
6.17 + # a method.
6.18 +
6.19 + if self.in_method():
6.20 + for name in self.importer.function_attr_initialisers.get(function_name) or []:
6.21 + self.process_assignment_node(
6.22 + compiler.ast.AssAttr(compiler.ast.Name("self"), name, "OP_ASSIGN"),
6.23 + compiler.ast.Name(name))
6.24 +
6.25 # Produce the body and any additional return statement.
6.26
6.27 expr = self.process_structure_node(n.code) or \