cpyte 3.3.2__tar.gz → 3.3.3__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.
Files changed (38) hide show
  1. {cpyte-3.3.2 → cpyte-3.3.3}/MANIFEST.in +1 -0
  2. {cpyte-3.3.2/source/cpyte.egg-info → cpyte-3.3.3}/PKG-INFO +1 -1
  3. {cpyte-3.3.2 → cpyte-3.3.3}/pyproject.toml +1 -1
  4. cpyte-3.3.3/source/cpyte/__init__.py +1 -0
  5. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/astparse.py +2 -2
  6. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/bytecoding.py +4 -1
  7. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/mainpie.py +25 -7
  8. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/semantic_analasis.py +43 -13
  9. cpyte-3.3.3/source/cpyte/ugc.h +426 -0
  10. {cpyte-3.3.2 → cpyte-3.3.3/source/cpyte.egg-info}/PKG-INFO +1 -1
  11. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte.egg-info/SOURCES.txt +1 -0
  12. cpyte-3.3.2/source/cpyte/__init__.py +0 -1
  13. {cpyte-3.3.2 → cpyte-3.3.3}/readme.md +0 -0
  14. {cpyte-3.3.2 → cpyte-3.3.3}/setup.cfg +0 -0
  15. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/__main__.py +0 -0
  16. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/_bignum_bc.py +0 -0
  17. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/_runtime_bc.py +0 -0
  18. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/bignum.c +0 -0
  19. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/clib.py +0 -0
  20. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/compiling.py +0 -0
  21. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/extension_hooks.py +0 -0
  22. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/formatter.py +0 -0
  23. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/gc_runtime.c +0 -0
  24. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/generate_bc.py +0 -0
  25. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/lexar.py +0 -0
  26. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/linker.py +0 -0
  27. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/lsp_server.py +0 -0
  28. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/package_manifest.py +0 -0
  29. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/runtime.c +0 -0
  30. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/runtime_scorpion.c +0 -0
  31. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/sef.py +0 -0
  32. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/ui.py +0 -0
  33. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte/update_check.py +0 -0
  34. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte.egg-info/dependency_links.txt +0 -0
  35. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte.egg-info/entry_points.txt +0 -0
  36. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte.egg-info/requires.txt +0 -0
  37. {cpyte-3.3.2 → cpyte-3.3.3}/source/cpyte.egg-info/top_level.txt +0 -0
  38. {cpyte-3.3.2 → cpyte-3.3.3}/test/test_bignum_jit.py +0 -0
