Skip to content

Commit 24b1c58

Browse files
committed
x2.3r1
1 parent 9fb0ad4 commit 24b1c58

40 files changed

+1012
-1923
lines changed

.x2config

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"main": "main.x2"
3+
}

.xtconfig

Lines changed: 0 additions & 3 deletions
This file was deleted.

main.py

Lines changed: 22 additions & 287 deletions
Original file line numberDiff line numberDiff line change
@@ -1,301 +1,36 @@
11
# Copyright 2022 iiPython
2-
# x2.3b1 Codename Goos
32

43
# Modules
54
import os
65
import sys
7-
import time
8-
import json
9-
import string
10-
from typing import Any, Tuple
11-
126
from x2 import (
13-
opmap,
14-
XTMemory, XTDatastore, XTContext,
15-
UnknownOperator, InvalidSection, IllegalSectionName
7+
load_sections, load_cli, config,
8+
Interpreter
169
)
1710

1811
# Initialization
19-
__version__ = "x2.3b1"
20-
21-
sys.argv = sys.argv[1:]
22-
xt_folder = os.path.join(os.path.dirname(__file__), "x2")
23-
24-
def check_argv(matches: list) -> bool:
25-
return bool([m for m in matches if m in sys.argv])
26-
27-
if check_argv(["-h", "--help"]):
28-
print("usage: x2 [-hv] [--help/version] [file]")
29-
print("-h (--help) shows this message and exits")
30-
print("-v (--version) prints the x2 version and exits")
31-
print()
32-
print("If file is not provided, it is loaded from .xtconfig")
33-
print("Copyright (c) 2022 iiPython + Dm123321_31mD")
34-
sys.exit(0)
35-
36-
elif check_argv(["-v", "--version"]):
37-
sys.exit(__version__)
38-
39-
# Load x2 configuration
40-
config = {}
41-
if os.path.isfile(".xtconfig"):
42-
with open(".xtconfig", "r") as f:
43-
config = json.loads(f.read())
44-
45-
# x2 Interpreter
46-
class XTInterpreter(object):
47-
def __init__(self, opmap: dict = {}) -> None:
48-
49-
# Memory initialization
50-
self.memory = XTMemory()
51-
self.memory.interpreter = self
52-
53-
self.linetrk = []
54-
self.sections = {}
55-
56-
self._live = False
57-
self._opmap = opmap
58-
59-
# Data attributes
60-
self._config = config
61-
self._uptime = time.time()
62-
self._version = __version__
63-
64-
def setvar(self, name: str, value: Any, **kwargs) -> Any:
65-
return XTDatastore(self.memory, name, **kwargs).set(value)
66-
67-
def getvar(self, name: str, **kwargs) -> XTDatastore:
68-
return XTDatastore(self.memory, name, **kwargs)
69-
70-
def execute(self, line: str, raise_error: bool = False) -> Any:
71-
if self._live and ((self.linetrk and self.linetrk[-1][0] != "<stdin>") or not self.linetrk):
72-
self.linetrk.append({"file": "<stdin>", "path": "<stdin>", "section": "<stdin>.global", "start": 0, "ended": False, "as": "<stdin>"})
73-
74-
try:
75-
tokens = self.parseline(line)
76-
try:
77-
trkdata = self.linetrk[-1]
78-
prevline = self.sections[trkdata["section"]]["lines"][trkdata["start"] - self.sections[trkdata["section"]]["start"] - 2]
79-
if prevline[-2:] in [" \\", ".."]:
80-
return None
81-
82-
except IndexError:
83-
pass
84-
85-
operator = tokens[0]
86-
if operator not in self._opmap:
87-
raise UnknownOperator(operator)
88-
89-
return self._opmap[operator](XTContext(self.memory, tokens[1:]))
90-
91-
except Exception as e:
92-
if raise_error or True:
93-
raise e
94-
95-
elif config.get("quiet", False):
96-
return None
97-
98-
print("Exception occured in x2 thread!")
99-
for tracker in self.linetrk:
100-
line = self.sections[tracker['section']]["lines"][tracker['start'] - self.sections[tracker['section']]["start"] - 1].lstrip()
101-
print(f"{tracker['file']} line {tracker['start']}, in {tracker['section'].split('.')[1]}:\n > {line}")
102-
103-
print(f"\n{type(e).__name__}: {e}")
104-
if not self._live:
105-
os._exit(1)
106-
107-
def parseline(self, line: str, multiline_offset: int = 0) -> list:
108-
data = {"val": "", "flags": [], "expridx": 0, "line": []}
109-
for idx, char in enumerate(line):
110-
if char == ":" and "qt" not in data["flags"]:
111-
if idx != len(line) - 1 and line[idx + 1] == ":":
112-
break
113-
114-
if char == ")" and "expr" in data["flags"]:
115-
if data["expridx"] > 1:
116-
data["val"] += ")"
117-
118-
elif data["expridx"] == 1:
119-
data["flags"].remove("expr")
120-
data["line"].append(f"({data['val']})")
121-
data["val"] = ""
122-
123-
data["expridx"] -= 1
124-
125-
elif char == "(" and "qt" not in data["flags"]:
126-
if "expr" not in data["flags"]:
127-
data["flags"].append("expr")
128-
129-
data["expridx"] += 1
130-
if data["expridx"] > 1:
131-
data["val"] += "("
132-
133-
elif "expr" in data["flags"]:
134-
data["val"] += char
135-
136-
elif char == " " and "qt" not in data["flags"]:
137-
if not data["val"]:
138-
continue
139-
140-
data["line"].append(data["val"])
141-
data["val"] = ""
12+
cli = load_cli() # Render CLI
14213

