astreum 0.1.2__py3-none-any.whl → 0.1.3__py3-none-any.whl

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.

Potentially problematic release.


This version of astreum might be problematic. Click here for more details.

@@ -9,30 +9,19 @@ from src.astreum.machine.parser import parse
9
9
 
10
10
  class AstreumMachine:
11
11
  def __init__(self):
12
- # Initialize the global environment
13
12
  self.global_env = Environment()
14
13
 
15
- # Dictionary to manage user sessions: session_id -> local Environment
16
14
  self.sessions: Dict[str, Environment] = {}
17
15
 
18
- # Lock for thread-safe access to the global environment and sessions
19
16
  self.lock = threading.Lock()
20
17
 
21
18
  def create_session(self) -> str:
22
- """
23
- Create a new user session with a unique session ID and a fresh local environment.
24
- Returns the session ID.
25
- """
26
19
  session_id = str(uuid.uuid4())
27
20
  with self.lock:
28
21
  self.sessions[session_id] = Environment(parent=self.global_env)
29
22
  return session_id
30
23
 
31
24
  def terminate_session(self, session_id: str) -> bool:
32
- """
33
- Terminate an existing user session.
34
- Returns True if the session was successfully terminated, False otherwise.
35
- """
36
25
  with self.lock:
37
26
  if session_id in self.sessions:
38
27
  del self.sessions[session_id]
@@ -41,123 +30,92 @@ class AstreumMachine:
41
30
  return False
42
31
 
43
32
  def get_session_env(self, session_id: str) -> Optional[Environment]:
44
- """
45
- Retrieve the local environment for a given session ID.
46
- Returns the Environment if found, None otherwise.
47
- """
48
33
  with self.lock:
49
34
  return self.sessions.get(session_id, None)
50
35
 
51
36
  def evaluate_code(self, code: str, session_id: str) -> Tuple[Optional[Expr], Optional[str]]:
52
- """
53
- Evaluate code within the context of a user's session.
54
- Returns a tuple of (Result Expression, Error Message).
55
- If evaluation is successful, Error Message is None.
56
- If an error occurs, Result Expression is None.
57
- """
58
- env = self.get_session_env(session_id)
59
- if env is None:
37
+ session_env = self.get_session_env(session_id)
38
+ if session_env is None:
60
39
  return None, f"Session ID {session_id} not found."
61
40
 
62
41
  try:
63
42
  tkns = tokenize(input=code)
64
43
  expr, _ = parse(tokens=tkns)
65
- result = self.evaluate(expr, env)
44
+ result = self.evaluate_expression(expr, session_env)
66
45
  return result, None
67
46
  except Exception as e:
68
47
  return None, str(e)
69
48
 
70
- def evaluate(self, expr: Expr, env: Environment) -> Expr:
71
-
49
+ def evaluate_expression(self, expr: Expr, env: Environment) -> Expr:
72
50
  if isinstance(expr, Expr.Integer):
73
51
  return expr
52
+
74
53
  elif isinstance(expr, Expr.String):
75
54
  return expr
55
+
76
56
  elif isinstance(expr, Expr.Symbol):
77
57
  value = env.get(expr.value)
78
58
  if value is not None:
79
59
  return value
80
60
  else:
81
- # Return the symbol itself if not found in the environment
82
- return expr
61
+ raise ValueError("Variable not found in environments.")
62
+
83
63
  elif isinstance(expr, Expr.ListExpr):
84
64
  if not expr.elements:
85
- raise ValueError("Empty list cannot be evaluated")
65
+ raise ValueError("Empty list cannot be evaluated.")
86
66
 
87
67
  first = expr.elements[0]
68
+
88
69
  if isinstance(first, Expr.Symbol):
89
- # Check if it's a user-defined function
90
- user_def_fn = env.get(first.value)
91
- if isinstance(user_def_fn, Expr.Function):
92
- fn_params, fn_body = user_def_fn.params, user_def_fn.body
70
+
71
+ first_symbol_value = env.get(first.value)
72
+
73
+ if first_symbol_value and not isinstance(first_symbol_value, Expr.Function):
74
+ evaluated_elements = [self.evaluate_expression(e, env) for e in expr.elements]
75
+ return Expr.ListExpr(evaluated_elements)
93
76
  args = expr.elements[1:]
94
77
 
