added inline functions
This commit is contained in:
77
main.py
77
main.py
@@ -202,6 +202,7 @@ class Definition:
|
|||||||
immediate: bool = False
|
immediate: bool = False
|
||||||
compile_only: bool = False
|
compile_only: bool = False
|
||||||
terminator: str = "end"
|
terminator: str = "end"
|
||||||
|
inline: bool = False
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -305,6 +306,7 @@ class Word:
|
|||||||
extern_inputs: int = 0
|
extern_inputs: int = 0
|
||||||
extern_outputs: int = 0
|
extern_outputs: int = 0
|
||||||
extern_signature: Optional[Tuple[List[str], str]] = None # (arg_types, ret_type)
|
extern_signature: Optional[Tuple[List[str], str]] = None # (arg_types, ret_type)
|
||||||
|
inline: bool = False
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -813,6 +815,7 @@ class Parser:
|
|||||||
word = self.definition_stack.pop()
|
word = self.definition_stack.pop()
|
||||||
ctx.immediate = word.immediate
|
ctx.immediate = word.immediate
|
||||||
ctx.compile_only = word.compile_only
|
ctx.compile_only = word.compile_only
|
||||||
|
ctx.inline = word.inline
|
||||||
if word.compile_only or word.immediate:
|
if word.compile_only or word.immediate:
|
||||||
word.compile_time_override = True
|
word.compile_time_override = True
|
||||||
word.compile_time_intrinsic = None
|
word.compile_time_intrinsic = None
|
||||||
@@ -1566,6 +1569,8 @@ class Assembler:
|
|||||||
self._string_literals: Dict[str, Tuple[str, int]] = {}
|
self._string_literals: Dict[str, Tuple[str, int]] = {}
|
||||||
self._float_literals: Dict[float, str] = {}
|
self._float_literals: Dict[float, str] = {}
|
||||||
self._data_section: Optional[List[str]] = None
|
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]:
|
def _reachable_runtime_defs(self, runtime_defs: Sequence[Union[Definition, AsmDefinition]]) -> Set[str]:
|
||||||
edges: Dict[str, Set[str]] = {}
|
edges: Dict[str, Set[str]] = {}
|
||||||
@@ -1618,6 +1623,9 @@ class Assembler:
|
|||||||
if len(reachable) != len(runtime_defs):
|
if len(reachable) != len(runtime_defs):
|
||||||
runtime_defs = [defn for defn in runtime_defs if defn.name in reachable]
|
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:
|
for definition in runtime_defs:
|
||||||
self._emit_definition(definition, emission.text)
|
self._emit_definition(definition, emission.text)
|
||||||
|
|
||||||
@@ -1696,6 +1704,56 @@ class Assembler:
|
|||||||
raise CompileError("unknown definition type")
|
raise CompileError("unknown definition type")
|
||||||
builder.emit(" ret")
|
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:
|
def _emit_asm_body(self, definition: AsmDefinition, builder: FunctionEmitter) -> None:
|
||||||
body = definition.body.strip("\n")
|
body = definition.body.strip("\n")
|
||||||
if not body:
|
if not body:
|
||||||
@@ -1823,6 +1881,13 @@ class Assembler:
|
|||||||
raise CompileError(f"unknown word '{name}'")
|
raise CompileError(f"unknown word '{name}'")
|
||||||
if word.compile_only:
|
if word.compile_only:
|
||||||
raise CompileError(f"word '{name}' is compile-time 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:
|
if word.intrinsic:
|
||||||
word.intrinsic(builder)
|
word.intrinsic(builder)
|
||||||
return
|
return
|
||||||
@@ -2004,6 +2069,17 @@ def macro_compile_only(ctx: MacroContext) -> Optional[List[Op]]:
|
|||||||
return None
|
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]]:
|
def macro_compile_time(ctx: MacroContext) -> Optional[List[Op]]:
|
||||||
"""Run the next word at compile time and still emit it for runtime."""
|
"""Run the next word at compile time and still emit it for runtime."""
|
||||||
parser = ctx.parser
|
parser = ctx.parser
|
||||||
@@ -2787,6 +2863,7 @@ def bootstrap_dictionary() -> Dictionary:
|
|||||||
dictionary = Dictionary()
|
dictionary = Dictionary()
|
||||||
dictionary.register(Word(name="immediate", immediate=True, macro=macro_immediate))
|
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="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="compile-time", immediate=True, macro=macro_compile_time))
|
||||||
dictionary.register(Word(name="here", immediate=True, macro=macro_here))
|
dictionary.register(Word(name="here", immediate=True, macro=macro_here))
|
||||||
dictionary.register(Word(name="with", immediate=True, macro=macro_with))
|
dictionary.register(Word(name="with", immediate=True, macro=macro_with))
|
||||||
|
|||||||
1
tests/inline.expected
Normal file
1
tests/inline.expected
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hello
|
||||||
8
tests/inline.sl
Normal file
8
tests/inline.sl
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
word fn
|
||||||
|
"hello"
|
||||||
|
end
|
||||||
|
inline
|
||||||
|
|
||||||
|
word main
|
||||||
|
1 fn 3 1 syscall 0
|
||||||
|
end
|
||||||
1
tests/inline.test
Normal file
1
tests/inline.test
Normal file
@@ -0,0 +1 @@
|
|||||||
|
python main.py tests/inline.sl -o /tmp/inline > /dev/null && /tmp/inline
|
||||||
Reference in New Issue
Block a user