MOGWAI 8.5.0
dotnet add package MOGWAI --version 8.5.0
NuGet\Install-Package MOGWAI -Version 8.5.0
<PackageReference Include="MOGWAI" Version="8.5.0" />
<PackageVersion Include="MOGWAI" Version="8.5.0" />
<PackageReference Include="MOGWAI" />
paket add MOGWAI --version 8.5.0
#r "nuget: MOGWAI, 8.5.0"
#:package MOGWAI@8.5.0
#addin nuget:?package=MOGWAI&version=8.5.0
#tool nuget:?package=MOGWAI&version=8.5.0
MOGWAI - Modern RPN Scripting Language
A powerful stack-based RPN (Reverse Polish Notation) scripting language for industrial IoT automation, embedded systems, and creative programming.
10 years of development | 200+ built-in functions | Industrial-grade | Open Source (Apache 2.0)
Quick Start
Installation
dotnet add package MOGWAI
Hello World
using MOGWAI.Engine;
using MOGWAI.Interfaces;
// Create the engine
var engine = new MogwaiEngine("MyApp");
engine.Delegate = this; // Your class implementing IDelegate
// Execute a script
var result = await engine.RunAsync(@"
console.clear
'Hello from MOGWAI!' ?
2 3 + ?
", debugMode: false);
if (result.IsError)
{
Console.WriteLine($"Error: {result}");
}
Note: This creates a folder structure in Documents/MOGWAI/ for scripts and data files.
Key Features
- Stack-Based RPN Syntax - Inspired by HP calculators (HP 28S, HP 48)
- 200+ Built-in Functions - Math, strings, lists, dates, HTTP, file I/O, and more
- Async/Await Support - Modern asynchronous execution
- IoT & BLE Functions - Bluetooth Low Energy, serial communication
- Industrial Automation - Designed for embedded systems and real-time control
- Extensible - Add your own custom functions easily
- Cross-Platform - Runs on Windows, Linux, macOS (.NET 9.0+)
- Thread-Safe - Built-in task management
- MOGWAI STUDIO Integration - Visual debugging with breakpoints
MOGWAI Language Overview
Stack-Based Programming
MOGWAI uses Reverse Polish Notation where operators follow operands:
# Traditional: (2 + 3) * 4
# MOGWAI:
2 3 + 4 *
# Result: 20
Variables
# Store values
42 -> 'answer'
"Hello" -> 'greeting'
# Use variables
answer 2 / ? # Prints: 21
greeting " World" + ? # Prints: Hello World
Functions
# Define a function
to 'square' with [n: .number] do
{
n n *
}
# Use it
5 square ? # Prints: 25
Lists
# Create a list
(1 2 3 4 5) -> 'numbers'
# Map function
numbers foreach 'n' do { n 2 * } -> 'doubled'
doubled ? # Prints: (2 4 6 8 10)
Records
# Create a record
[name: "MOGWAI", version: 8.0, author: "Stéphane Sibué"] -> 'info'
# Access fields
info->name ? # Prints: MOGWAI
info->version ? # Prints: 8.0
Conditional Logic
# If-then-else
if (x 10 >) then
{
"Greater than 10" ?
}
else
{
"Less or equal to 10" ?
}
Integration in Your .NET Application
1. Implement IDelegate
Your host application must implement the IDelegate interface:
using MOGWAI.Engine;
using MOGWAI.Interfaces;
using MOGWAI.Objects;
using System.Net;
public class MyApp : IDelegate
{
private MogwaiEngine _engine;
public MyApp()
{
_engine = new MogwaiEngine("MyApp");
_engine.Delegate = this;
}
// Called when a script starts
public async Task ProgramStart(MogwaiEngine engine, string code)
{
Console.WriteLine("Script starting...");
await Task.CompletedTask;
}
// Called when a script ends
public async Task ProgramEnd(MogwaiEngine engine, EvalResult result)
{
Console.WriteLine($"Script ended: {result}");
await Task.CompletedTask;
}
// MOGWAI's ? or console.printLn function
public async Task<EvalResult> ConsolePrintLn(MogwaiEngine engine, string message)
{
Console.WriteLine(message);
await Task.CompletedTask;
return EvalResult.NoError;
}
// MOGWAI's ?? or console.print function
public async Task<EvalResult> ConsolePrint(MogwaiEngine engine, string message)
{
Console.Write(message);
await Task.CompletedTask;
return EvalResult.NoError;
}
// Clear console
public async Task<EvalResult> ConsoleClearScreen(MogwaiEngine engine)
{
Console.Clear();
await Task.CompletedTask;
return EvalResult.NoError;
}
// Input from user
public async Task<(EvalResult result, string? value)> Prompt(
MogwaiEngine engine, string message)
{
Console.Write(message);
string? input = Console.ReadLine();
return (EvalResult.NoError, input);
}
// Advanced console methods (minimal implementation)
public async Task<EvalResult> ConsoleShow(MogwaiEngine engine) => EvalResult.NoError;
public async Task<EvalResult> ConsoleHide(MogwaiEngine engine) => EvalResult.NoError;
public async Task<EvalResult> ConsoleLocate(MogwaiEngine engine, int x, int y)
{
Console.SetCursorPosition(x, y);
return EvalResult.NoError;
}
public async Task<(EvalResult result, int x, int y)> ConsoleGetCursorPosition(MogwaiEngine engine)
=> (EvalResult.NoError, Console.CursorLeft, Console.CursorTop);
public async Task<EvalResult> ConsoleSetForegroundColor(MogwaiEngine engine, string color)
{
if (Enum.TryParse<ConsoleColor>(color, true, out var cc))
Console.ForegroundColor = cc;
return EvalResult.NoError;
}
public async Task<EvalResult> ConsoleSetBackgroundColor(MogwaiEngine engine, string color)
{
if (Enum.TryParse<ConsoleColor>(color, true, out var cc))
Console.BackgroundColor = cc;
return EvalResult.NoError;
}
public async Task<(EvalResult result, int key)> ConsoleGetInputKey(MogwaiEngine engine)
{
var k = Console.ReadKey(true);
return (EvalResult.NoError, (int)k.Key);
}
// List custom functions provided by your app
public string[] HostFunctions(MogwaiEngine engine)
{
return new[] { "myCustomFunction" };
}
// Execute custom functions
public async Task<EvalResult> ExecuteHostFunction(MogwaiEngine engine, string word)
{
if (word == "myCustomFunction")
{
Console.WriteLine("Custom function called!");
return EvalResult.NoError;
}
return EvalResult.NoExternalFunction;
}
// Runtime messages
public async Task<EvalResult> MessageReceivedFromRuntime(
MogwaiEngine engine, string message, MOGObject parameter)
=> EvalResult.NoError;
// Debug output
public async Task<EvalResult> DebugMessage(MogwaiEngine engine, string message)
=> EvalResult.NoError;
public async Task<EvalResult> DebugClear(MogwaiEngine engine)
=> EvalResult.NoError;
// Engine state
public async Task<EvalResult> EngineDidPause(MogwaiEngine engine)
=> EvalResult.NoError;
public async Task<EvalResult> EngineDidResume(MogwaiEngine engine)
=> EvalResult.NoError;
// STUDIO connection
public async Task<EvalResult> StudioDidConnect(MogwaiEngine engine)
=> EvalResult.NoError;
public async Task<EvalResult> StudioDidDisconnect(MogwaiEngine engine)
=> EvalResult.NoError;
public async Task<EvalResult> SocketServerDidStart(
MogwaiEngine engine, IPAddress address, int port)
=> EvalResult.NoError;
public async Task<EvalResult> SocketServerDidStop(MogwaiEngine engine)
=> EvalResult.NoError;
}
2. Add Custom Functions
Extend MOGWAI with your own functions by manipulating the stack:
public async Task<EvalResult> ExecuteHostFunction(MogwaiEngine engine, string word)
{
switch (word)
{
case "double":
// Check stack signature
var sig = engine.StackSign(1);
if (sig.Count == 0)
return EvalResult.Failure(engine, Error.TooFewArgumentsError, word);
if (sig[0] != typeof(MOGNumber))
return EvalResult.Failure(engine, Error.BadArgumentTypeError, word);
// Pop value, double it, push back
var num = engine.StackPopNumber();
engine.StackPush(new MOGNumber(num.Value * 2));
return EvalResult.NoError;
case "greet":
// Push a string to the stack
engine.StackPush(new MOGString("Hello from custom function!"));
return EvalResult.NoError;
}
return EvalResult.NoExternalFunction;
}
In MOGWAI script:
5 double ? # Prints: 10
greet ? # Prints: Hello from custom function!
Constructor Options
Basic Usage (Default)
var engine = new MogwaiEngine("MyApp");
Default settings:
keepAlive: false- Engine resets state between executionsuseDefaultFolders: true- CreatesDocuments/MOGWAI/folder structure
Best for: Getting started, tutorials, standalone applications
Embedded Applications
var engine = new MogwaiEngine("MyApp", useDefaultFolders: false);
Settings:
keepAlive: false- Clean state each executionuseDefaultFolders: false- No folder creation, use custom paths
Best for: WinForms, MAUI, backend services with embedded scripts
CLI / REPL Applications
var engine = new MogwaiEngine("MOGWAI CLI", keepAlive: true, useDefaultFolders: true);
// Global variables persist between executions
await engine.RunAsync("42 -> '$X'", debugMode: false);
await engine.RunAsync("$X 2 * ?", debugMode: false); // Prints: 84
Settings:
keepAlive: true- Variables persist between callsuseDefaultFolders: true- Use Documents/MOGWAI/ structure
Best for: Interactive scripting, REPL, CLI tools
Full Control
var engine = new MogwaiEngine(
name: "MyApp",
keepAlive: true, // State persists
useDefaultFolders: false // Custom file management
);
Default Folder Structure
When useDefaultFolders: true, MOGWAI creates:
Documents/
└── MOGWAI/
├── Programs/ ← User scripts (.mog files)
├── Files/ ← Data files
└── Usings/ ← Shared modules
Access these paths:
string programsPath = engine.ProgramsDirectory;
string filesPath = engine.FilesDirectory;
string usingsPath = engine.UsingsDirectory;
MOGWAI STUDIO Integration
Enabling Remote Debugging
Connect your runtime to MOGWAI STUDIO for visual debugging:
var engine = new MogwaiEngine("MyApp");
engine.Delegate = this;
// Start network server for STUDIO
await engine.StartNetworkCommunication();
// Keep running while STUDIO is connected
while (true)
{
await Task.Delay(250);
}
MOGWAI CLI Studio Mode
In MOGWAI CLI, type studio to enable STUDIO connection:
MOGWAI > studio
Starting network communication on port 1968...
Waiting for MOGWAI STUDIO connection...
Discovery Protocol
STUDIO uses UDP broadcast (port 1968) to discover runtimes:
STUDIO sends:
{"Source": "MOGWAI STUDIO", "Function": "WHO IS HERE"}
Runtime responds:
{
"Source": "MOGWAI RUNTIME",
"Function": "I AM HERE",
"Parameters": ["MyApp", "63542", "8.0.0", "Windows", ...]
}
TCP debug connection established on auto-assigned port (63000-65000).
Features in STUDIO
Once connected, STUDIO provides:
- Visual breakpoints
- Step-by-step execution (step over, step into, step out)
- Variable inspection
- Stack visualization
- Expression evaluation
Network Ports
- UDP Discovery: Port 1968 (default, configurable)
- TCP Debug: Port 63000-65000 (auto-assigned)
Custom Configuration
// Listen on specific address and port
await engine.StartNetworkCommunication(address: "127.0.0.1", port: 1968);
Security
Important: The STUDIO connection allows full script control. Only enable on trusted networks (localhost, private LAN).
Use Cases
Industrial IoT Automation
# Read sensor via BLE
"AA:BB:CC:DD:EE:FF" ble.connect -> 'device'
device "temperature" ble.read -> 'temp'
# Control based on value
if (temp 25 >) then
{
"fan" gpio.on
"Temperature too high: {temp}°C" eval ?
}
HTTP API Calls
# GET request
[http.get uri: "https://api.example.com/data"] -> 'response'
if (response->state) then
{
response->response json.parse -> 'data'
data->items size "Found {!} items" eval ?
}
Advanced Features
Asynchronous Execution
// Run script asynchronously
var result = await engine.RunAsync(script, debugMode: false);
// Multiple scripts concurrently
var task1 = engine.RunAsync(script1, debugMode: false);
var task2 = engine.RunAsync(script2, debugMode: false);
await Task.WhenAll(task1, task2);
Halt Execution
// Stop a running script (Ctrl+C handler)
Console.CancelKeyPress += (sender, e) =>
{
engine.Halt();
e.Cancel = true;
};
Stack Manipulation
// Check what's on the stack
var signature = engine.StackSign(3); // Get types of top 3 items
// Pop values
var number = engine.StackPopNumber();
var text = engine.StackPopString();
var list = engine.StackPopList();
var record = engine.StackPopRecord();
// Push values
engine.StackPush(new MOGNumber(42));
engine.StackPush(new MOGString("Hello"));
engine.StackPush(new MOGBoolean(true));
Error Handling
var result = await engine.RunAsync(script, debugMode: false);
if (result.IsError)
{
Console.WriteLine($"Error: {result.Error.Code}");
Console.WriteLine($"Message: {result.Error.Message}");
Console.WriteLine($"Position: {result.StartErrorPosition}-{result.EndErrorPosition}");
}
Why MOGWAI?
Born from Real Needs
MOGWAI was created to simulate Bluetooth Low Energy devices for IoT testing. Over 10 years, it evolved into a full-featured scripting language used in industrial automation and embedded systems.
Inspired by HP Calculators
The syntax is inspired by the legendary HP 28S and HP 48 calculators, bringing the elegance of RPN to modern software development.
Battle-Tested
- 3 years in production in industrial environments
- Real-world IoT applications (astronomical clocks, public lighting)
- Thousands of scripts executed in field deployments
Unique Features
- Stack-based with modern conveniences (variables, functions, records)
- RPN syntax for clarity and consistency
- IoT-focused with BLE, HTTP, serial communication built-in
- Extensible - easily add domain-specific functions
Documentation
Complete Guides
- Integration Guide - How to integrate MOGWAI in your .NET application
- Language Reference - Complete MOGWAI language guide
- Function Reference - All 200+ built-in functions documented
Examples
- WinForms Example - Turtle graphics and more with MOGWAI
- Console Example - Console integration (MOGWAI CLI source code)
- IoT Example - .NET MAUI program example
What's Included
- MOGWAI.dll - The complete runtime (.NET 9.0+)
- 200+ Functions - Math, strings, lists, I/O, HTTP, BLE, dates, and more
- Type System - Numbers, strings, booleans, lists, records, data, code
- Async Support - Modern task-based execution
- Thread-Safe - Built-in concurrency management
- STUDIO Protocol - Network debugging support
Support & Community
- GitHub: https://github.com/Sydney680928/mogwai
- Issues: https://github.com/Sydney680928/mogwai/issues
- Website: MOGWAI
- Author: Stéphane Sibué
License
Apache License 2.0
MOGWAI is free and open source software. See LICENSE for details.
Copyright 2015-2026 Stéphane Sibué
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Get Started Now
dotnet add package MOGWAI
Happy scripting with MOGWAI! 🎉
MOGWAI - Where stack-based elegance meets modern .NET power ✨
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
MOGWAI 8.5.0
ADDED
- foreach...filter loop: filters elements of a list by applying a predicate block to each element. Only elements for which the block returns true are collected into a new list pushed onto the stack.
Example: (1 2 3 4 5 6 7 8 9 10) foreach 'i' filter { i 5 >= i 8 <= and } # Returns (5 6 7 8)
- bag primitive: pushes onto the stack the container (record or list) of the currently executing block or function, enabling prototype-based programming. Returns null if there is no container (top-level context).
Endianness conversion — integers:
- ->dataLE8/16/24/32/48/64 and ->dataBE8/16/24/32/48/64: convert a number to DATA in Little or Big Endian byte order (fixed size).
- dataLE8/16/24/32/48/64-> and dataBE8/16/24/32/48/64->: convert DATA to a number in Little or Big Endian byte order (fixed size).
- ->dataLE and ->dataBE: dynamic-size variants (number + size in bits -> DATA).
- dataLE-> and dataBE->: dynamic-size variants (DATA + size in bits -> number).
- LongValue property added to MOGNumber for 64-bit integer access.
Supported sizes: 8, 16, 24, 32, 48, 64 bits. Overflow is silently truncated.
Endianness conversion — floats:
- ->dataLE32F / ->dataBE32F: convert a number to DATA as IEEE 754 single-precision float (4 bytes).
- ->dataLE64F / ->dataBE64F: convert a number to DATA as IEEE 754 double-precision float (8 bytes).
- dataLE32F-> / dataBE32F->: convert DATA to a number as IEEE 754 single-precision float.
- dataLE64F-> / dataBE64F->: convert DATA to a number as IEEE 754 double-precision float.
Typed integer conversion:
- ->i8, ->i16, ->i32, ->i64: bidirectional conversion between number and DATA as signed integers (Little Endian).
- ->u8, ->u16, ->u32, ->u64: same for unsigned integers.
Bit testing:
- bit?: returns true if the bit at the specified position of a binary object (B:) is set. Position is zero-based from the rightmost bit.
New error:
- ConvertError (MW.32): raised when a type conversion fails.
CHANGED
- Renamed using to mogwai.using and usings to mogwai.usings for consistency with the mogwai.* namespace convention.
FIXED
- Fixed incorrect byte order in ->i16, ->i32, ->i64, ->u16, ->u32, ->u64. These primitives were producing Big Endian output instead of Little Endian. Now uses BinaryPrimitives.WriteInt*/WriteUInt*LittleEndian explicitly, ensuring correct and portable behavior.
Full changelog: https://github.com/Sydney680928/mogwai/blob/main/CHANGELOG.md