Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@helios-lang/ir

Package Overview
Dependencies
Maintainers
0
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@helios-lang/ir

Helios-lang intermediate representation

  • 0.1.47
  • Source
  • npm
  • Socket score

Version published
Maintainers
0
Created
Source

IR

Helios-lang Intermediate Representation (IR) library. This library takes care of:

  • Mutual recursion
  • Static analysis
  • Optimization
  • Detection of final dependencies
  • UPLC generation

The IR doesn't support operators.

Syntax

The Helios-lang IR is low-level human readable programming language with a very simple syntax:

__helios__value__contains_policy = (self) -> {
    (mph) -> {
        mph = __helios__mintingpolicyhash____to_data(mph);
        recurse = (map) -> {
            __core__chooseList(
                map,
                () -> {false},
                () -> {
                    __core__ifThenElse(
                        __core__equalsData(__core__fstPair(__core__headList__safe(map)), mph),
                        () -> {true},
                        () -> {recurse(__core__tailList__safe(map))}
                    )()
                }
            )()
        };
        recurse(self)
    }
};
...

The Helios-lang IR is stripped down version of the Helios language itself. Type annotations have been removed, assignments are only possible for single values. There are no const or func statements and everything is an expression.

Assignment

Assignment is syntactic sugar for a literal function passed as an arg to another literal function.

For example:

x = <expr-x>;
<expr-next>

Becomes:

(x) -> {
    <expr-next>
}(<expr-x>)

Many subsequent assignments look like:

(x) -> {
    (y) -> {
        (z) -> {
            <expr-nexts>
        }(<expr-z>)
    }(<expr-y>)
}(<expr-x>)

Mutual recursion

UPLC doesn't allow mutual recursion directly, so function definitions that appear after the expressions where they are being used must be injected.

For example:

a = b();

b = () -> {
    a
};

b()

Becomes:

a = (b) -> {
    b(b)()
};

b = (b) -> {
    () -> {
        a(b)
    }
};

b(b)()

Reshuffling to avoid mutual recursion should be done in a way that preserves the original order as much as possible. Once a set of mutually recursive expressions are detected they should be left in the same order. This is done because the compiler has no idea how frequently each function will be called.

How to detect a set of mutually dependent expressions

A graph is first created of all assigned expressions in a scope. The indirect dependencies are pushed until all nodes are aware of all dependencies. Then loop through the list of nodes in original order:

  • and node that depends on itself is (mutually) recursive
    • if any of the other dependencies don't depend on the same node, continue
    • if none of the other dependencies depend on the same node, collect all these nodes (assuring the same for each), and copy into the final list
  • if some of dependencies haven't been copied to the new list yet, continue
  • if all dependencies have been copied, copy the current node as well
Infinite loop handling

Will be detected during static analysis phase

Scopes

Although subsequent assignments form nested AST elements, they are treated as being part of the same scope. Scope boundaries are formed by function literals that aren't called immediately.

Optimizaton

Common sub-expression factorization

Common sub-expressions should be hoisted. For this to work each expression must have a unique key. Variable names must be unique in case of shadowing.

Expressions stringified in such a way form the keys mapping to those original expressions.

For example:

a = <common-expr>;

b = <common-expr>;

a + b

Becomes:

common = <common-expr>;

a = common;

b = common;

a + b

One of the difficulties is lifting of common sub-expressions:

fn_a = () -> {
    x = <common-expr>;
    ...
};

fn_b = () -> {
    y = <common-expr>;
    ...
};

fn_a() + fn_b()

This optimization algorithm must thus be aware of branches. Hence it makes sense to use information from the static analysis.

Keywords

FAQs

Package last updated on 03 Oct 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc