rising-sse 0.1.dev0__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.
@@ -0,0 +1,2 @@
1
+ # Created by venv; see https://docs.python.org/3/library/venv.html
2
+ *
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.4
2
+ Name: rising-sse
3
+ Version: 0.1.dev0
4
+ Summary: The base interpreter and mode system for semantic syntax
5
+ Author-email: rising <risingwanabe@gmail.com>
6
+ Maintainer-email: rising <risingwanabe@gmail.com>
7
+ Requires-Dist: lark
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+
6
+ [project]
7
+ name = "rising-sse"
8
+ version = "0.1dev"
9
+ description = "The base interpreter and mode system for semantic syntax"
10
+ authors = [
11
+ { name = "rising", email = "risingwanabe@gmail.com" },
12
+ ]
13
+ maintainers = [
14
+ { name = "rising", email = "risingwanabe@gmail.com" },
15
+ ]
16
+ dependencies = ["lark"]
17
+
18
+ [tool.hatch.envs.stretch]
19
+ type = "virtual"
20
+ path = ".stretch"
21
+ dependencies = ["requests", "lark"]
22
+
23
+ [tool.hatch.build]
24
+ include = ["sse"]
25
+
26
+ [tool.hatch.version]
27
+ #[project.scripts]
28
+
@@ -0,0 +1,17 @@
1
+ from .engine import Engine, run
2
+ from .mode import Mode, GetMode, primitive, prompt
3
+
4
+ def basic_engine():
5
+ """
6
+ call this function if you just want to play around with the base form of the engine
7
+ without modifying or extending its functionality or hooking it into an API or game.
8
+ Otherwise, you can create an instance of the engine using Engine(), and start it by calling run()
9
+ on it, or ticking it within your own loop function.
10
+ To retrieve any mode use its modename in GetMode(modename:str).
11
+ To create a mode use Mode(modename:str, available:bool=True), set available to False to hide it
12
+ from GetMode
13
+ """
14
+
15
+ semantic_syntax_engine = Engine()
16
+ run(semantic_syntax_engine)
17
+
@@ -0,0 +1,214 @@
1
+ from .mode import GetMode, default_globals
2
+ from .parser import tokenize
3
+
4
+ class Engine:
5
+ __slots__ = ("frame_stack", "running", "engine_globals", "mode")
6
+ def __init__(self, starter = GetMode('main'), engine_globals = default_globals):
7
+ self.frame_stack = []
8
+ self.running = False
9
+ self.mode = starter
10
+ self.engine_globals = engine_globals
11
+ @property
12
+ def frame(self):
13
+ return self.frame_stack[-1]
14
+ def tick(self):
15
+
16
+ if len(self.frame_stack) > 0:
17
+ # get the engines current frame
18
+ frame = self.frame
19
+
20
+ # extract the frames mode
21
+ mode = frame['mode']
22
+ # the frames positions
23
+ line_position = frame['line_position']
24
+ element_position = frame['element_position']
25
+
26
+ # the frames instructions
27
+ instructions = frame['instructions']
28
+ # the frames scope and the frames stack
29
+ scope = frame['scope']
30
+ stack = frame['stack']
31
+
32
+ engine_globals = self.engine_globals
33
+
34
+ if line_position >= len(instructions):
35
+ previous_frame = self.frame_stack.pop()
36
+ else:
37
+ # get the current line and element
38
+ current_line = instructions[line_position]
39
+ if element_position is None:
40
+ element_position = len(current_line) - 1
41
+ current_element = current_line[element_position]
42
+ frame['element_position'] = element_position
43
+
44
+ # TICK LOGIC
45
+ self.handle_element(current_element, frame, mode, scope, stack)
46
+
47
+ # increment positions
48
+ element_position = frame['element_position']
49
+ element_position -= 1
50
+ if element_position <= -1:
51
+ element_position = None
52
+ line_position += 1
53
+ frame['line_position'] = line_position
54
+ stack.clear()
55
+ frame['element_position'] = element_position
56
+
57
+ else:
58
+ mode = self.mode
59
+ if 'prompt' in mode:
60
+ mode['prompt'](mode)
61
+ else:
62
+ self.engine_globals["prompt"](mode)
63
+ usertext = input()
64
+ code = tokenize(self.structure_input(usertext))
65
+ frame = self.Frame(mode, mode['main'], code)
66
+ self.AddFrame(frame)
67
+
68
+ def handle_element(self, current_element, frame, mode, scope, stack):
69
+ element_type, value = current_element
70
+
71
+ engine_globals = self.engine_globals
72
+
73
+ match element_type:
74
+ case "string" | "integer" | "float" | "rawtoken" | "dotchain":
75
+ stack.append(value)
76
+ case "primitive":
77
+ mode_primitives = mode['primitives']
78
+ global_primitives = engine_globals['primitives']
79
+ if value in mode_primitives:
80
+ mode_primitives[value](frame, self, stack)
81
+ elif value in global_primitives:
82
+ global_primitives[value](frame, self, stack)
83
+ else:
84
+ self.error(f"There is no available primitive called '{value}'.", "Missing Primitive")
85
+ case "intentive":
86
+ if len(stack) > 0:
87
+ intent = stack.pop()
88
+ if isinstance(intent, list):
89
+ intent = intent[::-1]
90
+ mode_primitives = mode['primitives']
91
+ global_primitives = engine_globals['primitives']
92
+ if value in mode_primitives:
93
+ mode_primitives[value](frame, self, intent)
94
+ elif value in global_primitives:
95
+ global_primitives[value](frame, self, intent)
96
+ else:
97
+ self.error(f"There is no available primitive called '{value}'.", "Missing Primitive")
98
+ else:
99
+ self.error(f"Intentive primitive expects a stack not {intent}.", "Incorrect Intent")
100
+ else:
101
+ self.error(f"No available intentive stack.", "Missing Intent")
102
+ case "set_var":
103
+ set_val = stack.pop()
104
+
105
+ # find the start of the path
106
+ # only set in current_scope
107
+ current_scope = scope
108
+
109
+ for link in value[:-1]:
110
+ if link in current_scope:
111
+ current_scope = current_scope[link]
112
+ else:
113
+ self.error(f"Could not follow the path {value} past '{link}'.", "Missing Link")
114
+ break
115
+ else:
116
+ current_scope[value[-1]] = set_val
117
+
118
+ case "get_var":
119
+ start, path = value[0], value[1:]
120
+
121
+ current_scope = scope
122
+ nonlocal_scope = current_scope if '__nonlocal__' in current_scope else current_scope
123
+ global_scope = engine_globals['main']
124
+
125
+ # find the start of the path
126
+ # prioritize current_scope -> nonlocal_scope -> global_scope
127
+ getting = None
128
+ if start in current_scope:
129
+ getting = current_scope[start]
130
+ elif start in nonlocal_scope:
131
+ getting = nonlocal_scope[start]
132
+ elif start in global_scope:
133
+ getting = global_scope[start]
134
+ else:
135
+ self.error(f"There is no available variable called '{start}'.", "Missing Variable")
136
+ if getting is not None:
137
+ if len(path) > 0:
138
+ for link in path:
139
+ if link in getting:
140
+ getting = getting[link]
141
+ else:
142
+ self.error(f"Could not follow the path {path} from {start} past '{link}'.", "Missing Link")
143
+ getting = None
144
+ break
145
+ if getting is not None:
146
+ stack.append(getting)
147
+ else:
148
+ stack.append(getting)
149
+ case "stack":
150
+ new_stack = []
151
+ for element in value[::-1]:
152
+ self.handle_element(element, frame, mode, scope, new_stack)
153
+ stack.append(new_stack[::-1])
154
+ case "block":
155
+ stack.append({"__instructions__":value})
156
+ case other:
157
+ print(other, value)
158
+
159
+ @staticmethod
160
+ def Frame(mode, scope, instructions):
161
+ return {
162
+ "mode":mode,
163
+ "line_position":0,
164
+ "element_position":None,
165
+ "scope":scope,
166
+ "instructions":instructions,
167
+ "stack":[]
168
+ }
169
+ def AddFrame(self, frame):
170
+ self.frame_stack.append(frame)
171
+ def say(self, message:str, name:str="Semantic Syntax Engine"):
172
+ print(f"[{name}]: {message}")
173
+ def announce(self, message:str):
174
+ print(message)
175
+ def error(self, message:str, errortype:str="Exception"):
176
+ self.say(f"({errortype}) {message}")
177
+
178
+ def structure_input(self, usertext:str, section_start:str="[", section_end:str="]"):# -> list:
179
+ index = 0
180
+ section = ""
181
+ depth = 0
182
+ sections = []
183
+ while index < len(usertext):
184
+ char = usertext[index]
185
+ if char == section_start:
186
+ if depth > 0:
187
+ section += char
188
+ depth += 1
189
+
190
+ elif char == section_end:
191
+ if depth == 0:
192
+ raise Exception(f"No starting '[' to ']' at character {index}")
193
+ elif depth == 1:
194
+ sections.append(section)
195
+ section = ""
196
+ elif depth > 1:
197
+ section += char
198
+
199
+ depth -= 1
200
+ else:
201
+ if depth > 0:
202
+ section += char
203
+ index += 1
204
+ return "; ".join(sections)
205
+ def SetMode(self, modename:str):
206
+ mode = GetMode(modename)
207
+ if mode is not None:
208
+ self.mode = mode
209
+ else:
210
+ self.error(f"There is no available mode called {modename}", "Missing Mode")
211
+ def run(engine:Engine):
212
+ engine.running = True
213
+ while engine.running:
214
+ engine.tick()
@@ -0,0 +1,191 @@
1
+ """
2
+ In the Semantic Syntax Engine a mode is a module of the language
3
+ the engine will use its mode to determine how to interpret Semantic Syntax
4
+ switching out modules is like switching to an entirely new set of tools
5
+ while the basic structure remains the same
6
+ """
7
+ from .parser import tokenize
8
+ import os
9
+
10
+ __modes = {}
11
+
12
+ def Mode(modename:str, available:bool=True):
13
+ mode = {
14
+ "name":modename,
15
+ "primitives":{},
16
+ "main":{},
17
+ }
18
+ if available:
19
+ __modes[modename] = mode
20
+ return mode
21
+
22
+ def GetMode(modename:str):
23
+ if modename in __modes:
24
+ return __modes[modename]
25
+ else:
26
+ return None
27
+
28
+ def primitive(mode, name):
29
+ def wrap(method):
30
+ mode['primitives'][name] = method
31
+ return wrap
32
+
33
+ def prompt(mode):
34
+ def wrap(method):
35
+ mode['prompt'] = method
36
+ return wrap
37
+
38
+ # the default mode for globals that are accessible in any other mode (can be changed)
39
+ default_globals = Mode('default_globals', False)
40
+ main = Mode('main')
41
+
42
+
43
+ @prompt(default_globals)
44
+ def _prompt(self):
45
+ pass
46
+
47
+
48
+ # OUTPUT
49
+ @primitive(default_globals, "print")
50
+ def _print(frame, engine, stack):
51
+ output = " ".join(str(element) for element in stack[::-1])
52
+ print(output)
53
+ if not output.endswith('\n'):
54
+ print()
55
+
56
+ stack.clear()
57
+
58
+ # MATHEMATICS
59
+ @primitive(default_globals, "add")
60
+ def add(frame, engine, stack):
61
+ obj_a = stack.pop()
62
+ obj_b = stack.pop()
63
+ stack.append(obj_a + obj_b)
64
+ @primitive(default_globals, "sub")
65
+ def subtract(frame, engine, stack):
66
+ obj_a = stack.pop()
67
+ obj_b = stack.pop()
68
+ stack.append(obj_a - obj_b)
69
+ @primitive(default_globals, "mul")
70
+ def multiply(frame, engine, stack):
71
+ obj_a = stack.pop()
72
+ obj_b = stack.pop()
73
+ stack.append(obj_a * obj_b)
74
+ @primitive(default_globals, "div")
75
+ def divide(frame, engine, stack):
76
+ obj_a = stack.pop()
77
+ obj_b = stack.pop()
78
+ stack.append(obj_a / obj_b)
79
+
80
+ # STACK
81
+ @primitive(default_globals, "Stack")
82
+ def create_stack(frame, engine, stack):
83
+ new_stack = stack[::-1]
84
+ stack.clear()
85
+ stack.append(new_stack)
86
+ @primitive(default_globals, "pull")
87
+ def pull_stack(frame, engine, stack):
88
+ _stack = stack[-1]
89
+ stack.append(_stack.pop(0))
90
+ @primitive(default_globals, "push")
91
+ def push_stack(frame, engine, stack):
92
+ value = stack.pop()
93
+ _stack = stack[-1]
94
+ _stack.insert(0, value)
95
+
96
+ # BLOCK
97
+ @primitive(default_globals, "Block") # create an empty block
98
+ def create_block(frame, engine, stack):
99
+ new_block = {}
100
+ stack.append(new_block)
101
+ @primitive(default_globals, "def") # add parameters to a block
102
+ def define(frame, engine, stack):
103
+ parameters = stack.pop()
104
+ obj = stack.pop()
105
+ if '__instructions__' in obj:
106
+ obj['__params__'] = parameters
107
+ stack.append(obj)
108
+ else:
109
+ engine.error(f"Cannot add parameters to {obj}", "Incallable Object")
110
+ @primitive(default_globals, "call") # call a block
111
+ def call(frame, engine, stack):
112
+ obj = stack.pop()
113
+ if '__instructions__' in obj:
114
+ params = obj.get('__params__', tuple())
115
+ for param in params:
116
+ if len(stack) > 0:
117
+ argument = stack.pop()
118
+ obj[param] = argument
119
+ else:
120
+ engine.error(f"Failed to call {obj}", "Insifficient Arguments")
121
+ break
122
+ else:
123
+ new_frame = engine.Frame(frame['mode'], obj, obj['__instructions__'])
124
+ engine.AddFrame(new_frame)
125
+ else:
126
+ engine.error(f"Cannot call {obj}", "Incallable Object")
127
+ @primitive(default_globals, "return") # return a value
128
+ def return_value(frame, engine, stack):
129
+ if len(engine.frame_stack) > 1:
130
+ engine.frame_stack[-2]['stack'].append(stack.pop())
131
+ engine.frame_stack.pop()
132
+ @primitive(default_globals, "yield") # return a value without stopping
133
+ def return_value(frame, engine, stack):
134
+ if len(engine.frame_stack) > 1:
135
+ engine.frame_stack[-2]['stack'].append(stack.pop())
136
+ @primitive(default_globals, "script") # import a .sse file as a block
137
+ def script(frame, engine, stack):
138
+ dotchain = stack.pop()
139
+ if not isinstance(dotchain, str):
140
+ dotchain = "/".join(dotchain)
141
+ filepath = dotchain + ".sse"
142
+ if os.path.exists(filepath):
143
+ with open(filepath) as file:
144
+ code = file.read()
145
+ stack.append({'__instructions__':tokenize(code)})
146
+ else:
147
+ engine.error(f"Could not load script '{filepath}'.", "Missing File")
148
+
149
+ # CONTROL FLOW
150
+ @primitive(default_globals, "line") # get the current line as an integer
151
+ def get_current_line(frame, engine, stack):
152
+ stack.append(frame['line_position'])
153
+ @primitive(default_globals, "goto") # goto a given line
154
+ def goto_line(frame, engine, stack):
155
+ line_position = stack.pop()
156
+ engine.frame_stack.pop()
157
+ new_frame = engine.Frame(frame['mode'], frame['scope'], frame['instructions'])
158
+ new_frame['line_position'] = line_position
159
+ engine.AddFrame(new_frame)
160
+ @primitive(default_globals, "if")
161
+ def if_statement(frame, engine, stack):
162
+ if len(stack) > 0:
163
+ if stack.pop():
164
+ return
165
+ frame['element_position'] = 0
166
+ @primitive(default_globals, "not")
167
+ def _not(frame, engine, stack):
168
+ if len(stack) > 0:
169
+ stack.append(not stack.pop())
170
+ else:
171
+ stack.append(True)
172
+ @primitive(default_globals, "True")
173
+ def true(frame, engine, stack):
174
+ stack.append(True)
175
+ @primitive(default_globals, "False")
176
+ def false(frame, engine, stack):
177
+ stack.append(False)
178
+
179
+ @primitive(default_globals, "mode")
180
+ def get_mode_name(frame, engine, stack):
181
+ stack.insert(0, frame['mode']['name'])
182
+ @primitive(default_globals, "setmode")
183
+ def set_mode(frame, engine, stack):
184
+ modename = stack.pop()
185
+ engine.SetMode(modename)
186
+
187
+
188
+
189
+
190
+
191
+
@@ -0,0 +1,126 @@
1
+ from lark import Lark, Transformer, Discard
2
+
3
+
4
+ ss_structure = r"""
5
+
6
+ %import common.WS
7
+
8
+
9
+
10
+ ws: WS ?
11
+
12
+ start: ws (line (";" line)*) ? ws
13
+
14
+ line: ws (element (WS element)*) ? ws
15
+
16
+ element: STRING | NUMBER | rawtoken | stack | block | primitive | intentive | get_var | set_var | dotchain
17
+
18
+ %import common.ESCAPED_STRING -> STRING
19
+ %import common.SIGNED_NUMBER -> NUMBER
20
+ RAWTOKEN: /[a-zA-Z_][a-zA-Z0-9_-]*/
21
+ rawtoken: RAWTOKEN
22
+
23
+ stack: "[" line "]"
24
+ block: "{" start "}"
25
+
26
+ primitive: "/" RAWTOKEN
27
+ intentive: RAWTOKEN ws "->"
28
+
29
+ rawchain: (RAWTOKEN ("." RAWTOKEN)*) | ("." RAWTOKEN ("." RAWTOKEN)*) | (RAWTOKEN "." (RAWTOKEN ".")*) | ("." RAWTOKEN "." (RAWTOKEN ".")*) | (".")
30
+ dotchain: rawchain
31
+
32
+ get_var: rawchain "?"
33
+ set_var: rawchain ":"
34
+
35
+ """
36
+
37
+ class SS_Builder(Transformer):
38
+ def ws(self, ws):
39
+ return Discard
40
+ def WS(self, WS):
41
+ return Discard
42
+ def start(self, lines):
43
+ return tuple(lines)
44
+ def line(self, elements):
45
+ if len(elements) < 1:
46
+ return Discard
47
+ return tuple(elements)
48
+ def element(self, element):
49
+ return element[0]
50
+ def STRING(self, string):
51
+ return ("string", string[1:-1])
52
+ def NUMBER(self, number):
53
+ if '.' in number:
54
+ return ("float", float(number))
55
+ else:
56
+ return ("integer", int(number))
57
+ def RAWTOKEN(self, rawtoken):
58
+ return rawtoken[:]
59
+ def rawtoken(self, rawtoken):
60
+ return ("string", rawtoken[0])
61
+ def stack(self, stack):
62
+ if len(stack) >= 1:
63
+ return ("stack", stack[0])
64
+ else:
65
+ return ("stack", [])
66
+ def block(self, instructions):
67
+ if len(instructions) > 0:
68
+ return ("block", instructions[0])
69
+ else:
70
+ return ("block", tuple())
71
+ def primitive(self, primitive):
72
+ return ("primitive", primitive[0])
73
+ def intentive(self, primitive):
74
+ return ("intentive", primitive[0])
75
+ def rawchain(self, RAWTOKENS):
76
+ return tuple(RAWTOKENS)
77
+ def dotchain(self, rawchain):
78
+ return ("dotchain",rawchain[0])
79
+
80
+ def get_var(self, get_var):
81
+ return ("get_var", get_var[0])
82
+ def set_var(self, set_var):
83
+ return ("set_var", set_var[0])
84
+ ss_parser = Lark(ss_structure)
85
+ ss_builder = SS_Builder()
86
+
87
+ def tokenize(ss:str):
88
+ ss_tree = ss_parser.parse(ss)
89
+ ss_tokens = ss_builder.transform(ss_tree)
90
+ return ss_tokens
91
+
92
+ if __name__ == '__main__':
93
+ string_example = """
94
+ "here is a string" "and another"
95
+ """
96
+ print(tokenize(string_example))
97
+ number_example = """
98
+ 0.1 0 9 3 1.335
99
+ """
100
+ tokenize(number_example)
101
+ rawtoken_example = """
102
+ hello_wha-t9_
103
+ """
104
+ tokenize(rawtoken_example)
105
+ var_example = """
106
+ x: 0; x?;
107
+ x.x: 7;
108
+ """
109
+ print(tokenize(var_example))
110
+ stack_example = """
111
+ [0 hello_wow "heres a string in a stack"]
112
+ """
113
+ print(tokenize(stack_example))
114
+ block_example = """
115
+ {x 0 x-1;2.4 "string baby" i-1000}
116
+ """
117
+ print(tokenize(block_example))
118
+ primitive_example = """
119
+ ~prim
120
+ """
121
+ print(tokenize(primitive_example))
122
+
123
+
124
+
125
+
126
+