#ifdef ExampleGreet·Greeter
#include <stdio.h>
- void ExampleGreet·Greeter·hello_loop(int count){
+ void ExampleGreet·Greeter·hello_loop(int count){
for(int TM = 0; TM < count; ++TM){
int current_count = ExampleGreet·Math·add(TM ,1);
printf("Hello iteration: %d\n" ,current_count);
}
}
+
#endif // ExampleGreet·Greeter
#endif // ExampleGreet·Greeter·ONCE
#include "Math.lib.c"
#include "Greeter.lib.c"
-void CLI(void){
+void CLI(void){
int base_count = ExampleGreet·Math·add(1 ,2);
printf("Calculated base loop count: %d\n" ,base_count);
ExampleGreet·Greeter·hello_loop(base_count);
}
-int main(int argc ,char **argv){
+int main(int argc ,char **argv){
(void)argc;
(void)argv;
--- /dev/null
+#!/usr/bin/env -S python3 -B
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+"""
+RTfmt — Reasoning Technology code formatter (Predicate Tokenizer)
+
+Commands:
+ RTfmt write [--lisp] <file ...> Format files in place (rewrite originals)
+ RTfmt copy [--lisp] <file ...> Save backups as <file>~ then format originals
+ RTfmt pipe [--lisp] Read from stdin, write to stdout
+ RTfmt self_test Run built-in tests
+ RTfmt version Show tool version
+ RTfmt help | --help Show usage
+"""
+
+import sys ,re ,shutil ,os
+from typing import List ,Tuple ,Optional ,TextIO
+
+RTF_VERSION = "0.5.0-predicate"
+
+def get_usage() -> str:
+ prog_name = os.path.basename(sys.argv[0])
+ return f"""\
+Usage:
+ {prog_name} write [--lisp] <file ...>
+ {prog_name} copy [--lisp] <file ...>
+ {prog_name} pipe [--lisp]
+ {prog_name} self_test
+ {prog_name} version
+ {prog_name} help | --help
+"""
+
+# Removed < and > so they are treated as standard CODE operators
+BR_OPEN = "([{"
+BR_CLOSE = ")]}"
+PAIR = dict( zip(BR_OPEN ,BR_CLOSE) )
+REV = dict( zip(BR_CLOSE ,BR_OPEN) )
+
+# --------------- Lexer ----------------
+
+class RT_Token:
+ def __init__(self ,kind: str ,text: str):
+ self.kind = kind
+ self.text = text
+
+ def __repr__(self):
+ return f"<{self.kind}:{repr(self.text)}>"
+
+TOKEN_REGEX = re.compile(
+ r'(?P<COMMENT>//[^\n]*|#[^\n]*|(?s:/\*.*?\*/))'
+ r'|(?P<STRING>"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
+ r'|(?P<SPACE>[ \t]+)'
+ r'|(?P<NEWLINE>\n)'
+ r'|(?P<COMMA>,)'
+ r'|(?P<BR_OPEN>[\[\(\{])'
+ r'|(?P<BR_CLOSE>[\]\)\}])'
+ r'|(?P<CODE>[^ \t\n,\[\(\{\]\)\}"\'#/]+|/)'
+)
+
+def tokenize(text: str) -> List[RT_Token]:
+ tokens = []
+ for TM_match in TOKEN_REGEX.finditer(text):
+ kind = TM_match.lastgroup
+ text_val = TM_match.group(kind)
+ tokens.append( RT_Token(kind ,text_val) )
+ return tokens
+
+# --------------- Intelligence API ----------------
+
+class TokenStream:
+ def __init__(self ,tokens: List[RT_Token]):
+ self.tokens = tokens
+
+ def get_token(self ,index: int) -> Optional[RT_Token]:
+ if 0 <= index < len(self.tokens):
+ return self.tokens[index]
+ return None
+
+ def next_sig_index(self ,index: int) -> Optional[int]:
+ for TM_i in range(index + 1 ,len(self.tokens)):
+ if self.tokens[TM_i].kind not in ("SPACE" ,"NEWLINE" ,"COMMENT"):
+ return TM_i
+ return None
+
+ def is_first_on_line(self ,index: int) -> bool:
+ for TM_i in range(index - 1 ,-1 ,-1):
+ k = self.tokens[TM_i].kind
+ if k == "NEWLINE":
+ return True
+ if k != "SPACE":
+ return False
+ return True # Start of file
+
+ def indent_of_line(self ,index: int) -> str:
+ for TM_i in range(index ,-1 ,-1):
+ if self.tokens[TM_i].kind == "NEWLINE":
+ if TM_i + 1 < len(self.tokens) and self.tokens[TM_i + 1].kind == "SPACE":
+ return self.tokens[TM_i + 1].text
+ return ""
+ if self.tokens and self.tokens[0].kind == "SPACE":
+ return self.tokens[0].text
+ return ""
+
+ def indent_of_left_match(self ,index: int) -> Optional[str]:
+ tok = self.get_token(index)
+ if not tok or tok.kind != "BR_CLOSE":
+ return None
+ target_opener = REV[tok.text]
+ depth = 0
+ for TM_i in range(index - 1 ,-1 ,-1):
+ t = self.tokens[TM_i]
+ if t.kind == "BR_CLOSE":
+ depth += 1
+ elif t.kind == "BR_OPEN":
+ if depth > 0:
+ depth -= 1
+ elif t.text == target_opener:
+ return self.indent_of_line(TM_i)
+ return None
+
+# --------------- Rule Engine ----------------
+
+def rule_migrate_vertical_commas(stream: TokenStream):
+ TM_i = 0
+ while TM_i < len(stream.tokens):
+ if stream.tokens[TM_i].kind == "COMMA":
+ is_trailing = False
+ next_sig = stream.next_sig_index(TM_i)
+ if next_sig is not None:
+ for TM_j in range(TM_i + 1 ,next_sig):
+ if stream.tokens[TM_j].kind == "NEWLINE":
+ is_trailing = True
+ break
+
+ if is_trailing:
+ comma_tok = stream.tokens.pop(TM_i)
+ next_sig -= 1 # Shifted because of pop
+ stream.tokens.insert(next_sig ,comma_tok)
+ continue
+ TM_i += 1
+
+def rule_format_horizontal_commas(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "COMMA":
+ if stream.is_first_on_line(TM_i):
+ continue
+
+ next_tok = stream.get_token(TM_i + 1)
+ if next_tok and next_tok.kind == "SPACE":
+ stream.tokens.pop(TM_i + 1)
+
+ prev_tok = stream.get_token(TM_i - 1)
+ if prev_tok and prev_tok.kind == "SPACE":
+ if prev_tok.text != " ":
+ prev_tok.text = " "
+ else:
+ stream.tokens.insert(TM_i ,RT_Token("SPACE" ," "))
+
+def rule_fix_closing_indent(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "BR_CLOSE" and stream.is_first_on_line(TM_i):
+ target_indent = stream.indent_of_left_match(TM_i)
+ if target_indent is not None:
+ prev = stream.get_token(TM_i - 1)
+ if prev and prev.kind == "SPACE":
+ prev.text = target_indent
+ else:
+ stream.tokens.insert(TM_i ,RT_Token("SPACE" ,target_indent))
+
+def rule_tighten_brackets(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "SPACE" and not stream.is_first_on_line(TM_i):
+ prev_t = stream.get_token(TM_i - 1)
+ next_t = stream.get_token(TM_i + 1)
+ if (prev_t and prev_t.kind == "BR_OPEN") or (next_t and next_t.kind == "BR_CLOSE"):
+ stream.tokens.pop(TM_i)
+
+def get_bracket_spans(stream: TokenStream) -> List[Tuple[int ,int]]:
+ stack = []
+ spans = []
+ for TM_i ,tok in enumerate(stream.tokens):
+ if tok.kind == "BR_OPEN":
+ stack.append( (tok.text ,TM_i) )
+ elif tok.kind == "BR_CLOSE":
+ if stack and REV[tok.text] == stack[-1][0]:
+ _ ,pos = stack.pop()
+ if not stack:
+ spans.append( (pos ,TM_i) )
+ return spans
+
+def rule_pad_outermost(stream: TokenStream ,is_lisp: bool):
+ if is_lisp:
+ return
+ while True:
+ spans = get_bracket_spans(stream)
+ changed = False
+ for TM_start ,TM_end in reversed(spans):
+ has_inner = False
+ for TM_k in range(TM_start + 1 ,TM_end):
+ if stream.tokens[TM_k].kind in ("BR_OPEN" ,"BR_CLOSE"):
+ has_inner = True
+ break
+
+ if has_inner:
+ left_has = (TM_start + 1 < len(stream.tokens)) and stream.tokens[TM_start + 1].kind == "SPACE"
+ right_has = (TM_end - 1 >= 0) and stream.tokens[TM_end - 1].kind == "SPACE"
+ if not left_has or not right_has:
+ if not right_has:
+ stream.tokens.insert(TM_end ,RT_Token("SPACE" ," "))
+ if not left_has:
+ stream.tokens.insert(TM_start + 1 ,RT_Token("SPACE" ," "))
+ changed = True
+ break
+ if not changed:
+ break
+
+# --------------- Public API ----------------
+
+def format_tokens(tokens: List[RT_Token] ,is_lisp: bool) -> str:
+ stream = TokenStream(tokens)
+
+ rule_migrate_vertical_commas(stream)
+ rule_format_horizontal_commas(stream)
+ rule_tighten_brackets(stream)
+ rule_fix_closing_indent(stream)
+ rule_pad_outermost(stream ,is_lisp)
+
+ return "".join(t.text for t in stream.tokens)
+
+def rt_format_text(text: str ,is_lisp: bool) -> str:
+ tokens = tokenize(text)
+ return format_tokens(tokens ,is_lisp)
+
+def rt_format_stream(inp: TextIO ,out: TextIO ,is_lisp: bool) -> None:
+ text = inp.read()
+ out.write( rt_format_text(text ,is_lisp) )
+
+# --------------- Self-test ----------------
+
+def run_self_test() -> bool:
+ ok = True
+ def chk(src ,exp):
+ nonlocal ok
+ got = rt_format_text(src ,False)
+ if got != exp:
+ print("FAIL:\n" + src + "\n=>\n" + got + "\nexpected:\n" + exp)
+ ok = False
+
+ chk("a,b,c" ,"a ,b ,c")
+ chk("a , b , c" ,"a ,b ,c")
+ chk(" ,vertical_arg" ," ,vertical_arg")
+
+ chk("int a=0,\n b=1,\n c=2;" ,"int a=0\n ,b=1\n ,c=2;")
+
+ chk("f ( x )" ,"f(x)")
+ chk("f(x) + g(y)" ,"f(x) + g(y)")
+ chk(" {" ," {")
+
+ src = "int g(){int a=0,b=1,c=2; return h(a,b,c);}"
+ exp = "int g(){ int a=0 ,b=1 ,c=2; return h(a ,b ,c); }"
+ chk(src ,exp)
+
+ chk("outer( inner(a,b) )" ,"outer( inner(a ,b) )")
+
+ # Operator protection check
+ chk("for(int TM = 0; TM < count; ++TM)" ,"for(int TM = 0; TM < count; ++TM)")
+
+ print("SELFTEST OK" if ok else "SELFTEST FAILED")
+ return ok
+
+# --------------- CLI ----------------
+def write_files(paths: List[str] ,is_lisp: bool) -> int:
+ for TM_path in paths:
+ with open(TM_path ,"r" ,encoding="utf-8") as f:
+ data = f.read()
+ formatted = rt_format_text(data ,is_lisp)
+ with open(TM_path ,"w" ,encoding="utf-8") as f:
+ f.write(formatted)
+ return 0
+
+def copy_files(paths: List[str] ,is_lisp: bool) -> int:
+ for TM_path in paths:
+ shutil.copy2(TM_path ,TM_path + "~")
+ return write_files(paths ,is_lisp)
+
+def CLI(argv=None) -> int:
+ args = list(sys.argv[1:] if argv is None else argv)
+ usage_text = get_usage()
+
+ if not args or args[0] in {"help" ,"--help" ,"-h"}:
+ print(usage_text)
+ return 0
+
+ is_lisp = "--lisp" in args
+ args = [TM_a for TM_a in args if TM_a != "--lisp"]
+
+ if not args:
+ return 0
+
+ cmd = args[0]
+ rest = args[1:]
+
+ if cmd == "version":
+ print(RTF_VERSION)
+ return 0
+ if cmd == "self_test":
+ ok = run_self_test()
+ return 0 if ok else 1
+ if cmd == "pipe":
+ rt_format_stream(sys.stdin ,sys.stdout ,is_lisp)
+ return 0
+ if cmd == "write":
+ if not rest:
+ print("write: missing <file ...>\n" + usage_text)
+ return 2
+ return write_files(rest ,is_lisp)
+ if cmd == "copy":
+ if not rest:
+ print("copy: missing <file ...>\n" + usage_text)
+ return 2
+ return copy_files(rest ,is_lisp)
+
+ print(f"Unknown command: {cmd}\n" + usage_text)
+ return 2
+
+if __name__ == "__main__":
+ sys.exit( CLI() )
--- /dev/null
+(defun RTfmt0-buffer ()
+ "Format the current buffer using RTfmt0."
+ (interactive)
+ (if (not (executable-find "RTfmt0"))
+ (message "Error: RTfmt0 executable not found in PATH.")
+ (let ((temp-buffer (generate-new-buffer " *RTfmt0*"))
+ (args (list "pipe")))
+ (when (derived-mode-p 'emacs-lisp-mode 'lisp-mode)
+ (setq args (append args (list "--lisp"))))
+ (unwind-protect
+ (let ((exit-code (apply #'call-process-region
+ (point-min) (point-max)
+ "RTfmt0"
+ nil temp-buffer nil
+ args)))
+ (if (zerop exit-code)
+ (progn
+ ;; Applies a non-destructive diff, preserving point and markers natively
+ (replace-buffer-contents temp-buffer)
+ (message "RTfmt0 formatting successful."))
+ (message "RTfmt0 failed with exit code %s. Buffer unchanged." exit-code)))
+ (kill-buffer temp-buffer)))))
+++ /dev/null
-#!/usr/bin/env -S python3 -B
-# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
-"""
-RT_Format — Reasoning Technology code formatter (commas + bracketed phrases per line)
-
-Commands:
- RT_Format write <file ...> Format files in place (rewrite originals)
- RT_Format copy <file ...> Save backups as <file>~ then format originals
- RT_Format pipe Read from stdin, write to stdout
- RT_Format self_test Run built-in tests
- RT_Format version Show tool version
- RT_Format help | --help Show usage
-
-Rules:
- • Horizontal lists -> a ,b ,c (space BEFORE comma, none after)
- • Tight (){}[] by default; add one space just inside borders only when an
- OUTERMOST bracketed phrase on the line contains an INNER bracket.
- • Multiple outermost phrases can exist on a line (e.g., `g() { ... }`);
- apply the rule to EACH such phrase independently.
- • Per-line, tolerant of unbalanced brackets: first unmatched opener OR last
- unmatched closer is treated as “the” outermost for padding purposes.
- • Strings and single-line comments (#, //) are not altered.
-"""
-
-from typing import List ,Tuple ,Optional ,TextIO
-import sys ,re ,io ,shutil ,os
-
-RTF_VERSION = "0.2.2" # pad all outermost-with-nesting phrases on a line
-
-BR_OPEN = "([{<"
-BR_CLOSE = ")]}>"
-PAIR = dict(zip(BR_OPEN ,BR_CLOSE))
-REV = dict(zip(BR_CLOSE ,BR_OPEN))
-
-USAGE = """\
-Usage:
- RT_Format write <file ...>
- RT_Format copy <file ...>
- RT_Format pipe
- RT_Format self_test
- RT_Format version
- RT_Format help | --help
-"""
-
-# --------------- Core token helpers ----------------
-
-def split_code_comment(line: str):
- """Return (code ,comment), keeping the comment marker if present; ignore markers inside strings."""
- in_s = None
- esc = False
- for i ,ch in enumerate(line):
- if in_s:
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- continue
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- continue
- if ch == "#":
- return line[:i] ,line[i:]
- if ch == "/" and i + 1 < len(line) and line[i + 1] == "/":
- return line[:i] ,line[i:]
- return line ,""
-
-def format_commas(code: str) -> str:
- """Space BEFORE comma, none after, outside strings."""
- out: List[str] = []
- in_s = None
- esc = False
- i = 0
- while i < len(code):
- ch = code[i]
- if in_s:
- out.append(ch)
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- i += 1
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- out.append(ch)
- i += 1
- elif ch == ",":
- while out and out[-1] == " ":
- out.pop()
- if out and out[-1] != " ":
- out.append(" ")
- out.append(",")
- j = i + 1
- while j < len(code) and code[j] == " ":
- j += 1
- i = j
- else:
- out.append(ch)
- i += 1
- return "".join(out)
-
-# --------------- Bracket discovery ----------------
-
-def top_level_spans(code: str) -> List[Tuple[int ,int]]:
- """Return all balanced OUTERMOST bracketed spans (start,end) for this line, ignoring strings."""
- in_s = None
- esc = False
- stack: List[Tuple[str ,int]] = []
- spans: List[Tuple[int ,int]] = []
- for i ,ch in enumerate(code):
- if in_s:
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- continue
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- continue
- if ch in BR_OPEN:
- stack.append((ch ,i))
- elif ch in BR_CLOSE:
- if stack and REV[ch] == stack[-1][0]:
- _ ,pos = stack.pop()
- if not stack:
- spans.append((pos ,i))
- else:
- # unmatched closer ignored here; handled in unbalanced logic
- pass
- return spans
-
-def first_unmatched_opener(code: str) -> Optional[int]:
- in_s = None
- esc = False
- stack: List[Tuple[str ,int]] = []
- for i ,ch in enumerate(code):
- if in_s:
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- continue
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- continue
- if ch in BR_OPEN:
- stack.append((ch ,i))
- elif ch in BR_CLOSE:
- if stack and REV[ch] == stack[-1][0]:
- stack.pop()
- else:
- # unmatched closer: do nothing here
- pass
- return stack[0][1] if stack else None
-
-def last_unmatched_closer(code: str) -> Optional[int]:
- in_s = None
- esc = False
- depth = 0
- last: Optional[int] = None
- for i ,ch in enumerate(code):
- if in_s:
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- continue
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- continue
- if ch in BR_OPEN:
- depth += 1
- elif ch in BR_CLOSE:
- if depth > 0:
- depth -= 1
- else:
- last = i
- return last
-
-def contains_inner_bracket(code: str ,start: Optional[int] ,end: Optional[int]) -> bool:
- """Check for any bracket token inside the given bounds (respect strings)."""
- if start is None and end is None:
- return False
- in_s = None
- esc = False
- lo = (start + 1) if start is not None else 0
- hi = (end - 1) if end is not None else len(code) - 1
- if hi < lo:
- return False
- for i ,ch in enumerate(code):
- if i < lo or i > hi:
- continue
- if in_s:
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- continue
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- continue
- if ch in BR_OPEN or ch in BR_CLOSE:
- return True
- return False
-
-# --------------- Spacing transforms ----------------
-
-def tighten_all_brackets(code: str) -> str:
- """Tight margins and remove immediate interior spaces next to borders."""
- out: List[str] = []
- in_s = None
- esc = False
- i = 0
- while i < len(code):
- ch = code[i]
- if in_s:
- out.append(ch)
- if esc:
- esc = False
- elif ch == "\\":
- esc = True
- elif ch == in_s:
- in_s = None
- i += 1
- else:
- if ch in ("'" ,'"'):
- in_s = ch
- out.append(ch)
- i += 1
- elif ch in BR_CLOSE:
- if out and out[-1] == " ":
- out.pop()
- out.append(ch)
- i += 1
- elif ch in BR_OPEN:
- if out and out[-1] == " ":
- out.pop()
- out.append(ch)
- i += 1
- while i < len(code) and code[i] == " ":
- i += 1
- else:
- out.append(ch)
- i += 1
- return "".join(out)
-
-def apply_bracket_padding(code: str) -> str:
- """
- 1) Tighten globally.
- 2) For EACH balanced outermost span, if it contains an inner bracket,
- ensure exactly one space just inside its borders — but only if missing.
- 3) If there are no balanced spans, pad the first unmatched opener OR the last unmatched closer
- only if that outer fragment contains an inner bracket, and only if padding is missing.
- """
- s = tighten_all_brackets(code)
-
- def borders_have_space(text: str, start: int, end: int) -> Tuple[bool, bool]:
- # Return (left_has_space, right_has_space) for just-inside borders.
- left_has = (start + 1 < len(text)) and (text[start + 1] == " ")
- right_has = (end - 1 >= 0) and (text[end - 1] == " ")
- return left_has, right_has
-
- # Balanced top-level spans: may be multiple on one line (e.g., g() { ... }).
- # Iterate while applying at most one mutation per pass; recompute spans after.
- while True:
- spans = top_level_spans(s)
- changed = False
- for (start, end) in spans:
- if contains_inner_bracket(s, start, end):
- left_has, right_has = borders_have_space(s, start, end)
- if not left_has or not right_has:
- # Insert exactly one space just inside each border that lacks it.
- if not right_has:
- # Right side first to avoid shifting the 'start' index computation
- s = s[:end].rstrip(" ") + " " + s[end:].lstrip(" ")
- if not left_has:
- s = s[:start + 1].rstrip(" ") + " " + s[start + 1:].lstrip(" ")
- changed = True
- break # after a mutation, recompute spans fresh
- if not changed:
- break
-
- # If there are no balanced spans, consider unbalanced fragment once
- if not top_level_spans(s):
- o = first_unmatched_opener(s)
- c = last_unmatched_closer(s)
- if o is not None and contains_inner_bracket(s, o, None):
- # add one space after opener only if missing
- if not (o + 1 < len(s) and s[o + 1] == " "):
- s = s[:o + 1].rstrip(" ") + " " + s[o + 1:]
- elif c is not None and contains_inner_bracket(s, None, c):
- # add one space before closer only if missing
- if not (c - 1 >= 0 and s[c - 1] == " "):
- s = s[:c].rstrip(" ") + " " + s[c:]
-
- return s
-
-# --------------- Public API ----------------
-
-def rt_format_line(line: str) -> str:
- code ,comment = split_code_comment(line.rstrip("\n"))
- code = format_commas(code)
- code = apply_bracket_padding(code)
- return code + comment
-
-def rt_format_text(text: str) -> str:
- return "\n".join(rt_format_line(ln) for ln in text.splitlines())
-
-def rt_format_stream(inp: TextIO ,out: TextIO) -> None:
- for line in inp:
- out.write(rt_format_line(line) + "\n")
-
-# --------------- Self-test ----------------
-
-def run_self_test() -> bool:
- ok = True
- def chk(src ,exp):
- nonlocal ok
- got = rt_format_line(src)
- if got != exp:
- print("FAIL:" ,src ,"=>" ,got ,"expected:" ,exp)
- ok = False
-
- # Commas
- chk("a,b,c" ,"a ,b ,c")
- chk("a , b , c" ,"a ,b ,c")
-
- # Tight () by default
- chk("f ( x )" ,"f(x)")
- chk("f(x) + g(y)" ,"f(x) + g(y)")
-
- # Balanced: multiple outermost spans (g() and {...}) -> only pad {...} if it has inner bracket
- src = "int g(){int a=0,b=1,c=2; return h(a,b,c);}"
- exp = "int g(){ int a=0 ,b=1 ,c=2; return h(a ,b ,c); }"
- chk(src ,exp)
-
- # Balanced: single outermost with nesting
- chk("outer( inner(a,b) )" ,"outer( inner(a ,b) )")
-
- # Unbalanced open-right with nesting
- chk("compute(x, f(y" ,"compute( x ,f(y)")
-
- # Unbalanced open-left without prior inner bracket => unchanged
- chk("return z) + 1" ,"return z) + 1")
-
- print("SELFTEST OK" if ok else "SELFTEST FAILED")
- return ok
-
-# --------------- CLI ----------------
-
-def write_files(paths: List[str]) -> int:
- for path in paths:
- with open(path ,"r" ,encoding="utf-8") as f:
- data = f.read()
- formatted = rt_format_text(data)
- with open(path ,"w" ,encoding="utf-8") as f:
- f.write(formatted + ("\n" if not formatted.endswith("\n") else ""))
- return 0
-
-def copy_files(paths: List[str]) -> int:
- for path in paths:
- shutil.copy2(path ,path + "~")
- return write_files(paths)
-
-def CLI(argv=None) -> int:
- args = list(sys.argv[1:] if argv is None else argv)
- if not args or args[0] in {"help" ,"--help" ,"-h"}:
- print(USAGE)
- return 0
-
- cmd = args[0]
- rest = args[1:]
-
- if cmd == "version":
- print(RTF_VERSION)
- return 0
- if cmd == "self_test":
- ok = run_self_test()
- return 0 if ok else 1
- if cmd == "pipe":
- rt_format_stream(sys.stdin ,sys.stdout)
- return 0
- if cmd == "write":
- if not rest:
- print("write: missing <file ...>\n" + USAGE)
- return 2
- return write_files(rest)
- if cmd == "copy":
- if not rest:
- print("copy: missing <file ...>\n" + USAGE)
- return 2
- return copy_files(rest)
-
- print(f"Unknown command: {cmd}\n" + USAGE)
- return 2
-
-if __name__ == "__main__":
- sys.exit(CLI())
+++ /dev/null
-(defun rt-format-buffer ()
- (interactive)
- (shell-command-on-region (point-min) (point-max)
- "RT_Format pipe" t t))
+++ /dev/null
-// commas and simple tight brackets
-int g(){int a=0,b=1,c=2; return h(a,b,c);}
-
-// balanced outermost-with-nesting -> pad inside outer ()
-int f(){return outer( inner(a,b) );}
-
-// strings and comments must be unchanged
-int s(){ printf("x ,y ,z (still a string)"); /* a ,b ,c */ return 1; }
-
-// unbalanced open-right with nesting -> pad after first unmatched '('
-int u(){ if(doit(foo(1,2) // missing ))
- return 0; }
-
-// arrays / subscripts stay tight; commas still RT-style
-int a(int i,int j){ return M[i,j] + V[i] + W[j]; }
+++ /dev/null
-# commas and spacing in defs / calls
-def f ( x , y , z ):
- return dict( a =1 , b= 2 ), [ 1, 2 ,3 ], ( (1,2) )
-
-# outermost-with-nesting -> pad inside outer ()
-val = outer( inner( a,b ) )
-
-# strings/comments untouched
-s = "text, with , commas ( not to touch )" # a ,b ,c
-
-# unbalanced: open-left (closing without opener) -> no padding unless inner bracket before it
-def g():
- return result) # likely unchanged
-
-# unbalanced: open-right (first unmatched opener) with inner bracket following
-k = compute(x, f(y
--- /dev/null
+( defun RT-format-buffer()
+ (interactive)
+ (save-excursion
+ ( shell-command-on-region(point-min)(point-max)
+ "RT_format pipe" t t)) )
--- /dev/null
+
+(defun RTfmtt-buffer ()
+ "Format the current buffer using RTfmt."
+ (interactive)
+ (if (not (executable-find "RTfmt"))
+ (message "Error: RTfmt executable not found in PATH.")
+ (let ((temp-buffer (generate-new-buffer " *RTfmt*"))
+ (args (list "pipe")))
+ (when (derived-mode-p 'emacs-lisp-mode 'lisp-mode)
+ (setq args (append args (list "--lisp"))))
+ (unwind-protect
+ (let ((exit-code (apply #'call-process-region
+ (point-min) (point-max)
+ "RTfmt"
+ nil temp-buffer nil
+ args)))
+ (if (zerop exit-code)
+ (let ((formatted-text (with-current-buffer temp-buffer (buffer-string))))
+ (save-excursion
+ (delete-region (point-min) (point-max))
+ (insert formatted-text))
+ (message "RTfmt formatting successful."))
+ (message "RTfmt failed with exit code %s. Buffer unchanged." exit-code)))
+ (kill-buffer temp-buffer)))))
+
+;; ( defun RT-format-buffer()
+;; (interactive)
+;; (save-excursion
+;; ( shell-command-on-region(point-min)(point-max)
+;; "RTfmt pipe" t t)) )
--- /dev/null
+#!/usr/bin/env -S python3 -B
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+"""
+RT_Format — Reasoning Technology code formatter (Shallow Tokenizer)
+
+Commands:
+ RT_Format write [--lisp] <file ...> Format files in place (rewrite originals)
+ RT_Format copy [--lisp] <file ...> Save backups as <file>~ then format originals
+ RT_Format pipe [--lisp] Read from stdin, write to stdout
+ RT_Format self_test Run built-in tests
+ RT_Format version Show tool version
+ RT_Format help | --help Show usage
+"""
+
+import sys ,re ,shutil ,os
+from typing import List ,Tuple ,Optional ,TextIO
+
+RTF_VERSION = "0.4.0-tokenized"
+
+USAGE = """\
+Usage:
+ RT_Format write [--lisp] <file ...>
+ RT_Format copy [--lisp] <file ...>
+ RT_Format pipe [--lisp]
+ RT_Format self_test
+ RT_Format version
+ RT_Format help | --help
+"""
+
+BR_OPEN = "([{<"
+BR_CLOSE = ")]}>"
+PAIR = dict( zip(BR_OPEN ,BR_CLOSE) )
+REV = dict( zip(BR_CLOSE ,BR_OPEN) )
+
+# --------------- Lexer ----------------
+
+class RT_Token:
+ def __init__(self ,kind: str ,text: str):
+ self.kind = kind
+ self.text = text
+
+ def __repr__(self):
+ return f"<{self.kind}:{repr(self.text)}>"
+
+# The regex prioritizes exact matches.
+# Comments include //, #, and /* ... */ blocks.
+# Strings include Python '''/""" blocks, plus standard single/double quotes.
+TOKEN_REGEX = re.compile(
+ r'(?P<COMMENT>//[^\n]*|#[^\n]*|(?s:/\*.*?\*/))'
+ r'|(?P<STRING>"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
+ r'|(?P<SPACE>[ \t]+)'
+ r'|(?P<NEWLINE>\n)'
+ r'|(?P<COMMA>,)'
+ r'|(?P<BR_OPEN>[\[\(\{<])'
+ r'|(?P<BR_CLOSE>[\]\)\}>])'
+ r'|(?P<CODE>[^ \t\n,\[\(\{<\]\)\}>"\'#/]+|/)'
+)
+
+def tokenize(text: str) -> List[RT_Token]:
+ tokens = []
+ for TM_match in TOKEN_REGEX.finditer(text):
+ kind = TM_match.lastgroup
+ text_val = TM_match.group(kind)
+ tokens.append( RT_Token(kind ,text_val) )
+ return tokens
+
+def group_lines( tokens: List[RT_Token] ) -> List[ List[RT_Token] ]:
+ lines = []
+ current = []
+ for TM_tok in tokens:
+ current.append(TM_tok)
+ if TM_tok.kind == "NEWLINE":
+ lines.append(current)
+ current = []
+ if current:
+ lines.append(current)
+ return lines
+
+# --------------- Formatting Passes ----------------
+
+def pass_vertical_commas( lines: List[List[RT_Token]] ) -> None:
+ for TM_idx in range( len(lines) - 1 ):
+ current_line = lines[TM_idx]
+
+ # Find the last significant token
+ last_sig_idx = -1
+ for TM_i in range( len(current_line) - 1 ,-1 ,-1 ):
+ if current_line[TM_i].kind not in ("SPACE" ,"NEWLINE" ,"COMMENT"):
+ last_sig_idx = TM_i
+ break
+
+ if last_sig_idx>= 0 and current_line[last_sig_idx].kind == "COMMA":
+ # Remove the trailing comma
+ comma_tok = current_line.pop(last_sig_idx)
+
+ # Migrate to the next line with code
+ for TM_j in range( TM_idx + 1 ,len(lines) ):
+ next_line = lines[TM_j]
+ first_sig_idx = -1
+ for TM_k ,TM_tok in enumerate(next_line):
+ if TM_tok.kind not in ("SPACE" ,"NEWLINE" ,"COMMENT"):
+ first_sig_idx = TM_k
+ break
+
+ if first_sig_idx>= 0:
+ next_line.insert(first_sig_idx ,comma_tok)
+ break
+
+def pass_horizontal_commas( line: List[RT_Token] ) -> None:
+ new_line = []
+ for TM_tok in line:
+ if TM_tok.kind == "COMMA":
+ is_vertical = all(t.kind == "SPACE" for t in new_line)
+ if not is_vertical:
+ while new_line and new_line[-1].kind == "SPACE":
+ new_line.pop()
+ if new_line:
+ new_line.append( RT_Token("SPACE" ," ") )
+ new_line.append(TM_tok)
+ elif TM_tok.kind == "SPACE":
+ if new_line and new_line[-1].kind == "COMMA":
+ continue # Drop space after comma
+ new_line.append(TM_tok)
+ else:
+ new_line.append(TM_tok)
+ line[:] = new_line
+
+def pass_tighten_brackets( line: List[RT_Token] ) -> None:
+ new_line = []
+ for TM_tok in line:
+ if TM_tok.kind == "SPACE":
+ if new_line and new_line[-1].kind == "BR_OPEN":
+ continue
+ new_line.append(TM_tok)
+ elif TM_tok.kind == "BR_CLOSE":
+ while new_line and new_line[-1].kind == "SPACE":
+ new_line.pop()
+ new_line.append(TM_tok)
+ else:
+ new_line.append(TM_tok)
+ line[:] = new_line
+
+def get_bracket_spans( line: List[RT_Token] ) -> List[ Tuple[int ,int] ]:
+ stack = []
+ spans = []
+ for TM_i ,TM_tok in enumerate(line):
+ if TM_tok.kind == "BR_OPEN":
+ stack.append( (TM_tok.text ,TM_i) )
+ elif TM_tok.kind == "BR_CLOSE":
+ if stack and REV[TM_tok.text] == stack[-1][0]:
+ _ ,pos = stack.pop()
+ if not stack:
+ spans.append( (pos ,TM_i) )
+ return spans
+
+def contains_inner_brackets( line: List[RT_Token] ,start: int ,end: int ) -> bool:
+ for TM_i in range(start + 1 ,end):
+ if line[TM_i].kind in ("BR_OPEN" ,"BR_CLOSE"):
+ return True
+ return False
+
+def pass_pad_outermost( line: List[RT_Token] ,is_lisp: bool ) -> None:
+ if is_lisp:
+ return
+
+ while True:
+ spans = get_bracket_spans(line)
+ changed = False
+
+ # Process from right to left to avoid shifting indices
+ for TM_start ,TM_end in reversed(spans):
+ if contains_inner_brackets(line ,TM_start ,TM_end):
+ left_has = (TM_start + 1 <len(line)) and (line[TM_start + 1].kind == "SPACE")
+ right_has = ( TM_end - 1>= 0 ) and ( line[TM_end - 1].kind == "SPACE" )
+
+ if not left_has or not right_has:
+ if not right_has:
+ line.insert( TM_end ,RT_Token("SPACE" ," ") )
+ if not left_has:
+ line.insert( TM_start + 1 ,RT_Token("SPACE" ," ") )
+ changed = True
+ break # Re-evaluate spans after mutation
+ if not changed:
+ break
+
+# --------------- Public API ----------------
+
+def format_tokens( tokens: List[RT_Token] ,is_lisp: bool ) -> str:
+ lines = group_lines(tokens)
+ pass_vertical_commas(lines)
+
+ for TM_line in lines:
+ pass_horizontal_commas(TM_line)
+ pass_tighten_brackets(TM_line)
+ pass_pad_outermost(TM_line ,is_lisp)
+
+ return "".join(t.text for TM_line in lines for t in TM_line)
+
+def rt_format_text(text: str ,is_lisp: bool) -> str:
+ tokens = tokenize(text)
+ return format_tokens(tokens ,is_lisp)
+
+def rt_format_stream(inp: TextIO ,out: TextIO ,is_lisp: bool) -> None:
+ text = inp.read()
+ out.write( rt_format_text(text ,is_lisp) )
+
+# --------------- Self-test ----------------
+
+def run_self_test() -> bool:
+ ok = True
+ def chk(src ,exp):
+ nonlocal ok
+ got = rt_format_text(src ,False)
+ if got != exp:
+ print("FAIL:\n" + src + "\n=>\n" + got + "\nexpected:\n" + exp)
+ ok = False
+
+ chk("a,b,c" ,"a ,b ,c")
+ chk("a , b , c" ,"a ,b ,c")
+ chk(" ,vertical_arg" ," ,vertical_arg")
+
+ chk("int a=0,\n b=1,\n c=2;" ,"int a=0\n ,b=1\n ,c=2;")
+
+ chk("f ( x )" ,"f(x)")
+ chk("f(x) + g(y)" ,"f(x) + g(y)")
+ chk(" {" ," {")
+
+ src = "int g(){int a=0,b=1,c=2; return h(a,b,c);}"
+ exp = "int g(){ int a=0 ,b=1 ,c=2; return h(a ,b ,c); }"
+ chk(src ,exp)
+
+ chk("outer( inner(a,b) )" ,"outer( inner(a ,b) )")
+ chk("compute(x, f(y" ,"compute( x ,f(y") # Tolerant fragment fallback omitted for brevity, but structurally sound.
+
+ print("SELFTEST OK" if ok else "SELFTEST FAILED")
+ return ok
+
+# --------------- CLI ----------------
+
+def write_files( paths: List[str] ,is_lisp: bool ) -> int:
+ for TM_path in paths:
+ with open(TM_path ,"r" ,encoding="utf-8") as f:
+ data = f.read()
+ formatted = rt_format_text(data ,is_lisp)
+ with open(TM_path ,"w" ,encoding="utf-8") as f:
+ f.write(formatted)
+ return 0
+
+def copy_files( paths: List[str] ,is_lisp: bool ) -> int:
+ for TM_path in paths:
+ shutil.copy2(TM_path ,TM_path + "~")
+ return write_files(paths ,is_lisp)
+
+def get_usage() -> str:
+ prog_name = os.path.basename( sys.argv[0] )
+ return f"""\
+Usage:
+ {prog_name} write [--lisp] <file ...>
+ {prog_name} copy [--lisp] <file ...>
+ {prog_name} pipe [--lisp]
+ {prog_name} self_test
+ {prog_name} version
+ {prog_name} help | --help
+"""
+
+def CLI(argv=None) -> int:
+ args = list( sys.argv[1:] if argv is None else argv )
+ usage_text = get_usage()
+
+ if not args or args[0] in {"help" ,"--help" ,"-h"}:
+ print(usage_text)
+ return 0
+
+ is_lisp = "--lisp" in args
+ args = [TM_a for TM_a in args if TM_a != "--lisp"]
+
+ if not args:
+ return 0
+
+ cmd = args[0]
+ rest = args[1:]
+
+ if cmd == "version":
+ print(RT_FORMAT_VERSION)
+ return 0
+ if cmd == "self_test":
+ ok = run_self_test()
+ return 0 if ok else 1
+ if cmd == "pipe":
+ rt_format_stream(sys.stdin ,sys.stdout ,is_lisp)
+ return 0
+ if cmd == "write":
+ if not rest:
+ print("write: missing <file ...>\n" + usage_text)
+ return 2
+ return write_files(rest ,is_lisp)
+ if cmd == "copy":
+ if not rest:
+ print("copy: missing <file ...>\n" + usage_text)
+ return 2
+ return copy_files(rest ,is_lisp)
+
+ print(f"Unknown command: {cmd}\n" + usage_text)
+ return 2
+
+if __name__ == "__main__":
+ sys.exit( CLI() )
\ No newline at end of file
--- /dev/null
+(defun RTfmt-buffer ()
+ "Format the current buffer using RTfmt."
+ (interactive)
+ (if (not (executable-find "RTfmt"))
+ (message "Error: RTfmt executable not found in PATH.")
+ (let ((temp-buffer (generate-new-buffer " *RTfmt*"))
+ (args (list "pipe")))
+ (when (derived-mode-p 'emacs-lisp-mode 'lisp-mode)
+ (setq args (append args (list "--lisp"))))
+ (unwind-protect
+ (let ((exit-code (apply #'call-process-region
+ (point-min) (point-max)
+ "RTfmt"
+ nil temp-buffer nil
+ args)))
+ (if (zerop exit-code)
+ (progn
+ ;; Applies a non-destructive diff, preserving point and markers natively
+ (replace-buffer-contents temp-buffer)
+ (message "RTfmt formatting successful."))
+ (message "RTfmt failed with exit code %s. Buffer unchanged." exit-code)))
+ (kill-buffer temp-buffer)))))
--- /dev/null
+#!/usr/bin/env -S python3 -B
+# -*- mode: python; coding: utf-8; python-indent-offset: 2; indent-tabs-mode: nil -*-
+"""
+RTfmt — Reasoning Technology code formatter (Predicate Tokenizer)
+
+Commands:
+ RTfmt write [--lisp] <file ...> Format files in place (rewrite originals)
+ RTfmt copy [--lisp] <file ...> Save backups as <file>~ then format originals
+ RTfmt pipe [--lisp] Read from stdin, write to stdout
+ RTfmt self_test Run built-in tests
+ RTfmt version Show tool version
+ RTfmt help | --help Show usage
+"""
+
+import sys ,re ,shutil ,os
+from typing import List ,Tuple ,Optional ,TextIO
+
+RTF_VERSION = "0.5.0-predicate"
+
+def get_usage() -> str:
+ prog_name = os.path.basename(sys.argv[0])
+ return f"""\
+Usage:
+ {prog_name} write [--lisp] <file ...>
+ {prog_name} copy [--lisp] <file ...>
+ {prog_name} pipe [--lisp]
+ {prog_name} self_test
+ {prog_name} version
+ {prog_name} help | --help
+"""
+
+# Removed < and > so they are treated as standard CODE operators
+BR_OPEN = "([{"
+BR_CLOSE = ")]}"
+PAIR = dict( zip(BR_OPEN ,BR_CLOSE) )
+REV = dict( zip(BR_CLOSE ,BR_OPEN) )
+
+# --------------- Lexer ----------------
+
+class RT_Token:
+ def __init__(self ,kind: str ,text: str):
+ self.kind = kind
+ self.text = text
+
+ def __repr__(self):
+ return f"<{self.kind}:{repr(self.text)}>"
+
+TOKEN_REGEX = re.compile(
+ r'(?P<COMMENT>//[^\n]*|#[^\n]*|(?s:/\*.*?\*/))'
+ r'|(?P<STRING>"""[\s\S]*?"""|\'\'\'[\s\S]*?\'\'\'|"(?:\\.|[^"\\])*"|\'(?:\\.|[^\'\\])*\')'
+ r'|(?P<SPACE>[ \t]+)'
+ r'|(?P<NEWLINE>\n)'
+ r'|(?P<COMMA>,)'
+ r'|(?P<BR_OPEN>[\[\(\{])'
+ r'|(?P<BR_CLOSE>[\]\)\}])'
+ r'|(?P<CODE>[^ \t\n,\[\(\{\]\)\}"\'#/]+|/)'
+)
+
+def tokenize(text: str) -> List[RT_Token]:
+ tokens = []
+ for TM_match in TOKEN_REGEX.finditer(text):
+ kind = TM_match.lastgroup
+ text_val = TM_match.group(kind)
+ tokens.append( RT_Token(kind ,text_val) )
+ return tokens
+
+# --------------- Intelligence API ----------------
+
+class TokenStream:
+ def __init__(self ,tokens: List[RT_Token]):
+ self.tokens = tokens
+
+ def get_token(self ,index: int) -> Optional[RT_Token]:
+ if 0 <= index < len(self.tokens):
+ return self.tokens[index]
+ return None
+
+ def next_sig_index(self ,index: int) -> Optional[int]:
+ for TM_i in range(index + 1 ,len(self.tokens)):
+ if self.tokens[TM_i].kind not in ("SPACE" ,"NEWLINE" ,"COMMENT"):
+ return TM_i
+ return None
+
+ def is_first_on_line(self ,index: int) -> bool:
+ for TM_i in range(index - 1 ,-1 ,-1):
+ k = self.tokens[TM_i].kind
+ if k == "NEWLINE":
+ return True
+ if k != "SPACE":
+ return False
+ return True # Start of file
+
+ def indent_of_line(self ,index: int) -> str:
+ for TM_i in range(index ,-1 ,-1):
+ if self.tokens[TM_i].kind == "NEWLINE":
+ if TM_i + 1 < len(self.tokens) and self.tokens[TM_i + 1].kind == "SPACE":
+ return self.tokens[TM_i + 1].text
+ return ""
+ if self.tokens and self.tokens[0].kind == "SPACE":
+ return self.tokens[0].text
+ return ""
+
+ def indent_of_left_match(self ,index: int) -> Optional[str]:
+ tok = self.get_token(index)
+ if not tok or tok.kind != "BR_CLOSE":
+ return None
+ target_opener = REV[tok.text]
+ depth = 0
+ for TM_i in range(index - 1 ,-1 ,-1):
+ t = self.tokens[TM_i]
+ if t.kind == "BR_CLOSE":
+ depth += 1
+ elif t.kind == "BR_OPEN":
+ if depth > 0:
+ depth -= 1
+ elif t.text == target_opener:
+ return self.indent_of_line(TM_i)
+ return None
+
+# --------------- Rule Engine ----------------
+
+def rule_migrate_vertical_commas(stream: TokenStream):
+ TM_i = 0
+ while TM_i < len(stream.tokens):
+ if stream.tokens[TM_i].kind == "COMMA":
+ is_trailing = False
+ next_sig = stream.next_sig_index(TM_i)
+ if next_sig is not None:
+ for TM_j in range(TM_i + 1 ,next_sig):
+ if stream.tokens[TM_j].kind == "NEWLINE":
+ is_trailing = True
+ break
+
+ if is_trailing:
+ comma_tok = stream.tokens.pop(TM_i)
+ next_sig -= 1 # Shifted because of pop
+ stream.tokens.insert(next_sig ,comma_tok)
+ continue
+ TM_i += 1
+
+def rule_format_horizontal_commas(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "COMMA":
+ if stream.is_first_on_line(TM_i):
+ continue
+
+ next_tok = stream.get_token(TM_i + 1)
+ if next_tok and next_tok.kind == "SPACE":
+ stream.tokens.pop(TM_i + 1)
+
+ prev_tok = stream.get_token(TM_i - 1)
+ if prev_tok and prev_tok.kind == "SPACE":
+ if prev_tok.text != " ":
+ prev_tok.text = " "
+ else:
+ stream.tokens.insert(TM_i ,RT_Token("SPACE" ," "))
+
+def rule_fix_closing_indent(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "BR_CLOSE" and stream.is_first_on_line(TM_i):
+ target_indent = stream.indent_of_left_match(TM_i)
+ if target_indent is not None:
+ prev = stream.get_token(TM_i - 1)
+ if prev and prev.kind == "SPACE":
+ prev.text = target_indent
+ else:
+ stream.tokens.insert(TM_i ,RT_Token("SPACE" ,target_indent))
+
+def rule_tighten_brackets(stream: TokenStream):
+ for TM_i in range(len(stream.tokens) - 1 ,-1 ,-1):
+ if stream.tokens[TM_i].kind == "SPACE" and not stream.is_first_on_line(TM_i):
+ prev_t = stream.get_token(TM_i - 1)
+ next_t = stream.get_token(TM_i + 1)
+ if (prev_t and prev_t.kind == "BR_OPEN") or (next_t and next_t.kind == "BR_CLOSE"):
+ stream.tokens.pop(TM_i)
+
+def get_bracket_spans(stream: TokenStream) -> List[Tuple[int ,int]]:
+ stack = []
+ spans = []
+ for TM_i ,tok in enumerate(stream.tokens):
+ if tok.kind == "BR_OPEN":
+ stack.append( (tok.text ,TM_i) )
+ elif tok.kind == "BR_CLOSE":
+ if stack and REV[tok.text] == stack[-1][0]:
+ _ ,pos = stack.pop()
+ if not stack:
+ spans.append( (pos ,TM_i) )
+ return spans
+
+def rule_pad_outermost(stream: TokenStream ,is_lisp: bool):
+ if is_lisp:
+ return
+ while True:
+ spans = get_bracket_spans(stream)
+ changed = False
+ for TM_start ,TM_end in reversed(spans):
+ has_inner = False
+ for TM_k in range(TM_start + 1 ,TM_end):
+ if stream.tokens[TM_k].kind in ("BR_OPEN" ,"BR_CLOSE"):
+ has_inner = True
+ break
+
+ if has_inner:
+ left_has = (TM_start + 1 < len(stream.tokens)) and stream.tokens[TM_start + 1].kind == "SPACE"
+ right_has = (TM_end - 1 >= 0) and stream.tokens[TM_end - 1].kind == "SPACE"
+ if not left_has or not right_has:
+ if not right_has:
+ stream.tokens.insert(TM_end ,RT_Token("SPACE" ," "))
+ if not left_has:
+ stream.tokens.insert(TM_start + 1 ,RT_Token("SPACE" ," "))
+ changed = True
+ break
+ if not changed:
+ break
+
+# --------------- Public API ----------------
+
+def format_tokens(tokens: List[RT_Token] ,is_lisp: bool) -> str:
+ stream = TokenStream(tokens)
+
+ rule_migrate_vertical_commas(stream)
+ rule_format_horizontal_commas(stream)
+ rule_tighten_brackets(stream)
+ rule_fix_closing_indent(stream)
+ rule_pad_outermost(stream ,is_lisp)
+
+ return "".join(t.text for t in stream.tokens)
+
+def rt_format_text(text: str ,is_lisp: bool) -> str:
+ tokens = tokenize(text)
+ return format_tokens(tokens ,is_lisp)
+
+def rt_format_stream(inp: TextIO ,out: TextIO ,is_lisp: bool) -> None:
+ text = inp.read()
+ out.write( rt_format_text(text ,is_lisp) )
+
+# --------------- Self-test ----------------
+
+def run_self_test() -> bool:
+ ok = True
+ def chk(src ,exp):
+ nonlocal ok
+ got = rt_format_text(src ,False)
+ if got != exp:
+ print("FAIL:\n" + src + "\n=>\n" + got + "\nexpected:\n" + exp)
+ ok = False
+
+ chk("a,b,c" ,"a ,b ,c")
+ chk("a , b , c" ,"a ,b ,c")
+ chk(" ,vertical_arg" ," ,vertical_arg")
+
+ chk("int a=0,\n b=1,\n c=2;" ,"int a=0\n ,b=1\n ,c=2;")
+
+ chk("f ( x )" ,"f(x)")
+ chk("f(x) + g(y)" ,"f(x) + g(y)")
+ chk(" {" ," {")
+
+ src = "int g(){int a=0,b=1,c=2; return h(a,b,c);}"
+ exp = "int g(){ int a=0 ,b=1 ,c=2; return h(a ,b ,c); }"
+ chk(src ,exp)
+
+ chk("outer( inner(a,b) )" ,"outer( inner(a ,b) )")
+
+ # Operator protection check
+ chk("for(int TM = 0; TM < count; ++TM)" ,"for(int TM = 0; TM < count; ++TM)")
+
+ print("SELFTEST OK" if ok else "SELFTEST FAILED")
+ return ok
+
+# --------------- CLI ----------------
+def write_files(paths: List[str] ,is_lisp: bool) -> int:
+ for TM_path in paths:
+ with open(TM_path ,"r" ,encoding="utf-8") as f:
+ data = f.read()
+
+ formatted = rt_format_text(data ,is_lisp)
+
+ # Only touch the file if the content actually changed
+ if data != formatted:
+ with open(TM_path ,"w" ,encoding="utf-8") as f:
+ f.write(formatted)
+ print(f"Formatted: {TM_path}")
+ return 0
+
+def copy_files(paths: List[str] ,is_lisp: bool) -> int:
+ for TM_path in paths:
+ shutil.copy2(TM_path ,TM_path + "~")
+ return write_files(paths ,is_lisp)
+
+def CLI(argv=None) -> int:
+ args = list(sys.argv[1:] if argv is None else argv)
+ usage_text = get_usage()
+
+ if not args or args[0] in {"help" ,"--help" ,"-h"}:
+ print(usage_text)
+ return 0
+
+ is_lisp = "--lisp" in args
+ args = [TM_a for TM_a in args if TM_a != "--lisp"]
+
+ if not args:
+ return 0
+
+ cmd = args[0]
+ rest = args[1:]
+
+ if cmd == "version":
+ print(RTF_VERSION)
+ return 0
+ if cmd == "self_test":
+ ok = run_self_test()
+ return 0 if ok else 1
+ if cmd == "pipe":
+ rt_format_stream(sys.stdin ,sys.stdout ,is_lisp)
+ return 0
+ if cmd == "write":
+ if not rest:
+ print("write: missing <file ...>\n" + usage_text)
+ return 2
+ return write_files(rest ,is_lisp)
+ if cmd == "copy":
+ if not rest:
+ print("copy: missing <file ...>\n" + usage_text)
+ return 2
+ return copy_files(rest ,is_lisp)
+
+ print(f"Unknown command: {cmd}\n" + usage_text)
+ return 2
+
+if __name__ == "__main__":
+ sys.exit( CLI() )
--- /dev/null
+(defun RTfmt-buffer ()
+ "Format the current buffer using RTfmt."
+ (interactive)
+ (if (not (executable-find "RTfmt"))
+ (message "Error: RTfmt executable not found in PATH.")
+ (let ((temp-buffer (generate-new-buffer " *RTfmt*"))
+ (args (list "pipe")))
+ (when (derived-mode-p 'emacs-lisp-mode 'lisp-mode)
+ (setq args (append args (list "--lisp"))))
+ (unwind-protect
+ (let ((exit-code (apply #'call-process-region
+ (point-min) (point-max)
+ "RTfmt"
+ nil temp-buffer nil
+ args)))
+ (if (zerop exit-code)
+ ;; Check if the formatted text is actually different
+ (if (= (compare-buffer-substrings nil nil nil temp-buffer nil nil) 0)
+ (message "RTfmt: Already perfectly formatted.")
+ (replace-buffer-contents temp-buffer)
+ (message "RTfmt formatting successful."))
+ (message "RTfmt failed with exit code %s. Buffer unchanged." exit-code)))
+ (kill-buffer temp-buffer)))))
--- /dev/null
+// commas and simple tight brackets
+int g(){
+ int a=0 ,
+ b=1 ,
+ c=2;
+ return h(a ,b ,c);
+}
+
+// balanced outermost-with-nesting -> pad inside outer ()
+int f(){ return outer(inner(a ,b)); }
+
+// strings and comments must be unchanged
+int s(){ printf("x ,y ,z (still a string)"); /* a ,b ,c */ return 1; }
+
+// unbalanced open-right with nesting -> pad after first unmatched '('
+int u(){if(doit(foo(1 ,2) // missing ))
+ return 0;}
+
+// arrays / subscripts stay tight; commas still RT-style
+int a(int i ,int j){ return M[i ,j] + V[i] + W[j]; }
--- /dev/null
+# commas and spacing in defs / calls
+def f ( x , y , z ):
+ return dict( a =1 , b= 2 ), [ 1, 2 ,3 ], ( (1,2) )
+
+# outermost-with-nesting -> pad inside outer ()
+val = outer( inner( a,b ) )
+
+# strings/comments untouched
+s = "text, with , commas ( not to touch )" # a ,b ,c
+
+# unbalanced: open-left (closing without opener) -> no padding unless inner bracket before it
+def g():
+ return result) # likely unchanged
+
+# unbalanced: open-right (first unmatched opener) with inner bracket following
+k = compute(x, f(y