πŸ“– Introduction to Nixi

Design Philosophy

Nixi is a hybrid programming language designed to bridge the gap between functional programming, system scripting, and modern web development. Inspired by Nix's pure functional approach, Bash's practical built-in utilities, and React.js's component-based UI paradigm, Nixi offers a unique blend of declarative syntax, imperative operations, and declarative styling.

Design Principles

  • Functional Core: Everything is an expression, with immutable data and pure functions as foundation. No side effects in core logicβ€”changes are explicit and predictable.
  • Practical Imperative Layer: Built-in functions for system interactions (file I/O, directory operations) allow seamless scripting without sacrificing purity.
  • Declarative UI: GUI components are defined declaratively, with CSS styling integrated directly into the language for a cohesive development experience.
  • Compilation to Web: Nixi programs compile to standalone HTML files, making them portable and runnable in any browser.

Key Principles

  • Immutability: Data structures are immutable by default, promoting safer, more predictable code.
  • Composition over Inheritance: Functions and components are composed rather than extended, leading to modular, reusable code.
  • Zero Dependencies: Compiled output is pure HTML/CSS/JS, requiring no runtime dependencies.
  • Developer Experience: Syntax highlighting, error messages, and editor support make development intuitive.

Execution Model

Nixi code is interpreted and compiled in two phases:

  1. Interpretation: The AST is evaluated, executing functions and building component trees.
  2. Compilation: The result is rendered to HTML with embedded CSS and JavaScript for interactivity.

To execute Nixi code:

  1. Ensure Node.js is installed.
  2. Clone Nixi repository: git clone https://github.com/ijadux2/nixi.git && cd nixi
  3. Install dependencies: npm install
  4. Run a .nixi file: node src/cli.js path/to/your/file.nixi
  5. The output will be an HTML file (e.g., if your code uses saveHTML, it generates the specified file).

Example: node src/cli.js examples/simple-gui.nixi will generate simple-gui.html, which you can open in a browser.

πŸ”§ Core Syntax

Let-In Expressions

Nixi's syntax is inspired by Nix, using let expressions for bindings and in to define scope.

Let-In Expressions

Bindings are defined in a let block and used in in expression:

let
  x = 5;
  y = x + 3;
in
  y  # Returns 8

Data Types

  • Strings: Double or single quotes: "hello" or 'world'. Concatenation with +.
  • Numbers: Integers/floats: 42, 3.14. Support arithmetic operators.
  • Booleans: true, false. Used in conditionals.
  • Lists: Arrays: [1, 2, 3]. Access with head, tail, length.
  • Records: Objects: { name: "Alice"; age: 30 }. Access with dot notation or destructuring.
  • Null: null for absence of value.

Operators

  • Arithmetic: +, -, *, /, %
  • Comparison: ==, !=, <, >, <=, >=
  • Logical: &&, ||, !
  • List: ++ for concatenation

Comments

Single-line comments start with #:

# This is a comment
let x = 10; in x

πŸ”§ Functions and Expressions

Function Definitions

Functions are first-class citizens, supporting currying, lambdas, and higher-order patterns.

Function Definitions

Curried functions:

let
  add = x: y: x + y;
  increment = add 1;  # Partially applied
in
  increment 5  # Returns 6

Lambda Expressions

Anonymous functions:

let
  square = x: x * x;
  numbers = [1, 2, 3];
  squares = map square numbers;
in
  squares  # [1, 4, 9]

Higher-Order Functions

Functions taking/returning functions:

let
  applyTwice = f: x: f (f x);
  double = x: x * 2;
in
  applyTwice double 3  # Returns 12

Pattern Matching and Records

Destructure records in parameters:

let
  greet = { name, age }: "Hello " + name + ", age " + toString(age) + " years old";
in
  greet { name: "Alice"; age: 25 }

Recursion

For loops and iteration:

let
  factorial = n: if n <= 1 then 1 else n * factorial (n - 1);
in
  factorial 5  # Returns 120

πŸ”§ Built-in Functions

System Operations

Nixi provides built-in functions for system operations, data manipulation, and utilities.

System Operations

  • ls(path): List directory contents.
  • cd(path): Change directory.
  • pwd(): Get current directory.
  • echo(str): Print to console.
  • readFile(path): Read file contents.
  • writeFile(path, content): Write to file.
  • fileExists(path): Check if file exists.

String Operations

  • toUpperCase(str): Convert to uppercase.
  • toLowerCase(str): Convert to lowercase.
  • length(str): String length.
  • substring(str, start, end): Extract substring.
  • indexOf(str, substr): Find substring position.

Mathematical Operations

  • add(a, b), subtract(a, b), multiply(a, b), divide(a, b)
  • sqrt(n): Square root.
  • pow(base, exp): Power.
  • abs(n): Absolute value.

List Operations

  • head(list): First element.
  • tail(list): All but first.
  • length(list): List length.
  • map(f, list): Apply function to each element.
  • filter(pred, list): Filter elements.
  • fold(f, init, list): Reduce list.

Conversion and Utilities

  • toString(val): Convert to string.
  • toNumber(str): Convert to number.
  • typeOf(val): Get type as string.

Example Usage

let
  files = ls(".");
  upperFiles = map toUpperCase files;
in
  echo ("Files: " + toString(upperFiles))

🎨 GUI and Styling

Component Declaration

Nixi supports declarative GUI components with integrated CSS styling.

Component Declaration

Components are HTML-like elements:

let
  Button = button {
    text: "Click Me";
    class: "btn";
    onClick: echo "Clicked!"
  };
in
  Button

Props and Children

Components accept properties and nested children:

let
  Card = { title, content }: div {
    class: "card";
    children: [
      h3 { text: title };
      p { text: content }
    ]
  };
in
  Card { title: "Hello"; content: "World" }

CSS Styling

Use style keyword for CSS:

style "btn" {
  background: "blue";
  color: "white";
  padding: "10px 20px";
  border-radius: "6px";
}

Event Handlers

Attach functions to events:

input {
  onChange: value: echo ("Input: " + value)
}

Composition Patterns

Build complex UIs by composing components:

let
  App = div {
    class: "app";
    children: [
      header { text: "App Header" };
      main { children: [Button; Card] }
    ]
  };
in
  saveHTML(App, "app.html", "My App")

πŸ”§ Control Flow and Error Handling

Conditional Expressions

Nixi uses expressions for control flow and Result types for errors.

Conditionals

let
  sign = n:
    if n > 0
    then "positive"
    else if n < 0
    then "negative"
    else "zero";
in
  sign -5  # "negative"

Error Handling with Results

let
  Result = { success, value, error };
  safeDivide = a: b:
    if b == 0
    then Result { success: false; error: "Division by zero" }
    else Result { success: true; error: null; value: a / b };
in
  safeDivide 10 0

Debugging

Use echo for logging:

let
  debug = msg: val:
    let
      _ = echo ("[DEBUG] " + msg + ": " + toString(val));
    in val;
in
  debug "Starting..." (1 + 2)

πŸ”§ Advanced Topics

Modules and Imports

Nixi supports importing other .nixi files (future feature; currently, compose in single files).

Performance Tips

  • Use tail recursion for large iterations.
  • Avoid deep nesting; compose functions.
  • Lazy evaluation for large data structures.

Integration with JavaScript

Compiled output includes JS for events; extend with custom scripts.

Best Practices
  • Immutability: Never mutate data; return new values.
  • Pure Functions: Functions should depend only on inputs.
  • Component Reusability: Parameterize components for flexibility.
  • Error Boundaries: Wrap risky operations in Result types.
  • Testing: Test functions with various inputs; use assertions.