143-
elif char == "\"" and (line[idx - 1] != "\\" if idx > 0 else True): # Enables quoting with backslash
144-
if "qt" in data["flags"]:
145-
data["line"].append(data["val"] + "\"")
146-
data["val"] = ""
147-
data["flags"].remove("qt")
14+
# Load filepath
15+
filepath = cli.filepath
16+
if filepath is None:
17+
cli.show_help()
14818

149-
else:
150-
data["flags"].append("qt")
151-
data["val"] += "\""
19+
elif filepath == ".":
20+
filepath = config.get("main", "main.x2")
15221

153-
else:
154-
data["val"] += char
22+
if not os.path.isfile(filepath):
23+
sys.exit("x2 Exception: no such file")
15524

156-
# Construct missing data
157-
if data["val"]:
158-
data["line"].append(data["val"])
159-
data["val"] = ""
25+
# Load file content
26+
with open(filepath, "r") as f:
27+
data = f.read()
16028

161-
# Push lines
162-
if data["line"][-1] in ["\\", ".."]:
163-
trkdata = self.linetrk[-1]
164-
nextline = self.parseline(self.sections[trkdata[1]]["lines"][trkdata[2] - self.sections[trkdata[1]]["start"] + multiline_offset], multiline_offset + 1)
165-
if data["line"][-1] == "..":
166-
data["line"][-2], nextline = data["line"][-2][:-1] + "\n" + nextline[0][1:], nextline[1:]
167-
168-
data["line"] = data["line"][:-1]
169-
data["line"] = data["line"] + nextline
170-
171-
return data["line"]
172-
173-
def load_sections(self, code: str, filepath: str, namespace: str = None, external: bool = False) -> None:
174-
filename = filepath.replace("\\", "/").split("/")[-1]
175-
if not hasattr(self, "_entrypoint"):
176-
self._entrypoint = filename
177-
178-
self.memory.vars["file"][filepath] = {}
179-
180-
fileid = (namespace or filepath.replace("/", ".")).removesuffix(".xt")
181-
dt = {
182-
"active": "global",
183-
"code": [],
184-
"sections": {f"{fileid}.global": {
185-
"lines": [], "priv": False, "file": filename, "path": filepath,
186-
"start": 0, "args": [], "ret": None, "as": fileid
187-
}}
188-
}
189-
for lno, line in enumerate(code.split("\n")):
190-
if line.strip():
191-
if line[0] == ":" and line[:2] != "::":
192-
ns, sid, priv = f"{fileid}.{dt['active']}", line[1:].split(" ")[0], False
193-
if [c for c in sid if c not in string.ascii_letters + string.digits + "@"]:
194-
raise IllegalSectionName(f"section '{sid}' contains invalid characters")
195-
196-
elif "@" in sid:
197-
if sid[0] != "@":
198-
raise IllegalSectionName("section name cannot contain a '@' unless it indicates a private section")
199-
200-
priv, sid = True, sid[1:]
201-
202-
dt["sections"][ns]["lines"] = dt["code"]
203-
dt["sections"][f"{fileid}.{sid}"] = {
204-
"file": filename, "start": lno + 1, "lines": [], "priv": priv,
205-
"args": line.split(" ")[1:], "ret": None, "as": fileid, "path": filepath
206-
}
207-
dt["code"] = []
208-
dt["active"] = sid
209-
continue
210-
211-
dt["code"].append(line.lstrip())
212-
213-
if dt["code"]:
214-
dt["sections"][f"{fileid}.{dt['active']}"]["lines"] = dt["code"]
215-
216-
self.sections = {**self.sections, **dt["sections"]}
217-
if external:
218-
self.run_section(f"{fileid}.global")
219-
del self.sections[f"{fileid}.global"] # Save memory
220-
221-
def find_section(self, section: str) -> Tuple[str, str]:
222-
current_file = (self.linetrk[-1]["path"] if self.linetrk else self._entrypoint).removesuffix(".xt").replace("/", ".")
223-
if "." not in section:
224-
section = f"{current_file}.{section}"
225-
226-
if section not in self.sections:
227-
raise InvalidSection(section)
228-
229-
return section, current_file
230-
231-
def run_section(self, section: str) -> Any:
232-
section, current_file = self.find_section(section)
233-
secdata = section.split(".")
234-
s = self.sections[section]
235-
if s["priv"] and current_file + ".xt" != s["file"]:
236-
raise InvalidSection(f"{secdata[1]} is a private section and cannot be called")
237-
238-
if section not in self.memory.vars["local"]:
239-
self.memory.vars["local"][section] = {}
240-
241-
self.linetrk.append({"file": s["file"], "path": s["path"], "section": section, "start": s["start"], "ended": False, "as": s["as"]})
242-
for line in s["lines"]:
243-
self.linetrk[-1]["start"] += 1
244-
if line.strip() and line[:2] != "::":
245-
self.execute(line)
246-
if self.linetrk[-1]['ended']:
247-
break
248-
249-
del self.memory.vars["local"][section]
250-
251-
self.linetrk.pop()
252-
return s["ret"]
253-
254-
# Handler
255-
inter = XTInterpreter(opmap)
256-
if not sys.argv:
257-
print(f"{__version__} Copyright (c) 2022 iiPython")
258-
inter._live, linedata = True, ""
259-
inter.load_sections(":global\n", "<stdin>")
260-
inter.memory.vars["local"]["<stdin>.global"] = {}
261-
while True:
262-
try:
263-
line = input(f"{'>' if not linedata else ':'} ")
264-
if line[:2] == "::":
265-
continue
266-
267-
elif linedata and not line.strip():
268-
inter.load_sections(linedata, "<stdin>")
269-
linedata = ""
270-
271-
elif not line.strip():
272-
continue
273-
274-
elif line[0] == ":" and line[:2] != "::":
275-
linedata = line + "\n"
276-
277-
elif linedata:
278-
linedata += line + "\n"
279-
280-
else:
281-
inter.execute(line)
282-
283-
except KeyboardInterrupt:
284-
os._exit(0)
285-
286-
else:
287-
file = sys.argv[0]
288-
if file == ".":
289-
file = config.get("main", "main.xt")
290-
291-
try:
292-
with open(file, "r", encoding = "utf-8") as f:
293-
code = f.read()
294-
295-
except Exception:
296-
print("x2: failed to load file")
297-
os._exit(1)
298-
299-
inter.load_sections(code, file)
300-
file = file.replace("\\", "/").replace("/", ".").removesuffix(".xt").removeprefix("./")
301-
[inter.run_section(s) for s in [f"{file}.global", f"{file}.main"]]
29+
# Run file
30+
sections = load_sections(data, filepath)
31+
interpreter = Interpreter(
32+
filepath, sections,
33+
config = config,
34+
cli_vals = cli.vals
35+
)
36+
interpreter.run_section("main")

main.x2

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
:: Simple x2 program
2+
3+
:: This will run just fine
4+
prt "Hello, world!"
5+
6+
:: This will output color if you use -c
7+
prt "[green]Hello, world![/]"
8+
9+
:: Nice note
10+
prt "\nNo color? Run the interpreter with the -c flag."

main.xt

Lines changed: 0 additions & 2 deletions
This file was deleted.

pkg/iipython/main.xt

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)