IncludeCPP 4.3.0__py3-none-any.whl → 4.5.2__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.
Files changed (30) hide show
  1. includecpp/CHANGELOG.md +22 -0
  2. includecpp/__init__.py +1 -1
  3. includecpp/__init__.pyi +1 -4
  4. includecpp/cli/commands.py +1218 -25
  5. includecpp/core/cpp_api_extensions.pyi +204 -200
  6. includecpp/core/cssl/__init__.py +317 -0
  7. includecpp/core/cssl/cpp/build/api.pyd +0 -0
  8. includecpp/core/cssl/cpp/build/cssl_core.pyi +323 -0
  9. includecpp/core/cssl/cpp/build/libgcc_s_seh-1.dll +0 -0
  10. includecpp/core/cssl/cpp/build/libstdc++-6.dll +0 -0
  11. includecpp/core/cssl/cpp/build/libwinpthread-1.dll +0 -0
  12. includecpp/core/cssl/cpp/cssl_core.cp +108 -0
  13. includecpp/core/cssl/cpp/cssl_lexer.hpp +280 -0
  14. includecpp/core/cssl/cssl_builtins.py +142 -27
  15. includecpp/core/cssl/cssl_compiler.py +448 -0
  16. includecpp/core/cssl/cssl_optimizer.py +833 -0
  17. includecpp/core/cssl/cssl_parser.py +433 -38
  18. includecpp/core/cssl/cssl_runtime.py +294 -15
  19. includecpp/core/cssl/cssl_syntax.py +17 -0
  20. includecpp/core/cssl/cssl_types.py +143 -11
  21. includecpp/core/cssl_bridge.py +36 -2
  22. includecpp/generator/parser.cpp +38 -14
  23. includecpp/vscode/cssl/package.json +15 -0
  24. includecpp/vscode/cssl/syntaxes/cssl.tmLanguage.json +96 -0
  25. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/METADATA +1 -1
  26. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/RECORD +30 -21
  27. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/WHEEL +0 -0
  28. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/entry_points.txt +0 -0
  29. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/licenses/LICENSE +0 -0
  30. {includecpp-4.3.0.dist-info → includecpp-4.5.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,108 @@
1
+ SOURCE(include/cssl_core.cpp) cssl_core
2
+
3
+ PUBLIC(
4
+ // Full Interpreter - Main Entry Point
5
+ cssl_core FUNC(run_cssl)
6
+ cssl_core FUNC(version)
7
+ cssl_core FUNC(is_keyword)
8
+
9
+ // Lexer & Token Classes
10
+ cssl_core CLASS(Lexer) {
11
+ CONSTRUCTOR(const std::string&)
12
+ METHOD(tokenize)
13
+ }
14
+ cssl_core CLASS(Token) {
15
+ CONSTRUCTOR()
16
+ CONSTRUCTOR(int, int, int)
17
+ CONSTRUCTOR(int, const std::string&, int, int)
18
+ CONSTRUCTOR(int, double, int, int)
19
+ CONSTRUCTOR(int, bool, int, int)
20
+ FIELD(type)
21
+ FIELD(str_value)
22
+ FIELD(num_value)
23
+ FIELD(bool_value)
24
+ FIELD(value_type)
25
+ FIELD(line)
26
+ FIELD(column)
27
+ }
28
+
29
+ // Full Interpreter Class
30
+ cssl_core CLASS(Interpreter) {
31
+ CONSTRUCTOR()
32
+ METHOD(run)
33
+ METHOD(run_string)
34
+ }
35
+
36
+ // Value Class (for advanced usage)
37
+ cssl_core CLASS(Value) {
38
+ CONSTRUCTOR()
39
+ CONSTRUCTOR(bool)
40
+ CONSTRUCTOR(int64_t)
41
+ CONSTRUCTOR(double)
42
+ CONSTRUCTOR(const std::string&)
43
+ METHOD_CONST(as_bool)
44
+ METHOD_CONST(as_float)
45
+ METHOD_CONST(as_int)
46
+ METHOD_CONST(as_string)
47
+ METHOD_CONST(get_type)
48
+ METHOD_CONST(is_bool)
49
+ METHOD_CONST(is_dict)
50
+ METHOD_CONST(is_float)
51
+ METHOD_CONST(is_int)
52
+ METHOD_CONST(is_list)
53
+ METHOD_CONST(is_null)
54
+ METHOD_CONST(is_number)
55
+ METHOD_CONST(is_string)
56
+ METHOD_CONST(to_bool)
57
+ METHOD_CONST(to_string)
58
+ }
59
+
60
+ // String Operations
61
+ cssl_core FUNC(str_concat)
62
+ cssl_core FUNC(str_contains)
63
+ cssl_core FUNC(str_join)
64
+ cssl_core FUNC(str_lower)
65
+ cssl_core FUNC(str_replace)
66
+ cssl_core FUNC(str_split)
67
+ cssl_core FUNC(str_trim)
68
+ cssl_core FUNC(str_upper)
69
+ cssl_core FUNC(str_reverse)
70
+ cssl_core FUNC(str_len)
71
+ cssl_core FUNC(str_repeat)
72
+ cssl_core FUNC(str_startswith)
73
+ cssl_core FUNC(str_endswith)
74
+ cssl_core FUNC(str_indexof)
75
+ cssl_core FUNC(str_substr)
76
+ cssl_core FUNC(str_cmp)
77
+
78
+ // Math Operations
79
+ cssl_core FUNC(math_clamp)
80
+ cssl_core FUNC(math_ipow)
81
+ cssl_core FUNC(math_pow)
82
+ cssl_core FUNC(math_mod)
83
+ cssl_core FUNC(math_abs)
84
+ cssl_core FUNC(math_min)
85
+ cssl_core FUNC(math_max)
86
+ cssl_core FUNC(math_floor)
87
+ cssl_core FUNC(math_ceil)
88
+
89
+ // Array Operations
90
+ cssl_core FUNC(array_sum)
91
+ cssl_core FUNC(array_isum)
92
+ cssl_core FUNC(array_avg)
93
+ cssl_core FUNC(array_min)
94
+ cssl_core FUNC(array_max)
95
+ cssl_core FUNC(range)
96
+
97
+ // Loop Helpers
98
+ cssl_core FUNC(loop_check_lt)
99
+ cssl_core FUNC(loop_check_le)
100
+ cssl_core FUNC(loop_check_gt)
101
+ cssl_core FUNC(loop_check_ge)
102
+
103
+ // Comparison Helpers
104
+ cssl_core FUNC(num_cmp)
105
+ cssl_core FUNC(eq_int)
106
+ cssl_core FUNC(eq_float)
107
+ cssl_core FUNC(eq_str)
108
+ )
@@ -0,0 +1,280 @@
1
+ /**
2
+ * CSSL Lexer - High-performance tokenizer for CSSL language
3
+ *
4
+ * Part of IncludeCPP's self-hosting optimization strategy.
5
+ * This C++ implementation provides 10-20x speedup over Python.
6
+ *
7
+ * Copyright (c) 2024-2026 Lilias Hatterscheidt
8
+ * Licensed under MIT License
9
+ */
10
+
11
+ #pragma once
12
+
13
+ #include <string>
14
+ #include <string_view>
15
+ #include <vector>
16
+ #include <variant>
17
+ #include <unordered_set>
18
+ #include <cstdint>
19
+ #include <stdexcept>
20
+
21
+ namespace cssl {
22
+
23
+ /**
24
+ * Token types matching Python cssl_parser.py TokenType enum
25
+ */
26
+ enum class TokenType {
27
+ // Basic types
28
+ KEYWORD,
29
+ IDENTIFIER,
30
+ STRING,
31
+ STRING_INTERP, // <variable> in strings
32
+ NUMBER,
33
+ BOOLEAN,
34
+ NULL_T,
35
+ TYPE_LITERAL, // list, dict as type literals
36
+ TYPE_GENERIC, // datastruct<T>, shuffled<T>, etc.
37
+
38
+ // Injection operators
39
+ INJECT_LEFT, // <==
40
+ INJECT_RIGHT, // ==>
41
+ INJECT_PLUS_LEFT, // +<==
42
+ INJECT_PLUS_RIGHT, // ==>+
43
+ INJECT_MINUS_LEFT, // -<==
44
+ INJECT_MINUS_RIGHT, // ===>-
45
+
46
+ // Code Infusion operators
47
+ INFUSE_LEFT, // <<==
48
+ INFUSE_RIGHT, // ==>>
49
+ INFUSE_PLUS_LEFT, // +<<==
50
+ INFUSE_PLUS_RIGHT, // ==>>+
51
+ INFUSE_MINUS_LEFT, // -<<==
52
+ INFUSE_MINUS_RIGHT, // ==>>-
53
+
54
+ // Flow operators
55
+ FLOW_RIGHT, // ->
56
+ FLOW_LEFT, // <-
57
+
58
+ // Assignment and comparison
59
+ EQUALS, // =
60
+ COMPARE_EQ, // ==
61
+ COMPARE_NE, // !=
62
+ COMPARE_LT, // <
63
+ COMPARE_GT, // >
64
+ COMPARE_LE, // <=
65
+ COMPARE_GE, // >=
66
+
67
+ // Arithmetic
68
+ PLUS, // +
69
+ MINUS, // -
70
+ MULTIPLY, // *
71
+ DIVIDE, // /
72
+ MODULO, // %
73
+
74
+ // Logical
75
+ AND, // && or 'and'
76
+ OR, // || or 'or'
77
+ NOT, // ! or 'not'
78
+ AMPERSAND, // & (reference/bitwise)
79
+
80
+ // Delimiters
81
+ BLOCK_START, // {
82
+ BLOCK_END, // }
83
+ PAREN_START, // (
84
+ PAREN_END, // )
85
+ BRACKET_START, // [
86
+ BRACKET_END, // ]
87
+ SEMICOLON, // ;
88
+ COLON, // :
89
+ DOUBLE_COLON, // ::
90
+ COMMA, // ,
91
+ DOT, // .
92
+
93
+ // References
94
+ AT, // @
95
+ GLOBAL_REF, // r@name
96
+ SELF_REF, // s@name
97
+ SHARED_REF, // $name
98
+ CAPTURED_REF, // %name
99
+ THIS_REF, // this->
100
+
101
+ // Package/module
102
+ PACKAGE,
103
+ PACKAGE_INCLUDES,
104
+ AS,
105
+
106
+ // Special
107
+ COMMENT,
108
+ NEWLINE,
109
+ EOF_T,
110
+
111
+ // Super-functions (payload files)
112
+ SUPER_FUNC, // #$run(), #$exec(), etc.
113
+
114
+ // Append/extension operators
115
+ PLUS_PLUS, // ++ (constructor/function extension)
116
+ MINUS_MINUS, // --
117
+
118
+ // Multi-language support
119
+ LANG_INSTANCE_REF // cpp$InstanceName, py$Object
120
+ };
121
+
122
+ /**
123
+ * Token value - can hold string, number, or boolean
124
+ */
125
+ using TokenValue = std::variant<std::monostate, std::string, double, bool>;
126
+
127
+ /**
128
+ * Token structure
129
+ */
130
+ struct Token {
131
+ TokenType type;
132
+ TokenValue value;
133
+ uint32_t line;
134
+ uint32_t column;
135
+
136
+ // Convenience getters
137
+ bool has_string() const { return std::holds_alternative<std::string>(value); }
138
+ bool has_number() const { return std::holds_alternative<double>(value); }
139
+ bool has_bool() const { return std::holds_alternative<bool>(value); }
140
+
141
+ const std::string& as_string() const { return std::get<std::string>(value); }
142
+ double as_number() const { return std::get<double>(value); }
143
+ bool as_bool() const { return std::get<bool>(value); }
144
+ };
145
+
146
+ /**
147
+ * Lexer error with source location
148
+ */
149
+ class LexerError : public std::runtime_error {
150
+ public:
151
+ LexerError(const std::string& message, uint32_t line, uint32_t column,
152
+ const std::string& source_line = "")
153
+ : std::runtime_error(build_message(message, line, column, source_line)),
154
+ line_(line), column_(column) {}
155
+
156
+ uint32_t line() const { return line_; }
157
+ uint32_t column() const { return column_; }
158
+
159
+ private:
160
+ uint32_t line_;
161
+ uint32_t column_;
162
+
163
+ static std::string build_message(const std::string& msg, uint32_t line, uint32_t col,
164
+ const std::string& src_line) {
165
+ std::string result = "CSSL Lexer Error at line " + std::to_string(line) +
166
+ ", column " + std::to_string(col) + ": " + msg;
167
+ if (!src_line.empty()) {
168
+ result += "\n " + src_line;
169
+ if (col > 0) {
170
+ result += "\n " + std::string(col - 1, ' ') + "^";
171
+ }
172
+ }
173
+ return result;
174
+ }
175
+ };
176
+
177
+ /**
178
+ * High-performance CSSL Lexer
179
+ *
180
+ * Converts CSSL source code into a vector of tokens.
181
+ * Optimized for speed with minimal allocations.
182
+ */
183
+ class Lexer {
184
+ public:
185
+ /**
186
+ * Construct lexer with source code
187
+ * @param source CSSL source code (must remain valid during tokenization)
188
+ */
189
+ explicit Lexer(std::string_view source);
190
+
191
+ /**
192
+ * Tokenize entire source and return all tokens
193
+ * @return Vector of tokens including EOF token at end
194
+ */
195
+ std::vector<Token> tokenize();
196
+
197
+ /**
198
+ * Get next token (streaming mode)
199
+ * @return Next token, EOF_T when done
200
+ */
201
+ Token next_token();
202
+
203
+ /**
204
+ * Check if more tokens available
205
+ */
206
+ bool has_more() const { return pos_ < source_.size(); }
207
+
208
+ /**
209
+ * Reset lexer to beginning
210
+ */
211
+ void reset();
212
+
213
+ private:
214
+ std::string_view source_;
215
+ size_t pos_ = 0;
216
+ uint32_t line_ = 1;
217
+ uint32_t column_ = 1;
218
+
219
+ // Current character helpers
220
+ char current() const;
221
+ char peek(size_t offset = 1) const;
222
+ void advance(size_t count = 1);
223
+ bool at_end() const { return pos_ >= source_.size(); }
224
+
225
+ // Whitespace and comment handling
226
+ void skip_whitespace();
227
+ void skip_comment();
228
+ void skip_block_comment();
229
+
230
+ // Token readers
231
+ Token read_string(char quote);
232
+ Token read_raw_string();
233
+ Token read_number();
234
+ Token read_identifier();
235
+ Token read_operator();
236
+
237
+ // Special token readers
238
+ Token read_super_function();
239
+ Token read_global_ref();
240
+ Token read_self_ref();
241
+ Token read_shared_ref();
242
+ Token read_captured_ref();
243
+
244
+ // Operator readers
245
+ Token read_less_than();
246
+ Token read_greater_than();
247
+ Token read_equals();
248
+ Token read_not();
249
+ Token read_minus();
250
+ Token read_plus();
251
+
252
+ // Token creation helpers
253
+ Token make_token(TokenType type, TokenValue value = {}) const;
254
+
255
+ // Error helper
256
+ [[noreturn]] void error(const std::string& message) const;
257
+
258
+ // Static keyword sets (initialized once)
259
+ static const std::unordered_set<std::string> keywords_;
260
+ static const std::unordered_set<std::string> type_literals_;
261
+ static const std::unordered_set<std::string> type_generics_;
262
+ static const std::unordered_set<std::string> language_ids_;
263
+ };
264
+
265
+ /**
266
+ * Utility function: Tokenize source code
267
+ * @param source CSSL source code
268
+ * @return Vector of tokens
269
+ */
270
+ inline std::vector<Token> tokenize(const std::string& source) {
271
+ Lexer lexer(source);
272
+ return lexer.tokenize();
273
+ }
274
+
275
+ /**
276
+ * Get string representation of token type
277
+ */
278
+ const char* token_type_name(TokenType type);
279
+
280
+ } // namespace cssl
@@ -41,6 +41,7 @@ class CSSLBuiltins:
41
41
  self._functions['error'] = self.builtin_error
42
42
  self._functions['warn'] = self.builtin_warn
43
43
  self._functions['log'] = self.builtin_log
44
+ self._functions['encode'] = self.builtin_encode # v4.3.2: Safe unicode encoding
44
45
 
45
46
  # Type conversion
46
47
  self._functions['int'] = self.builtin_int
@@ -380,6 +381,44 @@ class CSSLBuiltins:
380
381
  encoded = output.encode(sys.stdout.encoding or 'utf-8', errors='replace')
381
382
  print(encoded.decode(sys.stdout.encoding or 'utf-8', errors='replace'))
382
383
 
384
+ def builtin_encode(self, content: str, fallback: str = "?") -> str:
385
+ """Encode unicode/emoji characters for safe console output.
386
+
387
+ v4.3.2: Safely encode emojis and special unicode characters that may not
388
+ be supported by the current console encoding (e.g., Windows cp1252).
389
+
390
+ Usage:
391
+ printl("Status: " + encode("✅"));
392
+ printl("Result: " + encode("😂", "[emoji]"));
393
+
394
+ // With custom fallback
395
+ msg = encode("🎉 Success!", "[party]");
396
+
397
+ Args:
398
+ content: String containing unicode/emoji characters
399
+ fallback: Replacement string for unencodable characters (default: "?")
400
+
401
+ Returns:
402
+ String safe for console output
403
+ """
404
+ import sys
405
+ encoding = sys.stdout.encoding or 'utf-8'
406
+
407
+ try:
408
+ # Test if content can be encoded with current console encoding
409
+ content.encode(encoding)
410
+ return content
411
+ except UnicodeEncodeError:
412
+ # Replace unencodable characters with fallback
413
+ result = []
414
+ for char in content:
415
+ try:
416
+ char.encode(encoding)
417
+ result.append(char)
418
+ except UnicodeEncodeError:
419
+ result.append(fallback)
420
+ return ''.join(result)
421
+
383
422
  def builtin_input(self, prompt: str = "") -> str:
384
423
  """Read user input from console.
385
424
 
@@ -645,19 +684,85 @@ class CSSLBuiltins:
645
684
  # ============= List Functions =============
646
685
 
647
686
  def builtin_push(self, lst: list, *items) -> list:
687
+ """Push items onto a list/stack/vector.
688
+
689
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
690
+ For regular lists, creates a copy (immutable behavior).
691
+ """
692
+ if lst is None:
693
+ lst = []
694
+ lst.extend(items)
695
+ return lst
696
+
697
+ # v4.5.1: For CSSL typed containers, modify in place
698
+ from .cssl_types import Stack, Vector, Array, DataStruct
699
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
700
+ for item in items:
701
+ lst.append(item)
702
+ return lst
703
+
704
+ # For regular lists, create a copy (immutable behavior)
648
705
  lst = list(lst)
649
706
  lst.extend(items)
650
707
  return lst
651
708
 
652
709
  def builtin_pop(self, lst: list, index: int = -1) -> Any:
710
+ """Pop item from list/stack/vector.
711
+
712
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
713
+ """
714
+ if lst is None:
715
+ return None
716
+
717
+ # v4.5.1: For CSSL typed containers, modify in place
718
+ from .cssl_types import Stack, Vector, Array, DataStruct
719
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
720
+ if len(lst) == 0:
721
+ return None
722
+ return lst.pop(index)
723
+
724
+ # For regular lists, create a copy
653
725
  lst = list(lst)
654
- return lst.pop(index)
726
+ return lst.pop(index) if lst else None
655
727
 
656
728
  def builtin_shift(self, lst: list) -> Any:
729
+ """Remove and return first element.
730
+
731
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
732
+ """
733
+ if lst is None:
734
+ return None
735
+
736
+ # v4.5.1: For CSSL typed containers, modify in place
737
+ from .cssl_types import Stack, Vector, Array, DataStruct
738
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
739
+ if len(lst) == 0:
740
+ return None
741
+ return lst.pop(0)
742
+
743
+ # For regular lists, create a copy
657
744
  lst = list(lst)
658
745
  return lst.pop(0) if lst else None
659
746
 
660
747
  def builtin_unshift(self, lst: list, *items) -> list:
748
+ """Add items to the front of a list/stack/vector.
749
+
750
+ v4.5.1: For Stack/Vector/Array types, modifies in place.
751
+ """
752
+ if lst is None:
753
+ lst = []
754
+ for item in reversed(items):
755
+ lst.insert(0, item)
756
+ return lst
757
+
758
+ # v4.5.1: For CSSL typed containers, modify in place
759
+ from .cssl_types import Stack, Vector, Array, DataStruct
760
+ if isinstance(lst, (Stack, Vector, Array, DataStruct)):
761
+ for item in reversed(items):
762
+ lst.insert(0, item)
763
+ return lst
764
+
765
+ # For regular lists, create a copy
661
766
  lst = list(lst)
662
767
  for item in reversed(items):
663
768
  lst.insert(0, item)
@@ -2250,17 +2355,20 @@ class CSSLBuiltins:
2250
2355
 
2251
2356
  All definitions go into the namespace dict.
2252
2357
  embedded replacements are scoped to the namespace only.
2358
+ Variables declared with 'global' keyword remain truly global (accessible via @).
2253
2359
  """
2254
2360
  # Create namespace dict
2255
2361
  namespace = {}
2256
2362
 
2257
- # Save current scope state
2258
- old_scope = self.runtime.scope.copy()
2259
- old_global = self.runtime.global_scope.copy()
2363
+ # Save current scope state (copy the variables dicts)
2364
+ old_scope_vars = dict(self.runtime.scope.variables)
2365
+ old_global_vars = dict(self.runtime.global_scope.variables)
2366
+ old_promoted_globals = dict(self.runtime._promoted_globals)
2260
2367
 
2261
2368
  # Track what gets added during payload execution
2262
- scope_before = set(self.runtime.scope.keys())
2263
- global_before = set(self.runtime.global_scope.keys())
2369
+ scope_before = set(self.runtime.scope.variables.keys())
2370
+ global_before = set(self.runtime.global_scope.variables.keys())
2371
+ promoted_before = set(self.runtime._promoted_globals.keys())
2264
2372
 
2265
2373
  # Set a flag to tell runtime we're in namespace mode
2266
2374
  self.runtime._payload_namespace_mode = libname
@@ -2269,46 +2377,53 @@ class CSSLBuiltins:
2269
2377
  # Execute the payload
2270
2378
  self.runtime._execute_node(ast)
2271
2379
 
2272
- # Collect new definitions from scope
2273
- for key in self.runtime.scope:
2274
- if key not in scope_before:
2275
- namespace[key] = self.runtime.scope[key]
2380
+ # Find which variables were explicitly promoted to global (via 'global' keyword)
2381
+ new_promoted = set(self.runtime._promoted_globals.keys()) - promoted_before
2276
2382
 
2277
- # Collect new definitions from global_scope (but not the namespace itself)
2278
- for key in self.runtime.global_scope:
2279
- if key not in global_before and key != libname:
2280
- namespace[key] = self.runtime.global_scope[key]
2383
+ # Collect new definitions from scope (but not promoted globals)
2384
+ for key in self.runtime.scope.variables:
2385
+ if key not in scope_before and key not in new_promoted:
2386
+ namespace[key] = self.runtime.scope.get(key)
2387
+
2388
+ # Collect new definitions from global_scope (but not namespace itself, not promoted globals)
2389
+ for key in self.runtime.global_scope.variables:
2390
+ if key not in global_before and key != libname and key not in new_promoted:
2391
+ namespace[key] = self.runtime.global_scope.get(key)
2281
2392
 
2282
2393
  # Handle embedded replacements: move replaced targets into namespace
2283
2394
  if hasattr(self.runtime, '_namespace_replacements'):
2284
2395
  for target_name, new_impl in self.runtime._namespace_replacements.items():
2285
2396
  # Get the original from before execution
2286
- original = old_scope.get(target_name) or old_global.get(target_name)
2397
+ original = old_scope_vars.get(target_name) or old_global_vars.get(target_name)
2287
2398
  if original is not None:
2288
2399
  # Restore original globally
2289
- if target_name in old_scope:
2290
- self.runtime.scope[target_name] = original
2291
- if target_name in old_global:
2292
- self.runtime.global_scope[target_name] = original
2400
+ if target_name in old_scope_vars:
2401
+ self.runtime.scope.set(target_name, original)
2402
+ if target_name in old_global_vars:
2403
+ self.runtime.global_scope.set(target_name, original)
2293
2404
  # Put the replacement in namespace
2294
2405
  namespace[target_name] = new_impl
2295
2406
  del self.runtime._namespace_replacements
2296
2407
 
2297
- # Remove new definitions from global scope (they're in namespace now)
2298
- for key in list(self.runtime.scope.keys()):
2299
- if key not in scope_before:
2300
- del self.runtime.scope[key]
2408
+ # Remove new definitions from scope (they're in namespace now)
2409
+ # BUT keep promoted globals - they stay global!
2410
+ for key in list(self.runtime.scope.variables.keys()):
2411
+ if key not in scope_before and key not in new_promoted:
2412
+ del self.runtime.scope.variables[key]
2413
+
2414
+ for key in list(self.runtime.global_scope.variables.keys()):
2415
+ if key not in global_before and key != libname and key not in new_promoted:
2416
+ del self.runtime.global_scope.variables[key]
2301
2417
 
2302
- for key in list(self.runtime.global_scope.keys()):
2303
- if key not in global_before and key != libname:
2304
- del self.runtime.global_scope[key]
2418
+ # Promoted globals stay in _promoted_globals and global_scope (not moved to namespace)
2419
+ # They are accessible via @name from anywhere
2305
2420
 
2306
2421
  finally:
2307
2422
  # Clear namespace mode flag
2308
2423
  self.runtime._payload_namespace_mode = None
2309
2424
 
2310
2425
  # Register namespace in global scope
2311
- self.runtime.global_scope[libname] = namespace
2426
+ self.runtime.global_scope.set(libname, namespace)
2312
2427
 
2313
2428
  def builtin_get(self, source: Any, key: str = None) -> Any:
2314
2429
  """