nondescript: a simple embedded programming language
Summary
Nondescript is a new single-file, embeddable scripting language for C projects, offering AppleScript-style syntax and features like list comprehensions and extensible grammar.
View Cached Full Text
Cached at: 04/22/26, 09:06 PM
deadpixi/nondescript
Source: https://github.com/deadpixi/nondescript
Nondescript
A simple, embeddable scripting language for C applications. Nondescript occupies a space similar to Lua: a small, single-file implementation that can be compiled into any C project with minimal fuss.
Features
- Single-file implementation — one
.cand one.h, no dependencies beyond the C standard library - C11 compatible (really C99 +
_Alignof) - AppleScript-style syntax — natural-language-inspired, case-insensitive
- Extensible grammar — register host commands with custom keyword patterns
- Chunk accessors —
word 1 of myString,item 3 of myList, etc. You can register your own chunk types at runtime givenblocks — pass a block of code to a function- List comprehensions -
set nonSpaces to every character of myString where it != ' ' - Pluggable allocators — pool and limit allocators included
Building
Nondescript is designed to be compiled directly into your project:
#include "nondescript.h"
cc -o myapp myapp.c nondescript.c -lm
Quick Start
#include <stdio.h>
#include "nondescript.h"
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "usage: nds <script.nds>\n");
return 1;
}
NDSConfig config = {0};
NDSContext *ctx = NDSContext_new(&config);
NDSStatus status = NDSContext_evaluateFile(ctx, argv[1]);
if (status != NDSStatus_OK)
fprintf(stderr, "%s\n", NDSContext_getError(ctx));
NDSContext_free(ctx);
return status == NDSStatus_OK ? 0 : 1;
}
-- Functions
function greet(name)
println("hello, ", name, "!")
end function
greet("world")
-- Chunks and set expressions.
set firstItem to item 1 of ["foo", "bar", "baz"]
println("firstItem:", firstItem)
-- List comprehensions.
set nonSpaces to every character of "foo bar baz" where it != ' '
println("nonSpaces:", nonSpaces)
-- Blocks.
function map(input)
my result is []
for each item i in input do
append given(i) to result
end for
return result
end function
set plus2 to map([1, 2, 3]) given (i)
return i + 2
end given
println("plus2:", plus2)
-- Block scope. Set will set the innermost binding of that variable.
-- Use "my" to claim an inner binding for yourself. All structures
-- introduce new scope.
function functionScope()
my outer is "outer"
if true then
my outer
set outer to "inner now!"
println("inside if block:", outer)
end if
println("outside if block:", outer)
end function
functionScope()
-- Error handling is per-function.
function errorFunction()
my NaN is 1 / 0
on error myError
println("errored:", myError)
end function
errorFunction()
-- Errors bubble up
function innerError()
raise nothing message "foo"
end function
function outerError()
innerError()
on error myError
println("got error with message", message of myError)
end function
outerError()
Examples
See the examples/ directory:
- calc — Defines functions in script, calls them from C via
NDSContext_callFunction - turtle — Registers natural-language host commands (
move forward 100,turn right 90), runs a script, and writes SVG output
Build an example:
cd examples
c11 -o turtle turtle.c ../nondescript.c
./turtle
License
Apache 2.0
TODO
- The whole bifurcation of bytes/characters is weird…should probably just make separate types.
- Tons of little fixes and cleanups. NDSValue/NDSObject split is ugly…
Similar Articles
Show HN: Nibble
Nibble is a C-like systems programming language implemented in 3000 lines of C that generates LLVM IR without external dependencies or heap allocations. It supports defer, recursion, various types, structs, pointers, and includes graphical demos.
Nanopass Framework: Clean Compiler Creation Language
Nanopass Framework is a domain-specific language embedded in Scheme for creating compilers through small passes and intermediate representations, reducing boilerplate and improving maintainability.
7 lines of code, 3 minutes: Implement a programming language (2010)
This article presents a minimalist 7-line interpreter for a Turing-equivalent functional language based on lambda calculus, demonstrating the eval/apply design pattern.
Making your own programming language is easier than you think (but also harder)
The author shares their experience building a custom programming language for a game modding system, discussing design motivations and technical challenges. The post serves as a reflection on the feasibility and complexity of implementing a non-toy language for personal projects.
New Agent-Oriented Markdown Object Language called MOL
MOL (Markdown Object Language) is a new formal specification for parsing markdown-based config and data files designed to be more human and LLM-friendly than JSON.