@@ -1 +1,2 @@
1
1
  include source/cpyte/*.c
2
+ include source/cpyte/*.h
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cpyte
3
- Version: 3.3.2
3
+ Version: 3.3.3
4
4
  Summary: The Cpyte programming language compiler
5
5
  Author: Hoang Duy Tung
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "cpyte"
7
- version = "3.3.2"
7
+ version = "3.3.3"
8
8
  description = "The Cpyte programming language compiler"
9
9
  readme = "readme.md"
10
10
  requires-python = ">=3.11"
@@ -0,0 +1 @@
1
+ __version__ = "3.3.3"
@@ -1245,10 +1245,10 @@ def parse_import(tokens: list[Token], pos: int):
1245
1245
  assert first is not None
1246
1246
  parts = [first]
1247
1247
  pos += 1
1248
- while pos < len(tokens) and tokens[pos].type == TokenType.DOT:
1248
+ while pos < len(tokens) and tokens[pos].type in (TokenType.DOT, TokenType.SLASH):
1249
1249
  pos += 1
1250
1250
  if pos >= len(tokens) or tokens[pos].type != TokenType.IDENTIFIER:
1251
- raise ParseError('Expected identifier after . in package name', tokens[pos] if pos < len(tokens) else None)
1251
+ raise ParseError('Expected identifier after package separator in package name', tokens[pos] if pos < len(tokens) else None)
1252
1252
  part = tokens[pos].value
1253
1253
  assert part is not None
1254
1254
  parts.append(part)
@@ -2050,7 +2050,10 @@ class LLVM:
2050
2050
  if parent_struct and parent_struct in self.struct_fields:
2051
2051
  return self._field_type_name(parent_struct, node.name)
2052
2052
  if isinstance(node, Index):
2053
- return self._struct_name_from_node(node.obj)
2053
+ base = self._struct_name_from_node(node.obj)
2054
+ if base:
2055
+ return self._base_type_name(base)
2056
+ return None
2054
2057
  return None
2055
2058
 
2056
2059
  def _emit_lvalue_attr(self, node: Attr):
@@ -7,14 +7,14 @@ if __package__:
7
7
  from .astparse import Import, ParseError, parse_file
8
8
  from .bytecoding import LLVM
9
9
  from .compiling import (
10
- _RUNTIME_C,
11
10
  _GC_RUNTIME_C,
11
+ _RUNTIME_C,
12
12
  optimize,
13
13
  run_aot,
14
14
  run_jit,
15
15
  run_scorpion,
16
16
  )
17
- from .extension_hooks import HookLoader, HookStage, get_global_hook_registry
17
+ from .extension_hooks import HookStage, get_global_hook_registry
18
18
  from .lexar import Lexer, LexerError, register_keywords
19
19
  from .linker import Linker
20
20
  from .package_manifest import (
@@ -32,14 +32,14 @@ else:
32
32
  from cpyte.astparse import Import, ParseError, parse_file
33
33
  from cpyte.bytecoding import LLVM
34
34
  from cpyte.compiling import (
35
- _RUNTIME_C,
36
35
  _GC_RUNTIME_C,
36
+ _RUNTIME_C,
37
37
  optimize,
38
38
  run_aot,
39
39
  run_jit,
40
40
  run_scorpion,
41
41
  )
42
- from cpyte.extension_hooks import HookLoader, HookStage, get_global_hook_registry
42
+ from cpyte.extension_hooks import HookStage, get_global_hook_registry
43
43
  from cpyte.lexar import Lexer, LexerError, register_keywords
44
44
  from cpyte.linker import Linker
45
45
  from cpyte.package_manifest import (
@@ -326,10 +326,26 @@ def _notify_deep_hook_usage() -> None:
326
326
  )
327
327
 
328
328
 
329
- def _compile(source, tab_size=4, strict=False, enable_extensions=True, no_gc=False):
329
+ def _find_workspace_root(filepath: str | None) -> str:
330
+ if not filepath:
331
+ return os.getcwd()
332
+ path = os.path.abspath(filepath)
333
+ dirpath = os.path.dirname(path)
334
+ while True:
335
+ if os.path.isdir(os.path.join(dirpath, ".cpm")):
336
+ return dirpath
337
+ parent = os.path.dirname(dirpath)
338
+ if parent == dirpath:
339
+ return os.getcwd()
340
+ dirpath = parent
341
+
342
+
343
+ def _compile(source, tab_size=4, strict=False, enable_extensions=True, no_gc=False, filepath=None):
344
+ workspace_root = _find_workspace_root(filepath)
345
+
330
346
  # Pre-load package manifests if extensions are enabled
331
347
  if enable_extensions:
332
- _load_package_manifests_from_source(os.getcwd())
348
+ _load_package_manifests_from_source(workspace_root)
333
349
 
334
350
  lex = Lexer(source, tab_size=tab_size, enable_extensions=enable_extensions)
335
351
  tokens = lex.get_tokens()
@@ -342,7 +358,8 @@ def _compile(source, tab_size=4, strict=False, enable_extensions=True, no_gc=Fal
342
358
  source,
343
359
  parsed,
344
360
  strict=strict,
345
- workspace_root=os.getcwd(),
361
+ workspace_root=workspace_root,
362
+ filepath=filepath,
346
363
  enable_extensions=enable_extensions,
347
364
  no_gc=no_gc,
348
365
  )
@@ -839,6 +856,7 @@ def _main():
839
856
  strict=strict,
840
857
  enable_extensions=not no_userspace,
841
858
  no_gc=no_gc,
859
+ filepath=os.path.abspath(args[0]),
842
860
  )
843
861
 
844
862
  if mode == "ast":
@@ -1125,6 +1125,18 @@ class SemanticAnalyzer:
1125
1125
  node,
1126
1126
  note="cannot divide integer by zero",
1127
1127
  )
1128
+ if left_t is not None and right_t is not None:
1129
+ left_ptr = left_t.endswith("*")
1130
+ right_ptr = right_t.endswith("*")
1131
+ if node.op.name in ("PLUS", "MINUS") and (
1132
+ (left_ptr and right_t == "int")
1133
+ or (right_ptr and left_t == "int")
1134
+ ):
1135
+ node.inferred_type = left_t if left_ptr else right_t
1136
+ return node.inferred_type
1137
+ if node.op.name == "MINUS" and left_ptr and right_ptr:
1138
+ node.inferred_type = "int"
1139
+ return "int"
1128
1140
  if left_t is not None and right_t is not None and left_t != right_t:
1129
1141
  # Usual arithmetic conversions: promote to the widest type
1130
1142
  promoted = self._numeric_promote(left_t, right_t)
@@ -1996,21 +2008,33 @@ class SemanticAnalyzer:
1996
2008
  return None
1997
2009
 
1998
2010
  def _try_cpm_import(self, node: Import, module: str) -> bool:
1999
- # Check if package was already loaded via manifest
2000
- # Handle both @package.name and package.name formats
2001
- pkg_name = module.lstrip("@").rsplit("/", 1)[-1]
2002
- if pkg_name in self._loaded_packages:
2003
- # Package was loaded via manifest, register empty symbols and succeed
2004
- self._register_import_symbols({}, node)
2005
- return True
2011
+ # Support both @scope.name and @scope/name import forms.
2012
+ import_name = module[1:] if module.startswith("@") else module
2013
+ pkg_name = import_name.replace("/", ".").split(".")[-1]
2006
2014
 
2007
2015
  cpm_root = None
2008
2016
  if self._workspace_root:
2009
2017
  cpm_root = os.path.join(self._workspace_root, ".cpm", "modules")
2010
2018
  elif self._filedir:
2011
2019
  cpm_root = os.path.join(self._filedir, "..", ".cpm", "modules")
2020
+
2021
+ # A package already loaded purely via its manifest (extension hooks only)
2022
+ # has no real symbols; short-circuit only when no CPM directory exists to
2023
+ # resolve a real entry from. A package that ships an entry file must still
2024
+ # re-export its actual symbols below.
2025
+ if pkg_name in self._loaded_packages and not (
2026
+ cpm_root and os.path.isdir(cpm_root)
2027
+ ):
2028
+ self._register_import_symbols({}, node)
2029
+ return True
2030
+
2012
2031
  if cpm_root and os.path.isdir(cpm_root):
2013
- pkg_dir = os.path.join(cpm_root, module.lstrip("@"))
2032
+ if module.startswith("@"):
2033
+ scoped = module[1:].replace("/", ".").replace(".", os.sep)
2034
+ pkg_dir = os.path.join(cpm_root, f"@{scoped.split(os.sep)[0]}", *scoped.split(os.sep)[1:])
2035
+ else:
2036
+ pkg_dir = os.path.join(cpm_root, *module.replace("/", ".").split("."))
2037
+
2014
2038
  if os.path.isdir(pkg_dir):
2015
2039
  versions = sorted(
2016
2040
  [
@@ -2021,10 +2045,8 @@ class SemanticAnalyzer:
2021
2045
  reverse=True,
2022
2046
  )
2023
2047
  if versions:
2024
- pkg_name = module.lstrip("@").rsplit("/", 1)[-1]
2025
2048
  version_dir = os.path.join(pkg_dir, versions[0])
2026
2049
 
2027
- # Load package manifest if extensions are enabled
2028
2050
  manifest_loaded = False
2029
2051
  if self.enable_extensions:
2030
2052
  manifest_loaded = self._load_package_manifest(
@@ -2041,12 +2063,12 @@ class SemanticAnalyzer:
2041
2063
  if result:
2042
2064
  return True
2043
2065
 
2044
- # If no .cpy or prebuilt files but manifest was loaded, allow the import
2045
- # This supports extension-only packages
2046
2066
  if manifest_loaded:
2047
- # Register empty symbols for extension-only packages
2048
2067
  self._register_import_symbols({}, node)
2049
2068
  return True
2069
+ if self.enable_extensions and pkg_name in self._loaded_packages:
2070
+ self._register_import_symbols({}, node)
2071
+ return True
2050
2072
  return False
2051
2073
 
2052
2074
  def _import_cpy(self, module: str, node: Import | None = None):
@@ -2097,6 +2119,12 @@ class SemanticAnalyzer:
2097
2119
  if fname not in symbols:
2098
2120
  symbols[fname] = (ret_type, params, vararg)
2099
2121
 
2122
+ # Preserve the sub-AST chain for re-exported imports so codegen
2123
+ # can still reach the aggregated module's function definitions
2124
+ # (emit_program recurses through Import sub_ast).
2125
+ if getattr(ast_node, "sub_ast", None):
2126
+ sub_ast.append(ast_node)
2127
+
2100
2128
  if node is not None:
2101
2129
  node.sub_ast = sub_ast
2102
2130
  return symbols, "cpy"
@@ -3335,11 +3363,13 @@ def analyze(
3335
3363
  nodes: list,
3336
3364
  strict: bool = False,
3337
3365
  workspace_root: str | None = None,
3366
+ filepath: str | None = None,
3338
3367
  enable_extensions: bool = True,
3339
3368
  no_gc: bool = False,
3340
3369
  ):
3341
3370
  analyzer = SemanticAnalyzer(
3342
3371
  source,
3372
+ filepath=filepath,
3343
3373
  strict=strict,
3344
3374
  workspace_root=workspace_root,
3345
3375
  enable_extensions=enable_extensions,
@@ -0,0 +1,426 @@
1
+ #ifndef UGC_H
2
+ #define UGC_H
3
+
4
+ #include <stddef.h>
5
+ #include <stdint.h>
6
+
7
+ #ifndef UGC_DECL
8
+ #define UGC_DECL
9
+ #endif
10
+
11
+ #ifndef UGC_USE_TAGGED_POINTER
12
+ #define UGC_USE_TAGGED_POINTER 1
13
+ #endif
14
+
15
+ typedef struct ugc_s ugc_t;
16
+ typedef struct ugc_header_s ugc_header_t;
17
+
18
+ /**
19
+ * @brief Callback function type.
20
+ * @see ugc_init
21
+ */
22
+ typedef void(*ugc_visit_fn_t)(ugc_t* gc, ugc_header_t* obj);
23
+
24
+ enum ugc_state_e
25
+ {
26
+ UGC_IDLE,
27
+ UGC_MARK,
28
+ UGC_SWEEP
29
+ };
30
+
31
+ enum ugc_barrier_direction_e
32
+ {
33
+ UGC_BARRIER_FORWARD,
34
+ UGC_BARRIER_BACKWARD,
35
+ };
36
+
37
+ /// Header for a managed object. All fields MUST NOT be accessed.
38
+ struct ugc_header_s
39
+ {
40
+ ugc_header_t* next;
41
+ ugc_header_t* prev;
42
+ #if !UGC_USE_TAGGED_POINTER
43
+ unsigned color: 2;
44
+ #endif
45
+ };
46
+
47
+ /**
48
+ * @brief Garbage collector data
49
+ *
50
+ * All fields MUST NOT be accessed unless stated otherwise.
51
+ */
52
+ struct ugc_s
53
+ {
54
+ ugc_header_t set1, set2;
55
+ ugc_header_t *from, *to, *iterator;
56
+ ugc_visit_fn_t scan_fn, release_fn;
57
+
58
+ /// Arbitrary userdata, not used by the library.
59
+ void* userdata;
60
+
61
+ /// Current state of the garbage collection. Read-only.
62
+ unsigned char state;
63
+ unsigned char white;
64
+ };
65
+
66
+ /**
67
+ * @brief Initialize a GC.
68
+ *
69
+ * Two callbacks are required: one for scanning and the other for releasing.
70
+ *
71
+ * The scan callback must do the following:
72
+ *
73
+ * - If `obj` is NULL, it must call ugc_visit on all root objects.
74
+ * - If `obj` is not NULL, it must call ugc_visit on all objects referenced by
75
+ * the given object.
76
+ *
77
+ * The release callback will be invoked whenever the GC has determined that
78
+ * an object has become garbage.
79
+ */
80
+ UGC_DECL void
81
+ ugc_init(ugc_t* gc, ugc_visit_fn_t scan_fn, ugc_visit_fn_t release_fn);
82
+
83
+ /**
84
+ * @brief Release all allocated objects.
85
+ *
86
+ * This is faster than clearing the root and forcing a full collection.
87
+ */
88
+ UGC_DECL void
89
+ ugc_release_all(ugc_t* gc);
90
+
91
+ /// Register a new object to be managed by the GC.
92
+ UGC_DECL void
93
+ ugc_register(ugc_t* gc, ugc_header_t* obj);
94
+
95
+ /**
96
+ * @brief Execute a write barrier.
97
+ *
98
+ * Whenever an object stores a reference to another object, this function MUST
99
+ * be called to ensure that the GC works correctly.
100
+ *
101
+ * Root objects (stack, globals) are treated differently so there is no need to
102
+ * call this function when a store to them occurs.
103
+ *
104
+ * @remarks Both objects MUST NOT be NULL.
105
+ */
106
+ UGC_DECL void
107
+ ugc_write_barrier(
108
+ ugc_t* gc,
109
+ enum ugc_barrier_direction_e direction,
110
+ ugc_header_t* parent,
111
+ ugc_header_t* child
112
+ );
113
+
114
+ /**
115
+ * @brief Make the GC perform one unit of work.
116
+ *
117
+ * What happens depends on the current GC's state.
118
+ *
119
+ * - In UGC_IDLE state, it will scan the root by calling the scan callback then
120
+ * switch to UGC_MARK state.
121
+ * - In UGC_MARK state, it will mark one object and discover its children using
122
+ * the scan callback. When there is no object left to mark, the GC will scan
123
+ * the root once more to account for changes during the mark phase. When all
124
+ * live objects are marked, it will switch to UGC_SWEEP state.
125
+ * - In UGC_SWEEP state, it will release one object. When all garbage are
126
+ * released, it wil switch to UGC_IDLE state.
127
+ *
128
+ * @see ugc_init
129
+ */
130
+ UGC_DECL void
131
+ ugc_step(ugc_t* gc);
132
+
133
+
134
+ /**
135
+ * @brief Perform a collection cycle.
136
+ *
137
+ * Start the GC if it's not already running and only return once the GC has
138
+ * finished collecting all garbage identified at the point of calling.
139
+ *
140
+ * @remarks If the GC is already in the UGC_SWEEP state, it will leave newly
141
+ * created garbage for the next cycle.
142
+ */
143
+ UGC_DECL void
144
+ ugc_collect(ugc_t* gc);
145
+
146
+ /**
147
+ * @brief Inform the GC of a referred object during the mark phase.
148
+ *
149
+ * @remarks This function MUST ONLY be called inside the scan callback.
150
+ * @remarks The provided object MUST NOT be NULL.
151
+ * @see ugc_init
152
+ */
153
+ UGC_DECL void
154
+ ugc_visit(ugc_t* gc, ugc_header_t* obj);
155
+
156
+ #ifdef UGC_IMPLEMENTATION
157
+
158
+ #define UGC_GRAY 2
159
+
160
+ #if UGC_USE_TAGGED_POINTER
161
+
162
+ #define UGC_PTR(ptr) ((uintptr_t)ptr & (~0x03))
163
+ #define UGC_TAG(ptr) ((uintptr_t)ptr & 0x03)
164
+ #define UGC_SET_PTR(ptr, val) \
165
+ do { ptr = (ugc_header_t*)((uintptr_t)val | UGC_TAG(ptr)); } while(0)
166
+ #define UGC_SET_TAG(ptr, val) \
167
+ do { ptr = (ugc_header_t*)(UGC_PTR(ptr) | (uintptr_t)val); } while(0)
168
+
169
+ static inline void
170
+ ugc_set_next(ugc_header_t* obj, ugc_header_t* value)
171
+ {
172
+ UGC_SET_PTR(obj->next, value);
173
+ }
174
+
175
+ static inline ugc_header_t*
176
+ ugc_next(ugc_header_t* obj)
177
+ {
178
+ return (ugc_header_t*)UGC_PTR(obj->next);
179
+ }
180
+
181
+ static inline void
182
+ ugc_set_prev(ugc_header_t* obj, ugc_header_t* value)
183
+ {
184
+ UGC_SET_PTR(obj->prev, value);
185
+ }
186
+
187
+ static inline ugc_header_t*
188
+ ugc_prev(ugc_header_t* obj)
189
+ {
190
+ return (ugc_header_t*)UGC_PTR(obj->prev);
191
+ }
192
+
193
+ static inline void
194
+ ugc_set_color(ugc_header_t* obj, unsigned char color)
195
+ {
196
+ UGC_SET_TAG(obj->next, color);
197
+ }
198
+
199
+ static inline unsigned char
200
+ ugc_color(ugc_header_t* obj)
201
+ {
202
+ return (unsigned char)UGC_TAG(obj->next);
203
+ }
204
+
205
+ #else
206
+
207
+ static inline void
208
+ ugc_set_next(ugc_header_t* obj, ugc_header_t* value)
209
+ {
210
+ obj->next = value;
211
+ }
212
+
213
+ static inline ugc_header_t*
214
+ ugc_next(ugc_header_t* obj)
215
+ {
216
+ return obj->next;
217
+ }
218
+
219
+ static inline void
220
+ ugc_set_prev(ugc_header_t* obj, ugc_header_t* value)
221
+ {
222
+ obj->prev = value;
223
+ }
224
+
225
+ static inline ugc_header_t*
226
+ ugc_prev(ugc_header_t* obj)
227
+ {
228
+ return obj->prev;
229
+ }
230
+
231
+ static inline void
232
+ ugc_set_color(ugc_header_t* obj, unsigned char color)
233
+ {
234
+ obj->color = color;
235
+ }
236
+
237
+ static unsigned char
238
+ ugc_color(ugc_header_t* obj)
239
+ {
240
+ return obj->color;
241
+ }
242
+
243
+ #endif
244
+
245
+ static void
246
+ ugc_push(ugc_header_t* list, ugc_header_t* element)
247
+ {
248
+ ugc_set_next(element, list);
249
+ ugc_set_prev(element, list->prev);
250
+ ugc_set_next(list->prev, element);
251
+ ugc_set_prev(list, element);
252
+ }
253
+
254
+ static void
255
+ ugc_unlink(ugc_header_t* element)
256
+ {
257
+ ugc_header_t* next = ugc_next(element);
258
+ ugc_header_t* prev = ugc_prev(element);
259
+
260
+ ugc_set_prev(next, prev);
261
+ ugc_set_next(prev, next);
262
+ }
263
+
264
+ static void
265
+ ugc_make_gray(ugc_t* gc, ugc_header_t* obj)
266
+ {
267
+ // Move iterator back before moving obj
268
+ if(obj == gc->iterator) { gc->iterator = ugc_prev(obj); }
269
+
270
+ ugc_unlink(obj);
271
+ ugc_push(gc->to, obj);
272
+ ugc_set_color(obj, UGC_GRAY);
273
+ }
274
+
275
+ static void
276
+ ugc_clear(ugc_header_t* list)
277
+ {
278
+ list->next = list;
279
+ list->prev = list;
280
+ }
281
+
282
+ static void
283
+ ugc_release_set(ugc_t* gc, ugc_header_t* set)
284
+ {
285
+ for(ugc_header_t* itr = ugc_next(set); itr != set;)
286
+ {
287
+ ugc_header_t* next = ugc_next(itr);
288
+
289
+ gc->release_fn(gc, itr);
290
+
291
+ itr = next;
292
+ }
293
+ }
294
+
295
+ void
296
+ ugc_init(ugc_t* gc, ugc_visit_fn_t scan_fn, ugc_visit_fn_t release_fn)
297
+ {
298
+ ugc_clear(&gc->set1);
299
+ ugc_clear(&gc->set2);
300
+
301
+ gc->state = UGC_IDLE;
302
+ gc->scan_fn = scan_fn;
303
+ gc->release_fn = release_fn;
304
+ gc->white = 0;
305
+ gc->from = &gc->set1;
306
+ gc->to = &gc->set2;
307
+ gc->iterator = gc->to;
308
+ gc->userdata = NULL;
309
+ }
310
+
311
+ void
312
+ ugc_register(ugc_t* gc, ugc_header_t* obj)
313
+ {
314
+ ugc_push(gc->from, obj);
315
+ ugc_set_color(obj, gc->white);
316
+ }
317
+
318
+ void
319
+ ugc_release_all(ugc_t* gc)
320
+ {
321
+ ugc_release_set(gc, gc->from);
322
+ ugc_release_set(gc, gc->to);
323
+ }
324
+
325
+ void
326
+ ugc_write_barrier(
327
+ ugc_t* gc,
328
+ enum ugc_barrier_direction_e direction,
329
+ ugc_header_t* parent,
330
+ ugc_header_t* child
331
+ )
332
+ {
333
+ unsigned char white = gc->white;
334
+ unsigned char black = !gc->white;
335
+
336
+ if(ugc_color(parent) == black && ugc_color(child) == white)
337
+ {
338
+ switch(direction)
339
+ {
340
+ case UGC_BARRIER_FORWARD:
341
+ ugc_make_gray(gc, child);
342
+ break;
343
+ case UGC_BARRIER_BACKWARD:
344
+ ugc_make_gray(gc, parent);
345
+ break;
346
+ }
347
+ }
348
+ }
349
+
350
+ void
351
+ ugc_visit(ugc_t* gc, ugc_header_t* obj)
352
+ {
353
+ if(ugc_color(obj) == gc->white)
354
+ {
355
+ ugc_make_gray(gc, obj);
356
+ }
357
+ }
358
+
359
+ void
360
+ ugc_step(ugc_t* gc)
361
+ {
362
+ ugc_header_t* obj;
363
+ ugc_header_t* to = gc->to;
364
+
365
+ switch((enum ugc_state_e)gc->state)
366
+ {
367
+ case UGC_IDLE:
368
+ gc->scan_fn(gc, NULL);
369
+ gc->state = UGC_MARK;
370
+ break;
371
+ case UGC_MARK:
372
+ {
373
+ obj = ugc_next(gc->iterator);
374
+ unsigned char white = gc->white;
375
+
376
+ if(obj != to)
377
+ {
378
+ gc->iterator = obj;
379
+ ugc_set_color(obj, !white);
380
+ gc->scan_fn(gc, obj);
381
+ }
382
+ else
383
+ {
384
+ gc->scan_fn(gc, NULL);
385
+ obj = ugc_next(gc->iterator);
386
+ if(obj == to)
387
+ {
388
+ // Since we can get interrupted during the sweep phase,
389
+ // swap "from" and "to" set, flip white color before
390
+ // starting the sweep phase.
391
+ ugc_header_t* from = gc->from;
392
+ gc->from = to;
393
+ gc->to = from;
394
+ gc->white = !white;
395
+ gc->iterator = from->next;
396
+ gc->state = UGC_SWEEP;
397
+ }
398
+ }
399
+ }
400
+ break;
401
+ case UGC_SWEEP:
402
+ obj = gc->iterator;
403
+ if(obj != to)
404
+ {
405
+ gc->iterator = ugc_next(obj);
406
+ gc->release_fn(gc, obj);
407
+ }
408
+ else
409
+ {
410
+ ugc_clear(to);
411
+ gc->state = UGC_IDLE;
412
+ }
413
+ break;
414
+ }
415
+ }
416
+
417
+ void
418
+ ugc_collect(ugc_t* gc)
419
+ {
420
+ if(gc->state == UGC_IDLE) { ugc_step(gc); }
421
+ while(gc->state != UGC_IDLE) { ugc_step(gc); }
422
+ }
423
+
424
+ #endif
425
+
426
+ #endif
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cpyte
3
- Version: 3.3.2
3
+ Version: 3.3.3
4
4
  Summary: The Cpyte programming language compiler
5
5
  Author: Hoang Duy Tung
6
6
  License: MIT
@@ -23,6 +23,7 @@ source/cpyte/runtime.c
23
23
  source/cpyte/runtime_scorpion.c
24
24
  source/cpyte/sef.py
25
25
  source/cpyte/semantic_analasis.py
26
+ source/cpyte/ugc.h
26
27
  source/cpyte/ui.py
27
28
  source/cpyte/update_check.py
28
29
  source/cpyte.egg-info/PKG-INFO
@@ -1 +0,0 @@
1
- __version__ = "3.3.2"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes