therl 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
therl-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: therl
3
+ Version: 0.1.0
4
+ Summary: A human readable programming language
5
+ Author-email: CyzmiX <itzmedigamingx@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.13
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Therl
13
+
14
+ > **T**ruly **H**uman **R**eadaby **L**anguage
15
+ > _(Yes, the acronym is a little cursed. I know.)_
16
+
17
+ Therl is a human-readable, instruction-based programming language written entirely in pure Python. Its goal is to make code read almost like plain English while remaining predictable and easy to parse.
18
+
19
+ ```therl
20
+ set greeting to "hello"
21
+
22
+ func greet <name>
23
+
24
+ say greeting + " " + name + "!"
25
+
26
+ eof
27
+
28
+ func main
29
+
30
+ run greet with <name> as "Jeff"
31
+
32
+ set numbers to [1..10]
33
+
34
+ say numbers
35
+
36
+ eof
37
+
38
+ run main
39
+ ```
40
+
41
+ Output:
42
+
43
+ ```text
44
+ hello Jeff!
45
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Features
51
+
52
+ - 📖 Human-readable syntax
53
+ - 📝 Instruction-based language design
54
+ - 🐍 Written entirely in pure Python
55
+ - 🔄 Strictly dynamically typed variables
56
+ - 📦 Built-in lists
57
+ - 🔢 Integer, float, string and boolean types
58
+ - 🧩 Functions with named parameters
59
+ - 📢 Simple `say` statement for output
60
+ - ✏️ Mutable list elements
61
+ - 🚀 Easy to extend
62
+
63
+ ---
64
+
65
+ ## Example
66
+
67
+ ```therl
68
+ set greeting to "hello"
69
+
70
+ func greet <name>
71
+
72
+ say greeting + " " + name + "!"
73
+
74
+ eof
75
+
76
+ func main
77
+
78
+ say "Welcome!"
79
+
80
+ run greet with <name> as "Jeff"
81
+
82
+ set ids to [1..10]
83
+
84
+ say ids
85
+
86
+ set ids at 0 to 1000
87
+
88
+ say ids
89
+
90
+ add 10 to ids
91
+
92
+ say ids
93
+
94
+ eof
95
+
96
+ run main
97
+ ```
98
+
99
+ Output:
100
+
101
+ ```text
102
+ Welcome!
103
+ hello Jeff!
104
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
105
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9]
106
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9, 10]
107
+ ```
108
+
109
+ ---
110
+
111
+ # Project Status
112
+
113
+ ⚠️ Therl is currently in active development.
114
+
115
+ Expect missing features, breaking changes, and plenty of experimentation as the language evolves.
116
+
117
+ ---
118
+
119
+ # Roadmap
120
+
121
+ - [ ] Arithmetic expressions
122
+ - [ ] Conditional statements
123
+ - [ ] Loops
124
+ - [ ] Dictionaries / Maps
125
+ - [ ] Modules
126
+ - [ ] Classes
127
+ - [ ] Error reporting with line numbers
128
+ - [ ] Standard library
129
+
130
+ ---
131
+
132
+ # Why?
133
+
134
+ Because making programming languages is fun.
135
+
136
+ And because writing
137
+
138
+ ```therl
139
+ set score to 100
140
+
141
+ add 10 to score
142
+
143
+ say score
144
+ ```
145
+
146
+ just feels oddly satisfying.
147
+
148
+ ---
therl-0.1.0/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # Therl
2
+
3
+ > **T**ruly **H**uman **R**eadaby **L**anguage
4
+ > _(Yes, the acronym is a little cursed. I know.)_
5
+
6
+ Therl is a human-readable, instruction-based programming language written entirely in pure Python. Its goal is to make code read almost like plain English while remaining predictable and easy to parse.
7
+
8
+ ```therl
9
+ set greeting to "hello"
10
+
11
+ func greet <name>
12
+
13
+ say greeting + " " + name + "!"
14
+
15
+ eof
16
+
17
+ func main
18
+
19
+ run greet with <name> as "Jeff"
20
+
21
+ set numbers to [1..10]
22
+
23
+ say numbers
24
+
25
+ eof
26
+
27
+ run main
28
+ ```
29
+
30
+ Output:
31
+
32
+ ```text
33
+ hello Jeff!
34
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Features
40
+
41
+ - 📖 Human-readable syntax
42
+ - 📝 Instruction-based language design
43
+ - 🐍 Written entirely in pure Python
44
+ - 🔄 Strictly dynamically typed variables
45
+ - 📦 Built-in lists
46
+ - 🔢 Integer, float, string and boolean types
47
+ - 🧩 Functions with named parameters
48
+ - 📢 Simple `say` statement for output
49
+ - ✏️ Mutable list elements
50
+ - 🚀 Easy to extend
51
+
52
+ ---
53
+
54
+ ## Example
55
+
56
+ ```therl
57
+ set greeting to "hello"
58
+
59
+ func greet <name>
60
+
61
+ say greeting + " " + name + "!"
62
+
63
+ eof
64
+
65
+ func main
66
+
67
+ say "Welcome!"
68
+
69
+ run greet with <name> as "Jeff"
70
+
71
+ set ids to [1..10]
72
+
73
+ say ids
74
+
75
+ set ids at 0 to 1000
76
+
77
+ say ids
78
+
79
+ add 10 to ids
80
+
81
+ say ids
82
+
83
+ eof
84
+
85
+ run main
86
+ ```
87
+
88
+ Output:
89
+
90
+ ```text
91
+ Welcome!
92
+ hello Jeff!
93
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
94
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9]
95
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9, 10]
96
+ ```
97
+
98
+ ---
99
+
100
+ # Project Status
101
+
102
+ ⚠️ Therl is currently in active development.
103
+
104
+ Expect missing features, breaking changes, and plenty of experimentation as the language evolves.
105
+
106
+ ---
107
+
108
+ # Roadmap
109
+
110
+ - [ ] Arithmetic expressions
111
+ - [ ] Conditional statements
112
+ - [ ] Loops
113
+ - [ ] Dictionaries / Maps
114
+ - [ ] Modules
115
+ - [ ] Classes
116
+ - [ ] Error reporting with line numbers
117
+ - [ ] Standard library
118
+
119
+ ---
120
+
121
+ # Why?
122
+
123
+ Because making programming languages is fun.
124
+
125
+ And because writing
126
+
127
+ ```therl
128
+ set score to 100
129
+
130
+ add 10 to score
131
+
132
+ say score
133
+ ```
134
+
135
+ just feels oddly satisfying.
136
+
137
+ ---
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "therl"
7
+ version = "0.1.0"
8
+ description = "A human readable programming language"
9
+ authors = [
10
+ { name="CyzmiX", email="itzmedigamingx@gmail.com" },
11
+ ]
12
+ readme = "README.md"
13
+ requires-python = ">=3.13"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+
20
+ [project.scripts]
21
+ run-my-tool = "therl.app:main"
therl-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,4 @@
1
+ from therl.main import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
@@ -0,0 +1,13 @@
1
+ import re
2
+
3
+ from .instructions import ADD, CAST, RUN, SAY, SET
4
+
5
+ OPERATORS = ["+", "-", "/", "*", "**"]
6
+ INSTRUCTIONS_KEYWORDS = sorted(
7
+ ["add", "set", "say", "cast", "func", "eof", "run"],
8
+ key=len,
9
+ reverse=True,
10
+ )
11
+ INSTRUCTION_TO_FUNC = {"say": SAY, "set": SET, "cast": CAST, "add": ADD, "run": RUN}
12
+ pattern = f"({'|'.join(map(re.escape, INSTRUCTIONS_KEYWORDS))})"
13
+ params_pattern = f"({'|'.join(map(re.escape, ['<', '>']))})"
@@ -0,0 +1,40 @@
1
+ import sys
2
+
3
+ from .consts import INSTRUCTION_TO_FUNC
4
+ from .types import VARIABLES_TYPE
5
+
6
+
7
+ class Function:
8
+ def __init__(
9
+ self,
10
+ name: str,
11
+ params: list[str],
12
+ instructions: list[str] | None = None,
13
+ ) -> None:
14
+ self.instructions = instructions
15
+ self.name = name
16
+ self.params = params
17
+
18
+ def __name__(self):
19
+ return "function"
20
+
21
+ def run(self, params: VARIABLES_TYPE | None = None):
22
+ import therl.runtime
23
+
24
+ if self.instructions is None:
25
+ return
26
+
27
+ OLD_VARIABLES = therl.runtime.VARIABLES
28
+
29
+ if params:
30
+ therl.runtime.VARIABLES = therl.runtime.VARIABLES | params
31
+
32
+ for instruction in self.instructions:
33
+ action = instruction[0]
34
+
35
+ try:
36
+ INSTRUCTION_TO_FUNC[action](instruction[1])
37
+ therl.runtime.VARIABLES = OLD_VARIABLES
38
+ except (KeyError, IndexError):
39
+ print("invalid instruction:", str(instruction))
40
+ sys.exit(1)
@@ -0,0 +1,205 @@
1
+ import re
2
+ import sys
3
+
4
+ from .types import VARIABLES_TYPE
5
+ from .utils import _decode_value
6
+ from .variable import Variable
7
+
8
+
9
+ def SET(string: str):
10
+ from .runtime import VARIABLES
11
+
12
+ check_slices = string.split(" ")
13
+
14
+ if check_slices[1] == "to":
15
+ slices = string.split(" ", maxsplit=2)
16
+
17
+ name = slices[0]
18
+ value = slices[2]
19
+ alr_exits = VARIABLES.get(name)
20
+
21
+ if alr_exits is not None:
22
+ alr_exits.set(new_value=_decode_value(value))
23
+ return
24
+
25
+ VARIABLES[name] = Variable(name=name, value=_decode_value(value))
26
+
27
+ elif check_slices[1] == "at":
28
+ slices = string.split(" ", maxsplit=2)
29
+
30
+ name = slices[0]
31
+ alr_exits = VARIABLES.get(name)
32
+ if alr_exits is None:
33
+ print(f"Cannot modify unexisisting array named {name}")
34
+ sys.exit(1)
35
+
36
+ if alr_exits.type != list and alr_exits.type != str:
37
+ print(
38
+ f"Cannot perform index based modification on {alr_exits.type.__name__}, must list or str"
39
+ )
40
+ sys.exit(1)
41
+
42
+ index_and_value = [i.strip() for i in slices[2].split("to")]
43
+ try:
44
+ index = index_and_value[0]
45
+ if VARIABLES.get(index) is not None:
46
+ if VARIABLES.get(index).type != int:
47
+ print(
48
+ f"Invalid index type, expected int found {VARIABLES.get(index).type.__name__}"
49
+ )
50
+ sys.exit(1)
51
+ index = VARIABLES.get(index).value
52
+ else:
53
+ index = int(index)
54
+ except ValueError:
55
+ print("Invalid index type, expected int found str")
56
+ sys.exit(1)
57
+ value = index_and_value[1]
58
+ try:
59
+ VARIABLES[name].value[index] = (
60
+ _decode_value(value) if alr_exits.type == list else str(value)
61
+ )
62
+ except IndexError:
63
+ print("Index out of range!")
64
+ sys.exit(1)
65
+
66
+ else:
67
+ print("invalid syntax expected 'to' in variable assignment")
68
+ sys.exit(1)
69
+
70
+
71
+ def SAY(string: str):
72
+ from .runtime import VARIABLES
73
+
74
+ alr_exits = VARIABLES.get(string.strip())
75
+
76
+ if "at" in string:
77
+ var_and_index = [s.strip() for s in string.split("at")]
78
+ name = var_and_index[0]
79
+
80
+ if VARIABLES.get(name) is None:
81
+ print(f"Variable with name {name} doesnt exist")
82
+ sys.exit(1)
83
+
84
+ try:
85
+ index = var_and_index[1]
86
+ if VARIABLES.get(index) is not None:
87
+ if VARIABLES.get(index).type != int:
88
+ print(
89
+ f"Invalid index type, expected int found {VARIABLES.get(index).type.__name__}"
90
+ )
91
+ sys.exit(1)
92
+ index = VARIABLES.get(index).value
93
+ else:
94
+ index = int(index)
95
+ except ValueError:
96
+ print("Invalid index type, expected int found str")
97
+ sys.exit(1)
98
+
99
+ try:
100
+ print(VARIABLES[name].value[index])
101
+ return
102
+ except IndexError:
103
+ print("Index out of range")
104
+ sys.exit(1)
105
+
106
+ if alr_exits is not None:
107
+ print(alr_exits.value)
108
+ return
109
+
110
+ print(_decode_value(string))
111
+
112
+
113
+ def CAST(string: str):
114
+ from .runtime import VARIABLES
115
+
116
+ slices = [s.strip() for s in string.split("to") if s]
117
+ name = slices[0]
118
+ new_type = slices[1]
119
+ alr_exits = VARIABLES.get(name)
120
+
121
+ if alr_exits is None:
122
+ print(f"Variable with name {name} doesnt exist")
123
+ sys.exit(1)
124
+
125
+ if new_type == "int":
126
+ alr_exits.cast(int(alr_exits.value))
127
+
128
+ elif new_type == "float":
129
+ alr_exits.cast(float(alr_exits.value))
130
+
131
+ elif new_type == "str":
132
+ alr_exits.cast(str(alr_exits.value))
133
+
134
+ elif new_type == "array":
135
+ alr_exits.cast(list(alr_exits.value))
136
+
137
+ else:
138
+ print(f"Invalid type {new_type}")
139
+ sys.exit(1)
140
+
141
+
142
+ def ADD(string: str):
143
+ from .runtime import VARIABLES
144
+
145
+ slices = [s.strip() for s in string.split("to") if s]
146
+ name = slices[1]
147
+ new_value = _decode_value(slices[0])
148
+ alr_exits = VARIABLES.get(name)
149
+
150
+ if alr_exits is None:
151
+ print(f"Variable with name {name} doesnt exist")
152
+ sys.exit(1)
153
+
154
+ if alr_exits.type != list:
155
+ print(f"Variable must be an array not a {alr_exits.type.__name__}")
156
+ sys.exit(1)
157
+
158
+ alr_exits.value.append(new_value)
159
+
160
+
161
+ def RUN(string: str):
162
+ from .functions import Function
163
+ from .runtime import VARIABLES
164
+
165
+ slices = [_.strip() for _ in string.split(" ") if _]
166
+
167
+ func_name = slices[0]
168
+
169
+ if VARIABLES.get(func_name) is None:
170
+ print(f"Function named {func_name} doesnt exist!")
171
+ sys.exit(1)
172
+
173
+ if VARIABLES.get(func_name).type != Function:
174
+ print(
175
+ f"Cant run variable of type {VARIABLES.get(func_name).type.__name__}, must be a function!"
176
+ )
177
+ sys.exit(1)
178
+
179
+ if len(slices) == 1:
180
+ VARIABLES[func_name].value.run()
181
+ return
182
+
183
+ if slices[1] == "with":
184
+ params: VARIABLES_TYPE = {}
185
+ params_slices = [_.strip() for _ in " ".join(slices[2:]).split("and")]
186
+
187
+ for param in params_slices:
188
+ s = [_.strip() for _ in re.split(re.escape(" "), param) if _]
189
+ if s[1] != "as":
190
+ print(f"Expected as in parameter assignment, found {s[1]}")
191
+ sys.exit()
192
+ name = s[0].strip().replace("<", "").replace(">", "")
193
+
194
+ if name not in VARIABLES.get(func_name).value.params:
195
+ print(f"Unknown parameter {name}")
196
+ sys.exit(1)
197
+
198
+ value = s[2].strip()
199
+
200
+ if VARIABLES.get(value) is not None:
201
+ params[name] = VARIABLES.get(value)
202
+ else:
203
+ params[name] = Variable(name=name, value=_decode_value(value))
204
+
205
+ VARIABLES[func_name].value.run(params=params)
@@ -0,0 +1,81 @@
1
+ import re
2
+ import sys
3
+
4
+ from therl.consts import INSTRUCTION_TO_FUNC, params_pattern, pattern
5
+ from therl.functions import Function
6
+ from therl.runtime import VARIABLES
7
+ from therl.variable import Variable
8
+
9
+
10
+ def main():
11
+ try:
12
+ if sys.argv[1].split(".")[-1] != "therl":
13
+ print("Invalid file type, file must be .therl")
14
+ sys.exit(1)
15
+
16
+ with open(sys.argv[1], "r") as file:
17
+ instructions = [line.strip() for line in file if line.strip()]
18
+ except IndexError:
19
+ print("no file provided!")
20
+ sys.exit(1)
21
+ except FileNotFoundError:
22
+ print("file doesnt exist!")
23
+ sys.exit(1)
24
+
25
+ inside_function = False
26
+ cur_func_instuctions = []
27
+ cur_func_name = ""
28
+ cur_func_params = set()
29
+
30
+ for instruction in instructions:
31
+ tokens = [t.strip() for t in re.split(pattern, instruction, maxsplit=2) if t]
32
+
33
+ action = tokens[0]
34
+
35
+ arg = "".join(tokens[1:])
36
+
37
+ if action == "eof":
38
+ inside_function = False
39
+
40
+ VARIABLES[cur_func_name] = Variable(
41
+ name=cur_func_name,
42
+ value=Function(
43
+ name=cur_func_name,
44
+ instructions=cur_func_instuctions,
45
+ params=list(cur_func_params),
46
+ ),
47
+ )
48
+ cur_func_name = ""
49
+ cur_func_instuctions = []
50
+ cur_func_params.clear()
51
+ continue
52
+
53
+ if inside_function:
54
+ cur_func_instuctions.append(tokens)
55
+ continue
56
+
57
+ if action == "func":
58
+ name_and_params = [l.strip() for l in arg.split(" ") if l]
59
+ cur_func_name = name_and_params[0]
60
+
61
+ if VARIABLES.get(cur_func_name) is not None:
62
+ print(
63
+ f"Cant name function to a variable of the same name, '{cur_func_name}' is already defined!"
64
+ )
65
+ sys.exit(1)
66
+
67
+ inside_function = True
68
+ params_split = [
69
+ t.strip()
70
+ for t in re.split(params_pattern, "".join(name_and_params[1:]))
71
+ if t
72
+ ]
73
+ for i, param in enumerate(params_split):
74
+ try:
75
+ if param == "<" and params_split[i + 2] == ">":
76
+ cur_func_params.add(params_split[i + 1])
77
+ except IndexError:
78
+ break
79
+
80
+ if not inside_function:
81
+ INSTRUCTION_TO_FUNC[action](arg)
@@ -0,0 +1,4 @@
1
+ from .types import VARIABLES_TYPE
2
+
3
+ VARIABLES: VARIABLES_TYPE = {}
4
+ SYNTAX = {"assign_value": "to"}
@@ -0,0 +1,3 @@
1
+ from .variable import Variable
2
+
3
+ type VARIABLES_TYPE = dict[str, Variable]
@@ -0,0 +1,83 @@
1
+ import sys
2
+ from typing import Any
3
+
4
+ import therl.consts
5
+
6
+
7
+ def _decode_value(value: str) -> Any:
8
+ from therl.runtime import VARIABLES
9
+
10
+ if value[0] == "[" and value[-1] == "]":
11
+ return _decode_array(value)
12
+
13
+ used_operator = not set(value.split(" ")).isdisjoint(therl.consts.OPERATORS)
14
+
15
+ if used_operator:
16
+ try:
17
+ return eval(
18
+ value,
19
+ None,
20
+ {
21
+ var[0]: var[1].value for var in VARIABLES.items()
22
+ }, # will it be unsafe in this case ?
23
+ )
24
+ except NameError as e:
25
+ print(f"variable nammed {e.name} doesnt exist!")
26
+ sys.exit(1)
27
+
28
+ if value.strip()[0] == value.strip()[-1] == '"':
29
+ return str(value[1:-1])
30
+
31
+ if value.strip().lower() == "true":
32
+ return True
33
+ if value.strip().lower() == "false":
34
+ return False
35
+
36
+ # Try Integer
37
+ try:
38
+ return int(value)
39
+ except ValueError:
40
+ pass
41
+
42
+ # Try Float
43
+ try:
44
+ return float(value)
45
+ except ValueError:
46
+ pass
47
+
48
+ if VARIABLES.get(value) is not None:
49
+ return VARIABLES.get(value).value
50
+
51
+ print("Invalid data value: ", value.strip())
52
+ sys.exit(1)
53
+
54
+
55
+ def _decode_array(array_str: str) -> list:
56
+ clean_str = array_str[1:-1] # remove [ ]
57
+
58
+ if clean_str.strip() == "":
59
+ return []
60
+
61
+ if ".." in clean_str:
62
+ try:
63
+ s_and_f = clean_str.split("..")
64
+ start = int(s_and_f[0])
65
+
66
+ finish = int(s_and_f[-1])
67
+
68
+ return list(range(start, finish))
69
+ except ValueError:
70
+ print("Array sequence must be made with two ints!")
71
+ sys.exit(1)
72
+
73
+ array = []
74
+
75
+ for val in clean_str.split(","):
76
+ v = _decode_value(val.strip())
77
+ if len(array) > 0 and type(array[0]) != type(v):
78
+ print("Cannot mix and match data types in array!")
79
+ sys.exit(1)
80
+
81
+ array.append(v)
82
+
83
+ return array
@@ -0,0 +1,24 @@
1
+ import sys
2
+ from typing import Any, Generic, TypeVar
3
+
4
+ T = TypeVar("T")
5
+
6
+
7
+ class Variable(Generic[T]):
8
+ def __init__(self, name: str, value: T) -> None:
9
+ self.name = name
10
+ self.type: type[T] = type(value)
11
+ self.value: T = value
12
+
13
+ def set(self, new_value: Any):
14
+ if type(new_value) is not self.type:
15
+ print(
16
+ f"Error variable types doesnt match! from {self.type.__name__} to {type(new_value).__name__}"
17
+ )
18
+ sys.exit(1)
19
+
20
+ self.value = new_value
21
+
22
+ def cast(self, new_value: T):
23
+ self.type: type[T] = type(new_value)
24
+ self.value: T = new_value
@@ -0,0 +1,148 @@
1
+ Metadata-Version: 2.4
2
+ Name: therl
3
+ Version: 0.1.0
4
+ Summary: A human readable programming language
5
+ Author-email: CyzmiX <itzmedigamingx@gmail.com>
6
+ Classifier: Programming Language :: Python :: 3
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.13
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Therl
13
+
14
+ > **T**ruly **H**uman **R**eadaby **L**anguage
15
+ > _(Yes, the acronym is a little cursed. I know.)_
16
+
17
+ Therl is a human-readable, instruction-based programming language written entirely in pure Python. Its goal is to make code read almost like plain English while remaining predictable and easy to parse.
18
+
19
+ ```therl
20
+ set greeting to "hello"
21
+
22
+ func greet <name>
23
+
24
+ say greeting + " " + name + "!"
25
+
26
+ eof
27
+
28
+ func main
29
+
30
+ run greet with <name> as "Jeff"
31
+
32
+ set numbers to [1..10]
33
+
34
+ say numbers
35
+
36
+ eof
37
+
38
+ run main
39
+ ```
40
+
41
+ Output:
42
+
43
+ ```text
44
+ hello Jeff!
45
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Features
51
+
52
+ - 📖 Human-readable syntax
53
+ - 📝 Instruction-based language design
54
+ - 🐍 Written entirely in pure Python
55
+ - 🔄 Strictly dynamically typed variables
56
+ - 📦 Built-in lists
57
+ - 🔢 Integer, float, string and boolean types
58
+ - 🧩 Functions with named parameters
59
+ - 📢 Simple `say` statement for output
60
+ - ✏️ Mutable list elements
61
+ - 🚀 Easy to extend
62
+
63
+ ---
64
+
65
+ ## Example
66
+
67
+ ```therl
68
+ set greeting to "hello"
69
+
70
+ func greet <name>
71
+
72
+ say greeting + " " + name + "!"
73
+
74
+ eof
75
+
76
+ func main
77
+
78
+ say "Welcome!"
79
+
80
+ run greet with <name> as "Jeff"
81
+
82
+ set ids to [1..10]
83
+
84
+ say ids
85
+
86
+ set ids at 0 to 1000
87
+
88
+ say ids
89
+
90
+ add 10 to ids
91
+
92
+ say ids
93
+
94
+ eof
95
+
96
+ run main
97
+ ```
98
+
99
+ Output:
100
+
101
+ ```text
102
+ Welcome!
103
+ hello Jeff!
104
+ [1, 2, 3, 4, 5, 6, 7, 8, 9]
105
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9]
106
+ [1000, 2, 3, 4, 5, 6, 7, 8, 9, 10]
107
+ ```
108
+
109
+ ---
110
+
111
+ # Project Status
112
+
113
+ ⚠️ Therl is currently in active development.
114
+
115
+ Expect missing features, breaking changes, and plenty of experimentation as the language evolves.
116
+
117
+ ---
118
+
119
+ # Roadmap
120
+
121
+ - [ ] Arithmetic expressions
122
+ - [ ] Conditional statements
123
+ - [ ] Loops
124
+ - [ ] Dictionaries / Maps
125
+ - [ ] Modules
126
+ - [ ] Classes
127
+ - [ ] Error reporting with line numbers
128
+ - [ ] Standard library
129
+
130
+ ---
131
+
132
+ # Why?
133
+
134
+ Because making programming languages is fun.
135
+
136
+ And because writing
137
+
138
+ ```therl
139
+ set score to 100
140
+
141
+ add 10 to score
142
+
143
+ say score
144
+ ```
145
+
146
+ just feels oddly satisfying.
147
+
148
+ ---
@@ -0,0 +1,17 @@
1
+ README.md
2
+ pyproject.toml
3
+ src/therl/__init__.py
4
+ src/therl/__main__.py
5
+ src/therl/consts.py
6
+ src/therl/functions.py
7
+ src/therl/instructions.py
8
+ src/therl/main.py
9
+ src/therl/runtime.py
10
+ src/therl/types.py
11
+ src/therl/utils.py
12
+ src/therl/variable.py
13
+ src/therl.egg-info/PKG-INFO
14
+ src/therl.egg-info/SOURCES.txt
15
+ src/therl.egg-info/dependency_links.txt
16
+ src/therl.egg-info/entry_points.txt
17
+ src/therl.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ run-my-tool = therl.app:main
@@ -0,0 +1 @@
1
+ therl