diff --git a/ir.py b/ir.py index 55d722e..cf7d2ba 100644 --- a/ir.py +++ b/ir.py @@ -116,10 +116,40 @@ class Function: def codegen_inner(self) -> str: return unwrap_r(self.eliminate(Variable('$'))).codegen() + def try_codegen_sp(self) -> Option[Tuple[str, str]]: + """ A special-case of codegen inner (see description) + + In certain cases, starting a function with a full match tree may be unnecessary. + Specifically, if there exists only one possible branch and that branch binds only + one value and that value is equal to the whole entire input, rather than assigning + that input to a new variable, we may simply use argument variable instead. + + This method returns the generated code for the inner branch in such a case. + Additionally, the second string returned represents the name of the variable which + ought to be bound as the argument. If the argument is unused, this will be "$". + """ + match self.forms: + case [(patt, expr)]: # A single possible branch + match patt.bindings(): + case []: # Binds nothing + return Some((expr.codegen(), '$')) + case [(var, [])]: # Binds a single variable to the entire input + return Some((expr.codegen(), var)) + return None def codegen(self) -> str: - return '$=>' + self.codegen_inner() + match self.try_codegen_sp(): + case Some((codegen, var)): + return f'{var}=>{codegen}' + case None: + return '$=>' + self.codegen_inner() + raise Exception('Unreachable') def codegen_named(self, name) -> str: - return f'function {name}($){{return {self.codegen_inner()}}}' + match self.try_codegen_sp(): + case Some((codegen, var)): + return f'function {name}({var}){{return {codegen}}}' + case None: + return f'function {name}($){{return {self.codegen_inner()}}}' + raise Exception('Unreachable') def __repr__(self) -> str: return '{ ' + ', '.join('"' + repr(repr(p))[1:-1] + '" : ' + repr(e) for (p, e) in self.forms) + ' }'