From 9817424fb3128853f0f175508252a3d8a5e04e33 Mon Sep 17 00:00:00 2001 From: Travis CI <> Date: Fri, 16 Apr 2021 18:16:35 +0000 Subject: [PATCH] Deploy to GitHub Pages: --- modules/meta/index.html | 4 +- modules/meta/meta.html | 120 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 120 insertions(+), 4 deletions(-) diff --git a/modules/meta/index.html b/modules/meta/index.html index 536f83ae..4545629a 100644 --- a/modules/meta/index.html +++ b/modules/meta/index.html @@ -59,7 +59,9 @@

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:

diff --git a/modules/meta/meta.html b/modules/meta/meta.html index 073ec4ae..fe3803f5 100644 --- a/modules/meta/meta.html +++ b/modules/meta/meta.html @@ -59,9 +59,123 @@

Meta Class

-

TODO

-

Methods #

-

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) at runtime.

+

It must be imported from the meta module:

+
+    import "meta" for Meta
+
+ +

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:

+
+/* module.wren */
+var M = 1
+
+ +

and then import it into this module:

+
+/* 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
+
+ +

the output when the latter module is run is:

+
+[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]
+
+ +

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:

+
+import "meta" for Meta
+
+var a = 2
+var b = 3
+var source = """
+  var c = a * b
+  System.print(c)
+"""
+Meta.eval(source)  //> 6
+
+ +

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:

+
+import "meta" for Meta
+
+var d = 4
+var e = 5
+var expression = "d * e"
+var closure = Meta.compileExpression(expression)
+System.print(closure.call()) //> 20
+
+ +

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:

+
+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]
+