module volt.semantic.nested

Code Map

module volt.semantic.nested;


//! This module contains utility functions for dealing with nested
//! functions; 'functions within functions'.
fn nestExtyperTagVariable(loc: const(Location), ctx: Context, var: ir.Variable, store: ir.Store) { }
//! Add a child function to the list of nested functions in a parent
//! function.
fn nestExtyperFunction(parent: ir.Function, func: ir.Function) { }
//! Add the context struct to a nested function.
fn nestLowererFunction(lp: LanguagePass, parent: ir.Function, func: ir.Function) { }
//! Replace nested Variable declarations with assign expressions.
fn insertBinOpAssignsForNestedVariableAssigns(lp: LanguagePass, bs: ir.BlockStatement) { }
//! If the current function is a nested one, replace a given ExpReference
//! with an expression that will retrieve the correct value from the nested
//! struct.
fn replaceNested(lp: LanguagePass, exp: ir.Exp, eref: ir.ExpReference, currentFunction: ir.Function) bool { }
fn nestExtyperTagVariable(loc: const(Location), ctx: Context, var: ir.Variable, store: ir.Store)

This module contains utility functions for dealing with nested functions; 'functions within functions'.

LLVM (and most other potential backend tooling) generates in top level functions. That means, when the user writes:

int getX() {
    int x = 32;
    void doubleX() { x *= 2; }
    return x;
}

A fair amount of magic has to take place to create a shared context that contains x, give it to doubleX, and rewrite every reference appropriately so nothing explodes, and everything works as expected. That's what the functions in this module help with.

Not that nested functions preceded by 'global', i.e. ir.Function.Kind.GlobalNested, are not 'truly' nested -- the above rewriting doesn't take place, and trying to access something in the parent function will generate an error.

Tag referenced Variables as nested if appropriate.

If an identifier references a Variable, and that variables parent scope is higher than the current -- that is to say, the reference is in a nested function -- then that Variable's storage will be tagged as Nested. Otherwise, nothing happens.

Params: loc: If an error is generated, this location will be what it points at. ctx: The extyper Context. var: The Variable that the reference refers to. store: The Store that var was found in.

fn nestExtyperFunction(parent: ir.Function, func: ir.Function)

Add a child function to the list of nested functions in a parent function.

Params: parent: The parent function. func: The child function.

fn nestLowererFunction(lp: LanguagePass, parent: ir.Function, func: ir.Function)

Add the context struct to a nested function.

Params: lp: The LanguagePass. parent: The parent function that the nested function resides in. func: The nested function to add the context struct to.

fn insertBinOpAssignsForNestedVariableAssigns(lp: LanguagePass, bs: ir.BlockStatement)

Replace nested Variable declarations with assign expressions.

Because all nested Variables will be transformed to exist on the nested struct, every declaration needs to be turned into an assignment, to ensure the values are what they should be.

Params: lp: The LanguagePass. bs: The BlockStatement to scan for Variables.

fn replaceNested(lp: LanguagePass, exp: ir.Exp, eref: ir.ExpReference, currentFunction: ir.Function) bool

If the current function is a nested one, replace a given ExpReference with an expression that will retrieve the correct value from the nested struct.

Params: lp: The LanguagePass. exp: The expression where the reference took place. May be rewritten. eref: The ExpReference to check. currentFunction: The current function when eref was found.

fn doParent(lp: LanguagePass, parent: ir.Function)

Utility function to be called on Functions with a function nested in them. Adds the struct, actualizes it, adds parameters, etc.

fn createAndAddNestedStruct(func: ir.Function) ir.Struct

Create the nested struct and a declaration pointing to it. Populates the nestedVariable and nestStruct members of a Function.

fn handleNestedParams(errSink: ErrorSink, func: ir.Function, bs: ir.BlockStatement)

Given a nested function func, add its parameters to the nested struct and insert statements after the nested declaration.

fn handleNestedThis(errSink: ErrorSink, func: ir.Function, bs: ir.BlockStatement)

Correct this references in nested functions.

Rewrites them to refer to a this hosted on the nested struct.