The Wren Programming Language. Wren is a small, fast, class-based concurrent scripting language.

Wren is a small, fast, class-based concurrent scripting language

Think Smalltalk in a Lua-sized package with a dash of Erlang and wrapped up in a familiar, modern syntax.

System.print("Hello, world!")

class Wren {
  flyTo(city) {
    System.print("Flying to %(city)")
  }
}

var adjectives = Fiber.new {
  ["small", "clean", "fast"].each {|word| Fiber.yield(word) }
}

while (!adjectives.isDone) System.print(adjectives.call())
  • Wren is small. The VM implementation is under 4,000 semicolons. You can skim the whole thing in an afternoon. It's small, but not dense. It is readable and lovingly-commented.

  • Wren is fast. A fast single-pass compiler to tight bytecode, and a compact object representation help Wren compete with other dynamic languages.

  • Wren is class-based. There are lots of scripting languages out there, but many have unusual or non-existent object models. Wren places classes front and center.

  • Wren is concurrent. Lightweight fibers are core to the execution model and let you organize your program into an army of communicating coroutines.

  • Wren is a scripting language. Wren is intended for embedding in applications. It has no dependencies, a small standard library, and an easy-to-use C API. It compiles cleanly as C99, C++98 or anything later.

If you like the sound of this, let's get started. You can even try it in your browser! Excited? Well, come on and get involved!

Build Status

