added inline functions

This commit is contained in:
IgorCielniak
2026-01-09 11:01:24 +01:00
parent f2af252bc4
commit 8466664637
4 changed files with 87 additions and 0 deletions

77
main.py
View File

@@ -202,6 +202,7 @@ class Definition:
immediate: bool = False
compile_only: bool = False
terminator: str = "end"
inline: bool = False
@dataclass
@@ -305,6 +306,7 @@ class Word:
extern_inputs: int = 0
extern_outputs: int = 0
extern_signature: Optional[Tuple[List[str], str]] = None # (arg_types, ret_type)
inline: bool = False
@dataclass
@@ -813,6 +815,7 @@ class Parser:
word = self.definition_stack.pop()
ctx.immediate = word.immediate
ctx.compile_only = word.compile_only
ctx.inline = word.inline
if word.compile_only or word.immediate:
word.compile_time_override = True
word.compile_time_intrinsic = None
@@ -1566,6 +1569,8 @@ class Assembler:
self._string_literals: Dict[str, Tuple[str, int]] = {}
self._float_literals: Dict[float, str] = {}
self._data_section: Optional[List[str]] = None
self._inline_stack: List[str] = []
self._inline_counter: int = 0
def _reachable_runtime_defs(self, runtime_defs: Sequence[Union[Definition, AsmDefinition]]) -> Set[str]:
edges: Dict[str, Set[str]] = {}
@@ -1618,6 +1623,9 @@ class Assembler:
if len(reachable) != len(runtime_defs):
runtime_defs = [defn for defn in runtime_defs if defn.name in reachable]
# Inline-only definitions are expanded at call sites; skip emitting standalone labels.
runtime_defs = [defn for defn in runtime_defs if not getattr(defn, "inline", False)]
for definition in runtime_defs:
self._emit_definition(definition, emission.text)
@@ -1696,6 +1704,56 @@ class Assembler:
raise CompileError("unknown definition type")
builder.emit(" ret")
def _emit_inline_definition(self, word: Word, builder: FunctionEmitter) -> None:
definition = word.definition
if not isinstance(definition, Definition):
raise CompileError(f"inline word '{word.name}' requires a high-level definition")
suffix = self._inline_counter
self._inline_counter += 1
label_map: Dict[str, str] = {}
def remap(label: str) -> str:
if label not in label_map:
label_map[label] = f"{label}__inl{suffix}"
return label_map[label]
for node in definition.body:
kind = node.op
data = node.data
if kind == "label":
mapped = remap(str(data))
self._emit_node(Op(op="label", data=mapped), builder)
continue
if kind == "jump":
mapped = remap(str(data))
self._emit_node(Op(op="jump", data=mapped), builder)
continue
if kind == "branch_zero":
mapped = remap(str(data))
self._emit_node(Op(op="branch_zero", data=mapped), builder)
continue
if kind == "for_begin":
mapped = {
"loop": remap(data["loop"]),
"end": remap(data["end"]),
}
self._emit_node(Op(op="for_begin", data=mapped), builder)
continue
if kind == "for_end":
mapped = {
"loop": remap(data["loop"]),
"end": remap(data["end"]),
}
self._emit_node(Op(op="for_end", data=mapped), builder)
continue
if kind in ("list_begin", "list_end"):
mapped = remap(str(data))
self._emit_node(Op(op=kind, data=mapped), builder)
continue
self._emit_node(node, builder)
def _emit_asm_body(self, definition: AsmDefinition, builder: FunctionEmitter) -> None:
body = definition.body.strip("\n")
if not body:
@@ -1823,6 +1881,13 @@ class Assembler:
raise CompileError(f"unknown word '{name}'")
if word.compile_only:
raise CompileError(f"word '{name}' is compile-time only")
if getattr(word, "inline", False) and isinstance(word.definition, Definition):
if word.name in self._inline_stack:
raise CompileError(f"recursive inline expansion for '{word.name}'")
self._inline_stack.append(word.name)
self._emit_inline_definition(word, builder)
self._inline_stack.pop()
return
if word.intrinsic:
word.intrinsic(builder)
return
@@ -2004,6 +2069,17 @@ def macro_compile_only(ctx: MacroContext) -> Optional[List[Op]]:
return None
def macro_inline(ctx: MacroContext) -> Optional[List[Op]]:
parser = ctx.parser
word = parser.most_recent_definition()
if word is None:
raise ParseError("'inline' must follow a definition")
word.inline = True
if word.definition is not None:
word.definition.inline = True
return None
def macro_compile_time(ctx: MacroContext) -> Optional[List[Op]]:
"""Run the next word at compile time and still emit it for runtime."""
parser = ctx.parser
@@ -2787,6 +2863,7 @@ def bootstrap_dictionary() -> Dictionary:
dictionary = Dictionary()
dictionary.register(Word(name="immediate", immediate=True, macro=macro_immediate))
dictionary.register(Word(name="compile-only", immediate=True, macro=macro_compile_only))
dictionary.register(Word(name="inline", immediate=True, macro=macro_inline))
dictionary.register(Word(name="compile-time", immediate=True, macro=macro_compile_time))
dictionary.register(Word(name="here", immediate=True, macro=macro_here))
dictionary.register(Word(name="with", immediate=True, macro=macro_with))