npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

h2lang

v0.5.4

Published

H2 Language - A Herbert Online Judge compatible programming language with multi-agent support

Downloads

735

Readme

H2 Language

CI License: MIT Rust WebAssembly Crates.io Documentation

H2 Language (h2lang) is a programming language compiler fully compatible with the Herbert Online Judge (HOJ) H language specification, extended with multi-agent support for robot swarm control.

Features

  • HOJ Compatible - Full support for Herbert Online Judge syntax including macros, functions, and recursion
  • Multi-Agent Support - Control multiple robots simultaneously with parallel scheduling
  • WebAssembly Ready - Runs in browsers via wasm-bindgen
  • Zero Dependencies Runtime - Lightweight compiled output
  • Type-Safe - Written in Rust with comprehensive error handling
  • Well Documented - Extensive documentation following Rust API guidelines

Quick Start

# Single robot drawing a square
0: f(X):XXXX f(sssr)

# Two robots moving in parallel
0: srl
1: lrs

# Recursive pattern with numeric argument
0: a(X):sra(X-1) a(4)

Installation

From crates.io (Rust)

cargo add h2lang

From npm (WebAssembly)

npm install h2lang

From Source

# Clone the repository
git clone https://github.com/ekusiadadus/h2lang.git
cd h2lang

# Build WebAssembly package
wasm-pack build --target web --out-dir pkg

# Or build native library
cargo build --release

# Run tests
cargo test

Requirements

  • Rust 1.70+
  • wasm-pack (for WebAssembly builds)
  • Node.js 16+ (for npm usage)

Language Specification

Basic Commands

| Command | Description | Action | |---------|-------------|--------| | s | Straight | Move forward one step | | r | Right | Rotate 90° clockwise | | l | Left | Rotate 90° counter-clockwise |

Agent Definition

Each line defines commands for a specific robot (agent):

agent_id: commands

# Examples
0: srl        # Agent 0: straight, right, left
1: llss       # Agent 1: left, left, straight, straight

Macros

Define reusable command sequences with single lowercase letters:

# Syntax: name:body
x:ss          # Define macro 'x' as 'ss'
xrx           # Expands to: ssrss

# Full example
0: x:sssr xrxrxrx   # Square pattern using macro

Functions

Functions support parameters (uppercase letters) and recursion:

# Syntax: name(PARAMS):body
f(X):XXX f(s)           # Repeats argument 3 times → sss
f(X):XXXX f(sssr)       # Square pattern → sssrsssrsssrsssr

# Multiple parameters
a(X,Y):Ya(X-1,Y) a(4,s) # Repeat 's' four times → ssss

# Numeric arguments with recursion
a(X):sra(X-1) a(4)      # Spiral pattern (terminates when X ≤ 0)

Numeric Expressions

Functions support numeric arguments and arithmetic:

a(X):sa(X-1) a(4)       # X decrements: 4→3→2→1→0(stop)
a(X):sa(X+1) a(-2)      # X increments: -2→-1→0(stop)

Termination Rule: When a numeric argument is ≤ 0, the function returns empty (recursion stops).

Comments

# This is a comment
0: srl  # Inline comment
// C-style comments also work

Implementation Notes

