Welcome to Sprig 🌿 A Language Sprouting From NodeJS

Sprig is a dynamic programming language built on NodeJS that allows developers to write efficient and powerful code. It leverages the capabilities of NodeJS while providing its own syntax and useful extensions.

Key features

  • Bi-Directional Data Flow: Sprig enables seamless data exchange between NodeJS and the Sprig environment, making it easy to utilize existing NodeJS libraries and functions within your Sprig code.

  • Extensibility: Sprig is designed for easy extension, allowing developers to create native JS functionality on the fly to extend the language.

  • Integration with NodeJS: Sprig takes advantage of NodeJS’s non-blocking I/O and asynchronous programming model, providing a robust framework for building scalable applications.

A taste of Sprig

Basic example

Let's define a basic function greet that accepts a name and returns an interpolated string. We'll call that function multiple times to showcase the different ways functions can be called.

const greet = (name) => `Hey {{name}}, welcome to Sprig 🌿`

// We can chain functions through the -> operator
// Note how if a function accepts one argument, we don't need to add ()

"friend"->greet->print // Hey friend, welcome to Sprig 🌿

greet("pal")->print() // Hey pal, welcome to Sprig 🌿

print(greet("buddy")) // Hey buddy, welcome to Sprig 🌿

Leveraging NodeJS on the fly

Sprig allows you to utilise NodeJS functionality on the fly, making use of the powerhouse that is the V8 engine. Since bi-directional data flow is core to Sprig, we can define native JS functions and call them directly from our Sprig programs.

The arguments we pass to these functions are automatically transformed to raw JavaScript constructs, and the results we get back are automatically transformed to Sprig constructs.

Note that some constructs come back as Raw values. These values are essentially raw JS objects (think of them as pointers in a language like C). We can unwrap these Raw constructs through the built-in value function, or work with them as Raw constructs in such cases where we need to retain the same construct when interoperating between languages.

const nativeAdd = jsEval(`(a, b) => a + b`);

(100 + nativeAdd(20, 30))->print // 150

const rawBuffer = jsEval(`(size) => Buffer.alloc(size)`)
const buffer = rawBuffer(10)

print(buffer) // Buffer* Raw<object>

print(buffer->value) // { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, readBigUInt64LE: native: 'readBigUInt64LE' (offset = 0), readBigUInt64BE: native: 'readBigUInt64BE' (offset = 0) ... }

Jump right in

Last updated