Skip to content

Commit c6afdef

Browse files
Add UNLICENSE; improve REPL, module import/export, I/O and freezing
Add UNLICENSE (public-domain dedication). Wire REPL to behave like script top-level: use <string> as source filename, create a top-level frame, and route input/output via configurable input_provider/output_sink. Ensure prompts start on a fresh line when prior output exists and reset call stack after errored evaluations so the REPL remains usable. Add module caching for IMPORT: cache module Environment and created Function objects so subsequent imports reuse the same namespace instance and avoid re-executing module code. Publish module top-level bindings as dotted names (module.name) into the caller environment. Add EXPORT(symbol, module) to copy a caller binding into an imported module's dotted namespace. Improve INPUT to accept an optional prompt, forward prompts to the output sink, and record prompts in the I/O log for deterministic replay. Add shushing controls: SHUSH/UNSHUSH to temporarily suppress forwarding of console output (while still recording I/O events); make RUN temporarily disable shushing so run-invoked output is always forwarded. Make PRINT, child process output, and other forwarders respect the shushed flag so forwarded console output is suppressed when shushed. Add identifier freeze controls: FREEZE, THAW, PERMAFREEZE with runtime enforcement (prevent reassignment/deletion of frozen bindings), plus query helpers FROZEN and PERMAFROZEN. Add EXPORT, FROZEN, PERMAFROZEN builtins and hook their behaviors into the interpreter environment. Improve READFILE to read raw bytes and decode robustly (UTF-8 with/without BOM, UTF-16, fallback with replacement) to avoid decoding crashes on BOM or different encodings. Update lexer to accept both single and double quotes for string literals (must open and close with same delimiter). Add small warning in collection.asmln and expand test.asmln to print progress and success messages for library tests. Update spec.txt to document new behaviors: string quoting, INPUT(prompt), SHUSH/UNSHUSH, freezing semantics, EXPORT, and IMPORT caching semantics.
1 parent a80b9f7 commit c6afdef

File tree

8 files changed

+468
-57
lines changed

8 files changed

+468
-57
lines changed

UNLICENSE

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to https://unlicense.org

asmln.exe

7.21 KB
Binary file not shown.

asmln.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,26 @@ def _parse_statements_from_source(text: str, filename: str) -> List[Statement]:
1919

2020
def run_repl(verbose: bool) -> int:
2121
print("\x1b[38;2;153;221;255mASM-Lang\033[0m REPL. Enter statements, blank line to run buffer.")
22-
interpreter = Interpreter(source="", filename="<repl>", verbose=verbose)
22+
# Use "<string>" as the REPL's effective source filename so that MAIN() and imports behave
23+
had_output = False
24+
def _output_sink(text: str) -> None:
25+
nonlocal had_output
26+
had_output = True
27+
print(text, end="")
28+
29+
interpreter = Interpreter(source="", filename="<string>", verbose=verbose, input_provider=(lambda: input()), output_sink=_output_sink)
2330
global_env = Environment()
24-
global_frame = interpreter._new_frame("<repl>", global_env, None)
31+
# Make the REPL top-level frame mimic script top-level frame
32+
global_frame = interpreter._new_frame("<top-level>", global_env, None)
2533
interpreter.call_stack.append(global_frame)
2634
buffer: List[str] = []
2735

2836
while True:
2937
prompt = "\x1b[38;2;153;221;255m>>>\033[0m " if not buffer else "\x1b[38;2;153;221;255m..>\033[0m "
38+
if had_output:
39+
# Ensure prompt starts on a fresh line if the program printed anything
40+
print()
41+
had_output = False
3042
try:
3143
line = input(prompt)
3244
except EOFError:
@@ -45,20 +57,21 @@ def run_repl(verbose: bool) -> int:
4557

4658
if not buffer and stripped != "" and not is_block_start:
4759
try:
48-
statements = _parse_statements_from_source(line, "<repl>")
60+
statements = _parse_statements_from_source(line, "<string>")
4961
try:
5062
interpreter._execute_block(statements, global_env)
5163
except ExitSignal as sig:
5264
return sig.code
5365
except ASMParseError:
66+
# If a single-line parse fails, treat it as start of multi-line input
5467
buffer.append(line)
5568
continue
5669

5770
if stripped == "" and buffer:
5871
source_text = "\n".join(buffer)
5972
buffer.clear()
6073
try:
61-
statements = _parse_statements_from_source(source_text, "<repl>")
74+
statements = _parse_statements_from_source(source_text, "<string>")
6275
interpreter._execute_block(statements, global_env)
6376
except ExitSignal as sig:
6477
return sig.code
@@ -69,13 +82,12 @@ def run_repl(verbose: bool) -> int:
6982
error.step_index = interpreter.logger.entries[-1].step_index
7083
formatter = TracebackFormatter(interpreter)
7184
print(formatter.format_text(error, verbose=interpreter.verbose), file=sys.stderr)
85+
# reset call stack to single top-level frame to keep REPL usable
7286
interpreter.call_stack = [global_frame]
7387
continue
7488

7589
buffer.append(line)
7690

77-
return 0
78-
7991

8092
def run_cli(argv: Optional[List[str]] = None) -> int:
8193
parser = argparse.ArgumentParser(description="ASM-Lang reference interpreter")

0 commit comments

Comments
 (0)