A rusty dynamically typed scripting language

Overview

dyon

A rusty dynamically typed scripting language

Tutorial
Dyon-Interactive
Dyon Snippets
/r/dyon

Dyon script files end with .dyon.

To run Dyon script files from command line, type:

cargo install --example dyonrun dyon

Then, to run a script file you type:

dyonrun <file.dyon>

Editor-plugins

Dyon for Atom
Dyon for Vim
Dyon for Visual Studio Code

coding

List of features

Why the name Dyon?

Dyon is a hypothetical particle predicted by several grand unified theories in physics with both electrical and magnetic charge. See this Wikipedia article for more information.

The name Dyon fits because, just like the particle, there are things that are yet to be discovered about language design. However, this language was not born out of a grand new vision, but is the result of exploring and testing new ideas.

Motivation and goals

Sven Nilsen started this project in early 2016. The idea was to make a simple, but convenient scripting language that integrated well with Rust.

  • During the first week of coding, a way to do lifetime checking on function arguments was discovered
  • A different approach to code organization was explored by adding the ability to dynamically load modules
  • For nice error handling, added option, result and ? operator
  • To test the design of the language, created a demo for interactive coding
  • Mutability check to improve readability
  • Short For loop to improve readability and performance
  • Mathematical loops and Unicode symbols to improve readability
  • Go-like coroutines to add multi-thread support
  • 4D vectors with unpack and swizzle to make 2D and 3D programming easier
  • Html hex colors to make copying colors from image editors possible
  • Optional type system to help scaling a project
  • Ad-hoc types for extra type safety
  • Current objects to improve prototyping and tailored environments
  • Macros for easier embedding with Rust
  • Secrets to automatically derive meaning from mathematical loops
  • Closures that can be printed out, use current objects and grab from closure environment
  • Type safety for secrets, easy load/save of Dyon data
  • Link loop for easier and faster code generation and templates
  • In-types for easy cross thread communication

Main goals:

  • Integrate well with Rust
  • Flexible way of organizing code

Performance will be optimized for the cycle:

coding -> parsing -> running -> debugging -> coding

Sub goals:

  • Safety

Non-goals:

  • Rust equivalent performance
  • Replace Rust to build libraries
  • Interfacing with other languages than Rust

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions.

