Skip to content

Commit be0b538

Browse files
authored
Merge pull request #573 from boriel/feature/optional_parameters
feat: allow optional parameters!
2 parents 69b6ed8 + 707aafc commit be0b538

66 files changed

Lines changed: 1703 additions & 881 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

setup.py

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,56 @@
22
import pathlib
33
from setuptools import setup
44

5-
packages = [
6-
'src'
7-
]
5+
packages = ["src"]
86

97
# The directory containing this file
108
HERE = pathlib.Path(__file__).parent
119

1210
# The text of the README file
1311
README = (HERE / "README.md").read_text()
1412

15-
package_data = {'': ['*'], 'arch.zx48k.peephole': ['opts/*']}
13+
package_data = {"": ["*"], "arch.zx48k.peephole": ["opts/*"]}
1614

1715
entry_points = {
18-
'console_scripts': ['zxb = src.libzxbc.zxb:main',
19-
'zxbasm = src.libzxbasm.zxbasm:main',
20-
'zxbc = src.libzxbc.zxb:main',
21-
'zxbpp = src.libzxbpp.zxbpp:entry_point']
16+
"console_scripts": [
17+
"zxb = src.libzxbc.zxb:main",
18+
"zxbasm = src.libzxbasm.zxbasm:main",
19+
"zxbc = src.libzxbc.zxb:main",
20+
"zxbpp = src.libzxbpp.zxbpp:entry_point",
21+
]
2222
}
2323

