33 Commits
0.4.0 ... main

Author SHA1 Message Date
99d2f0b8fc Update .githubCI.yml 2025-11-19 14:18:54 -08:00
a1112587db try v4 of artifact actions 2025-11-19 14:17:58 -08:00
e3fc56376c Merge pull request #1194 from Mai-Lapyst/add-methodlimit-checks
Add check for method limit; closes #1193
2025-11-19 14:15:38 -08:00
77aeb12ab8 tidy up warning
warning: incompatible pointer types passing 'ObjModule *' to parameter of type 'Obj *'
2025-03-11 17:06:45 -07:00
415f7b24ac Merge pull request #1195 from rune-scape/gray-fn-module
Mark a functions module as reachable for the GC
2025-03-10 17:46:00 -07:00
9bafddadd6 Update wren_value.c 2025-03-10 17:43:44 -07:00
59a834e97c Gray the module that functions belong to 2025-03-05 19:31:38 -08:00
7c3985f8a0 Add check for method limit; closes #1193 2025-02-25 01:03:45 +01:00
bd07122f92 Fix a typo (#1192) 2025-02-16 10:54:34 -08:00
c2a75f1eaf docs: add link to cli in mobile view (#1107) 2022-09-28 18:32:10 -07:00
5287f6cd2b Added an example of 'else if' to the docs (#1097)
* Added an example of else if to the docs

* Added an example of else if to the Control Flow section of the docs
2022-08-30 22:49:13 -07:00
4ffe2ed38b Fix formatting error (#1078)
Fixed error that caused `<stdio.h>` to disappear from C `#include` directive
2022-01-31 15:43:01 -08:00
77079f2f49 CI: artifacts 2021-11-14 01:00:19 -08:00
2adb220686 CI: add initial github actions 2021-11-14 00:50:43 -08:00
accfa598b3 Allow people to share links to the playground (#1046)
* Allow people to share links to the playground

We do that by encoding the code (compressed) in the URL.

The compression is the same used in the TypeScript playground:
e9d8f66f6b/packages/sandbox/src/compilerOptions.ts (L119-L120)
2021-08-09 17:41:00 -07:00
55e8807aba fix #1039 clarity in header comments 2021-08-09 17:24:47 -07:00
dd1e8a00db docs; values; add note about newline normalization in docs 2021-05-21 16:30:08 -07:00
3c43de7485 minor consistency fixes 2021-05-21 16:24:34 -07:00
59e496e26a Fix CRLF being significant inside of strings, now strings are normalized to \n only and the same output regardless of the file line endings (see #988)
https://github.com/wren-lang/wren/issues/988#issuecomment-842670624
2021-05-21 16:24:12 -07:00
d78f481079 wren_core.wren.inc backslash characters escaped (#1023) 2021-05-21 16:09:00 -07:00
9903ddf76b docs; string; clarify indexOf(_,_) to be clearer 2021-05-16 12:17:31 -07:00
f09ebf6acc fix attributes causing crash when GC is triggered by compiler init 2021-05-05 14:34:16 -07:00
7fb7f6430d minor 2021-05-05 14:29:39 -07:00
aca7c70079 docs; fix example with 'continue' (#1007) 2021-05-04 14:56:53 -07:00
eca90e29e9 Document the Meta class. (#977) 2021-04-16 11:12:32 -07:00
a346494922 Documents 'return from module'. (#976)
Fixes #974.
2021-04-16 11:09:28 -07:00
754d5a59e9 correct attributes example (#978) 2021-04-16 11:08:01 -07:00
8eb51d9327 doc: fix links from Object to values (#975)
Fix two broken links from the documentation for the Object class to the
page describing values.
2021-04-15 21:29:26 -07:00
22ff3b5549 update try to 0.4.0 2021-04-09 12:48:39 -07:00
e4b4df2e62 minor; remove redundant comment bit 2021-04-09 11:17:15 -07:00
46b06f0620 minor formatting fix 2021-04-08 22:22:34 -07:00
d650b60c25 0.4.0 release - fix links and formatting 2021-04-08 22:17:13 -07:00
30c9f1ee37 initial 0.4.0 blog post 2021-04-08 22:09:02 -07:00
38 changed files with 657 additions and 42 deletions

61
.github/workflows/.githubCI.yml vendored Normal file
View File

@ -0,0 +1,61 @@
name: WrenCI
on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: build
run: ./.travis.sh
shell: bash
working-directory: ./
- uses: actions/upload-artifact@v4
with:
name: wren-linux
path: |
bin/*
lib/*
mac:
runs-on: macos-latest
env:
WREN_TARGET_MAC: 1
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: build
run: ./.travis.sh
shell: bash
working-directory: ./
- uses: actions/upload-artifact@v4
with:
name: wren-mac
path: |
bin/*
lib/*
windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: msbuild
uses: microsoft/setup-msbuild@v1.1
- name: build
working-directory: ./projects/vs2019/
run: msbuild ./wren.sln /property:Configuration=Release /property:Platform=64bit
- uses: actions/upload-artifact@v4
with:
name: wren-windows
path: |
bin/*
lib/*

View File

@ -29,4 +29,5 @@ ruby0x1 <ruby0x1@pm.me>
Kolja Kube <code@koljaku.be>
Alexander Klingenbeck <alexander.klingenbeck@gmx.de>
Aviv Beeri <avbeeri@gmail.com>
Mai Lapyst <floss@lapyst.dev>

View File

@ -0,0 +1,183 @@
^title 0.4.0 released!
8 April 2021
---
This post is all about the 0.4.0 release since it's a big one!
<small>(A separate post for 0.5.0 goals would likely come later.)</small>
## 0.4.0 details
**0.4.0 contains 145 commits from 28 contributors.**
The [full release notes](https://github.com/wren-lang/wren/releases/tag/0.4.0)
link to each PR or commit, and contains a lot more details than this post.
**Goals**
As usual, let's revisit the goals from the [0.3.0 post](2-0.3.0-released.html#goals-for-0.4.0).
Most importantly - compound operators didn't land in 0.4.0 for various reasons.
Still working on it, it's just a fun and nuanced problem and I don't want to
keep 0.4.0 back cos of it.
With that out the way, let's see what 0.4.0 contains!
## 0.4.0 highlights
Below we'll highlight some key features, fixes and improvements from the release.
**A lot of work came from the community, much thanks to everyone contributing!**
You can find all the details and the contributions in the [release notes](https://github.com/wren-lang/wren/releases/tag/0.4.0).
**Take note!** There are two minor breaking changes in the API on the release notes.
---
### Bug fixes
Several important bugs have been fixed, sneaky stack corruptions and some user
experience fixes that clarify confusing states.
### Documentation
A lot of work has gone into documentation this release, revising, fixing, adding
and closing gaps that were left. For example, Wren supports multi-line strings
but this was never mentioned anywhere!
### New **continue** keyword
Loops can now use continue, which is a welcome addition.
### New **as** keyword
You can now use `import "..." for Name as OtherName` to avoid name conflicts,
or to use aliases/shorthand for imported variables.
### Raw strings
Wren now supports triple quotes for a string `"""`.
This type of string is only unique in how it's parsed, the content of the
string is ignored (no interpolation or escapes are processed), which allows
complex strings to be expressed without needing to escape things.
A common example is json or regex, where there's a lot of escaping that obscures
the string content and makes it hard to read and maintain.
If they span multiple lines, the string ignores the open and closing newlines
and whitespace and preserves anything in between.
<pre class="snippet">
var json = """
{
"hello": "wren",
"from" : "json"
}
"""
</pre>
### Attributes
Attributes are user-defined metadata associated with a class or method that
can be used at runtime, by external tools (and potentially by Wren itself).
<pre class="snippet">
#hidden = true
#doc = "A simple example class"
class Example {}
</pre>
They can be:
- a `#key` on it's own
- a `#key = value`
- a `#group(with, multiple = true, keys = "value")`
**Example**
Below you can one obvious use case, a wip version where attributes for docs were
parsed and sent over to [vscode](https://code.visualstudio.com/) to display.
<video preload="auto" controls="" loop="loop" style="max-width:100%; width:auto; margin:auto; display:block;">
<source src="https://i.imgur.com/W9DWysP.mp4" type="video/mp4">
</video>
**Runtime access**
By default, attributes are compiled out and ignored.
For an attribute to be visible at runtime, mark it for runtime access using an
exclamation:
<pre class="snippet">
#doc = "not runtime data"
#!runtimeAccess = true
#!maxIterations = 16
</pre>
Attributes at runtime are stored on the class itself. You can access them via
`YourClass.attributes`. If any attributes are made available, they'll be found here:
- `YourClass.attributes.self` for the class attributes
- `YourClass.attributes.methods` for the method attributes
All the details for [Attributes can be found here](https://wren.io/classes.html#attributes).
### Chained methods fixes ('fluent interfaces')
Mentioned in the last post, you can now use this pattern in code as intended,
the same-line requirement for the `.` has been removed.
<pre class="snippet">
example
.some()
.functions()
.here()
</pre>
### List additions
Lists are now sortable via `list.sort()` and `list.sort {|a, b| ... }`.
You can find an index of something via `list.indexOf(value)`, and remove a value
via `list.remove(value)`. There's also `list.swap(index0, index1)` for moving
items around within a list.
For the API, `wrenSetListElement` now exists, and both set and
`wrenGetListElement` now accept negative indices same as the language side.
### Num additions
A few new constants:
- `Num.tau`
- `Num.nan`
- `Num.infinity`
- `Num.minSafeInteger`/`Num.maxSafeInteger`
And some new methods on a number:
- `num.min(other)`
- `num.max(other)`
- `num.clamp(min, max)`
- `num.cbrt`
- `num.exp`
- `num.log2`
### Map access from the API
You can now create and access maps from the API:
- `wrenSetSlotNewMap`
- `wrenGetMapCount`
- `wrenGetMapContainsKey`
- `wrenGetMapValue`
- `wrenSetMapValue`
- `wrenRemoveMapValue`
## Till next time
---
- [The Wren Blog RSS](http://wren.io/blog/rss.xml)
- Join the [discord community](https://discord.gg/Kx6PxSX)
- Visit the [wren-lang organization](https://github.com/wren-lang) on GitHub to get involved.
- Follow the developers [@munificentbob](https://twitter.com/munificentbob) or [@ruby0x1](https://twitter.com/ruby0x1) on twitter

View File

@ -1,5 +1,8 @@
^title Development blogs
[<h3>0.4.0 released!</h3>](3-0.4.0-released.html)
> <date>8 April 2021</date> • 0.4.0 is a big release, here's all the info!
[<h3>0.3.0 released!</h3>](2-0.3.0-released.html)
> <date>5 June 2020</date> • 0.3.0 release info! Plus some notes and goals for the next release, 0.4.0.

View File

@ -3,12 +3,19 @@
<link>https://wren.io/</link>
<description>The development blog of the Wren programming language.</description>
<language>en-us</language>
<item>
<title>0.4.0 released</title>
<link>https://wren.io/blog/3-0.4.0-released.html</link>
<description>0.4.0 is a big release, here's all the info!</description>
<guid>https://wren.io/blog/3-0.4.0-released.html</guid>
<pubDate>Thu, 08 Apr 2021 00:00:00 GMT</pubDate>
</item>
<item>
<title>0.3.0 released</title>
<link>https://wren.io/blog/2-0.3.0-released.html</link>
<description>0.3.0 release info! Plus some notes and goals for the next release, 0.4.0.</description>
<guid>https://wren.io/blog/2-0.3.0-released.html</guid>
<pubDate>Mon, 30 Sep 2019 00:00:00 GMT</pubDate>
<pubDate>Mon, 05 Jun 2020 00:00:00 GMT</pubDate>
</item>
<item>
<title>0.2.0 and beyond</title>

View File

@ -746,15 +746,15 @@ class Example {
#!getter
getter {}
// { regular(_,_): { regular:[null] } }
// { regular(_,_): { null: { regular:[null] } } }
#!regular
regular(arg0, arg1) {}
// { static other(): { isStatic:[true] } }
// { static other(): { null: { isStatic:[true] } } }
#!isStatic = true
static other()
static other() {}
// { foreign static example(): { isForeignStatic:[32] } }
// { foreign static example(): { null: { isForeignStatic:[32] } } }
#!isForeignStatic=32
foreign static example()
}

View File

@ -61,6 +61,17 @@ if (ready) {
}
</pre>
You can also use `else if` branches to handle multiple possibilities. For example, what if `ready` was not a boolean value?
<pre class="snippet">
if (ready == true) {
System.print("go!")
} else if (ready == false) {
System.print("not ready!")
} else { // If ready isn't a boolean
System.print("not sure if I'm ready or not!")
}
</pre>
## Logical operators
Unlike most other [operators][] in Wren which are just a special syntax for
@ -187,8 +198,8 @@ loop conditions).
<pre class="snippet">
for (i in [1, 2, 3, 4]) {
System.print(i) //> 1
if (i == 2) continue //> 3
if (i == 2) continue //> 1
System.print(i) //> 3
} //> 4
</pre>

View File

@ -48,9 +48,9 @@ method is called. That's how many dynamic languages work.
But, as you can imagine, that's pretty slow. So, instead, Wren does as much of
that work at compile time as it can. When it's compiling the above code to
bytecode, it takes that method signature a converts it to a *method symbol*, a
number that uniquely identifes that method. That's the only part of the process
that requires treating a signature as a string.
bytecode, it takes that method signature and converts it to a *method symbol*,
a number that uniquely identifes that method. That's the only part of the
process that requires treating a signature as a string.
At runtime, the VM just looks for the method *symbol* in the receiver's class's
method table. In fact, the way it's implemented today, the symbol is simply the

View File

@ -208,7 +208,7 @@ You can find this file in the [example](https://github.com/wren-lang/wren/blob/m
<pre class="snippet" data-lang="c">
//For more details, visit https://wren.io/embedding/
#include <stdio.h>
#include &lt;stdio.h>
#include "wren.h"
static void writeFn(WrenVM* vm, const char* text)

View File

@ -306,5 +306,19 @@ This sounds super hairy, but that's because cyclic dependencies are hairy in
general. The key point here is that Wren *can* handle them in the rare cases
where you need them.
## Exiting a module early
Although the `return` statement is normally used to exit from a [method](classes.html#methods) or a [function](functions.html), it can also be used from a module's top-level code to exit the module. For example, if the script consists of a single module, this code would exit the module (and therefore the script) early:
<pre class="snippet">
for (i in 1..2) {
if (i == 2) return
System.print(i) //> prints 1 but not 2
}
System.print(3) //> not reached
</pre>
Although it is not invalid to return a value, there is no way to access that value and it is therefore simply discarded.
<br><hr>
<a href="error-handling.html">&larr; Error Handling</a>

View File

@ -5,7 +5,7 @@
### **same**(obj1, obj2)
Returns `true` if *obj1* and *obj2* are the same. For [value
types](../values.html), this returns `true` if the objects have equivalent
types](../../values.html), this returns `true` if the objects have equivalent
state. In other words, numbers, strings, booleans, and ranges compare by value.
For all other objects, this returns `true` only if *obj1* and *obj2* refer to
@ -26,7 +26,7 @@ Returns `false`, since most objects are considered [true][].
### **==**(other) and **!=**(other) operators
Compares two objects using built-in equality. This compares [value
types](../values.html) by value, and all other objects are compared by
types](../../values.html) by value, and all other objects are compared by
identity&mdash;two objects are equal only if they are the exact same object.
### **is**(class) operator

View File

@ -148,8 +148,9 @@ It is a runtime error if `search` is not a string.
### **indexOf**(search, start)
Returns the index of the first byte matching `search` in the string or `-1` if
`search` was not found, starting a byte offset `start`. The start can be
negative to count backwards from the end of the string.
`search` was not found, starting at byte offset `start`. The `start` offset can
also be negative, which will be offset relative to end of the string instead.
Searches forward, from the offset to the end of the string.
It is a runtime error if `search` is not a string or `start` is not an integer
index within the string's byte length.

View File

@ -1,5 +1,9 @@
^title Module "meta"
**TODO**
This module enables Wren to do certain kinds of meta-programming.
It is an optional module. You can omit it from your application by setting the preprocessor constant `WREN_OPT_META` to `0`.
It contains a single class:
* [Meta](meta.html)

View File

@ -1,7 +1,145 @@
^title Meta Class
**TODO**
This class contains static methods to list a module's top-level variables and to compile Wren expressions and source code into closures (i.e. [functions](functions.html)) at runtime.
## Methods
It must be imported from the [meta](meta.html) module:
**TODO**
<pre class="snippet">
import "meta" for Meta
</pre>
## Static Methods
### **getModuleVariables**(module)
Returns a list of all module level variables defined or visible in `module`.
This includes any variables explicitly imported from other modules or implicitly imported from the built-in modules. For example if we create this module:
<pre class="snippet">
/* module.wren */
var M = 1
</pre>
and then import it into this module:
<pre class="snippet">
/* get_mod_vars.wren */
import "meta" for Meta
import "./module" for M
var v = 42
var f = Fn.new {
var g = 2
}
class C {}
System.print(Meta.getModuleVariables("./get_mod_vars"))
var w = 43 // still returned even though defined later
</pre>
the output when the latter module is run is:
<pre class="snippet">
[Object, Class, Object metaclass, Bool, Fiber, Fn, Null, Num, Sequence, MapSequence, SkipSequence, TakeSequence, WhereSequence, List, String, StringByteSequence, StringCodePointSequence, Map, MapKeySequence, MapValueSequence, MapEntry, Range, System, Meta, M, v, f, C, w]
</pre>
Notice that `g` is not included in this list as it is a local variable rather than a module variable.
It is a runtime error if `module` is not a string or cannot be found.
### **eval**(source)
Compiles Wren source code into a closure and then executes the closure automatically.
It is a runtime error if `source` is not a string.
It is also an error if the source code cannot be compiled though the compilation errors themselves are not printed.
For example:
<pre class="snippet">
import "meta" for Meta
var a = 2
var b = 3
var source = """
var c = a * b
System.print(c)
"""
Meta.eval(source) //> 6
</pre>
### **compileExpression**(expression)
Compiles a Wren expression into a closure and then returns the closure. It does not execute it.
The closure returns the value of the expression.
It is a runtime error if `expression` is not a string.
Prints any compilation errors - in which event the closure will be null - but does not throw an error.
For example:
<pre class="snippet">
import "meta" for Meta
var d = 4
var e = 5
var expression = "d * e"
var closure = Meta.compileExpression(expression)
System.print(closure.call()) //> 20
</pre>
### **compile**(source)
Compiles Wren source code into a closure and then returns the closure. It does not execute it.
It is a runtime error if `source` is not a string.
Prints any compilation errors - in which event the closure will be null - but does not throw an error.
For example:
<pre class="snippet">
import "meta" for Meta
/* Enum creates an enum with any number of read-only static members.
Members are assigned in order an initial integer value (often 0), incremented by 1 each time.
The enum has:
1. static property getters for each member,
2. a static 'startsFrom' property, and
3. a static 'members' property which returns a list of its members as strings.
*/
class Enum {
// Creates a class for the Enum (with an underscore after the name to avoid duplicate definition)
// and returns a reference to it.
static create(name, members, startsFrom) {
if (name.type != String || name == "") Fiber.abort("Name must be a non-empty string.")
if (members.isEmpty) Fiber.abort("An enum must have at least one member.")
if (startsFrom.type != Num || !startsFrom.isInteger) {
Fiber.abort("Must start from an integer.")
}
name = name + "_"
var s = "class %(name) {\n"
for (i in 0...members.count) {
var m = members[i]
s = s + " static %(m) { %(i + startsFrom) }\n"
}
var mems = members.map { |m| "\"%(m)\"" }.join(", ")
s = s + " static startsFrom { %(startsFrom) }\n"
s = s + " static members { [%(mems)] }\n}\n"
s = s + "return %(name)"
return Meta.compile(s).call()
}
}
var Fruits = Enum.create("Fruits", ["orange", "apple", "banana", "lemon"], 0)
System.print(Fruits.banana) //> 2
System.print(Fruits.startsFrom) //> 0
System.print(Fruits.members) //> [orange, apple, banana, lemon]
</pre>

89
doc/site/static/lzstring.min.js vendored Normal file
View File

@ -0,0 +1,89 @@
// Minified from https://github.com/microsoft/TypeScript-Website/blob/e9d8f66f6b8be2dda06737d3686dcb795749dff2/packages/sandbox/src/vendor/lzstring.min.js
// Original license reproduced below:
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// Version 2, December 2004
//
// Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
//
// Everyone is permitted to copy and distribute verbatim or modified
// copies of this license document, and changing it is allowed as long
// as the name is changed.
//
// DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
// TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
//
// 0. You just DO WHAT THE FUCK YOU WANT TO.
//
var LZString=(function(){function o(o,r){if(!t[o]){t[o]={}
for(var n=0;n<o.length;n++)t[o][o.charAt(n)]=n}
return t[o][r]}
var r=String.fromCharCode,n='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',e='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$',t={},i={compressToBase64:function(o){if(null==o)return''
var r=i._compress(o,6,function(o){return n.charAt(o)})
switch(r.length%4){default:case 0:return r
case 1:return r+'==='
case 2:return r+'=='
case 3:return r+'='}},decompressFromBase64:function(r){return null==r?'':''==r?null:i._decompress(r.length,32,function(e){return o(n,r.charAt(e))})},compressToUTF16:function(o){return null==o?'':i._compress(o,15,function(o){return r(o+32)})+' '},decompressFromUTF16:function(o){return null==o?'':''==o?null:i._decompress(o.length,16384,function(r){return o.charCodeAt(r)-32})},compressToUint8Array:function(o){for(var r=i.compress(o),n=new Uint8Array(2*r.length),e=0,t=r.length;t>e;e++){var s=r.charCodeAt(e);(n[2*e]=s>>>8),(n[2*e+1]=s%256)}
return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o)
for(var n=new Array(o.length / 2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1]
var s=[]
return(n.forEach(function(o){s.push(r(o))}),i.decompress(s.join('')))},compressToEncodedURIComponent:function(o){return null==o?'':i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?'':''==r?null:((r=r.replace(/ /g,'+')),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return''
var e,t,i,s={},p={},u='',c='',a='',l=2,f=3,h=2,d=[],m=0,v=0
for(i=0;i<o.length;i+=1)
if(((u=o.charAt(i)),Object.prototype.hasOwnProperty.call(s,u)||((s[u]=f++),(p[u]=!0)),(c=a+u),Object.prototype.hasOwnProperty.call(s,c)))
a=c
else{if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)(m<<=1),v==r-1?((v=0),d.push(n(m)),(m=0)):v++
for(t=a.charCodeAt(0),e=0;8>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}else{for(t=1,e=0;h>e;e++)
(m=(m<<1)|t),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t=0)
for(t=a.charCodeAt(0),e=0;16>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}
l--,0==l&&((l=Math.pow(2,h)),h++),delete p[a]}else
for(t=s[a],e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
l--,0==l&&((l=Math.pow(2,h)),h++),(s[c]=f++),(a=String(u))}
if(''!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)(m<<=1),v==r-1?((v=0),d.push(n(m)),(m=0)):v++
for(t=a.charCodeAt(0),e=0;8>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}else{for(t=1,e=0;h>e;e++)
(m=(m<<1)|t),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t=0)
for(t=a.charCodeAt(0),e=0;16>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)}
l--,0==l&&((l=Math.pow(2,h)),h++),delete p[a]}else
for(t=s[a],e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
l--,0==l&&((l=Math.pow(2,h)),h++)}
for(t=2,e=0;h>e;e++)
(m=(m<<1)|(1&t)),v==r-1?((v=0),d.push(n(m)),(m=0)):v++,(t>>=1)
for(;;){if(((m<<=1),v==r-1)){d.push(n(m))
break}
v++}
return d.join('')},decompress:function(o){return null==o?'':''==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v='',w=[],A={val:e(0),position:n,index:1}
for(i=0;3>i;i+=1)f[i]=i
for(p=0,c=Math.pow(2,2),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
switch((t=p)){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
l=r(p)
break
case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
l=r(p)
break
case 2:return''}
for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return''
for(p=0,c=Math.pow(2,m),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1)
switch((l=p)){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1);(f[d++]=r(p)),(l=d-1),h--
break
case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)
(u=A.val&A.position),(A.position>>=1),0==A.position&&((A.position=n),(A.val=e(A.index++))),(p|=(u>0?1:0)*a),(a<<=1);(f[d++]=r(p)),(l=d-1),h--
break
case 2:return w.join('')}
if((0==h&&((h=Math.pow(2,m)),m++),f[l]))v=f[l]
else{if(l!==d)return null
v=s+s.charAt(0)}
w.push(v),(f[d++]=s+v.charAt(0)),h--,(s=v),0==h&&((h=Math.pow(2,m)),m++)}},}
return i})();'function'==typeof define&&define.amd?define(function(){return LZString}):'undefined'!=typeof module&&null!=module&&(module.exports=LZString)

View File

@ -502,6 +502,39 @@ table.precedence td {
border-bottom: solid 1px var(--gray-10);
}
/*
Sourced from https://github.com/microsoft/TypeScript-Website/blob/e9d8f66f6b8be2dda06737d3686dcb795749dff2/packages/typescriptlang-org/src/templates/play.scss#L916-L943.
Licensed under the MIT license https://github.com/microsoft/TypeScript-Website/blob/e9d8f66f6b8be2dda06737d3686dcb795749dff2/LICENSE-CODE.
*/
#copied-popup {
top: 0;
left: 0;
right: 0;
bottom: 0;
position: fixed;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
#copied-popup p {
background-color: rgba(0, 0, 0, 0.8);
color: white;
padding: 20px;
font-size: 1.5rem;
border-radius: 1em;
padding: 0.5em 1.5em;
opacity: 0;
transition: opacity 0.1s ease-in-out;
/* Help Safari with blurred text */
transform: translateZ(0);
}
@media only screen and (max-width: 839px) {
/* 36 pixel columns.*/
.page { width: 720px; }

View File

@ -22,9 +22,11 @@ window.onload = function() {
Module.printErr = function(text) { output.innerText += text + "\n"; }
var run = document.querySelector("#try-run")
var share = document.querySelector("#share")
var hello = document.querySelector("#try-hello")
var fractal = document.querySelector("#try-fractal")
var loop = document.querySelector("#try-loop")
var copiedPopup = document.querySelector("#copied-popup p")
var compile = Module.cwrap('wren_compile', 'number', ['string'])
var set_input = (content) => {
@ -34,6 +36,21 @@ window.onload = function() {
jar.updateCode(content);
}
share.onclick = (e) => {
var code = jar.toString()
var compressed = LZString.compressToEncodedURIComponent(code)
var url = location.protocol + "//" + location.host + location.pathname + "?code=" + compressed
navigator.clipboard.writeText(url).then(
() => {
copiedPopup.style.opacity = "1"
setTimeout(() => {
copiedPopup.style.opacity = ""
}, 1000)
},
(e) => console.error(e)
)
}
run.onclick = (e) => {
console.log("run")
output.setAttribute('ready', '');
@ -75,5 +92,11 @@ window.onload = function() {
}`);
} //fractal
var initial_code = new URLSearchParams(location.search).get("code")
if (initial_code !== null) {
initial_code = LZString.decompressFromEncodedURIComponent(initial_code)
set_input(initial_code)
}
} //if try_code
}

View File

@ -607,8 +607,8 @@ var wasmMemory;
// In the wasm backend, we polyfill the WebAssembly object,
// so this creates a (non-native-wasm) table for us.
var wasmTable = new WebAssembly.Table({
'initial': 203,
'maximum': 203 + 0,
'initial': 206,
'maximum': 206 + 0,
'element': 'anyfunc'
});
@ -1229,11 +1229,11 @@ function updateGlobalBufferAndViews(buf) {
}
var STATIC_BASE = 1024,
STACK_BASE = 5271568,
STACK_BASE = 5272384,
STACKTOP = STACK_BASE,
STACK_MAX = 28688,
DYNAMIC_BASE = 5271568,
DYNAMICTOP_PTR = 28528;
STACK_MAX = 29504,
DYNAMIC_BASE = 5272384,
DYNAMICTOP_PTR = 29344;
assert(STACK_BASE % 16 === 0, 'stack must start aligned');
assert(DYNAMIC_BASE % 16 === 0, 'heap must start aligned');
@ -1817,7 +1817,7 @@ var ASM_CONSTS = {
// STATICTOP = STATIC_BASE + 27664;
// STATICTOP = STATIC_BASE + 28480;
/* global initializers */ __ATINIT__.push({ func: function() { ___wasm_call_ctors() } });
@ -1875,7 +1875,7 @@ var ASM_CONSTS = {
}
function _emscripten_get_sbrk_ptr() {
return 28528;
return 29344;
}
function _emscripten_memcpy_big(dest, src, num) {

Binary file not shown.

View File

@ -100,6 +100,7 @@
<td>
<ul>
<li><a href="modules">API/Modules</a></li>
<li><a href="cli">Wren CLI</a></li>
<li><a href="embedding">Embedding</a></li>
<li><a href="performance.html">Performance</a></li>
<li><a href="qa.html">Q &amp; A</a></li>

View File

@ -14,6 +14,7 @@ examples: &nbsp;
<p>enter code below</p>
<div class="buttons">
<a class="button" id="share">share</a>&bullet;
<a class="button" id="try-run">run</a>
</div>
@ -25,3 +26,5 @@ examples: &nbsp;
<pre><div id="try-output">...</div></pre>
</div>
<div id="copied-popup"><p>URL copied to clipboard</p></div>

View File

@ -6,6 +6,7 @@
<script type="application/javascript" src="../prism.js" data-manual></script>
<script type="application/javascript" src="../codejar.js"></script>
<script type="application/javascript" src="../codejar-linenumbers.js"></script>
<script type="application/javascript" src="../lzstring.min.js"></script>
<script type="application/javascript" src="../wren.js"></script>
<link rel="stylesheet" type="text/css" href="../prism.css" />
<link rel="stylesheet" type="text/css" href="../style.css" />

View File

@ -50,7 +50,8 @@ String literals are surrounded in double quotes:
"hi there"
</pre>
They can also span multiple lines:
They can also span multiple lines. When they do, the newline character within
the string will always be `\n` (`\r\n` is normalized to `\n`).
<pre class="snippet">
"hi

View File

@ -113,6 +113,9 @@
// field index*.
#define MAX_FIELDS 255
// The maximum number of methods the vm can handle.
#define MAX_METHODS 65535
// Use the VM's allocator to allocate an object of [type].
#define ALLOCATE(vm, type) \
((type*)wrenReallocate(vm, NULL, 0, sizeof(type)))

View File

@ -542,6 +542,7 @@ static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent,
// the middle of initializing the compiler.
compiler->fn = NULL;
compiler->constants = NULL;
compiler->attributes = NULL;
parser->vm->compiler = compiler;
@ -910,13 +911,15 @@ static void readRawString(Parser* parser)
char c1 = peekChar(parser);
char c2 = peekNextChar(parser);
if(c == '\n') {
if (c == '\r') continue;
if (c == '\n') {
lastNewline = string.count;
skipEnd = lastNewline;
firstNewline = firstNewline == -1 ? string.count : firstNewline;
}
if(c == '"' && c1 == '"' && c2 == '"') break;
if (c == '"' && c1 == '"' && c2 == '"') break;
bool isWhitespace = c == ' ' || c == '\t';
skipEnd = c == '\n' || isWhitespace ? skipEnd : -1;
@ -974,6 +977,7 @@ static void readString(Parser* parser)
{
char c = nextChar(parser);
if (c == '"') break;
if (c == '\r') continue;
if (c == '\0')
{
@ -1098,7 +1102,7 @@ static void nextToken(Parser* parser)
skipLineComment(parser);
break;
}
// Otherwise we treat it as a token a token
// Otherwise we treat it as a token
makeToken(parser, TOKEN_HASH);
return;
}
@ -1848,8 +1852,14 @@ static void finishParameterList(Compiler* compiler, Signature* signature)
// Gets the symbol for a method [name] with [length].
static int methodSymbol(Compiler* compiler, const char* name, int length)
{
return wrenSymbolTableEnsure(compiler->parser->vm,
int symbol = wrenSymbolTableEnsure(compiler->parser->vm,
&compiler->parser->vm->methodNames, name, length);
if (symbol > MAX_METHODS) {
error(compiler, "Method limit of %d reached.", MAX_METHODS);
}
return symbol;
}
// Appends characters to [name] (and updates [length]) for [numParams] "_"

View File

@ -15,7 +15,7 @@
// There is one limitation, though. Methods written in C cannot call Wren ones.
// They can only be the top of the callstack, and immediately return. This
// makes it difficult to have primitive methods that rely on polymorphic
// behavior. For example, `IO.write` should call `toString` on its argument,
// behavior. For example, `System.print` should call `toString` on its argument,
// including user-defined `toString` methods on user-defined classes.
void wrenInitializeCore(WrenVM* vm);

View File

@ -480,4 +480,4 @@ class ClassAttributes {
_methods = methods
}
toString { "attributes:%(_attributes) methods:%(_methods)" }
}
}

View File

@ -238,11 +238,11 @@ static const char* coreModuleSource =
" return result\n"
" }\n"
"\n"
" trim() { trim_(\"\t\r\n \", true, true) }\n"
" trim() { trim_(\"\\t\\r\\n \", true, true) }\n"
" trim(chars) { trim_(chars, true, true) }\n"
" trimEnd() { trim_(\"\t\r\n \", false, true) }\n"
" trimEnd() { trim_(\"\\t\\r\\n \", false, true) }\n"
" trimEnd(chars) { trim_(chars, false, true) }\n"
" trimStart() { trim_(\"\t\r\n \", true, false) }\n"
" trimStart() { trim_(\"\\t\\r\\n \", true, false) }\n"
" trimStart(chars) { trim_(chars, true, false) }\n"
"\n"
" trim_(chars, trimStart, trimEnd) {\n"
@ -441,18 +441,18 @@ static const char* coreModuleSource =
"\n"
"class System {\n"
" static print() {\n"
" writeString_(\"\n\")\n"
" writeString_(\"\\n\")\n"
" }\n"
"\n"
" static print(obj) {\n"
" writeObject_(obj)\n"
" writeString_(\"\n\")\n"
" writeString_(\"\\n\")\n"
" return obj\n"
" }\n"
"\n"
" static printAll(sequence) {\n"
" for (object in sequence) writeObject_(object)\n"
" writeString_(\"\n\")\n"
" writeString_(\"\\n\")\n"
" }\n"
"\n"
" static write(obj) {\n"
@ -483,4 +483,3 @@ static const char* coreModuleSource =
" }\n"
" toString { \"attributes:%(_attributes) methods:%(_methods)\" }\n"
"}\n";

View File

@ -81,7 +81,7 @@ bool validateInt(WrenVM* vm, Value arg, const char* argName);
// Validates that [arg] is a valid object for use as a map key. Returns true if
// it is. If not, reports an error and returns false.
bool validateKey(WrenVM * vm, Value arg);
bool validateKey(WrenVM* vm, Value arg);
// Validates that the argument at [argIndex] is an integer within `[0, count)`.
// Also allows negative indices which map backwards from the end. Returns the

View File

@ -1089,6 +1089,9 @@ static void blackenFn(WrenVM* vm, ObjFn* fn)
// Mark the constants.
wrenGrayBuffer(vm, &fn->constants);
// Mark the module it belongs to, in case it's been unloaded.
wrenGrayObj(vm, (Obj*)fn->module);
// Keep track of how much memory is still in use.
vm->bytesAllocated += sizeof(ObjFn);
vm->bytesAllocated += sizeof(uint8_t) * fn->code.capacity;

View File

@ -1418,6 +1418,7 @@ WrenHandle* wrenMakeCallHandle(WrenVM* vm, const char* signature)
// Add the signatue to the method table.
int method = wrenSymbolTableEnsure(vm, &vm->methodNames,
signature, signatureLength);
ASSERT(method <= MAX_METHODS, "Method limit reached.");
// Create a little stub function that assumes the arguments are on the stack
// and calls the method.

View File

@ -0,0 +1,4 @@
// nontest
System.print("foo")
return
System.print("bar")

View File

@ -0,0 +1,4 @@
// nontest
System.print("foo")
return 42
System.print("bar")

View File

@ -0,0 +1,3 @@
System.print("foo") // expect: foo
return
System.print("bar")

View File

@ -0,0 +1,5 @@
import "./module_return"
System.print("baz")
// expect: foo
// expect: baz

View File

@ -0,0 +1,3 @@
System.print("foo") // expect: foo
return 42
System.print("bar")

View File

@ -0,0 +1,5 @@
import "./module_return_value"
System.print("baz")
// expect: foo
// expect: baz

View File

@ -22,6 +22,7 @@ static const char* {1}ModuleSource =
def wren_to_c_string(input_path, wren_source_lines, module):
wren_source = ""
for line in wren_source_lines:
line = line.replace("\\", "\\\\")
line = line.replace('"', "\\\"")
line = line.replace("\n", "\\n\"")
if wren_source: wren_source += "\n"