Comments
  • Make Hyper/HTTP support an optional feature

    Make Hyper/HTTP support an optional feature

    I would like to request you make Hyper/HTTP support an optional feature, as the language presents a good platform to use for a bunch of project ideas I have, but Hyper (thanks to OpenSSL), is difficult and unpredictable to build on Windows machines, and I think making it an optional feature would both allow for easy building on windows, and the ability to lock down a potential security hole in applications that don't need HTTP support, while also giving the developer the choice to use other HTTP libraries if they so wish (or even simply implement tighter controls on when/where HTTP is allowed).

    easy 
    opened by nicka101 9
  • Passing data between two functions called from rust

    Passing data between two functions called from rust

    I'm trying to use dyon as a scripting language for a fantasy console coded in rust. The console calls a init() function defined in the script, then for each frame a render() function is called. How can I pass a context from the init function to the render function ? Using current object doesn't work because render is not called directly by init itself but by the rust part. My idea was to return a context from the init function that the rust engine had to pass as parameter to the render function, but the type is unknown at compile time.

    opened by jice-nospam 5
  • Higher Order Operator Overloading

    Higher Order Operator Overloading

    Higher Order Operator Overloading (HOOO) is very important for higher order reasoning. For reference, see papers on path semantics notation https://github.com/advancedresearch/path_semantics/blob/master/sequences.md#notation

    By adding HOOO support to Dyon, it could open up a new functional programming paradigm. I suggest that HOOO should inline by default.

    Algebra With Closures

    The syntax for "algebra with closures":

    a := \(x: f64) = x + 1
    b := \(x: f64) = x + 2
    c := a + b
    

    This is the same as:

    a := \(x: f64) = x + 1
    b := \(x: f64) = x + 2
    c := \(x: f64) = {
        a := grab a
        b := grab b
        \a(x) + \b(x)
    }
    

    The above is inlined to this:

    a := \(x: f64) = x + 1
    b := \(x: f64) = x + 2
    c := \(x: f64) = (x + 1) + (x + 2)
    

    This is generalized for any binary and unary operator.

    draft discussion 
    opened by bvssvni 5
  • current object / dynamic scope

    current object / dynamic scope

    The 'current object' feature is interesting, I think it's the same as (or similar to) 'dynamic scope'? https://en.wikipedia.org/wiki/Scope_(computer_science)#Dynamic_scoping

    In lisp I think they have 'defvar ' for this;

    are there any differences, would you change the way you describe it?

    I think it's uncommon in modern languages because the shadowing is less predictable (its also hard to do efficiently), but having 'lexical scope' as the default and something else to make something dynamically scoped seems like the best of both worlds.

    The other suggestion I was going to make was to use a different syntax for it, because I remember the ~foo pointers rust used to have (not sure what though. maybe some keyword infront)

    discussion 
    opened by dobkeratops 5
  • Overhead of Secrets ?

    Overhead of Secrets ?

    Greetings,

    This is not a critical issue since said "overhead" is likely to be negligible, and Dyon is a scripting language anyway, so practical affordances are likely to matter most.

    The thing is, as a reader of the Dyon tutorial, I couldn't help but raise an eyebrow at the concept of "Secrets", for these reasons :

    • I'm hardly convinced by the use cases shown in the tutorial (i.e If I want to pair a bool with a string, I'd rather use a tuple or struct), but those demonstrated in #266 actually look cool and practical;
    • There has got to be some overhead, somewhere, if any bool or f64 is implicitly able to store extra info such as strings. Could it be that bools are actually 32-bit integers which point to string memory if they're not false ? (I don't actually think so, but it's the kind of question that comes to mind).

    IMO the tutorial could benefit from mentioning better, more concrete use cases for Secrets, and explaining how they're implemented under the hood.

    discussion 
    opened by yoanlcq 4
  • Any reason you can't publish the dyon theme for Atom on atom.io?

    Any reason you can't publish the dyon theme for Atom on atom.io?

    Atom has a default package management tool called apm. You can easily put the theme on Atom's official site (aka where it will not only get more downloads but will be easier for other users to receive updates from.) It's very easy to do: literally just go to the folder where it is downloaded, type apm login, and then apm publish patch (for bug fixes) and apm publish minor for minor releases.

    opened by qolop 4
  • Define some broad goals/use cases

    Define some broad goals/use cases

    Given it's place in the Piston project, I've been assuming that dynamo is intended to be used for game scripting. However, that's not explicitly mentioned anywhere and I don't want to spend time writing a proposal that turns out to be inappropriate for your vision of the language.

    If it is game scripting, what kind of level are you expecting it to be best at (keeping in mind that people will contort any language into any situation with enough effort)? Is it intended to be mainly used for large amounts of game logic, or for small bits of custom behaviour?

    I'd like to help with the language, but I don't really know anything about the language to do so.

    discussion 
    opened by Aatch 4
  • Redesign AST to use Vec<Expression>

    Redesign AST to use Vec

    ast::Expression is the most central node in the AST. Currently it uses a lot of Box. It might be that reserving some memory upfront and packing the nodes in a Vec will improve performance a bit.

    • [ ] Redesign to use usize and Vec<Expression>
    • [ ] Test performance before merging
    draft discussion 
    opened by bvssvni 4
  • Failure to build for openssl v0.9.24

    Failure to build for openssl v0.9.24

    I tried building dyonrun by making a new package, first running cargo new testdyon then pasting the code for dyonrun into main.rs and then in cargo.toml the only thing I have is

    [dependencies]
    dyon="0.43.0"
    

    When I run cargo run I then get the following

    Updating crates.io index
       Compiling maybe-uninit v2.0.0
       Compiling libc v0.2.65
       Compiling cc v1.0.47
       Compiling autocfg v0.1.7
       Compiling pkg-config v0.3.17
       Compiling log v0.4.8
       Compiling matches v0.1.8
       Compiling cfg-if v0.1.10
       Compiling version_check v0.1.5
       Compiling byteorder v1.3.2
       Compiling openssl v0.9.24
       Compiling httparse v1.3.4
       Compiling foreign-types-shared v0.1.1
       Compiling bitflags v0.9.1
       Compiling percent-encoding v1.0.1
       Compiling safemem v0.3.3
       Compiling lazy_static v1.4.0
       Compiling traitobject v0.1.0
       Compiling lazy_static v0.2.11
       Compiling language-tags v0.2.2
       Compiling rand_core v0.4.2
       Compiling typeable v0.1.2
       Compiling itoa v0.3.4
       Compiling dtoa v0.4.4
       Compiling antidote v1.0.0
       Compiling range v1.0.0
       Compiling serde v0.9.15
       Compiling piston-float v1.0.0
       Compiling read_color v1.0.0
       Compiling unicode-bidi v0.3.4
       Compiling foreign-types v0.3.2
       Compiling unicase v1.4.2
       Compiling num-traits v0.2.9
       Compiling rand_chacha v0.1.1
       Compiling rand_pcg v0.1.2
       Compiling rand v0.6.5
       Compiling rand_core v0.3.1
       Compiling rand_jitter v0.1.4
       Compiling read_token v1.0.0
       Compiling vecmath v1.0.0
       Compiling rand_hc v0.1.0
       Compiling rand_xorshift v0.1.1
       Compiling rand_isaac v0.1.1
       Compiling piston_meta v1.0.0
       Compiling smallvec v0.6.13
       Compiling log v0.3.9
       Compiling base64 v0.9.3
       Compiling num_cpus v1.11.1
       Compiling time v0.1.42
       Compiling rand_os v0.1.3
       Compiling mime v0.2.6
       Compiling unicode-normalization v0.1.9
       Compiling openssl-sys v0.9.52
       Compiling num-traits v0.1.43
       Compiling idna v0.1.5
    error: failed to run custom build command for `openssl v0.9.24`
    
    Caused by:
      process didn't exit successfully: `/home/ryan/Desktop/code/games/test-dyon/target/debug/build/openssl-fa018ab47555f4ee/build-script-build` (exit code: 101)
    --- stderr
    thread 'main' panicked at 'Unable to detect OpenSSL version', /home/ryan/.cargo/registry/src/github.com-1ecc6299db9ec823/openssl-0.9.24/build.rs:16:14
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
    
    warning: build failed, waiting for other jobs to finish...
    error: build failed
    

    I have seen a related error elsewhere on the internet so it may be useful that openssl version returns OpenSSL 1.1.1 11 Sep 2018

    opened by ryanswilson59 3
  • Simple refinement types

    Simple refinement types

    Dyon is a rusty dynamically typed scripting language.

    What are simple refinement types?

    A simple refinement type system is an "extra layer" of types in addition to the normal type signature of functions. This is used to catch more errors before runtime.

    The extra layer contains special knowledge about the function or alternative semantics from how the function is used.

    Dyon supports ad-hoc types which lets you write e.g. Unknown bool instead of just bool. Simple refinement types in Dyon works seamlessly ad-hoc types.

    For example, one can use this to type check many-valued boolean logic:

    use std as std
    
    fn flip() -> Unknown bool {return if random() < 0.5 {false} else {true}}
    fn tr() -> True bool {return true}
    fn fa() -> False bool {return false}
    
    // Override `!` operator.
    fn not(a: bool) -> bool {return std::not(a)}
        // Use simple refinement types to add extra type information.
        (True bool) -> False bool
        (False bool) -> True bool
        (Unknown bool) -> Unknown bool
    
    fn check_tr(_: True bool) {}
    
    fn main() {
        a := flip()
        check_tr(!a)
    }
    

    The ad-hoc type Unknown bool is constructed by a coin-flip. If you invert a coin-flip, you don't know whether it is true or false, so it is still Unknown bool.

    Dyon detects an error in the code above:

    Type mismatch (#100):
    Expected `True bool`, found `Unknown bool`
    17,14:     check_tr(!a)
    17,14:              ^
    

    In this example, I used simple refinement types to reason about nondeterministic behavior of many-valued boolean logic. Instead of writing code explicitly as many-valued boolean logic, one can use ad-hoc types to lift the many-value logic to type level.

    Design

    For design, see https://github.com/PistonDevelopers/dyon/issues/636

    This PR adds support for simple refinement types in Dyon. This allows e.g. binary operators to be type checked as external functions.

    • Moved all unary and binary operations from runtime to the standard library (see https://github.com/PistonDevelopers/dyon/issues/635)
    • Make std namespace for standard external functions (see https://github.com/PistonDevelopers/dyon/issues/639)
    • Added lots of tests for type refinement
    • Added support for ad-hoc variables in refinement types (see https://github.com/PistonDevelopers/dyon/issues/645)
    • Added support for lazy invariants (see https://github.com/PistonDevelopers/dyon/issues/640)
    • Added check__in_string_imports (type checker knowledge, see https://github.com/PistonDevelopers/dyon/issues/646)
    • Added lazy invariant for unwrap_or

    Improvements in performance

    There is a 4.4% improvement in performance on the n-body benchmark for n=100_000. This is a longer run that is tested manually and measures performance on typical game-logic workloads.

    opened by bvssvni 3
  • Higher Order Types and Parameters

    Higher Order Types and Parameters

    Related to https://github.com/PistonDevelopers/dyon/issues/610

    A Higher Order Type is written \-> T and accepts any type T or a closure returning T:

    fn foo(a: \-> f64, b: \-> f64) -> \-> f64 {
        return a + b
    }
    

    The \ type operator can be thought of as specifying an unknown type ("from something") defined at runtime when calling the function. The type checker reports an error if the "from something" type does not match each other for every argument.

    Examples

    A higher order line:

    line(a: \-> vec4, b: \-> vec4, t : \-> f64) = a + (b - a) * t
    

    A higher order quadratic bezier:

    qbez(a : \-> vec4, b: \-> vec4, c: \-> vec4, t: \-> f64) =
        line(line(a, b, t), line(b, c, t), t)
    
    draft discussion 
    opened by bvssvni 3
  • Sandbox Untrusted Code?

    Sandbox Untrusted Code?

    Hello! I'm a game developer and I'm considering using dyon in my current project. I was wondering if it has the ability to sandbox untrusted code, as I'd like to have user-created scripts running on clients, and it would obviously be an issue if those scripts could maliciously affect clients. Thank you in advance!

    opened by Aurailus 2
  • Global objects

    Global objects

    A global object is declared at module level with some fields:

    ~ foo { a: f64 }
    
    fn bar() foo {
        println(foo.a)
    }
    fn baz() mut foo {
        foo.a = 42
    }
    

    The global object is created automatically if it doesn't exist already. A global object outlives any other lifetime.

    The globals function returns a list of all global objects:

    fn main() {
        println(globals())
    }
    

    A global can be destroyed, but it will recreated when calling some function accessing it or using it:

    fn main() {
        foo() // Creates global object `foo_object`
        destroy("foo")
        foo() // Recreates global object `foo_object`
    }
    
    ~ foo_object {}
    fn foo() foo_object {}
    

    A global object can inherit from another global object:

    ~ rect { pos: [vec4], size: [vec4] }
    ~ button: rect { label: [str] }
    

    When a global object only contains arrays as members, one can use the for-in syntax:

    fn foo() mut button {
        for b in button {
             b.label = "click me!"
        }
    }
    

    Methods can be declared on global objects that can be used inside for-in syntax:

    ~ rect {
        pos: [vec4],
        size: [vec4],
        min() = pos
        max() = pos + size
    }
    
    fn foo() rect {
        for r in rect {
            println(r.max())
        }
    }
    

    Methods can also combine lists and scalar fields:

    ~ foo {
        a: f64,
        b: [f64],
        bar() = a + b
    }
    

    To insert a new item in a global object, one uses push syntax:

    ~ rect { pos: vec4, size: vec4 }
    
    fn main() {
        foo()
    }
    fn foo() mut rect {
        push rect { pos: (0, 0), size: (0, 0) }
    }
    

    The super function returns the inherited global object of a global object:

    fn super(global: str) -> opt[str] { ... }
    

    The methods function returns a list of methods and their types:

    fn methods(global: str) -> [{}] { ... }
    

    The glob function converts a global into an ordinary object (read-only):

    fn glob(global: str) -> opt[{}] { ... }
    
    draft discussion 
    opened by bvssvni 0
  • Pausing execution

    Pausing execution

    Is it possible in the Rust side to pause the Runtime execution? To have, for example, a function that delays execution without blocking any threads, returning context back to the original Rust caller?

    This would make for great use in game scripting when certain elements are known to have delays that can then, from the Rust end, be continued once time has expired without hogging any resources.

    In the example project, I've seen lots of normal flow functions:

    dyon_fn!{fn mouse_cursor_pos() -> Option<Vec4> {
        unsafe { Current::<Option<Event>>::new()
            .as_ref().expect(NO_EVENT).mouse_cursor_args().map(|pos| pos.into()) }
    }}
    

    However, what I'm after would be similar to a wait_for_keypress(x) function, where the Rust wrapper application handles the actual continuation once the key was pressed, without really blocking the cpu.

    opened by Velocity- 0
  • Dynamically overriding / reloading functions / modules

    Dynamically overriding / reloading functions / modules

    Would it be possible to somehow dynamically rewrite/replace a function or module at runtime, without having to write to a file explicitly? I can't find anything like that documented anywhere.

    My usecase would be to use this in something like a vim-style text-editor where you (even as the user) could re-write functions and add new behaviour to the application at runtime. For this, being able to actually freely override any module or even just function would be a massive addition to flexibility.

    opened by elkowar 2
Releases(v0.36)
  • v0.36(Jun 16, 2018)

    This version adds a way to communicate between threads in Dyon.

    The design is very simple: Any loaded function can be turned into a channel. A new thread can subscribe to input data sent to a function, without having to communicate any new information with the other threads. One thread can listen in on the conversation after other threads have started. This allows reloading diagnostic tools at run-time without ever stopping the whole program. It also functions as a log feature: All data that is sent to a function can be recorded and analyzed later, which makes debugging of multiple threads easier. This can also be used in single-thread applications. The in-type uses Rust's std::sync::mpsc::Receiver which can also be used by external Rust functions.

    • in-types e.g. x := in foo to receive inputs when any thread calls foo
    • for msg in x { ... } loop (same for sum/prod/min/max/any/all/sift/link)
    • msg := next() for next message from in-type
    • msg := wait_next() for waiting for next message from in-type

    Single-thread example:

    fn log(a: f64) {}
    fn main() {
        xs := in log
        for i 10 {log(i)}
        println(sum x in xs {x[0]})
    }
    

    Multi-thread example:

    fn log(a: f64) {}
    fn finish() {}
    fn bar() -> bool {
        return = true
        for i 10 {log(i)}
        finish()
    }
    fn main() {
        xs := in log
        done := in finish
        _ := go bar()
        _ := wait_next(done)
        println(sum x in xs {x[0]})
    }
    
    Source code(tar.gz)
    Source code(zip)
  • v0.9(Sep 19, 2016)

  • v0.8(Jul 11, 2016)

    New features:

    • Infer range from loops
    • Packed loops
    • Secrets
    • Current objects (using hidden dynamical scope)
    • Ad-hoc types
    • Link type
    • Unpack and swizzle 4D vectors
    • vec2/vec3/vec4 un-loops
    • Closures
    • Grab expressions
    • Lazy || and &&
    • Lots of bug fixes
    • Better type inference
    Source code(tar.gz)
    Source code(zip)
Owner
PistonDevelopers
The Piston game engine organization for maintenance and research
PistonDevelopers
Rhai - An embedded scripting language for Rust.

Rhai - Embedded Scripting for Rust Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way to add scripti

Rhai - Embedded scripting language and engine for Rust 2.4k Dec 29, 2022
Scripting language focused on processing tabular data.

ogma Welcome to the ogma project! ogma is a scripting language focused on ergonomically and efficiently processing tabular data, with batteries includ

kdr-aus 146 Dec 26, 2022
A static, type inferred and embeddable language written in Rust.

gluon Gluon is a small, statically-typed, functional programming language designed for application embedding. Features Statically-typed - Static typin

null 2.7k Dec 29, 2022
Source code for the Mun language and runtime.

Mun Mun is a programming language empowering creation through iteration. Features Ahead of time compilation - Mun is compiled ahead of time (AOT), as

The Mun Programming Language 1.5k Jan 9, 2023
Implementation of Immix Mark-Region Garbage collector written in Rust Programming Language.

libimmixcons Implementation of Immix Mark-Region Garbage collector written in Rust Programming Language. Status This is mostly usable library. You can

playX 34 Dec 7, 2022
A computer programming language interpreter written in Rust

Ella lang Welcome to Ella lang! Ella lang is a computer programming language implemented in Rust.

Luke Chu 64 May 27, 2022
Oxide Programming Language

Oxide Programming Language Interpreted C-like language with a Rust influenced syntax. Latest release Example programs /// recursive function calls to

Arthur Kurbidaev 113 Nov 21, 2022
The hash programming language compiler

The Hash Programming language Run Using the command cargo run hash. This will compile, build and run the program in the current terminal/shell. Submit

Hash 13 Nov 3, 2022
Interpreted language developed in Rust

Xelis VM Xelis is an interpreted language developed in Rust. It supports constants, functions, while/for loops, arrays and structures. The syntax is s

null 8 Jun 21, 2022
Interactive interpreter for a statement-based proof-of-concept language.

nhotyp-lang Nhotyp is a conceptual language designed for ease of implementation during my tutoring in an introductive algorithmic course at Harbin Ins

Geoffrey Tang 5 Jun 26, 2022
🍖 ham, general purpose programming language

?? ham, a programming language made in rust status: alpha Goals Speed Security Comfort Example fn calc(value){ if value == 5 { return 0

Marc Espín 19 Nov 10, 2022
A small programming language created in an hour

Building a programming language in an hour This is the project I made while doing the Building a programming language in an hour video. You can run it

JT 40 Nov 24, 2022
The Loop programming language

Loop Language Documentation | Website A dynamic type-safe general purpose programming language Note: currently Loop is being re-written into Rust. Mea

LoopLanguage 20 Oct 21, 2022
Stackbased programming language

Rack is a stackbased programming language inspired by Forth, every operation push or pop on the stack. Because the language is stackbased and for a ve

Xavier Hamel 1 Oct 28, 2021
REPL for the Rust programming language

Rusti A REPL for the Rust programming language. The rusti project is deprecated. It is not recommended for regular use. Dependencies On Unix systems,

Murarth 1.3k Dec 20, 2022
A dynamically typed, interpreted, stack-based language.

Stacc A dynamically typed, interpreted, stack-based language. How does it work? Each call-frame/scope has its own variables and stack, so you can get/

null 8 Nov 12, 2021
Lagoon is a dynamic, weakly-typed and minimal scripting language. 🏞

Lagoon is a dynamic, weakly-typed and minimal scripting language. It draws inspiration from a handful of modern languages including JavaScript, Rust and PHP.

Ryan Chandler 25 Jul 5, 2022
A game made for the Rusty Jam https://itch.io/jam/rusty-jam

Murder-User Dungeon Introduction Tony is a young man. Finally having its own apartment is a good thing! He will learn how to live by himself and how t

null 62 Dec 6, 2022
Dynamically get the suggested clusters in the data for unsupervised learning.

Python implementation of the Gap Statistic Purpose Dynamically identify the suggested number of clusters in a data-set using the gap statistic. Full e

Miles Granger 163 Dec 9, 2022
Dynamically invoke arbitrary unmanaged code.

DInvoke_rs Rust port of Dinvoke. DInvoke_rs may be used for many purposes such as PE parsing, dynamic exported functions resolution, dynamically loadi

Kurosh Dabbagh Escalante 149 Dec 24, 2022