2424
setup_kwargs = {
25-
'name': 'zxbasic',
26-
'version': '1.15.2',
27-
'description': "Boriel's ZX BASIC Compiler",
28-
'classifiers': [
25+
"name": "zxbasic",
26+
"version": "1.15.2",
27+
"description": "Boriel's ZX BASIC Compiler",
28+
"classifiers": [
2929
# How mature is this project? Common values are
3030
# 3 - Alpha
3131
# 4 - Beta
3232
# 5 - Production/Stable
33-
'Development Status :: 5 - Production/Stable',
34-
33+
"Development Status :: 5 - Production/Stable",
3534
# Indicate who your project is intended for
36-
'Intended Audience :: Developers',
37-
'Topic :: Software Development :: Build Tools',
38-
35+
"Intended Audience :: Developers",
36+
"Topic :: Software Development :: Build Tools",
3937
# Pick your license as you wish (should match "license" above)
40-
'License :: OSI Approved :: GNU Affero General Public License v3',
41-
38+
"License :: OSI Approved :: GNU Affero General Public License v3",
4239
# Specify the Python versions you support here. In particular, ensure
4340
# that you indicate whether you support Python 2, Python 3 or both.
44-
'Programming Language :: Python :: 3.6',
45-
'Programming Language :: Python :: 3.8',
41+
"Programming Language :: Python :: 3.6",
42+
"Programming Language :: Python :: 3.8",
4643
],
47-
'long_description_content_type': "text/markdown",
48-
'long_description': README,
49-
'author': 'Jose Rodriguez',
50-
'author_email': 'boriel@gmail.com',
51-
'maintainer': None,
52-
'maintainer_email': None,
53-
'url': 'http://zxbasic.net',
54-
'packages': packages,
55-
'package_data': package_data,
56-
'entry_points': entry_points,
57-
'python_requires': '>=3.6,<4.0',
44+
"long_description_content_type": "text/markdown",
45+
"long_description": README,
46+
"author": "Jose Rodriguez",
47+
"author_email": "boriel@gmail.com",
48+
"maintainer": None,
49+
"maintainer_email": None,
50+
"url": "http://zxbasic.net",
51+
"packages": packages,
52+
"package_data": package_data,
53+
"entry_points": entry_points,
54+
"python_requires": ">=3.6,<4.0",
5855
}
5956

6057
setup(**setup_kwargs)

src/api/check.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ def check_call_arguments(lineno: int, id_: str, args):
112112

113113
entry = global_.SYMBOL_TABLE.get_entry(id_)
114114

115+
if len(args) < len(entry.params): # try filling default params
116+
for param in entry.params[len(args) :]:
117+
if param.default_value is None:
118+
break
119+
symbols.ARGLIST.make_node(args, symbols.ARGUMENT(param.default_value, lineno=lineno, byref=False))
120+
115121
if len(args) != len(entry.params):
116122
c = "s" if len(entry.params) != 1 else ""
117123
errmsg.error(

src/api/errmsg.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,13 @@ def syntax_error_cannot_initialize_array_of_type(lineno: int, type_name: str):
303303
error(lineno, f"Cannot initialize array of type {type_name}")
304304

305305

306+
# ----------------------------------------
307+
# Cannot define a default array argument
308+
# ----------------------------------------
309+
def syntax_error_cannot_define_default_array_argument(lineno: int):
310+
error(lineno, "Cannot define default array argument")
311+
312+
306313
# ----------------------------------------
307314
# Error, ID is a ... not a ...
308315
# ----------------------------------------
@@ -319,4 +326,11 @@ def syntax_error_already_declared(lineno: int, id_name: str, as_class: CLASS, at
319326
error(lineno, f"'{id_name}' already declared as {as_class} at {at_lineno}")
320327

321328

329+
# ----------------------------------------
330+
# Can't declare a mandatory parameter after an optional one
331+
# ----------------------------------------
332+
def syntax_error_mandatory_param_after_optional(lineno: int, param1: str, param2: str):
333+
error(lineno, f"Can't declare mandatory param '{param2}' after optional param '{param1}'")
334+
335+
322336
# endregion

src/api/symboltable.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from .errmsg import warning_not_used
3636
from .errmsg import syntax_error_func_type_mismatch
3737
from .errmsg import syntax_error_not_array_nor_func
38+
from .errmsg import syntax_error_cannot_define_default_array_argument
3839

3940
from .constants import DEPRECATED_SUFFIXES
4041
from .constants import SUFFIX_TYPE
@@ -695,26 +696,33 @@ def declare_label(self, id_: str, lineno: int) -> Optional[SymbolLABEL]:
695696
entry.type_ = self.basic_types[global_.PTR_TYPE]
696697
return entry
697698

698-
def declare_param(self, id_: str, lineno: int, type_=None, is_array=False) -> Optional[SymbolVAR]:
699+
def declare_param(
700+
self, id_: str, lineno: int, type_=None, is_array=False, default_value: Optional[Symbol] = None
701+
) -> Optional[SymbolVAR]:
699702
"""Declares a parameter
700703
Check if entry.declared is False. Otherwise raises an error.
701704
"""
702705
if not self.check_is_undeclared(id_, lineno, classname="parameter", scope=self.current_scope, show_error=True):
703706
return None
704707

705708
if is_array:
709+
if default_value is not None:
710+
syntax_error_cannot_define_default_array_argument(lineno)
711+
return None
712+
706713
entry = self.declare(id_, lineno, symbols.VARARRAY(id_, symbols.BOUNDLIST(), lineno, None, type_))
707714
entry.callable = True
708715
entry.scope = SCOPE.parameter
709716
else:
710-
entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_))
717+
entry = self.declare(id_, lineno, symbols.PARAMDECL(id_, lineno, type_, default_value))
711718

712719
if entry is None:
713720
return None
714721

715722
entry.declared = True
716723
if entry.type_.implicit:
717724
warning_implicit_type(lineno, id_, type_)
725+
718726
return entry
719727

720728
def declare_array(self, id_: str, lineno: int, type_, bounds, default_value=None, addr=None):

src/arch/z80/translator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1447,7 +1447,7 @@ def visit_FUNCTION(self, node):
14471447
if local_var.default_value is not None:
14481448
r.extend(self.array_default_value(local_var.type_, local_var.default_value))
14491449
self.ic_larrd(local_var.offset, q, local_var.size, r, bound_ptrs) # Initializes array bounds
1450-
elif local_var.class_ == CLASS.const:
1450+
elif local_var.class_ == CLASS.const or local_var.scope == SCOPE.parameter:
14511451
continue
14521452
else: # Local vars always defaults to 0, so if 0 we do nothing
14531453
if local_var.default_value is not None and local_var.default_value != 0:

src/parsetab/tabs.dbm.bak

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'zxbpp', (0, 76970)
22
'asmparse', (77312, 268394)
33
'zxnext_asmparse', (346112, 298411)
4-
'zxbparser', (644608, 703160)
4+
'zxbparser', (644608, 704752)

src/parsetab/tabs.dbm.dat

1.55 KB
Binary file not shown.

src/parsetab/tabs.dbm.dir

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
'zxbpp', (0, 76970)
22
'asmparse', (77312, 268394)
33
'zxnext_asmparse', (346112, 298411)
4-
'zxbparser', (644608, 703160)
4+
'zxbparser', (644608, 704752)

src/symbols/paramdecl.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,27 @@
88
# This program is Free Software and is released under the terms of
99
# the GNU General License
1010
# ----------------------------------------------------------------------
11+
from typing import Optional
12+
13+
import src.api.global_ as gl
1114

1215
from src.api.constants import CLASS
1316
from src.api.constants import SCOPE
1417
from src.api.config import OPTIONS
15-
import src.api.global_ as gl
16-
from .type_ import SymbolBASICTYPE as BasicType
17-
from .var import SymbolVAR
18+
from src.symbols.type_ import SymbolBASICTYPE as BasicType
19+
from src.symbols.var import SymbolVAR
20+
from src.symbols.symbol_ import Symbol
1821

1922

2023
class SymbolPARAMDECL(SymbolVAR):
2124
"""Defines a parameter declaration"""
2225

23-
def __init__(self, varname, lineno, type_=None):
24-
super(SymbolPARAMDECL, self).__init__(varname, lineno, type_=type_, class_=CLASS.var)
26+
def __init__(self, varname: str, lineno: int, type_=None, default_value: Optional[Symbol] = None):
27+
super().__init__(varname, lineno, type_=type_, class_=CLASS.var)
2528
self.byref = OPTIONS.default_byref # By default all params By value (false)
2629
self.offset = None # Set by PARAMLIST, contains positive offset from top of the stack
2730
self.scope = SCOPE.parameter
31+
self.default_value = default_value
2832

2933
@property
3034
def size(self):

src/zxbc/zxbparser.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,9 @@ def make_call(id_: str, lineno: int, args: symbols.ARGLIST):
411411
return make_func_call(id_, lineno, args)
412412

413413

414-
def make_param_decl(id_: str, lineno: int, typedef, is_array=False):
414+
def make_param_decl(id_: str, lineno: int, typedef, is_array: bool, default_value: Optional[symbols.SYMBOL] = None):
415415
"""Wrapper that creates a param declaration"""
416-
return SYMBOL_TABLE.declare_param(id_, lineno, typedef, is_array)
416+
return SYMBOL_TABLE.declare_param(id_, lineno, typedef, is_array, default_value)
417417

418418

419419
def make_type(typename, lineno, implicit=False):
@@ -2931,6 +2931,10 @@ def p_param_decl_list(p):
29312931

29322932
def p_param_decl_list2(p):
29332933
"""param_decl_list : param_decl_list COMMA param_definition"""
2934+
if p[1] is not None and p[3] is not None: # No errors in parsing
2935+
if p[3].default_value is None and p[1][-1].default_value is not None:
2936+
src.api.errmsg.syntax_error_mandatory_param_after_optional(p[3].lineno, p[1][-1].name, p[3].name)
2937+
29342938
p[0] = make_param_list(p[1], p[3])
29352939

29362940

@@ -2981,13 +2985,32 @@ def p_param_def_array(p):
29812985

29822986

29832987
def p_param_def_type(p):
2984-
"""param_def : singleid typedef"""
2988+
"""param_def : singleid typedef default_arg_value"""
29852989
id_: Id = p[1]
29862990
typedef = p[2]
29872991
if typedef is not None:
29882992
src.api.check.check_type_is_explicit(id_.lineno, id_.name, typedef)
29892993

2990-
p[0] = make_param_decl(id_.name, id_.lineno, typedef)
2994+
default_value = make_typecast(typedef, p[3], id_.lineno)
2995+
p[0] = make_param_decl(
2996+
id_.name,
2997+
id_.lineno,
2998+
typedef,
2999+
is_array=False,
3000+
default_value=default_value,
3001+
)
3002+
3003+
3004+
def p_param_def_default_arg_value(p):
3005+
"""default_arg_value :
3006+
| EQ expr
3007+
"""
3008+
if len(p) == 1:
3009+
p[0] = None
3010+
return
3011+
3012+
p[0] = p[2]
3013+
return
29913014

29923015

29933016
def p_function_body(p):
@@ -3307,7 +3330,7 @@ def p_sgn(p):
33073330

33083331

33093332
# ----------------------------------------
3310-
# Trigonometrics and LN, EXP, SQR
3333+
# Trigonometric and LN, EXP, SQR
33113334
# ----------------------------------------
33123335
def p_expr_trig(p):
33133336
"""bexpr : math_fn bexpr %prec UMINUS"""

0 commit comments

Comments
 (0)