95
78
  if len(fn_params) != len(args):
96
- raise TypeError(f"expected {len(fn_params)} arguments, got {len(args)}")
79
+ raise ValueError(f"Expected {len(fn_params)} arguments, got {len(args)}.")
97
80
 
98
81
  # Create a new environment for the function execution, inheriting from the function's defining environment
99
82
  new_env = Environment(parent=env)
100
83
 
101
84
  # Evaluate and bind each argument
102
85
  for param, arg in zip(fn_params, args):
103
- evaluated_arg = self.evaluate(arg, env)
86
+ evaluated_arg = self.evaluate_expression(arg, env)
104
87
  new_env.set(param, evaluated_arg)
105
88
 
106
89
  # Evaluate the function body within the new environment
107
- return self.evaluate(fn_body, new_env)
90
+ return self.evaluate_expression(fn_body, new_env)
108
91
 
109
- # Check for special functions
110
92
  elif first.value in ["def", "+"]:
111
93
  args = expr.elements[1:]
112
94
 
113
95
  match first.value:
114
96
  case "def":
115
97
  if len(args) != 2:
116
- raise TypeError("def expects exactly two arguments: a symbol and an expression")
98
+ raise ValueError("def expects exactly two arguments: a symbol and an expression")
117
99
  if not isinstance(args[0], Expr.Symbol):
118
- raise TypeError("First argument to def must be a symbol")
100
+ raise ValueError("First argument to def must be a symbol")
119
101
 
120
102
  var_name = args[0].value
121
- var_value = self.evaluate(args[1], env)
103
+ var_value = self.evaluate_expression(args[1], env)
122
104
  env.set(var_name, var_value)
123
- return args[0] # Return the symbol name
105
+ return args[0]
124
106
 
125
107
  case "+":
126
- # Ensure all arguments are integers
127
- evaluated_args = [self.evaluate(arg, env) for arg in args]
108
+ evaluated_args = [self.evaluate_expression(arg, env) for arg in args]
128
109
  if not all(isinstance(arg, Expr.Integer) for arg in evaluated_args):
129
- raise TypeError("All arguments to + must be integers")
110
+ raise ValueError("All arguments to + must be integers")
130
111
 
131
- # Sum the integer values and return as an Expr.Integer
132
112
  result = sum(arg.value for arg in evaluated_args)
133
113
  return Expr.Integer(result)
134
114
 
135
- else:
136
- # Attempt to evaluate as a function application
137
- func = self.evaluate(first, env)
138
- if isinstance(func, Expr.Function):
139
- fn_params, fn_body = func.params, func.body
140
- args = expr.elements[1:]
141
-
142
- if len(fn_params) != len(args):
143
- raise TypeError(f"expected {len(fn_params)} arguments, got {len(args)}")
144
-
145
- # Create a new environment for the function execution, inheriting from the function's defining environment
146
- new_env = Environment(parent=func.env)
147
-
148
- # Evaluate and bind each argument
149
- for param, arg in zip(fn_params, args):
150
- evaluated_arg = self.evaluate(arg, env)
151
- new_env.set(param, evaluated_arg)
152
-
153
- # Evaluate the function body within the new environment
154
- return self.evaluate(fn_body, new_env)
155
- else:
156
- raise TypeError(f"'{first.value}' is not a function")
157
115
  else:
158
- evaluated_elements = [self.evaluate(e, env) for e in expr.elements]
116
+ evaluated_elements = [self.evaluate_expression(e, env) for e in expr.elements]
159
117
  return Expr.ListExpr(evaluated_elements)
160
118
  elif isinstance(expr, Expr.Function):
161
119
  return expr
162
120
  else:
163
- raise TypeError(f"Unknown expression type: {type(expr)}")
121
+ raise ValueError(f"Unknown expression type: {type(expr)}")
@@ -1,5 +1,4 @@
1
- # Define the Environment class
2
- from typing import Callable, Dict, List, Optional
1
+ from typing import Dict, Optional
3
2
  from src.astreum.machine.expression import Expr
4
3
 
5
4
 
@@ -9,11 +8,9 @@ class Environment:
9
8
  self.parent = parent
10
9
 
11
10
  def set(self, name: str, value: Expr):
12
- """Set a variable in the current environment."""
13
11
  self.data[name] = value
14
12
 
