-
-
Notifications
You must be signed in to change notification settings - Fork 45
Expand file tree
/
Copy pathcall.py
More file actions
112 lines (93 loc) · 4.02 KB
/
call.py
File metadata and controls
112 lines (93 loc) · 4.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# --------------------------------------------------------------------
# SPDX-License-Identifier: AGPL-3.0-or-later
# © Copyright 2008-2024 José Manuel Rodríguez de la Rosa and contributors.
# See the file CONTRIBUTORS.md for copyright details.
# See https://www.gnu.org/licenses/agpl-3.0.html for details.
# --------------------------------------------------------------------
from collections.abc import Iterable
from typing import Self
import src.api.global_ as gl
from src.api import check, errmsg
from src.api.constants import CLASS
from src.symbols.arglist import SymbolARGLIST
from src.symbols.argument import SymbolARGUMENT
from src.symbols.id_ import SymbolID
from src.symbols.id_.ref import FuncRef
from src.symbols.symbol_ import Symbol
from src.symbols.type_ import Type
class SymbolCALL(Symbol):
"""Defines function / procedure call. E.g. F(1, A + 2)
It contains the symbol table entry of the called function (e.g. F)
And a list of arguments. (e.g. (1, A + 2) in this example).
Parameters:
id_: The symbol table entry
arglist: a SymbolARGLIST instance
lineno: source code line where this call was made
"""
def __init__(self, entry: SymbolID, arglist: Iterable[SymbolARGUMENT], lineno: int, filename: str):
assert isinstance(entry, SymbolID)
assert all(isinstance(x, SymbolARGUMENT) for x in arglist)
assert entry.class_ in (CLASS.array, CLASS.function, CLASS.sub, CLASS.unknown)
super().__init__()
self.entry = entry
self.args = arglist # Func. call / array access
self.lineno: int = lineno
self.filename: str = filename
ref = entry.ref
if isinstance(ref, FuncRef):
for arg, param in zip(arglist, ref.params): # Sets dependency graph for each argument -> parameter
if arg.value is not None:
arg.value.add_required_symbol(param)
if (
isinstance(arg.value, SymbolID)
and arg.value.class_ == CLASS.array
and param.class_ == CLASS.array
and param.ref.is_dynamically_accessed is True
):
arg.value.ref.is_dynamically_accessed = True
@property
def entry(self):
return self.children[0]
@entry.setter
def entry(self, value: SymbolID):
assert value.token == "FUNCTION"
if self.children is None or not self.children:
self.children = [value]
else:
self.children[0] = value
@property
def args(self):
return self.children[1]
@args.setter
def args(self, value):
assert isinstance(value, SymbolARGLIST)
if self.children is None or not self.children:
self.children = [None]
if len(self.children) < 2:
self.children.append(value)
return
self.children[1] = value
@property
def type_(self):
return self.entry.type_
@classmethod
def make_node(cls, id_: str, params, lineno: int, filename: str) -> Self | None:
"""This will return an AST node for a function/procedure call."""
assert isinstance(params, SymbolARGLIST)
entry = gl.SYMBOL_TABLE.access_func(id_, lineno)
if entry is None: # A syntax / semantic error
return None
if entry.callable is False: # Is it NOT callable?
if entry.type_ != Type.string:
errmsg.syntax_error_not_array_nor_func(lineno, id_)
return None
if entry.declared and not entry.forwarded:
check.check_call_arguments(lineno, id_, params, filename)
else: # All functions go to global scope by default
if entry.token != "FUNCTION":
entry = entry.to_function(lineno)
gl.SYMBOL_TABLE.move_to_global_scope(id_)
result = cls(entry, params, lineno, filename)
gl.FUNCTION_CALLS.append(result)
return result
return cls(entry, params, lineno, filename)