Owner
Wren
Organization for the Wren programming language
Wren
Comments
  • Proposal for smarter imports.

    Proposal for smarter imports.

    I'd like to make imports work better for reusing code. The change is big enough that I thought it made sense to write it up like an actual "RFC" proposal as a separate doc. This PR tracks the proposal text itself. Feel free to comment on it here or on the mailing list.

    Rendered proposal

  • Extended valid identifier character list

    Extended valid identifier character list

    Regarding https://github.com/wren-lang/wren/issues/891

    This implementation is not UTF-8 complete (no emojis). But at least it gives a room for most roman/latin languages to use variable names with non ascii chars + some symbols.

    • Supported Characters: A small subset of https://en.wikipedia.org/wiki/ISO/IEC_8859-1
  • [RFC] Make 0 falsy

    [RFC] Make 0 falsy

    (Forked off @PureFox48's https://github.com/wren-lang/wren/pull/987#issuecomment-826284806 for visibility)

    At present,

    ... 0, empty strings, and empty collections are all considered “true” values.

    This proposal is to change +0 and -0 to be falsy. Per @mhermier's https://github.com/wren-lang/wren/pull/987#issuecomment-826361383, that is pretty easy to do.

    This change would reduce the surprise for programmers coming from other languages --- falsy zero is the case in at least the C- and Perl-family languages, and in PHP (just to pick another random example :) ).

  • [RFC] Use `in` keyword as a binary operator.

    [RFC] Use `in` keyword as a binary operator.

    At present, the in keyword isn't an operator as such but a particle whose only use is within a for statement:

    for (e in seq) // blah
    

    Despite this, I keep finding myself wanting to type stuff like this:

    if (e in list)   // list
    if (i in 0..5)   // range
    if ("e" in str)  // string
    

    Now all of these scenarios can be dealt with by using the Sequence.contains method or an override thereof for a particular class:

    if (list.contains(e))   // list
    if ((0..5).contains(i)) // range
    if (str.contains(e))    // string
    

    but I think most folks would agree that it's not as nice.

    So do you think it would be worthwhile re-classifying in as an overloadable binary operator (perhaps with the same precedence as is) which would enable us to use it as syntax sugar for the contains method?

    For example:

    class String {
       // ...
       in(str) { (str is String) && str.contains(this) }
    }
    
  • [RFC] Introduce a Long type for 64-bit signed integers.

    [RFC] Introduce a Long type for 64-bit signed integers.

    One thing I miss when programming in Wren is not being able to perform (full) 64 bit integer arithmetic, as we are effectively limited to no more than 53 bits because of the way that Nums are represented.

    I've been wondering whether there might be a way to achieve this without impacting on the simplicity of dealing with smaller integers and numbers generally that the Num class gives us and have come up with an idea.

    This is a fairly rough sketch so please bear with me.

    The basic idea is to introduce a Long class into the core library. A Long object would be 8 bytes long and would be represented internally by a C99 signed long long. It would be immutable as numbers are now.

    Consequently, a Long would be a value type as a variable of that type would hold its value directly.

    The Long class would not have constructors but instead a Long object could be created in one of three ways:

    1. From a literal - an integer with an 'L' suffix. Lower case 'l' would not be allowed as it's too easily confused with the digit '1'.

    2. From a string by giving the String class a toLong method which could optionally specify a base from 2 to 36.

    3. From a number by giving the Num class a toLong method.

    The Long class itself would support all the usual integer operators:

    + - * / % & | ^ ~ << >> < <= == != >= and >.

    However, the operands would always need to be Long objects - mixed operations with Nums would not be allowed.

    We'd also need a few methods such as: largest, smallest, min, max, pow and sign as well as toNum and toString.

    Here's a few simple examples to show how some of this would look:

    var r = 123456789L                  // Long created from a literal
    var s = "123456789123456789".toLong // Long created from a String
    var t = 12345678912345.toLong       // Long created from a Num
    var u = "abcdef".toLong(16)         // Long created from a base 16 string
    var v = s + t * u                   // arithmetic operations on Longs
    var w = (s > t) && (t > u)          // relational operations on Long
    var x = s + 6                       // not allowed, can't add Num to a Long
    var y = s + 6L                      // fine
    var z = r.toNum                     // Long converted to Num 
    

    Internally all operations would be performed from the C side using long long arithmetic and conversion functions such as strtoll.

    There would clearly be a lot of work needed to implement this and so the question is would it be worth it?

    On the plus side:

    1. We'd get full 64-bit integer representation and arithmetic including bit-wise operations though the latter might necessitate an internal conversion to unsigned long long. It would probably be best for overflows to wrap rather than producing an error.

    2. As we'd just be dealing with integers, base conversions would be straightforward to implement.

    3. Integer division would be just that (i.e. any remainder would be discarded) which is something I was banging on about in #907.

    4. There would be no impact whatsoever on Num arithmetic.

    5. It would be backwards compatible.

    On the minus side:

    1. There would be a certain amount of inconvenience in not permitting mixed arithmetic with Nums.

    2. There would inevitably be an impact on the size of the core library though I don't really see how it could done as an optional module as you'd need support for Long literals in the language itself.

    3. Using a numeric suffix for literals is arguably a bit ugly but I can't think of a sensible alternative and, of course, C has used suffixes from day one.

    4. A Long would have a lower range than an unsigned 64 bit integer but I feel that the convenience of having signed integers outweighs this.

    5. There would be more for newcomers to the language to learn.

    Finally, I'd add that you could do a lot of this with a custom type which is represented internally by a List of two Nums. However, the trouble with this is that it's relatively slow and, as it's a reference type, it will be subject to garbage collection and can't be used directly as a Map key.

    I look forward to hearing what you all think.

  • Implement sum method for Sequence class

    Implement sum method for Sequence class

    This PR:

    • Implements the sum method of the Sequence class; includes tests
    • Adds documentation for the sum method.

    Examples:

    System.print([1, 3.14].sum)  //> 4.14
    System.print((1..3).sum)  //> 6
    System.print([].sum)  //> 0
    
    System.print(["string", 1, 2].sum)  //> runtime error "Can't sum non-numeric values"
    
  • Add System.version

    Add System.version

    References https://github.com/wren-lang/wren-cli/issues/95

    System.version
    

    It returns WREN_VERSION_NUMBER. Was thinking of retrieving the string, or having version.major, version.minor, but I think keeping it dead simple like this is best.

  • Language: Infinity and NaN

    Language: Infinity and NaN

    Currently, due to C's double nature (and IEEE-754), you can get NaN via 0 / 0, Infinity via 1 / 0, and -Infinity via -1 / 0 (or -(1 / 0), i.e. -Infinity). Example:

    var NaN = 0 / 0
    var Infinity = 1 / 0
    var MinusInfinity = -Infinity
    System.print("NaN: %(NaN), Infinity: %(Infinity), MinusInfinity: %(MinusInfinity)") // NaN: nan, Infinity: infinity, MinusInfinity: -infinity
    System.print("NaN == NaN? %(NaN == NaN)") // NaN == NaN? false
    

    I think there are two things two improve here:

    1. The .toString is bad. Really 😺. I think it would be better to capitalize it, that is, NaN, Infinity, and -Infinity.
    2. We should have a way to construct them. There are two manners in different programming languages (you're welcome to add more languages):
      1. JavaScript uses keywords: NaN and Infinity. C and C++ use macros (NAN and INFINITY in <math.h> or <cmath>, since C99 and C++ 11), which are similar.
      2. Python, C#, Java and Rust uses methods/properties/constant. In C# it's double.NaN, double.PositiveInfinity, and double.NegativeInfinity (or their float counterparts). Java has similar names: Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY. Python has math.nan and math.inf since 3.5; before that, the recommended way was to convert from string (see https://stackoverflow.com/a/7781273/7884305, https://stackoverflow.com/a/19374296/7884305). Rust has f64::NAN, f64::INFINITY, and f64::NEG_INFINITY (or f32 counterparts). C++ also has methods, inside <limits>, std::numeric_limits<{double, float, long double}>::{infinity, quiet_NaN, signaling_NaN}().

    I think the methods approach is better. However, do we need to also insert Num.negativeInfinity or no because users can just do -Num.infinity?

  • Performance

    Performance

    Likewise, when you access a field in other languages, the interpreter has to look it up by name in a hash table in the object.

    I ran some tests in Swift:

    • 0.0005 for hash table
    • 0.00000618 for pointers

    Sorry for the beginner question, but why does the hash table approach differ by orders of magnitude in performance? I did not expect this.

  • Binding class methods and other primitives at runtime

    Binding class methods and other primitives at runtime

    I'm studying how to implement binding Wren to my classes at runtime based on my own reflection metadata, in a similar fashion as I bound lua. (https://github.com/hugoam/mud/blob/master/src/lang/Lua.cpp) I'm almost in a dead end, or all designs I can think of will end up way too complex. So I want to know if you can help me or give me some pointers :)

    The crux of the problem is that, unlike in lua where there is a function call mechanism with upvalues (for closures) at the core of the library, in Wren everything is the other way around: everything is an object, so you only ever call methods, and the C API method binding mechanism doesn't allow you to store any closure data with it : you only give a bare function pointer, which is biased towards implementing all your foreign methods manually (or generating C++ code).

    I can't bind C/C++ primitives at runtime without being able to store some "closed-over" values somehow (like a wren handle) together with the bound method in bindForeignMethod. Which, if I'm starting to understand Wren design, seems likely to be impossible.

    So I've been trying to think of ways to store a Wren handle (to a foreign class that I defined to store my callable), but since I have no way to attach it to the bound method in the bindForeignMethod handler, I need an alternative.

    Since in Wren closures seem to be a higher level construct based on the former mechanisms (objects, methods, etc...), I can think of some very contrived workarounds where I would define my closure classes, create instances of these closures for each of my primitives, and write boilerplate "proxy" methods that would call these closures in the body of the foreign class, and then compile all this Wren boilerplate. But there are two things about such a design :

    1. I'm still not sure it's entirely possible
    2. that's more an argument towards not using Wren so far, and I really wanted to provide this otherwise very neat language :)

    Did I miss something crucial that would help me implement this with Wren ? If I haven't been clear or making sense let me know too :)

  • Proposition for a fork.

    Proposition for a fork.

    Hi,

    I'm really considering to do a fork of the project under the name 'canary'. As the situation goes, wren is stalling with a pile of issues accumulating.

    The short plan is to have a decent vm. Probably not the fastest, but with less bugs, and with a revisited design. At long term there will be a clear separation of code path with rebranding, and code style changes.

    The big aim is to make the language and vm evoluate, and even consider to support other languages.

    But first I would like to see if the community is interested?

  • Specialize `Range.contains(_)`

    Specialize `Range.contains(_)`

    Creates a specialization for Range.contains(_) that is a bound check rather than using Sequence's implementation which uses iteration instead.

    This came up when I was implementing some Project Euler stuff when and I noticed the pathological behavior in some of those problems as well. Particularly problem 17 was about 1000x slower using ranges (I had like 6 different ranges).

    I didn't add any new tests since this method is pretty extensively covered. I did create a pathological benchmark for it though.

    Benchmark included below uses ./bin/wren_test. I wasn't sure if I should include it in the benchmarks folder since it looks like that is for comparing against different languages.

    Looks like it's roughly 300x faster in this pathological case, but I reran it for (0...10) and it still is about 5x faster.

    Anyway, let me know if I should change anything here! This isn't too big of a change and I think it can help all users of the language.

    var start = System.clock
    var total = 0
    for (i in 0..1e5) {
        if ((0...1e3).contains(i)) {
            total = total + 1
        }
    }
    System.print(total)
    System.print("elapsed: %(System.clock - start)")
    
    // Before
    // 1000
    // elapsed: 2.968864
    
    // After
    // 1000
    // elapsed: 0.010275
    
  • Remove `randomSeed1()`'s reliance on cstdlib's rand implementation.

    Remove `randomSeed1()`'s reliance on cstdlib's rand implementation.

    This adds a simple TLCG to initialize the random state when only a number is supplied as seed.

    This has the result of removing the reliance on cstdlib's srand()/rand() implementations for setting the initial state, meaning that the same seed value will have the same effect regardless of platform.

    Proposed as a solution for #1098

  • `Random.new(seed)` where `seed` : `Num` relies on platform's cstdlib `srand()`/`rand()`

    `Random.new(seed)` where `seed` : `Num` relies on platform's cstdlib `srand()`/`rand()`

    Making use of passing a number to Random.new(seed) eventually calls randomSeed1(WrenVM* vm).

    randomSeed1 uses that number cast as a uint32_t to call cstdlib's srand(), and then fills out the initial Well512 state with 16 subsequent calls to rand().

    The result of this is that on a given platform, seeding random with a single number will produce an expected, repeatable output. Using the same seed on a different platform however, may not produce the same output as the original.

    Example:

    import "random" for Random
    var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    var rng = Random.new(1234)
    System.print(rng.sample(letters, 10))
    

    On my windows machine outputs: [P, Q, D, T, G, V, W, C, J, F] However, the try wren page prints: [G, O, H, E, U, A, W, J, M, Z]

    Forcing Random.new() to seed the initial state with non-rand() values by passing a Sequence instead causes the behavior to be properly deterministic:

        import "random" for Random
        var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        var rng = Random.new([1234]) // note [1234] rather than 1234
        System.print(rng.sample(letters, 10))
    

    windows: [Q, B, S, T, U, C, I, F, W, P] try wren: [Q, B, S, T, U, C, I, F, W, P]

    I would think that providing a seed of any sort should be deterministic even between platforms.

    Cheers!

    (Edit: fixed typo in link)

  • Added an example of 'else if' to the docs

    Added an example of 'else if' to the docs

    Currently there isn't any example of an else if statement currently in docs, or an explicit mention of else if statements existing at all, I wanted to add an example of else if statement so new users aren't confused as to whether they exist in Wren.

  • Get slot class and class identification

    Get slot class and class identification

    This PR implements a few functions in the C API to:

    • get the class of a value at a specific slot ;
    • compare two classes for equality or inheritance ;

    Some of these functions were initially discussed and implemented in https://github.com/wren-lang/wren/pull/591 but were eventually abandoned by the developer of the PR.

    I have been in need for these for the following use case:

    • say we have several foreign classes in the enchantment module, how does Wizard.enchant(_) can be certain it is been given a Unicorn and not an Orc as parameter ? The Wizard must use the foreign pointer of the Unicorn in order to enchant it, but if it is given another class instance, bad things would happen : allowing the developer to validate the parameters would be nice ;
    • how do we know it is given a Unicorn from enchantment and not from upside_down ? Both use different foreign pointer types and APIs : allowing the developer to tell the origin of a class would be nice ;
    • sometimes, we just need to know the name of what we are given, so having the name of the class could be useful too ;

    This PR has been tested (with make only):

    • debug_64bit with tests (--suffix _d) :white_check_mark: ;
    • debug_64bit-no-nan-tagging with tests (--suffix _d) :white_check_mark: ;
    • release_64bit-no-nan-tagging with tests :white_check_mark: ;
    • release_64bit-no-nan-tagging with tests :white_check_mark: ;

    There is a point that might need improvements:

    • the procedure in isParameterForeignType (in the tests) is useful but quite long to be copied in basically any foreign class we want to validate the parameters of : I was thinking that having a function to do it (possibly without using any slot apart from the source, bool wrenIsSlotSameClassAs(WrenVM* vm, int slot, const char* module, const char* className) would be nice to have ;
ArkScript is a small, fast, functional and scripting language for C++ projects
ArkScript is a small, fast, functional and scripting language for C++ projects

ArkScript Documentation Discord server: invite link, to discuss the specification of the language and receive help Modules Nota bene: the project is r

Aug 2, 2022
A proof-of-oncept module adding real-time Wren support to Godot

Godot Wren Module This module adds a new node, called WrenManager, that allows for executing Wren code in Godot during runtime! Wren is a cool lightwe

Nov 28, 2021
RemixDB: A read- and write-optimized concurrent KV store. Fast point and range queries. Extremely low write-amplification.

REMIX and RemixDB The REMIX data structure was introduced in paper "REMIX: Efficient Range Query for LSM-trees", FAST'21. This repository maintains a

Aug 15, 2022
Simple, fast, JIT-compiled scripting language for game engines.
Simple, fast, JIT-compiled scripting language for game engines.

Aftel Aftel (acronym for «A Far Too Easy Language») is a programming language, primarily intended to serve as an embeddable scripting language for gam

May 20, 2022
A small and fast programming language.
A small and fast programming language.

Pocketlang is a small (~3000 semicolons) and fast functional language written in C. It's syntactically similar to Ruby and it can be learned within 15

Aug 4, 2022
StarkScript - or the Stark programming language - is a compiled C-based programming language that aims to offer the same usability as that of JavaScript's and TypeScript's

StarkScript StarkScript - or the Stark programming language - is a compiled C-based programming language that aims to offer the same usability as that

May 10, 2022
🎩 An interpreted general-purpose scripting language 🔨

Dunamis Version 0.0.0.2 - Alpha Version 1.1 An interpreted general-purpose programming language Contents Syntax Functions Variables Objects Enums Incl

Dec 21, 2021
a C++ scripting language

/>mpl setup />mpl requires CMake and a C++ compiler to build, rlwrap is highly recommended for running the REPL. $ cd ampl $ mkdir build $ cd build $

Nov 6, 2021
A scripting language written in C

News KGScript will be rewritten from scratch in C or C++ (a big update) Usage Usage: ./KGScript file.kgs [options] Examples prints("Example") printi(1

Nov 12, 2021
ACL - A simple scripting language made in c++

ACL ACL is a simple and easy to learn language. ACL is a compiled language, made with C++. For code examples look at the examples/ folder. We would ap

May 2, 2022
The UwU's Scripting language. Made with love for UwU Nyanny Commuwiwwy!

UwUscript UwUscript is a scripting language. Installation Prerequisite LLVM 10.0 flex and bison. CMake 3.10 Build Clone this repository. git clone htt

Jul 23, 2022
PLP Project Programming Language | Programming for projects and computer science and research on computer and programming.
PLP Project Programming Language | Programming for projects and computer science and research on computer and programming.

PLPv2b PLP Project Programming Language Programming Language for projects and computer science and research on computer and programming. What is PLP L

Jun 23, 2022
A small, fast codeforces command line tool for competitive programming.
A small, fast codeforces command line tool for competitive programming.

chainsaw: A Codeforces Commandline Tool chainsaw is a small and faster drop-in replacement for your copy and paste while attending Codeforces contests

Jul 21, 2022
SJTU ACM Honors Class - Programming 2021

?? 图书管理系统 ?? SJTU ACM班 2021级 程序设计课程大作业 ?? 目录 ?? 简介 ?? 作业说明 ?? 评测方式 ?? 分数组成 ⏱ 中期检查 ⏱ 检查时间表 ?? 项目说明 ??‍?? 开发要求 开发文档 Github 仓库管理 代码风格 ?? 业务需求 交互方式 用户系统 图

Jul 16, 2022
rax/RAX is a C++ extension library designed to provide new, fast, and reliable cross-platform class types.

rax rax/RAX is a C++ extension library designed to provide cross-platform new, fast, and reliable class types for different fields such as work with I

May 2, 2022
Dynamic 3D cellular automata engine with lua scripting support
Dynamic 3D cellular automata engine with lua scripting support

Cell3D Cell3D is a dynamic 3D cellular automata engine with lua scripting support Installation Dependencies: Lua 5.3 Raylib Simplest possible build co

May 25, 2021
Unity Scripting in C++

Unity Native Scripting A library to allow writing Unity scripts in native code: C, C++, assembly. Purpose This project aims to give you a viable alter

Aug 11, 2022
An REFramework plugin that adds Direct2D scripting APIs

REFramework Direct 2D This is an REFramework plugin that adds a Direct2D scripting API. Building Currently suggest building in RelWithDebInfo so that

Aug 6, 2022