Skip to content
This repository has been archived by the owner on May 21, 2024. It is now read-only.

Commit

Permalink
Merge pull request boriel-basic#692 from boriel/bugfix/const_substr
Browse files Browse the repository at this point in the history
fix: allow substr of CONST strings
  • Loading branch information
boriel committed Dec 8, 2023
2 parents 427a64a + 133de73 commit 267b57d
Show file tree
Hide file tree
Showing 15 changed files with 4,806 additions and 18 deletions.
9 changes: 6 additions & 3 deletions src/api/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ def is_null(*symbols_):
return True


def is_SYMBOL(token, *symbols_):
def is_SYMBOL(token: str, *symbols_: symbols.SYMBOL):
"""Returns True if ALL the given argument are AST nodes
of the given token (e.g. 'BINARY')
"""
Expand All @@ -291,7 +291,10 @@ def is_LABEL(*p):


def is_string(*p):
return is_SYMBOL("STRING", *p)
"""Returns True if ALL the arguments are AST nodes
containing STRING or string CONSTANTS
"""
return all(is_SYMBOL("STRING", x) or is_const(x) and is_type(Type.string, x) for x in p)


def is_const(*p):
Expand All @@ -317,7 +320,7 @@ def is_number(*p):
"""Returns True if ALL the arguments are AST nodes
containing NUMBER or numeric CONSTANTS
"""
return all(i.token in ("NUMBER", "CONST") for i in p)
return all(i.token in ("NUMBER", "CONST") and Type.is_numeric(i.type_) for i in p)


def is_static_str(*p):
Expand Down
7 changes: 3 additions & 4 deletions src/api/string_labels.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,23 @@
a mapping of constant Strings to Labels.
"""
from collections import defaultdict
from typing import Final

from src.api import tmp_labels

STRING_LABELS: dict[str, str] = defaultdict(tmp_labels.tmp_label)
STRING_LABELS: Final[dict[str, str]] = defaultdict(tmp_labels.tmp_label)


def reset():
"""Initializes this module"""
global STRING_LABELS
STRING_LABELS.clear()


def add_string_label(string: str) -> str:
"""Maps ("folds") the given string, returning an unique label ID.
"""Maps ("folds") the given string, returning a unique label ID.
This allows several constant labels to be initialized to the same address
thus saving memory space.
:param string: the string to map
:return: the unique label ID
"""
global STRING_LABELS
return STRING_LABELS[string]
2 changes: 1 addition & 1 deletion src/symbols/binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def make_node(cls, operator, left, right, lineno, func=None, type_=None):
a, b = left, right # short form names
# Check for constant non-numeric operations
c_type = check.common_type(a, b) # Resulting operation type or None
if c_type: # there must be a common type for a and b
if TYPE.is_numeric(c_type): # there must be a common type for a and b
if (
check.is_numeric(a, b)
and (check.is_const(a) or check.is_number(a))
Expand Down
5 changes: 2 additions & 3 deletions src/symbols/strslice.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,9 @@ def make_node(cls, lineno: int, s, lower, upper):
if lo > up:
return STRING("", lineno)

if s.token == "STRING": # A constant string? Recalculate it now
if s.token in ("STRING", "CONST"): # A constant string? Recalculate it now
up += 1
st = s.value.ljust(up) # Procrustean filled (right)
return STRING(st[lo:up], lineno)
return STRING(s.value[lo:up], lineno)

# a$(0 TO INF.) = a$
if lo == gl.MIN_STRSLICE_IDX and up == gl.MAX_STRSLICE_IDX:
Expand Down
23 changes: 16 additions & 7 deletions src/zxbc/zxbparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ def make_constexpr(lineno, expr):
return sym.CONSTEXPR(expr, lineno=lineno)


def make_strslice(lineno, s, lower, upper):
def make_strslice(lineno: int, s, lower, upper):
"""Wrapper: returns String Slice node"""
return sym.STRSLICE.make_node(lineno, s, lower, upper)

Expand Down Expand Up @@ -395,17 +395,21 @@ def make_call(id_: str, lineno: int, args: sym.ARGLIST):
arr.append_child(offset)
return arr

if entry.class_ == CLASS.var: # An already declared/used string var
if entry.class_ in (CLASS.var, CLASS.const): # An already declared/used string var
if len(args) > 1:
errmsg.syntax_error_not_array_nor_func(lineno, id_)
return None

entry = SYMBOL_TABLE.access_var(id_, lineno)
if entry is None:
return None
if entry.class_ == CLASS.var:
entry = SYMBOL_TABLE.access_var(id_, lineno)
if entry is None:
return None

if len(args) == 1:
return sym.STRSLICE.make_node(lineno, entry, args[0].value, args[0].value)
if entry.class_ == CLASS.var:
return make_strslice(lineno, entry, args[0].value, args[0].value)
# it's a const
return make_strslice(lineno, sym.STRING(entry.value, lineno), args[0].value, args[0].value)

mark_entry_as_accessed(entry)
return entry
Expand Down Expand Up @@ -2478,6 +2482,11 @@ def p_string_lp_expr_rp(p):

def p_expr_id_substr(p):
"""string : ID substr"""
entry = SYMBOL_TABLE.get_entry(p[1])
if entry is not None and entry.type_ == TYPE.string and entry.token == "CONST":
p[0] = make_strslice(p.lineno(1), entry, p[2][0], p[2][1])
return

entry = SYMBOL_TABLE.access_var(p[1], p.lineno(1), default_type=TYPE.string)
p[0] = None
if entry is None:
Expand Down Expand Up @@ -2595,7 +2604,7 @@ def p_idcall_expr(p):
if p[0] is None:
return

if p[0].token in ("STRSLICE", "ID", "STRING"):
if p[0].token in ("STRSLICE", "ID", "STRING") or p[0].token == "CONST" and p[0].type_ == TYPE.string:
entry = SYMBOL_TABLE.access_call(p[1], p.lineno(1))
mark_entry_as_accessed(entry)
return
Expand Down

0 comments on commit 267b57d

Please sign in to comment.