15
13
  def get(self, name: str) -> Optional[Expr]:
16
- """Retrieve a variable's value, searching parent environments if necessary."""
17
14
  if name in self.data:
18
15
  return self.data[name]
19
16
  elif self.parent:
astreum/machine/parser.py CHANGED
@@ -1,4 +1,3 @@
1
- # Parser function
2
1
  from typing import List, Tuple
3
2
  from src.astreum.machine.error import ParseError
4
3
  from src.astreum.machine.expression import Expr
@@ -19,7 +18,6 @@ def parse(tokens: List[str]) -> Tuple[Expr, List[str]]:
19
18
 
20
19
  while inner_tokens:
21
20
  if inner_tokens[0] == ')':
22
- # End of list
23
21
  return Expr.ListExpr(list_items), inner_tokens[1:]
24
22
 
25
23
  expr, inner_tokens = parse(inner_tokens)
@@ -35,10 +33,8 @@ def parse(tokens: List[str]) -> Tuple[Expr, List[str]]:
35
33
  return Expr.String(string_content), rest
36
34
 
37
35
  else:
38
- # Try to parse as integer
39
36
  try:
40
37
  number = int(first_token)
41
38
  return Expr.Integer(number), rest
42
39
  except ValueError:
43
- # Treat as symbol
44
40
  return Expr.Symbol(first_token), rest
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: astreum
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Python library to interact with the Astreum blockchain and its Lispeum virtual machine.
5
5
  Author-email: "Roy R. O. Okello" <roy@stelar.xyz>
6
6
  Project-URL: Homepage, https://github.com/astreum/lib
@@ -0,0 +1,12 @@
1
+ astreum/__init__.py,sha256=-hmy95qFWlCbmHEcj5sGniM-UtpIn-iwwhVWFrFkd_w,37
2
+ astreum/machine/__init__.py,sha256=xitq5kFvtcBY88w3yEfsV3r75IIwBhoX6x0jx7as2Fw,5240
3
+ astreum/machine/environment.py,sha256=F1zXHTZpfX4GazUbPhgh43j8EdfV5bedS-b4xWBB_NY,611
4
+ astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
5
+ astreum/machine/expression.py,sha256=yOovmkiE11IEIjqEuYwuG7-jx6msOpgyzl3C3yD331c,1298
6
+ astreum/machine/parser.py,sha256=5tSAVi5z7laEYZHsoDofEOq4KKTfo5md6epT2Bsgk8o,1199
7
+ astreum/machine/tokenizer.py,sha256=4QzdZ11ocZKxlcjvV54PUxDuZxuL4et_sz3ILwfp3ko,1441
8
+ astreum-0.1.3.dist-info/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
9
+ astreum-0.1.3.dist-info/METADATA,sha256=RoW6ek_WGNmQzA_n5oHrY7YHS6Z2hMJQeF1OoMOL7z4,740
10
+ astreum-0.1.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
11
+ astreum-0.1.3.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
12
+ astreum-0.1.3.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- astreum/__init__.py,sha256=-hmy95qFWlCbmHEcj5sGniM-UtpIn-iwwhVWFrFkd_w,37
2
- astreum/machine/__init__.py,sha256=H0phu-6FDw3ByJfm8Tm3ewq0MVNHoJhEVeGkqwDZTc8,7481
3
- astreum/machine/environment.py,sha256=vL6vL4INfWslgK4KfNFvqH__0t25HRJRptrEQM1aofo,805
4
- astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
5
- astreum/machine/expression.py,sha256=yOovmkiE11IEIjqEuYwuG7-jx6msOpgyzl3C3yD331c,1298
6
- astreum/machine/parser.py,sha256=k8gPsQppV-61_n-bmOBekIE-6sO1xMYudJBYlwlVw8k,1315
7
- astreum/machine/tokenizer.py,sha256=4QzdZ11ocZKxlcjvV54PUxDuZxuL4et_sz3ILwfp3ko,1441
8
- astreum-0.1.2.dist-info/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
9
- astreum-0.1.2.dist-info/METADATA,sha256=BGnpbctoLafXbPjio-V6i7Bf-3JktwDtokeSeDc1OUA,740
10
- astreum-0.1.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
11
- astreum-0.1.2.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
12
- astreum-0.1.2.dist-info/RECORD,,