dragonstone v0.1.5-Alpha
What is Dragonstone?
Dragonstone is a general purpose, high-level, object-oriented programming language. It is both an interpreted and compiled language, it's inspired by Ruby and Crystal but designed for programmer happiness, productivity, and choice.
WARNING: Some compile targets are still a work in progress, as of
v0.1.5the LLVM backend has limited support, all examples, excluding the stdlibs are working fine. Please report any you find so they outside of that so they can be fixed. In regards to the other backends these still need built out as they only create temporary artifacts for minimal functions, I haven't merged that work yet. The priority right now is 100% llvm backend support.
| Information | Description |
| Implementation language | Current Version v5: Crystal, C |
| Platform | Supports: x86, x86_64, AArch64 |
| Operating System | Supports: Windows, Linux, MacOS |
| File Extension | .ds, .dragonstone |
| Influenced by | Ruby, Crystal, Python, Go, Nim, Rust |
| Website | dragonstone-lang.org |
โ๏ธ Project Setup
Requirements
- The Crystal needs to be installed (1.17.1+ but has been tested down to 1.11.2 on Ubuntu).
- (optional) LLVM/Clang; While Crystal also installs LLVM/Clang, installing a standalone version is recommended if you want to target
dragonstone build --target llvmordragonstone build --target c. - (optional) The Ruby is needed if you want to use
dragonstone build --target ruby(3.4.6+).
To Build from Source (All Platforms)
(MacOS/Linux/Windows)
- Clone this repository.
cdto the project directory.- Run
shards build --release
Tip: Always use the
--releaseflag for production builds as it significantly improves performance, without it a standard build is made and the dragonstone interpreter will run files roughly about 3-5x slower.
To Build from Source (Linux)
(Linux Recommended)
- Clone this repository.
cdto the project directory.- Run
./bin/dragonstone.sh --rebuild - (optional) Run
./bin/dragonstone.sh --installwhich adds.\binto your user PATH.- After running that command please restart your terminal, then you can use
dragonstonefrom anywhere.
- After running that command please restart your terminal, then you can use
(Linux Alternative)
- Run
shards build --releasefor a standard build and without PATH.
Tip for Linux Users: If you want to rebuild the project, after already doing so, you can use
./bin/dragonstone.sh --cleanwhich will remove the build files, then you can use./bin/dragonstone.sh --rebuildto build it again. For an automated version you can use./bin/dragonstone.sh --clean-rebuildwhich will clean first then rebuild for you.
To Build from Source (Windows)
(Windows Recommended)
- Clone this repository.
cdto the project directory.- Run
.\bin\dragonstone.bat --rebuild- This builds with the icons/resources and adds
.\binto your user PATH. - After running that command please restart your terminal, then you can use
dragonstonefrom anywhere.
- This builds with the icons/resources and adds
(Windows Alternative)
- Run
shards build --releasefor a standard build, without any icons/resources or PATH.
Tip for Windows Users: If you want to rebuild the project, after already doing so, you can use
.\bin\dragonstone.bat --cleanwhich will remove the build files, then you can use.\bin\dragonstone.bat --rebuildto build it again. For an automated version you can use.\bin\dragonstone.bat --clean-rebuildwhich will clean first then rebuild for you.
Tip for Windows Users: An installer is also available in the Releases section.
๐งช Usage
Run Files via Interpreter.
# On PATH:
dragonstone run examples/hello_world.ds
# Not on PATH:
./bin/dragonstone.exe run examples/hello_world.ds
Select a Backend to Use.
For now this is a temporary flag so I can verify some of my --backend build targets, this may change in the future when the self-host/bootstrap process begins.
# Select between native (interpreter) or core (compiler) backends.
dragonstone run --backend native examples/hello_world.ds
dragonstone run --backend core examples/hello_world.ds
# Without specifying it will automatically use the native (interpreter) or
# with auto it can choose the correct backend based on what is being ran
# within the file.
dragonstone run examples/hello_world.ds
dragonstone run --backend auto examples/hello_world.ds
# However, if you don't want to specify the flag every time you can just
# set it change it anytime, this works on the fly.
DRAGONSTONE_BACKEND=core dragonstone run examples/hello_world.ds
# Or export the flag once, to set it permanently for the CI:
export DRAGONSTONE_BACKEND=core
Build and Run Files via the Compiler with a target.
# Supported Target Flags: bytecode, llvm, c, crystal, and ruby
dragonstone build --target bytecode examples/hello_world.ds
# Build and immediately execute the produced artifacts.
dragonstone build-run --target bytecode examples/hello_world.ds
Run Test/Spec (still building out unit tests).
# To run the full spec/unit testing suite.
crystal spec
# Helper script that runs the spec for just a specific backend.
./scripts/backend_ci.sh spec --backend native
./scripts/backend_ci.sh spec --backend core
โจ Examples
Example of a sting output using echo:
echo "Hello World!"
Example of comments/block comments using # and #[ ]#:
# This is a Single Line Comment.
#[
This is a Multi-Line Comment.
]#
message = "Hello!" # Trailing Comment.
#[ Multi-Line Comment on same line. ]# numbers = 10 #[ Inside or outside. ]#
Some Examples:
Examples of a String.
# Using echo
name = "Ringo"
echo name
# OUTPUT: Ringo
# Using e!, for printing debug information.
name = "Jules"
e! name
# OUTPUT: name # -> "Jules"
# Using eecho, without a newline.
greet = "Hello, "
name = "Ringo!"
eecho greet
eecho name
# OUTPUT: Hello, Ringo!
# Using ee!, for printing debug information without a newline.
greet = "Hello, "
name = "Jules!"
ee! greet
ee! name
# OUTPUT: greet + name # -> "Hello, " + "Jules!"
In dragonstone you can optionally be very explicit. Using con for constants, var for variables, fix for block-scoped constants, and let for block-scoped variables.
con first = 20
var mul = 2
def example
fix second = 10
let div = first // second
echo first
echo second
echo div
echo first * mul
end
example
Example of a Module with con, an immutable constant, and :: for scope resolution for modules and . for classes. Dragonstone also supports both module and mod for user preference.
module Grades
con Score = 100
class Greeting
def greet
"Hello! I got a #{Grades::Score}%!"
end
end
end
echo Grades::Score
echo Grades::Greeting.greet
Example of a Class, dragonstone also support both class and cls for user preference.
class Person
happy = true
def greet
if happy
echo "Hello!"
end
end
end
person = Person.new
person.greet
Also Ascii and Unicode are supported.
class ๐ฅ
ใ = true
def ้
if ใ
echo "Hello!"
end
end
end
๐ฅ.้
Example of a def Method and String Interpolation, and supports both def and define.
def greet(name)
echo "Hello, #{name}!"
end
greet("Jules")
Example of fun, which is a first-class citizen and a function object that can be passed around. Dragonstone also supports both fun and function for preference.
# Store a function object in a variable.
add = fun(a, b)
return a + b
end
echo add.call(2, 3)
# Define a reusable function object.
fun shout(text)
return text + "!"
end
def print_one(word, fmt)
echo fmt.call(word)
end
print_one("Ringo", shout)
# And an advanced version, to pass an anonymous function inline.
def print_formatted(words, fmt)
words.each do |w|
echo fmt.call(w)
end
end
names = ["Ringo", "Peet", "Jules"]
print_formatted(
names, fun(text) do
return ">> " + text + " <<"
end
)
Example of a Abstract Class and Super, dragonstone supports both abstract and abs for preference.
abstract class Animal
def make_sound(sound)
echo "#{sound}"
end
end
class Dog < Animal
def make_sound(sound)
super(sound)
super("The sound a dog makes!")
end
end
dog = Dog.new
echo dog.make_sound("Woof!")
Two examples of a ternary and being nested.
age = 20
status = age >= 18 ? "Adult" : "Minor"
echo "Status: #{status}"
# Nested ternary
score = 85
grade = score > 90 ? "A" : (score > 80 ? "B" : "C")
echo "Grade: #{grade}"
Example of a Map literal with key -> value pairs.
ages = { "Jules" -> 32, "Ringo" -> 29, "Peet" -> 35 }
echo ages["Jules"]
ages["Ringo"] = 30
echo ages["Ringo"]
ages.each do |name, age|
echo "#{name} is #{age}"
end
e! ages.keys
e! ages.values
Example of enum.
enum Direction
North
East
South
West
end
Direction.each do |direction|
echo "Direction: #{direction}"
end
Some More Examples but with Optional Types:
Example of a String with types.
name: str = "Peet"
echo name
Example of some math/integers with types.
a: int = 10
b: int = 10
numbers = a + b
echo numbers
Two examples of a Class with types, one of which showing Unicode support again.
def ๐ฑ(name: str) -> str
echo "Hello, #{name}!"
end
๐ฑ("V")
With this example using a bit more complex features.
class Person
property name: str
def initialize(name: str)
self.name = name
end
def greet
echo "Hello, my name is #{self.name}"
end
end
person = Person.new("Jules")
person.greet
Examples of struct.
struct Point
property x: int
property y: int
def initialize(@x: int, @y: int)
end
end
point = Point.new(10, 20)
echo "x: #{point.x}, y: #{point.y}"
Example of a record, similar to struct but are are immutable data structures that automatically generate the struct, the constructor, and getters for those fields.
record Person
name: str
age: int
end
greet = Person.new("V", 30)
echo "Name: #{greet.name}, Age: #{greet.age}"
Examples of Type Casting/Switching.
def process(input)
case input
when input: str
echo "It is a string: #{input}"
when input: int
echo "It is a number: #{input}"
when input: bool
echo "It is a boolean"
else
echo "Unknown type"
end
end
process("Hello")
process(42)
process(true)
Example of using/importing other files with use.
From (./examples/use.ds)
use "./test_use"
echo add(magic, 8)
What's being grabbed from (./examples/test_use.ds).
magic = 42
def add(a, b)
a + b
end
Two examples of para, this is the Dragonstone version of what another languages calls a Proc.
For any {} used within Dragonstone, these can also be split between lines or placed on the same line.
greet = ->(name: str) {
"Hello, #{name}!"
}
echo greet.call("Jalyn")
Another bit more complex para.
square: para(int, int) = ->(x: int) { x * x }
echo square.call(6)
Examples the interop (some done but still a work in progress).
# Call puts from Ruby.
# This works too: ffi.call_ruby("puts", ["Hello from Ruby!"])
Invoke Ruby
with puts
as {
"Hello from Ruby!"
}
end
# Call puts from Crystal.
# This works too: ffi.call_crystal("puts", ["Hello from Crystal!"])
Invoke Crystal
with puts
as {
"Hello from Crystal!"
}
end
# Call printf from C.
# This works too: ffi.call_c("printf", ["Hello from C!"])
Invoke C
with printf
as {
"Hello from C!"
}
end
Imports via use are built out, so you can import a file, selectively import as well, and the same applies by importing through a url.
# Both by file and selectively using `from` with it.
use "./test_use"
use { divide } from "./raise"
# Any both by file and selectively via a url, I used `cdn.jsdelivr.net`
# because it was the only thing I could find that would grab the examples from GitHub.
use "https://cdn.jsdelivr.net/gh/vallereya/dragonstone@main/examples/unicode"
use { MyModule } from "https://cdn.jsdelivr.net/gh/vallereya/dragonstone@main/examples/resolution"
See the examples/ directory for more sample .ds files.
โก Benchmark Information
- Built with --release.
- Results are for this specific benchmark + machine; expect variance across CPUs/Operating Systems.
- "Nested" means an extra loop layer (measuring loop-overhead vs a single loop), not extra work.
- <2% overhead at scale.
- Near identical for loops vs single.
You can run these yourself from the ./scripts/benchmark directory.
1 Billion Nested Loop Iteration Benchmark (Interpreter)
Iterations: ~4.47M iterations/s
Per-iteration cost: ~223.71 ns
Actual Time: 223.71 s (~3.73 min)
1 Billion Nested Loop Iteration Benchmark (LLVM Compiler)
Iterations: ~811M iterations/s
Per-iteration cost: ~1.23 ns
LLVM Compiler Time: 1.2326 s
Results: ~182ร vs Interpreter
Comparison Context (Rough context, not direct comparable)
For 1 billion iterations of this benchmark (Interpreter):
Ruby v2.X.X = ~15-30 minutes (varies by version)
Python v3.X.X = ~5-15 minutes (varies by version)
-> Dragonstone = ~3.7 minutes
Lua = ~1-2 minutes
JavaScript = ~10-30 seconds (using V8)
For 1 billion iterations of this benchmark (Compiler/LLVM):
C = ~0.5-1.5 seconds
Rust = ~0.5-1.5 seconds
-> Dragonstone LLVM = ~1.23 seconds
GO = ~1-2 seconds
Java = ~2-5 seconds (using JIT)
PyPy = ~10-20 seconds (using JIT)
Node.js = ~10-30 seconds (using V8)
ยฉ 2025 Vallereya
dragonstone
- 4
- 1
- 0
- 0
- 0
- 4 days ago
- October 24, 2025
Apache License 2.0
Thu, 01 Jan 2026 06:54:52 GMT