objective-lol 0.0.1__cp310-cp310-win_amd64.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.
objective_lol/olol.py ADDED
@@ -0,0 +1,581 @@
1
+ import asyncio
2
+ import concurrent.futures
3
+ import functools
4
+ import inspect
5
+ import json
6
+ import threading
7
+ from typing import Any, Callable, Dict, Tuple, Type
8
+ import uuid
9
+
10
+ from .api import (
11
+ VM,
12
+ VMCompatibilityShim,
13
+ NewVM,
14
+ DefaultConfig,
15
+ WrapInt,
16
+ WrapFloat,
17
+ WrapString,
18
+ WrapBool,
19
+ GoValue,
20
+ Slice_api_GoValue,
21
+ Map_string_api_GoValue,
22
+ ClassDefinition,
23
+ ClassVariable,
24
+ ClassMethod,
25
+ NewClassDefinition,
26
+ GoValueIDKey,
27
+ ForeignModuleNamespace,
28
+ )
29
+
30
+
31
+ defined_functions: Dict[str, Tuple['ObjectiveLOLVM', Callable]] = {}
32
+ defined_classes: Dict[str, Type] = {}
33
+ object_instances: Dict[str, Any] = {}
34
+
35
+
36
+ # gopy does not support passing complex types directly,
37
+ # so we wrap arguments and return values as JSON strings.
38
+ # Additionally, using closures seems to result in a segfault
39
+ # at https://github.com/python/cpython/blob/v3.13.5/Python/generated_cases.c.h#L2462
40
+ # so we use a global dictionary to store the actual functions.
41
+ def gopy_wrapper(id: str, json_args: str) -> bytes:
42
+ args = json.loads(json_args)
43
+ try:
44
+ vm, fn = defined_functions[id]
45
+ converted_args = [vm.convert_from_go_value(arg) for arg in args]
46
+ result = fn(*converted_args)
47
+ return json.dumps({"result": vm.convert_to_go_value(result), "error": None}, default=vm.serialize_go_value).encode('utf-8')
48
+ except Exception as e:
49
+ return json.dumps({"result": None, "error": str(e)}).encode('utf-8')
50
+
51
+
52
+ def convert_to_simple_mro(mro: list[str]) -> list[str]:
53
+ simple_mro = []
54
+ for cls_name in mro:
55
+ if cls_name.startswith(ForeignModuleNamespace):
56
+ simple_mro.append(cls_name[len(ForeignModuleNamespace)+1:])
57
+ return simple_mro
58
+
59
+
60
+ def generate_case_permutations(fname):
61
+ """Generate all possible case combinations of fname"""
62
+ if not fname:
63
+ return ['']
64
+
65
+ result = []
66
+ first_char = fname[0]
67
+ rest_permutations = generate_case_permutations(fname[1:])
68
+
69
+ for rest in rest_permutations:
70
+ if first_char.isalpha():
71
+ result.append(first_char.lower() + rest)
72
+ result.append(first_char.upper() + rest)
73
+ else:
74
+ result.append(first_char + rest)
75
+
76
+ return result
77
+
78
+
79
+ class ProxyMeta(type):
80
+ def __new__(mcs: Type, name: str, bases: tuple, attrs: dict, go_value: GoValue = None):
81
+ cls = super().__new__(mcs, name, bases, attrs)
82
+ cls._go_value = go_value
83
+ return cls
84
+
85
+ def __call__(cls, *args, **kwargs):
86
+ instance = super().__call__(*args, **kwargs)
87
+ instance._go_value = cls._go_value
88
+ return instance
89
+
90
+
91
+ class ObjectiveLOLVM:
92
+ class ClassBuilder:
93
+ _vm: 'ObjectiveLOLVM'
94
+ _class: ClassDefinition
95
+
96
+ def __init__(self, vm: 'ObjectiveLOLVM'):
97
+ self._vm = vm
98
+ self._class = NewClassDefinition()
99
+
100
+ def get(self) -> ClassDefinition:
101
+ return self._class
102
+
103
+ def set_name(self, name: str) -> 'ObjectiveLOLVM.ClassBuilder':
104
+ self._class.Name = name
105
+ return self
106
+
107
+ def __build_variable(self, name: str, value, locked: bool, getter=None, setter=None) -> ClassVariable:
108
+ class_variable = ClassVariable()
109
+ class_variable.Name = name
110
+ class_variable.Value = self._vm.convert_to_go_value(value)
111
+ class_variable.Locked = locked
112
+ if getter is not None:
113
+ unique_id = str(uuid.uuid4())
114
+
115
+ def wrapper(this_id):
116
+ return self._vm.convert_to_go_value(getter(object_instances[this_id]))
117
+
118
+ defined_functions[unique_id] = (self._vm, wrapper)
119
+ self._vm._compat.BuildNewClassVariableWithGetter(class_variable, unique_id, gopy_wrapper)
120
+ if setter is not None:
121
+ unique_id = str(uuid.uuid4())
122
+
123
+ def wrapper(this_id, value):
124
+ setter(object_instances[this_id], self._vm.convert_from_go_value(value))
125
+
126
+ defined_functions[unique_id] = (self._vm, wrapper)
127
+ self._vm._compat.BuildNewClassVariableWithSetter(class_variable, unique_id, gopy_wrapper)
128
+ return class_variable
129
+
130
+ def add_public_variable(self, name: str, value = None, locked: bool = False, getter=None, setter=None) -> 'ObjectiveLOLVM.ClassBuilder':
131
+ variable = self.__build_variable(name, value, locked, getter, setter)
132
+ self._class.PublicVariables[name] = variable
133
+ return self
134
+
135
+ def add_private_variable(self, name: str, value = None, locked: bool = False, getter=None, setter=None) -> 'ObjectiveLOLVM.ClassBuilder':
136
+ variable = self.__build_variable(name, value, locked, getter, setter)
137
+ self._class.PrivateVariables[name] = variable
138
+ return self
139
+
140
+ def add_shared_variable(self, name: str, value = None, locked: bool = False, getter=None, setter=None) -> 'ObjectiveLOLVM.ClassBuilder':
141
+ variable = self.__build_variable(name, value, locked, getter, setter)
142
+ self._class.SharedVariables[name] = variable
143
+ return self
144
+
145
+ def __build_method(self, name: str, function, argc: int = None) -> ClassMethod:
146
+ argc = len(inspect.signature(function).parameters) - 1 if argc is None else argc
147
+ unique_id = str(uuid.uuid4())
148
+
149
+ def wrapper(this_id, *args):
150
+ return self._vm.convert_to_go_value(function(object_instances[this_id], *args))
151
+
152
+ defined_functions[unique_id] = (self._vm, wrapper)
153
+ class_method = ClassMethod()
154
+ class_method.Name = name
155
+ class_method.Argc = argc
156
+
157
+ self._vm._compat.BuildNewClassMethod(class_method, unique_id, gopy_wrapper)
158
+ return class_method
159
+
160
+ def add_constructor(self, typ: type) -> 'ObjectiveLOLVM.ClassBuilder':
161
+ # get init function
162
+ init_function = typ.__init__
163
+ argc = len(inspect.signature(init_function).parameters) - 1
164
+
165
+ # ignore args and kwargs
166
+ for param in inspect.signature(init_function).parameters.values():
167
+ if param.kind in (param.VAR_POSITIONAL, param.VAR_KEYWORD):
168
+ argc = argc - 1
169
+
170
+ unique_id = str(uuid.uuid4())
171
+
172
+ def ctor_wrapper(this_id, *args):
173
+ mro = self._vm._compat.GetObjectMRO(this_id)
174
+ simple_mro = convert_to_simple_mro(mro)
175
+
176
+ instance_class = typ
177
+ if len(mro) > 1:
178
+ go_value = self._vm._compat.LookupObject(this_id)
179
+ instance_class = self._vm.create_proxy_class([defined_classes[cls_name.upper()] for cls_name in simple_mro if cls_name.upper() in defined_classes], go_value)
180
+
181
+ instance = instance_class(*args)
182
+ object_instances[this_id] = instance
183
+
184
+ defined_functions[unique_id] = (self._vm, ctor_wrapper)
185
+ class_method = ClassMethod()
186
+ class_method.Name = typ.__name__
187
+ class_method.Argc = argc
188
+
189
+ self._vm._compat.BuildNewClassMethod(class_method, unique_id, gopy_wrapper)
190
+ self._class.PublicMethods[typ.__name__] = class_method
191
+ return self
192
+
193
+ def add_public_method(self, name: str, function, argc: int = None) -> 'ObjectiveLOLVM.ClassBuilder':
194
+ method = self.__build_method(name, function, argc)
195
+ self._class.PublicMethods[name] = method
196
+ return self
197
+
198
+ def add_public_coroutine(self, name: str, function) -> 'ObjectiveLOLVM.ClassBuilder':
199
+ argc = len(inspect.signature(function).parameters) - 1
200
+
201
+ def wrapper(this, *args):
202
+ fut = concurrent.futures.Future()
203
+ def do():
204
+ try:
205
+ result = asyncio.run_coroutine_threadsafe(function(this, *args), self._vm._loop).result()
206
+ fut.set_result(result)
207
+ except Exception as e:
208
+ fut.set_exception(e)
209
+ threading.Thread(target=do).start()
210
+ return fut.result()
211
+
212
+ method = self.__build_method(name, wrapper, argc)
213
+ self._class.PublicMethods[name] = method
214
+ return self
215
+
216
+ def add_private_method(self, name: str, function, argc: int = None) -> 'ObjectiveLOLVM.ClassBuilder':
217
+ method = self.__build_method(name, function, argc)
218
+ self._class.PrivateMethods[name] = method
219
+ return self
220
+
221
+ def add_private_coroutine(self, name: str, function) -> 'ObjectiveLOLVM.ClassBuilder':
222
+ argc = len(inspect.signature(function).parameters) - 1
223
+
224
+ def wrapper(this, *args):
225
+ fut = concurrent.futures.Future()
226
+ def do():
227
+ try:
228
+ result = asyncio.run_coroutine_threadsafe(function(this, *args), self._vm._loop).result()
229
+ fut.set_result(result)
230
+ except Exception as e:
231
+ fut.set_exception(e)
232
+ threading.Thread(target=do).start()
233
+ return fut.result()
234
+
235
+ method = self.__build_method(name, wrapper, argc)
236
+ self._class.PrivateMethods[name] = method
237
+ return self
238
+
239
+ def add_unknown_function_handler(self, function) -> 'ObjectiveLOLVM.ClassBuilder':
240
+ def handler(this_id: str, fname: str, from_context: str, *args):
241
+ return function(object_instances[this_id], fname, from_context, *args)
242
+
243
+ unique_id = str(uuid.uuid4())
244
+ defined_functions[unique_id] = (self._vm, handler)
245
+ self._class.UnknownFunctionHandler = self._vm._compat.BuildNewUnknownFunctionHandler(unique_id, gopy_wrapper)
246
+ return self
247
+
248
+ def add_unknown_coroutine_handler(self, function) -> 'ObjectiveLOLVM.ClassBuilder':
249
+ def handler(this_id: str, fname: str, from_context: str, *args):
250
+ fut = concurrent.futures.Future()
251
+ def do():
252
+ try:
253
+ result = asyncio.run_coroutine_threadsafe(function(object_instances[this_id], fname, from_context, *args), self._vm._loop).result()
254
+ fut.set_result(result)
255
+ except Exception as e:
256
+ fut.set_exception(e)
257
+ threading.Thread(target=do).start()
258
+ return fut.result()
259
+
260
+ unique_id = str(uuid.uuid4())
261
+ defined_functions[unique_id] = (self._vm, handler)
262
+ self._class.UnknownFunctionHandler = self._vm._compat.BuildNewUnknownFunctionHandler(unique_id, gopy_wrapper)
263
+ return self
264
+
265
+ _vm: VM
266
+ _compat: VMCompatibilityShim
267
+ _loop: asyncio.AbstractEventLoop
268
+ _prefer_async_loop: bool
269
+
270
+ def __init__(self, prefer_async_loop: bool = True):
271
+ # todo: figure out how to bridge stdout/stdin
272
+ self._vm = NewVM(DefaultConfig())
273
+ self._compat = self._vm.GetCompatibilityShim()
274
+ self._loop = asyncio.get_event_loop()
275
+ self._prefer_async_loop = prefer_async_loop
276
+
277
+ def convert_from_go_value(self, go_value: GoValue):
278
+ if not isinstance(go_value, GoValue):
279
+ if go_value and GoValueIDKey in go_value:
280
+ go_value = self._compat.LookupObject(go_value[GoValueIDKey])
281
+ return self.convert_from_go_value(go_value)
282
+ return go_value
283
+ typ = go_value.Type()
284
+ if typ == "INTEGR":
285
+ return go_value.Int()
286
+ elif typ == "DUBBLE":
287
+ return go_value.Float()
288
+ elif typ == "STRIN":
289
+ return go_value.String()
290
+ elif typ == "BOOL":
291
+ return go_value.Bool()
292
+ elif typ == "NOTHIN":
293
+ return None
294
+ elif typ == "BUKKIT":
295
+ return [self.convert_from_go_value(v) for v in go_value.Slice()]
296
+ elif typ == "BASKIT":
297
+ return {k: self.convert_from_go_value(v) for k, v in go_value.Map().items()}
298
+ else:
299
+ # object handle
300
+ if go_value.ID() in object_instances:
301
+ return object_instances[go_value.ID()]
302
+
303
+ mro = self._compat.GetObjectMRO(go_value.ID())
304
+ simple_mro = convert_to_simple_mro(mro)
305
+ instance_class = self.create_proxy_class([defined_classes[cls_name.upper()] for cls_name in simple_mro if cls_name.upper() in defined_classes], go_value)
306
+ instance = instance_class()
307
+ object_instances[go_value.ID()] = instance
308
+ return instance
309
+
310
+ def convert_to_go_value(self, value):
311
+ if value is None:
312
+ return GoValue()
313
+ if isinstance(value, int):
314
+ return WrapInt(value)
315
+ elif isinstance(value, float):
316
+ return WrapFloat(value)
317
+ elif isinstance(value, str):
318
+ return WrapString(value)
319
+ elif isinstance(value, bool):
320
+ return WrapBool(value)
321
+ elif isinstance(value, GoValue):
322
+ # object handle, pass through
323
+ return value
324
+ elif isinstance(value, (list, tuple)):
325
+ slice = Slice_api_GoValue()
326
+ for v in value:
327
+ slice.append(self.convert_to_go_value(v))
328
+ return slice
329
+ elif isinstance(value, dict):
330
+ map = Map_string_api_GoValue()
331
+ for k, v in value.items():
332
+ map[k] = self.convert_to_go_value(v)
333
+ return map
334
+ elif isinstance(type(value), ProxyMeta):
335
+ return value._go_value
336
+ else:
337
+ self.define_class(type(value), fully_qualified=True)
338
+ instance = self._vm.NewObjectInstance("{}.{}".format(type(value).__module__, type(value).__name__))
339
+
340
+ # for attributes added at runtime (e.g. in __init__),
341
+ # inject getters and setters for them
342
+ for a in dir(value):
343
+ if hasattr(type(value), a):
344
+ continue
345
+
346
+ class_variable = ClassVariable()
347
+ class_variable.Name = a.upper()
348
+
349
+ getter = lambda obj, attr=a: getattr(obj, attr)
350
+ unique_id = str(uuid.uuid4())
351
+ def wrapper(this_id, getter=getter):
352
+ return self.convert_to_go_value(getter(object_instances[this_id]))
353
+ defined_functions[unique_id] = (self, wrapper)
354
+ self._compat.BuildNewClassVariableWithGetter(class_variable, unique_id, gopy_wrapper)
355
+
356
+ setter = lambda obj, val, attr=a: setattr(obj, attr, val)
357
+ unique_id = str(uuid.uuid4())
358
+ def wrapper(this_id, value, setter=setter):
359
+ setter(object_instances[this_id], self.convert_from_go_value(value))
360
+ defined_functions[unique_id] = (self, wrapper)
361
+ self._compat.BuildNewClassVariableWithSetter(class_variable, unique_id, gopy_wrapper)
362
+
363
+ self._compat.AddVariableToObject(instance.ID(), class_variable)
364
+
365
+ object_instances[instance.ID()] = value
366
+ return instance
367
+
368
+ def serialize_go_value(self, go_value: GoValue):
369
+ if isinstance(go_value, GoValue):
370
+ if go_value.ID() != "":
371
+ return {GoValueIDKey: go_value.ID()}
372
+ return self.convert_from_go_value(go_value)
373
+ else:
374
+ return go_value
375
+
376
+ def create_proxy_class(self, mro: list[type], go_value: GoValue) -> type:
377
+ instance_immediate_functions = self._compat.GetObjectImmediateFunctions(go_value.ID())
378
+ superself = self
379
+
380
+ class Proxy(*mro, metaclass=ProxyMeta, go_value=go_value):
381
+ def __getattribute__(self, name):
382
+ # Handles basic object attributes to avoid infinite recursion
383
+ if name in ('_go_value', '_create_proxy_method', '__class__', '__dict__'):
384
+ return super().__getattribute__(name)
385
+
386
+ # Check if this method should be proxied to the VM
387
+ if name.upper() in instance_immediate_functions:
388
+ # This method belongs to the immediate class, proxy to VM
389
+ return self._create_proxy_method(name)
390
+
391
+ # For everything else, get it normally
392
+ return super().__getattribute__(name)
393
+
394
+ def _create_proxy_method(self, method_name):
395
+ is_async = False
396
+ try:
397
+ method = super().__getattribute__(method_name)
398
+ if callable(method):
399
+ if inspect.iscoroutinefunction(method):
400
+ is_async = True
401
+ except:
402
+ pass
403
+
404
+ if is_async:
405
+ return functools.partial(superself.call_method_async, self._go_value, method_name)
406
+ else:
407
+ return functools.partial(superself.call_method, self._go_value, method_name)
408
+
409
+ return Proxy
410
+
411
+ def define_variable(self, name: str, value, constant: bool = False) -> None:
412
+ goValue = self.convert_to_go_value(value)
413
+ self._vm.DefineVariable(name, goValue, constant)
414
+
415
+ def define_function(self, name: str, function, argc: int = None) -> None:
416
+ argc = len(inspect.signature(function).parameters) if argc is None else argc
417
+ unique_id = str(uuid.uuid4())
418
+ defined_functions[unique_id] = (self, function)
419
+ self._compat.DefineFunction(unique_id, name, argc, gopy_wrapper)
420
+
421
+ def define_coroutine(self, name: str, function) -> None:
422
+ argc = len(inspect.signature(function).parameters)
423
+
424
+ def wrapper(*args):
425
+ fut = concurrent.futures.Future()
426
+ def do():
427
+ try:
428
+ result = asyncio.run_coroutine_threadsafe(function(*args), self._loop).result()
429
+ fut.set_result(result)
430
+ except Exception as e:
431
+ fut.set_exception(e)
432
+ threading.Thread(target=do).start()
433
+ return fut.result()
434
+
435
+ self.define_function(name, wrapper, argc)
436
+
437
+ def define_class(self, python_class: type, fully_qualified: bool = False) -> None:
438
+ class_name = f"{python_class.__module__}.{python_class.__name__}" if fully_qualified else python_class.__name__
439
+ if self._compat.IsClassDefined(class_name):
440
+ return
441
+
442
+ # Use class builder to introspect and build the class definition
443
+ builder = ObjectiveLOLVM.ClassBuilder(self)
444
+ builder.set_name(class_name)
445
+ builder.add_constructor(python_class)
446
+
447
+ # Add class attributes as variables with getters/setters
448
+ for attr_name in dir(python_class):
449
+ if not attr_name.startswith('_') and not callable(getattr(python_class, attr_name)):
450
+ builder.add_public_variable(
451
+ attr_name,
452
+ getter=lambda self, attr=attr_name: getattr(self, attr),
453
+ setter=lambda self, value, attr=attr_name: setattr(self, attr, value)
454
+ )
455
+
456
+ # Add methods
457
+ for method_name in dir(python_class):
458
+ if not method_name.startswith('_') and callable(getattr(python_class, method_name)):
459
+ method = getattr(python_class, method_name)
460
+ if not method_name == python_class.__name__: # Skip constructor
461
+ if inspect.iscoroutinefunction(method):
462
+ builder.add_public_coroutine(method_name, method)
463
+ else:
464
+ builder.add_public_method(method_name, method)
465
+
466
+ # Dynamic handler for unknown function calls
467
+ # We assume all unknown functions are publicly available, so
468
+ # no context checking is needed. However, since Objective-LOL
469
+ # is case-insensitive for method names, we need to try all
470
+ # case permutations to find a match.
471
+
472
+ # Cache for case-insensitive method name lookups
473
+ _method_name_cache = {}
474
+ if self._prefer_async_loop:
475
+ async def async_handler(this, fname: str, from_context: str, *args):
476
+ # Check cache first
477
+ cache_key = (id(this), fname.upper())
478
+ if cache_key in _method_name_cache:
479
+ actual_method_name = _method_name_cache[cache_key]
480
+ if actual_method_name:
481
+ method = getattr(this, actual_method_name)
482
+ return await method(*args)
483
+ else:
484
+ # Cached as not found
485
+ raise AttributeError(f"'{type(this).__name__}' object has no attribute '{fname}'")
486
+
487
+ # Try all case permutations
488
+ for candidate in generate_case_permutations(fname):
489
+ try:
490
+ if hasattr(this, candidate):
491
+ method = getattr(this, candidate)
492
+ if callable(method):
493
+ _method_name_cache[cache_key] = candidate
494
+ return await method(*args)
495
+ except Exception as e:
496
+ continue
497
+
498
+ # Cache as not found
499
+ _method_name_cache[cache_key] = None
500
+ raise AttributeError(f"'{type(this).__name__}' object has no attribute '{fname}'")
501
+ builder.add_unknown_coroutine_handler(async_handler)
502
+ else:
503
+ def handler(this, fname: str, from_context: str, *args):
504
+ # Check cache first
505
+ cache_key = (id(this), fname.upper())
506
+ if cache_key in _method_name_cache:
507
+ actual_method_name = _method_name_cache[cache_key]
508
+ if actual_method_name:
509
+ method = getattr(this, actual_method_name)
510
+ return method(*args)
511
+ else:
512
+ # Cached as not found
513
+ raise AttributeError(f"'{type(this).__name__}' object has no attribute '{fname}'")
514
+
515
+ # Try all case permutations
516
+ for candidate in generate_case_permutations(fname):
517
+ if hasattr(this, candidate):
518
+ method = getattr(this, candidate)
519
+ if callable(method):
520
+ _method_name_cache[cache_key] = candidate
521
+ return method(*args)
522
+
523
+ # Cache as not found
524
+ _method_name_cache[cache_key] = None
525
+ raise AttributeError(f"'{type(this).__name__}' object has no attribute '{fname}'")
526
+ builder.add_unknown_function_handler(handler)
527
+
528
+ class_def = builder.get()
529
+ self._vm.DefineClass(class_def)
530
+
531
+ defined_classes[class_name.upper()] = python_class
532
+
533
+ def call(self, name: str, *args):
534
+ goArgs = self.convert_to_go_value(args)
535
+ result = self._vm.Call(name, goArgs)
536
+ return self.convert_from_go_value(result)
537
+
538
+ async def call_async(self, name: str, *args):
539
+ goArgs = self.convert_to_go_value(args)
540
+ fut = concurrent.futures.Future()
541
+ def do():
542
+ try:
543
+ result = self._vm.Call(name, goArgs)
544
+ fut.set_result(self.convert_from_go_value(result))
545
+ except Exception as e:
546
+ fut.set_exception(e)
547
+ threading.Thread(target=do).start()
548
+ return await asyncio.wrap_future(fut)
549
+
550
+ def call_method(self, receiver: GoValue, name: str, *args):
551
+ goArgs = self.convert_to_go_value(args)
552
+ result = self._vm.CallMethod(receiver, name, goArgs)
553
+ return self.convert_from_go_value(result)
554
+
555
+ async def call_method_async(self, receiver: GoValue, name: str, *args):
556
+ goArgs = self.convert_to_go_value(args)
557
+ fut = concurrent.futures.Future()
558
+ def do():
559
+ try:
560
+ result = self._vm.CallMethod(receiver, name, goArgs)
561
+ fut.set_result(self.convert_from_go_value(result))
562
+ except Exception as e:
563
+ fut.set_exception(e)
564
+ threading.Thread(target=do).start()
565
+ result = await asyncio.wrap_future(fut)
566
+ return result
567
+
568
+ def execute(self, code: str) -> None:
569
+ return self._vm.Execute(code)
570
+
571
+ async def execute_async(self, code: str) -> None:
572
+ fut = concurrent.futures.Future()
573
+ def do():
574
+ try:
575
+ result = self._vm.Execute(code)
576
+ fut.set_result(result)
577
+ except Exception as e:
578
+ fut.set_exception(e)
579
+ threading.Thread(target=do).start()
580
+ return await asyncio.wrap_future(fut)
581
+
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: objective_lol
3
+ Version: 0.0.1
4
+ Summary: Python bindings for Objective-LOL
5
+ Home-page: https://github.com/bjia56/objective-lol
6
+ Author: Brett Jia
7
+ Author-email: dev.bjia56@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Description-Content-Type: text/markdown
11
+ Dynamic: author
12
+ Dynamic: author-email
13
+ Dynamic: classifier
14
+ Dynamic: description
15
+ Dynamic: description-content-type
16
+ Dynamic: home-page
17
+ Dynamic: summary
18
+
19
+ # Objective-LOL Python Bindings
20
+
21
+ Python bindings for the Objective-LOL programming language - a modern, strongly-typed language inspired by LOLCODE.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install objective-lol
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```python
32
+ import objective_lol as olol
33
+
34
+ # Create a VM instance
35
+ vm = olol.ObjectiveLOLVM()
36
+
37
+ # Execute Objective-LOL code
38
+ code = """
39
+ I CAN HAS STDIO?
40
+ HAI ME TEH FUNCSHUN MAIN
41
+ I HAS A VARIABLE X TEH INTEGR ITZ 42
42
+ SAYZ WIT X
43
+ KTHXBAI
44
+ """
45
+
46
+ vm.execute(code) # Prints: 42
47
+ ```
48
+
49
+ ## Features
50
+
51
+ - **Execute Objective-LOL code**: Run complete programs or code snippets
52
+ - **Python integration**: Call Python functions from Objective-LOL and vice versa
53
+ - **Type conversion**: Automatic conversion between Python and Objective-LOL types
54
+ - **Module system**: Import and use custom modules
55
+ - **Class definitions**: Define and use classes from Python
56
+
57
+ ## Advanced Usage
58
+
59
+ ### Defining Python Functions for Objective-LOL
60
+
61
+ ```python
62
+ vm = olol.ObjectiveLOLVM()
63
+
64
+ def add_numbers(a, b):
65
+ return a + b
66
+
67
+ vm.define_function("add_numbers", add_numbers)
68
+
69
+ code = """
70
+ I CAN HAS STDIO?
71
+ HAI ME TEH FUNCSHUN MAIN
72
+ I HAS A VARIABLE RESULT TEH INTEGR ITZ add_numbers WIT 10 AN WIT 20
73
+ SAYZ WIT RESULT
74
+ KTHXBAI
75
+ """
76
+
77
+ vm.execute(code) # Prints: 30
78
+ ```
79
+
80
+ ### Working with Classes
81
+
82
+ ```python
83
+ vm = olol.ObjectiveLOLVM()
84
+
85
+ class Calculator:
86
+ def add(self, x, y):
87
+ return x + y
88
+
89
+ def multiply(self, x, y):
90
+ return x * y
91
+
92
+ vm.define_class(Calculator)
93
+
94
+ code = """
95
+ I CAN HAS STDIO?
96
+ HAI ME TEH FUNCSHUN MAIN
97
+ I HAS A VARIABLE CALC TEH Calculator ITZ NEW Calculator
98
+ I HAS A VARIABLE SUM TEH INTEGR ITZ CALC DO add WIT 5 AN WIT 3
99
+ SAYZ WIT SUM
100
+ KTHXBAI
101
+ """
102
+
103
+ vm.execute(code) # Prints: 8
104
+ ```
105
+
106
+ ## Type Mapping
107
+
108
+ | Objective-LOL Type | Python Type |
109
+ |-------------------|-------------|
110
+ | INTEGR | int |
111
+ | DUBBLE | float |
112
+ | STRIN | str |
113
+ | BOOL | bool |
114
+ | NOTHIN | None |
115
+ | BUKKIT (array) | list |
116
+ | BASKIT (map) | dict |
117
+
118
+ ## Links
119
+
120
+ - [Main Project](https://github.com/bjia56/objective-lol)
121
+ - [Language Documentation](https://github.com/bjia56/objective-lol/tree/main/docs)
122
+
123
+ ## License
124
+
125
+ MIT License