Whitespace Handling

  • Agent ID: Agent IDs must appear at the start of a line. Leading spaces/tabs before the agent ID are permitted and treated as line-start context.
  • Function/Macro Definitions: No whitespace is allowed between the identifier and ( in function definitions (e.g., f(X):... is valid, f (X):... is not).
  • Spaces: Spaces and tabs between tokens are generally ignored except where they affect line-start detection.

Recursion and Termination

  • Maximum Recursion Depth: The expander has a maximum recursion depth of 100 to prevent stack overflow from deeply nested macro/function calls. Exceeding this limit results in an expansion error.
  • Numeric Termination: When any numeric argument becomes ≤ 0, the function call returns an empty sequence (no commands). This applies to all numeric parameters in the function.
  • Expansion Limit: There is no explicit limit on the total number of expanded commands, but deeply recursive patterns may hit the depth limit first.

Error Handling

Compilation errors include:

  • Line and column information for precise error location
  • Expected vs. found tokens for parse errors
  • Undefined macro/function references
  • Maximum recursion depth exceeded

Examples

Drawing Shapes

# Square (4 sides)
0: f(X):XXXX f(sssr)

# Triangle (3 sides)
0: f(X):XXX f(ssssrr)

# Spiral
0: a(X):sra(X-1) a(8)

Multi-Robot Choreography

# Two robots moving in mirror pattern
0: srlsrl
1: slrslr

# Three robots with different patterns
0: f(X):XXXX f(sr)
1: f(X):XXXX f(sl)
2: ssssssss

Complex Recursion

# Nested function calls
0: f(X):XX f(f(s))      # f(s)=ss, f(ss)=ssss → 4 commands

# Parameterized repetition
0: a(X,Y):Ya(X-1,Y) a(3,sr)  # srsrsr (repeat 'sr' 3 times)

API Reference

Rust (Native)

use h2lang::compile_native;
use h2lang::output::CompileResult;

let result = compile_native("0: srl\n1: lrs");

match result {
    CompileResult::Success { program } => {
        println!("Agents: {}", program.agents.len());
        println!("Max steps: {}", program.max_steps);
        for entry in &program.timeline {
            println!("Step {}: {:?}", entry.step, entry.agent_commands);
        }
    }
    CompileResult::Error { errors } => {
        for err in errors {
            eprintln!("Error at {}:{}: {}", err.line, err.column, err.message);
        }
    }
}

JavaScript/TypeScript (WebAssembly)

import init, { compile, validate, version } from 'h2lang';

await init();

// Compile source code
const result = compile('0: srl');
if (result.status === 'success') {
  console.log(result.program.timeline);  // Parallel execution timeline
  console.log(result.program.agents);    // Per-agent command lists
}

// Validate without compiling
const validation = validate('0: srl');
console.log(validation.valid);  // true or false

// Get compiler version
console.log(version());  // "0.1.0"

Output Format

The compiler produces a JSON structure:

{
  "status": "success",
  "program": {
    "agents": [
      {
        "id": 0,
        "commands": [
          {"type": "straight", "steps": 1},
          {"type": "rotate_right", "angle": 90},
          {"type": "rotate_left", "angle": -90}
        ]
      }
    ],
    "max_steps": 3,
    "timeline": [
      {
        "step": 0,
        "agent_commands": [
          {"agent_id": 0, "command": {"type": "straight", "steps": 1}}
        ]
      }
    ]
  }
}

Building from Source

WebAssembly Build

# Install wasm-pack if not already installed
cargo install wasm-pack

# Build for web
npm run build
# or
wasm-pack build --target web --out-dir pkg

# Build for Node.js
wasm-pack build --target nodejs --out-dir pkg

Native Build

# Debug build
cargo build

# Release build
cargo build --release

# Run tests
cargo test

# Generate documentation
cargo doc --no-deps --open

Testing

# Run all tests (241 tests)
cargo test

# Run tests with output
cargo test -- --nocapture

# Run specific test module
cargo test basic_commands

# WebAssembly tests (requires Chrome)
wasm-pack test --headless --chrome

Project Structure

h2lang/
├── .github/
│   ├── workflows/
│   │   └── ci.yml              # CI pipeline (fmt, clippy, test, wasm)
│   ├── ISSUE_TEMPLATE/         # Issue templates
│   └── PULL_REQUEST_TEMPLATE.md
├── src/
│   ├── lib.rs          # Main entry point, WASM bindings
│   ├── lexer.rs        # Tokenizer
│   ├── parser.rs       # Recursive descent parser
│   ├── ast.rs          # Abstract Syntax Tree definitions
│   ├── expander.rs     # Macro/function expansion
│   ├── scheduler.rs    # Multi-agent parallel scheduling
│   ├── output.rs       # JSON output structures
│   ├── token.rs        # Token definitions
│   └── error.rs        # Error types
├── tests/
│   └── h_language_compatibility.rs  # 145 HOJ compatibility tests
├── Cargo.toml          # Rust dependencies
├── package.json        # npm configuration
├── rust-toolchain.toml # Rust toolchain configuration
├── CONTRIBUTING.md     # Contribution guidelines
├── CODE_OF_CONDUCT.md  # Community guidelines (Contributor Covenant)
├── CHANGELOG.md        # Version history
└── LICENSE             # MIT License

Architecture

Source Code → Lexer → Parser → AST → Expander → Scheduler → Output
     ↓          ↓        ↓       ↓        ↓          ↓         ↓
   "0:srl"   Tokens   Parse   Tree   Commands   Timeline    JSON
                      Tree          (expanded)  (parallel)

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

Quick Contribution Guide

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for new functionality
  4. Ensure all tests pass (cargo test)
  5. Format code (cargo fmt)
  6. Run linter (cargo clippy)
  7. Commit with clear messages following Conventional Commits
  8. Open a Pull Request

Development Commands

# Format code
cargo fmt

# Run linter
cargo clippy -- -D warnings

# Run all checks before PR
cargo fmt --check && cargo clippy -- -D warnings && cargo test

Community

License

This project is licensed under the MIT License - see the LICENSE file for details.

Related Links

Acknowledgments

  • Herbert Online Judge by @quolc
  • Microsoft ImagineCup for the original Herbert game concept
  • The Rust community for excellent tooling