Repository navigation
Expand file tree
/
Copy pathparser.py
More file actions
113 lines (90 loc) · 3.51 KB
/
Copy pathparser.py
File metadata and controls
113 lines (90 loc) · 3.51 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
113
# Copyright (C) 2026-Present IndianCoder3
# This program 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.
# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
from error_handler import SyntaxErrorICTL
def parse_file(path):
"""
Parse an ICTL program file.
Args:
path (str): Path to the .ictl file
Returns:
list: Parsed program structure
Raises:
SyntaxErrorICTL: On parsing errors
"""
try:
with open(path, "r", encoding="utf-8") as f:
lines = f.readlines()
except FileNotFoundError:
raise SyntaxErrorICTL(f"File not found: {path}")
except IOError as e:
raise SyntaxErrorICTL(f"Cannot read file {path}: {e}")
program = []
stack = []
line_number = 0
for line_number, raw in enumerate(lines, 1):
line = raw.strip()
if not line or line.startswith("#") or line.startswith("//"):
continue
if line.endswith("{"):
header = line[:-1].strip()
# Validate block header format
if not _is_valid_block_header(header):
raise SyntaxErrorICTL(
f"Invalid block header: '{header}'",
line=line_number,
context=raw.rstrip()
)
block = {"header": header, "lines": []}
if stack:
stack[-1]["lines"].append(block)
else:
program.append(block)
stack.append(block)
continue
if line == "}":
if not stack:
raise SyntaxErrorICTL(
"Unexpected closing brace '}'",
line=line_number,
context=raw.rstrip(),
col=1
)
stack.pop()
continue
if stack:
stack[-1]["lines"].append(line)
else:
program.append(line)
if stack:
raise SyntaxErrorICTL(
f"Unclosed block '{stack[-1]['header']}'",
line=line_number,
context=f"End of file reached"
)
return program
def _is_valid_block_header(header):
"""Check if a block header is valid (case-insensitive)."""
# Normalize header to proper case for checking
header_lower = header.lower()
# Check if it matches any valid block pattern (case-insensitive)
valid_patterns = (
"program.main",
"program.if",
"program.else",
"program.loop",
"program.foreverloop",
"program.kheer"
)
# Check exact matches (case-insensitive)
if header_lower in valid_patterns:
return True
# Check pattern matches (with parameters)
if header_lower.startswith("program.if(") and header.endswith(")"):
return True
if header_lower.startswith("program.loop(") and header.endswith(")"):
return True
if header_lower.startswith("program.kheer(") and header.endswith(")"):
return True
return False