mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-12 06:38:45 +01:00
Compare commits
4 Commits
0.4.0-pre
...
explicit-s
| Author | SHA1 | Date | |
|---|---|---|---|
| 10f149f359 | |||
| c3e2f17758 | |||
| 9df6aa2f8a | |||
| 2e425ae840 |
@ -9,29 +9,27 @@ import "io" for Stdin
|
||||
// animals. Internal nodes are yes/no questions that choose which branch to
|
||||
// explore.
|
||||
|
||||
class Node {
|
||||
// Reads a "yes" or "no" (or something approximating) those and returns true
|
||||
// if yes was entered.
|
||||
promptYesNo(prompt) {
|
||||
while (true) {
|
||||
var line = promptString(prompt)
|
||||
// Reads a "yes" or "no" (or something approximating) those and returns true
|
||||
// if yes was entered.
|
||||
def promptYesNo(prompt) {
|
||||
while (true) {
|
||||
var line = promptString(prompt)
|
||||
|
||||
if (line.startsWith("y") || line.startsWith("Y")) return true
|
||||
if (line.startsWith("n") || line.startsWith("N")) return false
|
||||
if (line.startsWith("y") || line.startsWith("Y")) return true
|
||||
if (line.startsWith("n") || line.startsWith("N")) return false
|
||||
|
||||
// Quit.
|
||||
if (line.startsWith("q") || line.startsWith("Q")) Fiber.yield()
|
||||
}
|
||||
}
|
||||
|
||||
// Writes a prompt and reads a string of input.
|
||||
promptString(prompt) {
|
||||
System.write("%(prompt) ")
|
||||
return Stdin.readLine()
|
||||
// Quit.
|
||||
if (line.startsWith("q") || line.startsWith("Q")) Fiber.yield()
|
||||
}
|
||||
}
|
||||
|
||||
class Animal is Node {
|
||||
// Writes a prompt and reads a string of input.
|
||||
def promptString(prompt) {
|
||||
System.write("%(prompt) ")
|
||||
return Stdin.readLine()
|
||||
}
|
||||
|
||||
class Animal {
|
||||
construct new(name) {
|
||||
_name = name
|
||||
}
|
||||
@ -56,7 +54,7 @@ class Animal is Node {
|
||||
}
|
||||
}
|
||||
|
||||
class Question is Node {
|
||||
class Question {
|
||||
construct new(question, ifYes, ifNo) {
|
||||
_question = question
|
||||
_ifYes = ifYes
|
||||
@ -83,4 +81,4 @@ var root = Question.new("Does it live in the water?",
|
||||
// Play games until the user quits.
|
||||
Fiber.new {
|
||||
while (true) root.ask()
|
||||
}.call()
|
||||
}()
|
||||
|
||||
@ -11,15 +11,15 @@ class SyntaxExample {
|
||||
// Top-level name `IO`
|
||||
System.print("I am a constructor!")
|
||||
|
||||
// Method calls
|
||||
variables
|
||||
fields()
|
||||
// This calls
|
||||
@variables
|
||||
@fields()
|
||||
|
||||
// Block arguments
|
||||
fields { block }
|
||||
fields {|a, b| block }
|
||||
fields(argument) { block }
|
||||
fields(argument) {|a, b| block }
|
||||
@fields { "block" }
|
||||
@fields {|a, b| "block" }
|
||||
@fields("argument") { "block" }
|
||||
@fields("argument") {|a, b| "block" }
|
||||
|
||||
// Static method call
|
||||
SyntaxExample.fields(1)
|
||||
@ -27,8 +27,8 @@ class SyntaxExample {
|
||||
|
||||
// Constructor with arguments
|
||||
construct constructor(a, b) {
|
||||
print(a, b)
|
||||
field = a
|
||||
@print(a, b)
|
||||
@field = a
|
||||
}
|
||||
|
||||
// Method without arguments
|
||||
|
||||
@ -4,14 +4,14 @@ foreign class File {
|
||||
static open(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
|
||||
open_(path, Fiber.current)
|
||||
@open_(path, Fiber.current)
|
||||
var fd = Scheduler.runNextScheduled_()
|
||||
return new_(fd)
|
||||
return @new_(fd)
|
||||
}
|
||||
|
||||
static open(path, fn) {
|
||||
var file = open(path)
|
||||
var fiber = Fiber.new { fn.call(file) }
|
||||
var file = @open(path)
|
||||
var fiber = Fiber.new { fn(file) }
|
||||
|
||||
// Poor man's finally. Can we make this more elegant?
|
||||
var result = fiber.try()
|
||||
@ -29,33 +29,33 @@ foreign class File {
|
||||
static size(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
|
||||
sizePath_(path, Fiber.current)
|
||||
@sizePath_(path, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
construct new_(fd) {}
|
||||
|
||||
close() {
|
||||
if (close_(Fiber.current)) return
|
||||
if (@close_(Fiber.current)) return
|
||||
Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
isOpen { descriptor != -1 }
|
||||
isOpen { @descriptor != -1 }
|
||||
|
||||
size {
|
||||
if (!isOpen) Fiber.abort("File is not open.")
|
||||
if (!@isOpen) Fiber.abort("File is not open.")
|
||||
|
||||
size_(Fiber.current)
|
||||
@size_(Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
readBytes(count) {
|
||||
if (!isOpen) Fiber.abort("File is not open.")
|
||||
if (!@isOpen) Fiber.abort("File is not open.")
|
||||
if (!(count is Num)) Fiber.abort("Count must be an integer.")
|
||||
if (!count.isInteger) Fiber.abort("Count must be an integer.")
|
||||
if (count < 0) Fiber.abort("Count cannot be negative.")
|
||||
|
||||
readBytes_(count, Fiber.current)
|
||||
@readBytes_(count, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
@ -75,19 +75,19 @@ class Stdin {
|
||||
}
|
||||
|
||||
// TODO: Error if other fiber is already waiting.
|
||||
readStart_()
|
||||
@readStart_()
|
||||
|
||||
__waitingFiber = Fiber.current
|
||||
var line = Scheduler.runNextScheduled_()
|
||||
|
||||
readStop_()
|
||||
@readStop_()
|
||||
return line
|
||||
}
|
||||
|
||||
static onData_(data) {
|
||||
if (data == null) {
|
||||
__isClosed = true
|
||||
readStop_()
|
||||
@readStop_()
|
||||
|
||||
if (__line != null) {
|
||||
var line = __line
|
||||
|
||||
@ -6,14 +6,14 @@ static const char* ioModuleSource =
|
||||
" static open(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
"\n"
|
||||
" open_(path, Fiber.current)\n"
|
||||
" @open_(path, Fiber.current)\n"
|
||||
" var fd = Scheduler.runNextScheduled_()\n"
|
||||
" return new_(fd)\n"
|
||||
" return @new_(fd)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static open(path, fn) {\n"
|
||||
" var file = open(path)\n"
|
||||
" var fiber = Fiber.new { fn.call(file) }\n"
|
||||
" var file = @open(path)\n"
|
||||
" var fiber = Fiber.new { fn(file) }\n"
|
||||
"\n"
|
||||
" // Poor man's finally. Can we make this more elegant?\n"
|
||||
" var result = fiber.try()\n"
|
||||
@ -31,33 +31,33 @@ static const char* ioModuleSource =
|
||||
" static size(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
"\n"
|
||||
" sizePath_(path, Fiber.current)\n"
|
||||
" @sizePath_(path, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" construct new_(fd) {}\n"
|
||||
"\n"
|
||||
" close() {\n"
|
||||
" if (close_(Fiber.current)) return\n"
|
||||
" if (@close_(Fiber.current)) return\n"
|
||||
" Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isOpen { descriptor != -1 }\n"
|
||||
" isOpen { @descriptor != -1 }\n"
|
||||
"\n"
|
||||
" size {\n"
|
||||
" if (!isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
" if (!@isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
"\n"
|
||||
" size_(Fiber.current)\n"
|
||||
" @size_(Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" readBytes(count) {\n"
|
||||
" if (!isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
" if (!@isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
" if (!(count is Num)) Fiber.abort(\"Count must be an integer.\")\n"
|
||||
" if (!count.isInteger) Fiber.abort(\"Count must be an integer.\")\n"
|
||||
" if (count < 0) Fiber.abort(\"Count cannot be negative.\")\n"
|
||||
"\n"
|
||||
" readBytes_(count, Fiber.current)\n"
|
||||
" @readBytes_(count, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
@ -77,19 +77,19 @@ static const char* ioModuleSource =
|
||||
" }\n"
|
||||
"\n"
|
||||
" // TODO: Error if other fiber is already waiting.\n"
|
||||
" readStart_()\n"
|
||||
" @readStart_()\n"
|
||||
"\n"
|
||||
" __waitingFiber = Fiber.current\n"
|
||||
" var line = Scheduler.runNextScheduled_()\n"
|
||||
"\n"
|
||||
" readStop_()\n"
|
||||
" @readStop_()\n"
|
||||
" return line\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static onData_(data) {\n"
|
||||
" if (data == null) {\n"
|
||||
" __isClosed = true\n"
|
||||
" readStop_()\n"
|
||||
" @readStop_()\n"
|
||||
"\n"
|
||||
" if (__line != null) {\n"
|
||||
" var line = __line\n"
|
||||
|
||||
@ -3,8 +3,8 @@ class Scheduler {
|
||||
if (__scheduled == null) __scheduled = []
|
||||
|
||||
__scheduled.add(Fiber.new {
|
||||
callable.call()
|
||||
runNextScheduled_()
|
||||
callable()
|
||||
@runNextScheduled_()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,8 @@ static const char* schedulerModuleSource =
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
"\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" runNextScheduled_()\n"
|
||||
" callable()\n"
|
||||
" @runNextScheduled_()\n"
|
||||
" })\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
|
||||
@ -5,7 +5,7 @@ class Timer {
|
||||
if (!(milliseconds is Num)) Fiber.abort("Milliseconds must be a number.")
|
||||
if (milliseconds < 0) Fiber.abort("Milliseconds cannot be negative.")
|
||||
|
||||
startTimer_(milliseconds, Fiber.current)
|
||||
@startTimer_(milliseconds, Fiber.current)
|
||||
Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ static const char* timerModuleSource =
|
||||
" if (!(milliseconds is Num)) Fiber.abort(\"Milliseconds must be a number.\")\n"
|
||||
" if (milliseconds < 0) Fiber.abort(\"Milliseconds cannot be negative.\")\n"
|
||||
"\n"
|
||||
" startTimer_(milliseconds, Fiber.current)\n"
|
||||
" @startTimer_(milliseconds, Fiber.current)\n"
|
||||
" Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
|
||||
@ -2,11 +2,11 @@ class Meta {
|
||||
static eval(source) {
|
||||
if (!(source is String)) Fiber.abort("Source code must be a string.")
|
||||
|
||||
var fn = compile_(source)
|
||||
var fn = @compile_(source)
|
||||
// TODO: Include compile errors.
|
||||
if (fn == null) Fiber.abort("Could not compile source code.")
|
||||
|
||||
Fiber.new(fn).call()
|
||||
Fiber.new(fn)()
|
||||
}
|
||||
|
||||
foreign static compile_(source)
|
||||
|
||||
@ -4,11 +4,11 @@ static const char* metaModuleSource =
|
||||
" static eval(source) {\n"
|
||||
" if (!(source is String)) Fiber.abort(\"Source code must be a string.\")\n"
|
||||
"\n"
|
||||
" var fn = compile_(source)\n"
|
||||
" var fn = @compile_(source)\n"
|
||||
" // TODO: Include compile errors.\n"
|
||||
" if (fn == null) Fiber.abort(\"Could not compile source code.\")\n"
|
||||
"\n"
|
||||
" Fiber.new(fn).call()\n"
|
||||
" Fiber.new(fn)()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static compile_(source)\n"
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
foreign class Random {
|
||||
construct new() {
|
||||
seed_()
|
||||
@seed_()
|
||||
}
|
||||
|
||||
construct new(seed) {
|
||||
if (seed is Num) {
|
||||
seed_(seed)
|
||||
@seed_(seed)
|
||||
} else if (seed is Sequence) {
|
||||
if (seed.isEmpty) Fiber.abort("Sequence cannot be empty.")
|
||||
|
||||
@ -25,7 +25,7 @@ foreign class Random {
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
seed_(
|
||||
@seed_(
|
||||
seeds[0], seeds[1], seeds[2], seeds[3],
|
||||
seeds[4], seeds[5], seeds[6], seeds[7],
|
||||
seeds[8], seeds[9], seeds[10], seeds[11],
|
||||
@ -40,10 +40,10 @@ foreign class Random {
|
||||
foreign seed_(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16)
|
||||
|
||||
foreign float()
|
||||
float(end) { float() * end }
|
||||
float(start, end) { float() * (end - start) + start }
|
||||
float(end) { @float() * end }
|
||||
float(start, end) { @float() * (end - start) + start }
|
||||
|
||||
foreign int()
|
||||
int(end) { (float() * end).floor }
|
||||
int(start, end) { (float() * (end - start)).floor + start }
|
||||
int(end) { (@float() * end).floor }
|
||||
int(start, end) { (@float() * (end - start)).floor + start }
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@
|
||||
static const char* randomModuleSource =
|
||||
"foreign class Random {\n"
|
||||
" construct new() {\n"
|
||||
" seed_()\n"
|
||||
" @seed_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" construct new(seed) {\n"
|
||||
" if (seed is Num) {\n"
|
||||
" seed_(seed)\n"
|
||||
" @seed_(seed)\n"
|
||||
" } else if (seed is Sequence) {\n"
|
||||
" if (seed.isEmpty) Fiber.abort(\"Sequence cannot be empty.\")\n"
|
||||
"\n"
|
||||
@ -27,7 +27,7 @@ static const char* randomModuleSource =
|
||||
" i = i + 1\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" seed_(\n"
|
||||
" @seed_(\n"
|
||||
" seeds[0], seeds[1], seeds[2], seeds[3],\n"
|
||||
" seeds[4], seeds[5], seeds[6], seeds[7],\n"
|
||||
" seeds[8], seeds[9], seeds[10], seeds[11],\n"
|
||||
@ -42,10 +42,10 @@ static const char* randomModuleSource =
|
||||
" foreign seed_(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16)\n"
|
||||
"\n"
|
||||
" foreign float()\n"
|
||||
" float(end) { float() * end }\n"
|
||||
" float(start, end) { float() * (end - start) + start }\n"
|
||||
" float(end) { @float() * end }\n"
|
||||
" float(start, end) { @float() * (end - start) + start }\n"
|
||||
"\n"
|
||||
" foreign int()\n"
|
||||
" int(end) { (float() * end).floor }\n"
|
||||
" int(start, end) { (float() * (end - start)).floor + start }\n"
|
||||
" int(end) { (@float() * end).floor }\n"
|
||||
" int(start, end) { (@float() * (end - start)).floor + start }\n"
|
||||
"}\n";
|
||||
|
||||
@ -69,6 +69,7 @@ typedef enum
|
||||
TOKEN_BANG,
|
||||
TOKEN_TILDE,
|
||||
TOKEN_QUESTION,
|
||||
TOKEN_AT,
|
||||
TOKEN_EQ,
|
||||
TOKEN_LT,
|
||||
TOKEN_GT,
|
||||
@ -80,6 +81,7 @@ typedef enum
|
||||
TOKEN_BREAK,
|
||||
TOKEN_CLASS,
|
||||
TOKEN_CONSTRUCT,
|
||||
TOKEN_DEF,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FOR,
|
||||
@ -489,6 +491,7 @@ static Keyword keywords[] =
|
||||
{"break", 5, TOKEN_BREAK},
|
||||
{"class", 5, TOKEN_CLASS},
|
||||
{"construct", 9, TOKEN_CONSTRUCT},
|
||||
{"def", 3, TOKEN_DEF},
|
||||
{"else", 4, TOKEN_ELSE},
|
||||
{"false", 5, TOKEN_FALSE},
|
||||
{"for", 3, TOKEN_FOR},
|
||||
@ -886,6 +889,7 @@ static void nextToken(Parser* parser)
|
||||
case '-': makeToken(parser, TOKEN_MINUS); return;
|
||||
case '~': makeToken(parser, TOKEN_TILDE); return;
|
||||
case '?': makeToken(parser, TOKEN_QUESTION); return;
|
||||
case '@': makeToken(parser, TOKEN_AT); return;
|
||||
|
||||
case '|': twoCharToken(parser, '|', TOKEN_PIPEPIPE, TOKEN_PIPE); return;
|
||||
case '&': twoCharToken(parser, '&', TOKEN_AMPAMP, TOKEN_AMP); return;
|
||||
@ -1292,26 +1296,19 @@ static int addUpvalue(Compiler* compiler, bool isLocal, int index)
|
||||
return compiler->numUpvalues++;
|
||||
}
|
||||
|
||||
// Attempts to look up [name] in the functions enclosing the one being compiled
|
||||
// by [compiler]. If found, it adds an upvalue for it to this compiler's list
|
||||
// of upvalues (unless it's already in there) and returns its index. If not
|
||||
// found, returns -1.
|
||||
// Attempts to look up [name] in the local scopes enclosing the current one.
|
||||
// If found, it adds an upvalue for it to this compiler's list of upvalues
|
||||
// (unless it's already in there) and returns its index. If not found, returns
|
||||
// -1.
|
||||
//
|
||||
// If the name is found outside of the immediately enclosing function, this
|
||||
// will flatten the closure and add upvalues to all of the intermediate
|
||||
// functions so that it gets walked down to this one.
|
||||
//
|
||||
// If it reaches a method boundary, this stops and returns -1 since methods do
|
||||
// not close over local variables.
|
||||
static int findUpvalue(Compiler* compiler, const char* name, int length)
|
||||
{
|
||||
// If we are at the top level, we didn't find it.
|
||||
if (compiler->parent == NULL) return -1;
|
||||
|
||||
// If we hit the method boundary (and the name isn't a static field), then
|
||||
// stop looking for it. We'll instead treat it as a self send.
|
||||
if (name[0] != '_' && compiler->parent->enclosingClass != NULL) return -1;
|
||||
|
||||
// See if it's a local variable in the immediately enclosing function.
|
||||
int local = resolveLocal(compiler->parent, name, length);
|
||||
if (local != -1)
|
||||
@ -1340,42 +1337,48 @@ static int findUpvalue(Compiler* compiler, const char* name, int length)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Look up [name] in the current scope to see what name it is bound to. Returns
|
||||
// the index of the name either in local scope, or the enclosing function's
|
||||
// upvalue list. Does not search the module scope. Returns -1 if not found.
|
||||
// Look up [name] in the current stack of lexical scopes to see what variable
|
||||
// it refers to. Returns the index of the name either the current local scope,
|
||||
// the enclosing function's upvalue, or in module scope.
|
||||
//
|
||||
// Sets [loadInstruction] to the instruction needed to load the variable. Will
|
||||
// be [CODE_LOAD_LOCAL] or [CODE_LOAD_UPVALUE].
|
||||
static int resolveNonmodule(Compiler* compiler, const char* name, int length,
|
||||
Code* loadInstruction)
|
||||
{
|
||||
// Look it up in the local scopes. Look in reverse order so that the most
|
||||
// nested variable is found first and shadows outer ones.
|
||||
*loadInstruction = CODE_LOAD_LOCAL;
|
||||
int local = resolveLocal(compiler, name, length);
|
||||
if (local != -1) return local;
|
||||
|
||||
// If we got here, it's not a local, so lets see if we are closing over an
|
||||
// outer local.
|
||||
*loadInstruction = CODE_LOAD_UPVALUE;
|
||||
return findUpvalue(compiler, name, length);
|
||||
}
|
||||
|
||||
// Look up [name] in the current scope to see what name it is bound to. Returns
|
||||
// the index of the name either in module scope, local scope, or the enclosing
|
||||
// function's upvalue list. Returns -1 if not found.
|
||||
// If not found, implicitly declares a new module-level variable with the name,
|
||||
// assuming it's a forward reference to a variable that will be explicitly
|
||||
// defined later.
|
||||
//
|
||||
// Sets [loadInstruction] to the instruction needed to load the variable. Will
|
||||
// be one of [CODE_LOAD_LOCAL], [CODE_LOAD_UPVALUE], or [CODE_LOAD_MODULE_VAR].
|
||||
static int resolveName(Compiler* compiler, const char* name, int length,
|
||||
Code* loadInstruction)
|
||||
{
|
||||
int nonmodule = resolveNonmodule(compiler, name, length, loadInstruction);
|
||||
if (nonmodule != -1) return nonmodule;
|
||||
|
||||
// Look it up in the local scopes. Look in reverse order so that the most
|
||||
// nested variable is found first and shadows outer ones.
|
||||
*loadInstruction = CODE_LOAD_LOCAL;
|
||||
int local = resolveLocal(compiler, name, length);
|
||||
if (local != -1) return local;
|
||||
|
||||
// If we got here, it's not a local, so lets see if we are closing over an
|
||||
// outer local.
|
||||
*loadInstruction = CODE_LOAD_UPVALUE;
|
||||
int upvalue = findUpvalue(compiler, name, length);
|
||||
if (upvalue != -1) return upvalue;
|
||||
|
||||
// If all else fails, look at the module level.
|
||||
*loadInstruction = CODE_LOAD_MODULE_VAR;
|
||||
return wrenSymbolTableFind(&compiler->parser->module->variableNames,
|
||||
name, length);
|
||||
int module = wrenSymbolTableFind(&compiler->parser->module->variableNames,
|
||||
name, length);
|
||||
|
||||
// If it wasn't found, implicitly define a module-level variable.
|
||||
if (module == -1 && (length != 4 || memcmp(name, "this", 4) != 0))
|
||||
{
|
||||
// If it's a nonlocal name, implicitly define a module-level variable in
|
||||
// the hopes that we get a real definition later.
|
||||
module = wrenDeclareVariable(compiler->parser->vm, compiler->parser->module,
|
||||
name, length);
|
||||
|
||||
if (module == -2) error(compiler, "Too many module variables defined.");
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
static void loadLocal(Compiler* compiler, int slot)
|
||||
@ -1493,7 +1496,8 @@ typedef enum
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / %
|
||||
PREC_UNARY, // unary - ! ~
|
||||
PREC_CALL, // . () []
|
||||
PREC_CALL, // () [] {}
|
||||
PREC_METHOD, // .
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
||||
@ -1738,6 +1742,39 @@ static void finishArgumentList(Compiler* compiler, Signature* signature)
|
||||
ignoreNewlines(compiler);
|
||||
}
|
||||
|
||||
// Parses the rest of a block argument after the "{".
|
||||
static void finishBlockArgument(Compiler* compiler, Signature* signature)
|
||||
{
|
||||
// Include the block argument in the arity.
|
||||
signature->type = SIG_METHOD;
|
||||
signature->arity++;
|
||||
|
||||
Compiler fnCompiler;
|
||||
initCompiler(&fnCompiler, compiler->parser, compiler, true);
|
||||
|
||||
// Make a dummy signature to track the arity.
|
||||
Signature fnSignature = { "", 0, SIG_METHOD, 0 };
|
||||
|
||||
// Parse the parameter list, if any.
|
||||
if (match(compiler, TOKEN_PIPE))
|
||||
{
|
||||
finishParameterList(&fnCompiler, &fnSignature);
|
||||
consume(compiler, TOKEN_PIPE, "Expect '|' after function parameters.");
|
||||
}
|
||||
|
||||
fnCompiler.numParams = fnSignature.arity;
|
||||
|
||||
finishBody(&fnCompiler, false);
|
||||
|
||||
// Name the function based on the method its passed to.
|
||||
char blockName[MAX_METHOD_SIGNATURE + 15];
|
||||
int blockLength;
|
||||
signatureToString(signature, blockName, &blockLength);
|
||||
memmove(blockName + blockLength, " block argument", 16);
|
||||
|
||||
endCompiler(&fnCompiler, blockName, blockLength + 15);
|
||||
}
|
||||
|
||||
// Compiles a method call with [signature] using [instruction].
|
||||
static void callSignature(Compiler* compiler, Code instruction,
|
||||
Signature* signature)
|
||||
@ -1789,37 +1826,10 @@ static void methodCall(Compiler* compiler, Code instruction,
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after arguments.");
|
||||
}
|
||||
|
||||
// Parse the block argument, if any.
|
||||
// Parse an optional block argument.
|
||||
if (match(compiler, TOKEN_LEFT_BRACE))
|
||||
{
|
||||
// Include the block argument in the arity.
|
||||
called.type = SIG_METHOD;
|
||||
called.arity++;
|
||||
|
||||
Compiler fnCompiler;
|
||||
initCompiler(&fnCompiler, compiler->parser, compiler, true);
|
||||
|
||||
// Make a dummy signature to track the arity.
|
||||
Signature fnSignature = { "", 0, SIG_METHOD, 0 };
|
||||
|
||||
// Parse the parameter list, if any.
|
||||
if (match(compiler, TOKEN_PIPE))
|
||||
{
|
||||
finishParameterList(&fnCompiler, &fnSignature);
|
||||
consume(compiler, TOKEN_PIPE, "Expect '|' after function parameters.");
|
||||
}
|
||||
|
||||
fnCompiler.numParams = fnSignature.arity;
|
||||
|
||||
finishBody(&fnCompiler, false);
|
||||
|
||||
// Name the function based on the method its passed to.
|
||||
char blockName[MAX_METHOD_SIGNATURE + 15];
|
||||
int blockLength;
|
||||
signatureToString(&called, blockName, &blockLength);
|
||||
memmove(blockName + blockLength, " block argument", 16);
|
||||
|
||||
endCompiler(&fnCompiler, blockName, blockLength + 15);
|
||||
finishBlockArgument(compiler, &called);
|
||||
}
|
||||
|
||||
// TODO: Allow Grace-style mixfix methods?
|
||||
@ -1872,7 +1882,7 @@ static void namedCall(Compiler* compiler, bool allowAssignment,
|
||||
static void loadThis(Compiler* compiler)
|
||||
{
|
||||
Code loadInstruction;
|
||||
int index = resolveNonmodule(compiler, "this", 4, &loadInstruction);
|
||||
int index = resolveName(compiler, "this", 4, &loadInstruction);
|
||||
if (loadInstruction == CODE_LOAD_LOCAL)
|
||||
{
|
||||
loadLocal(compiler, index);
|
||||
@ -1899,6 +1909,30 @@ static void grouping(Compiler* compiler, bool allowAssignment)
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
||||
}
|
||||
|
||||
static void call(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// An infix parenthesized call is syntax sugar for invoking the "call" method
|
||||
// on the left-hand side.
|
||||
Signature signature = { "call", 4, SIG_METHOD, 0 };
|
||||
|
||||
// Allow empty an argument list.
|
||||
if (peek(compiler) != TOKEN_RIGHT_PAREN)
|
||||
{
|
||||
// Parse the argument list.
|
||||
finishArgumentList(compiler, &signature);
|
||||
}
|
||||
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after arguments.");
|
||||
|
||||
// Parse an optional block argument.
|
||||
if (match(compiler, TOKEN_LEFT_BRACE))
|
||||
{
|
||||
finishBlockArgument(compiler, &signature);
|
||||
}
|
||||
|
||||
callSignature(compiler, CODE_CALL_0, &signature);
|
||||
}
|
||||
|
||||
// A list literal.
|
||||
static void list(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
@ -1955,6 +1989,16 @@ static void map(Compiler* compiler, bool allowAssignment)
|
||||
consume(compiler, TOKEN_RIGHT_BRACE, "Expect '}' after map entries.");
|
||||
}
|
||||
|
||||
// A block argument call on an expression receiver like `fn { block }`.
|
||||
static void blockArgument(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// An infix block argument call is syntax sugar for invoking the "call"
|
||||
// method on the left-hand side.
|
||||
Signature signature = { "call", 4, SIG_METHOD, 0 };
|
||||
finishBlockArgument(compiler, &signature);
|
||||
callSignature(compiler, CODE_CALL_0, &signature);
|
||||
}
|
||||
|
||||
// Unary operators like `-foo`.
|
||||
static void unaryOp(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
@ -1996,6 +2040,17 @@ static ClassCompiler* getEnclosingClass(Compiler* compiler)
|
||||
return compiler == NULL ? NULL : compiler->enclosingClass;
|
||||
}
|
||||
|
||||
// Returns `true` if the compiler is currently inside a class definition.
|
||||
//
|
||||
// Otherwise, reports an error and returns `false`.
|
||||
static bool ensureInsideClass(Compiler* compiler, const char* syntax)
|
||||
{
|
||||
if (getEnclosingClass(compiler) != NULL) return true;
|
||||
|
||||
error(compiler, "Cannot use '%s' outside of a class definition.", syntax);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void field(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// Initialize it with a fake value so we can keep parsing and minimize the
|
||||
@ -2133,68 +2188,15 @@ static void staticField(Compiler* compiler, bool allowAssignment)
|
||||
variable(compiler, allowAssignment, index, loadInstruction);
|
||||
}
|
||||
|
||||
// Returns `true` if [name] is a local variable name (starts with a lowercase
|
||||
// letter).
|
||||
static bool isLocalName(const char* name)
|
||||
{
|
||||
return name[0] >= 'a' && name[0] <= 'z';
|
||||
}
|
||||
|
||||
// Compiles a variable name or method call with an implicit receiver.
|
||||
// Compiles a reference to a lexically scoped variable name.
|
||||
static void name(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
// Look for the name in the scope chain up to the nearest enclosing method.
|
||||
Token* token = &compiler->parser->previous;
|
||||
|
||||
Code loadInstruction;
|
||||
int index = resolveNonmodule(compiler, token->start, token->length,
|
||||
&loadInstruction);
|
||||
if (index != -1)
|
||||
{
|
||||
variable(compiler, allowAssignment, index, loadInstruction);
|
||||
return;
|
||||
}
|
||||
int index = resolveName(compiler, token->start, token->length,
|
||||
&loadInstruction);
|
||||
|
||||
// TODO: The fact that we return above here if the variable is known and parse
|
||||
// an optional argument list below if not means that the grammar is not
|
||||
// context-free. A line of code in a method like "someName(foo)" is a parse
|
||||
// error if "someName" is a defined variable in the surrounding scope and not
|
||||
// if it isn't. Fix this. One option is to have "someName(foo)" always
|
||||
// resolve to a self-call if there is an argument list, but that makes
|
||||
// getters a little confusing.
|
||||
|
||||
// If we're inside a method and the name is lowercase, treat it as a method
|
||||
// on this.
|
||||
if (isLocalName(token->start) && getEnclosingClass(compiler) != NULL)
|
||||
{
|
||||
loadThis(compiler);
|
||||
namedCall(compiler, allowAssignment, CODE_CALL_0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, look for a module-level variable with the name.
|
||||
int module = wrenSymbolTableFind(&compiler->parser->module->variableNames,
|
||||
token->start, token->length);
|
||||
if (module == -1)
|
||||
{
|
||||
if (isLocalName(token->start))
|
||||
{
|
||||
error(compiler, "Undefined variable.");
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a nonlocal name, implicitly define a module-level variable in
|
||||
// the hopes that we get a real definition later.
|
||||
module = wrenDeclareVariable(compiler->parser->vm, compiler->parser->module,
|
||||
token->start, token->length);
|
||||
|
||||
if (module == -2)
|
||||
{
|
||||
error(compiler, "Too many module variables defined.");
|
||||
}
|
||||
}
|
||||
|
||||
variable(compiler, allowAssignment, module, CODE_LOAD_MODULE_VAR);
|
||||
variable(compiler, allowAssignment, index, loadInstruction);
|
||||
}
|
||||
|
||||
static void null(Compiler* compiler, bool allowAssignment)
|
||||
@ -2280,12 +2282,7 @@ static void super_(Compiler* compiler, bool allowAssignment)
|
||||
|
||||
static void this_(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
if (getEnclosingClass(compiler) == NULL)
|
||||
{
|
||||
error(compiler, "Cannot use 'this' outside of a method.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ensureInsideClass(compiler, "this")) return;
|
||||
loadThis(compiler);
|
||||
}
|
||||
|
||||
@ -2312,7 +2309,7 @@ static void subscript(Compiler* compiler, bool allowAssignment)
|
||||
callSignature(compiler, CODE_CALL_0, &signature);
|
||||
}
|
||||
|
||||
static void call(Compiler* compiler, bool allowAssignment)
|
||||
static void dot(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
ignoreNewlines(compiler);
|
||||
consume(compiler, TOKEN_NAME, "Expect method name after '.'.");
|
||||
@ -2366,6 +2363,18 @@ static void conditional(Compiler* compiler, bool allowAssignment)
|
||||
patchJump(compiler, elseJump);
|
||||
}
|
||||
|
||||
// A method call on this like "@method()".
|
||||
static void thisCall(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
if (!ensureInsideClass(compiler, "@")) return;
|
||||
|
||||
loadThis(compiler);
|
||||
consume(compiler, TOKEN_NAME, "Expect method name after '@'.");
|
||||
namedCall(compiler, allowAssignment, CODE_CALL_0);
|
||||
|
||||
// TODO: Infix and subscript operators?
|
||||
}
|
||||
|
||||
void infixOp(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
GrammarRule* rule = getRule(compiler->parser->previous.type);
|
||||
@ -2531,14 +2540,14 @@ void constructorSignature(Compiler* compiler, Signature* signature)
|
||||
|
||||
GrammarRule rules[] =
|
||||
{
|
||||
/* TOKEN_LEFT_PAREN */ PREFIX(grouping),
|
||||
/* TOKEN_LEFT_PAREN */ { grouping, call, NULL, PREC_CALL, NULL },
|
||||
/* TOKEN_RIGHT_PAREN */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACKET */ { list, subscript, subscriptSignature, PREC_CALL, NULL },
|
||||
/* TOKEN_RIGHT_BRACKET */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACE */ PREFIX(map),
|
||||
/* TOKEN_LEFT_BRACE */ { map, blockArgument, NULL, PREC_CALL, NULL },
|
||||
/* TOKEN_RIGHT_BRACE */ UNUSED,
|
||||
/* TOKEN_COLON */ UNUSED,
|
||||
/* TOKEN_DOT */ INFIX(PREC_CALL, call),
|
||||
/* TOKEN_DOT */ INFIX(PREC_METHOD, dot),
|
||||
/* TOKEN_DOTDOT */ INFIX_OPERATOR(PREC_RANGE, ".."),
|
||||
/* TOKEN_DOTDOTDOT */ INFIX_OPERATOR(PREC_RANGE, "..."),
|
||||
/* TOKEN_COMMA */ UNUSED,
|
||||
@ -2557,6 +2566,7 @@ GrammarRule rules[] =
|
||||
/* TOKEN_BANG */ PREFIX_OPERATOR("!"),
|
||||
/* TOKEN_TILDE */ PREFIX_OPERATOR("~"),
|
||||
/* TOKEN_QUESTION */ INFIX(PREC_ASSIGNMENT, conditional),
|
||||
/* TOKEN_AT */ PREFIX(thisCall),
|
||||
/* TOKEN_EQ */ UNUSED,
|
||||
/* TOKEN_LT */ INFIX_OPERATOR(PREC_COMPARISON, "<"),
|
||||
/* TOKEN_GT */ INFIX_OPERATOR(PREC_COMPARISON, ">"),
|
||||
@ -2567,6 +2577,7 @@ GrammarRule rules[] =
|
||||
/* TOKEN_BREAK */ UNUSED,
|
||||
/* TOKEN_CLASS */ UNUSED,
|
||||
/* TOKEN_CONSTRUCT */ { NULL, NULL, constructorSignature, PREC_NONE, NULL },
|
||||
/* TOKEN_DEF */ UNUSED,
|
||||
/* TOKEN_ELSE */ UNUSED,
|
||||
/* TOKEN_FALSE */ PREFIX(boolean),
|
||||
/* TOKEN_FOR */ UNUSED,
|
||||
@ -3164,7 +3175,7 @@ static void classDefinition(Compiler* compiler, bool isForeign)
|
||||
// Load the superclass (if there is one).
|
||||
if (match(compiler, TOKEN_IS))
|
||||
{
|
||||
parsePrecedence(compiler, false, PREC_CALL);
|
||||
parsePrecedence(compiler, false, PREC_METHOD);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3269,6 +3280,32 @@ static void import(Compiler* compiler)
|
||||
} while (match(compiler, TOKEN_COMMA));
|
||||
}
|
||||
|
||||
// Compiles a "def" function definition statement.
|
||||
static void functionDefinition(Compiler* compiler)
|
||||
{
|
||||
// Create a variable to store the function in.
|
||||
int slot = declareNamedVariable(compiler);
|
||||
Token name = compiler->parser->previous;
|
||||
|
||||
Compiler fnCompiler;
|
||||
initCompiler(&fnCompiler, compiler->parser, compiler, true);
|
||||
|
||||
// Make a dummy signature to track the arity.
|
||||
Signature signature = { "", 0, SIG_METHOD, 0 };
|
||||
|
||||
parameterList(&fnCompiler, &signature);
|
||||
|
||||
fnCompiler.numParams = signature.arity;
|
||||
|
||||
consume(compiler, TOKEN_LEFT_BRACE, "Expect '{' to begin function body.");
|
||||
finishBody(&fnCompiler, false);
|
||||
|
||||
// Use the function's declared name.
|
||||
endCompiler(&fnCompiler, name.start, name.length);
|
||||
|
||||
defineVariable(compiler, slot);
|
||||
}
|
||||
|
||||
// Compiles a "var" variable definition statement.
|
||||
static void variableDefinition(Compiler* compiler)
|
||||
{
|
||||
@ -3302,6 +3339,10 @@ void definition(Compiler* compiler)
|
||||
{
|
||||
classDefinition(compiler, false);
|
||||
}
|
||||
else if (match(compiler, TOKEN_DEF))
|
||||
{
|
||||
functionDefinition(compiler);
|
||||
}
|
||||
else if (match(compiler, TOKEN_FOREIGN))
|
||||
{
|
||||
consume(compiler, TOKEN_CLASS, "Expect 'class' after 'foreign'.");
|
||||
|
||||
@ -5,19 +5,19 @@ class Null {}
|
||||
class Num {}
|
||||
|
||||
class Sequence {
|
||||
all(f) {
|
||||
all(fn) {
|
||||
var result = true
|
||||
for (element in this) {
|
||||
result = f.call(element)
|
||||
result = fn(element)
|
||||
if (!result) return result
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
any(f) {
|
||||
any(fn) {
|
||||
var result = false
|
||||
for (element in this) {
|
||||
result = f.call(element)
|
||||
result = fn(element)
|
||||
if (result) return result
|
||||
}
|
||||
return result
|
||||
@ -38,54 +38,54 @@ class Sequence {
|
||||
return result
|
||||
}
|
||||
|
||||
count(f) {
|
||||
count(fn) {
|
||||
var result = 0
|
||||
for (element in this) {
|
||||
if (f.call(element)) result = result + 1
|
||||
if (fn(element)) result = result + 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
each(f) {
|
||||
each(fn) {
|
||||
for (element in this) {
|
||||
f.call(element)
|
||||
fn(element)
|
||||
}
|
||||
}
|
||||
|
||||
isEmpty { iterate(null) ? false : true }
|
||||
isEmpty { @iterate(null) ? false : true }
|
||||
|
||||
map(transformation) { MapSequence.new(this, transformation) }
|
||||
|
||||
where(predicate) { WhereSequence.new(this, predicate) }
|
||||
|
||||
reduce(acc, f) {
|
||||
reduce(accumulator, fn) {
|
||||
for (element in this) {
|
||||
acc = f.call(acc, element)
|
||||
accumulator = fn(accumulator, element)
|
||||
}
|
||||
return acc
|
||||
return accumulator
|
||||
}
|
||||
|
||||
reduce(f) {
|
||||
var iter = iterate(null)
|
||||
if (!iter) Fiber.abort("Can't reduce an empty sequence.")
|
||||
reduce(fn) {
|
||||
var iterator = @iterate(null)
|
||||
if (!iterator) Fiber.abort("Can't reduce an empty sequence.")
|
||||
|
||||
// Seed with the first element.
|
||||
var result = iteratorValue(iter)
|
||||
while (iter = iterate(iter)) {
|
||||
result = f.call(result, iteratorValue(iter))
|
||||
var result = @iteratorValue(iterator)
|
||||
while (iterator = @iterate(iterator)) {
|
||||
result = fn(result, @iteratorValue(iterator))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
join() { join("") }
|
||||
join() { @join("") }
|
||||
|
||||
join(sep) {
|
||||
join(separator) {
|
||||
var first = true
|
||||
var result = ""
|
||||
|
||||
for (element in this) {
|
||||
if (!first) result = result + sep
|
||||
if (!first) result = result + separator
|
||||
first = false
|
||||
result = result + element.toString
|
||||
}
|
||||
@ -109,7 +109,7 @@ class MapSequence is Sequence {
|
||||
}
|
||||
|
||||
iterate(iterator) { _sequence.iterate(iterator) }
|
||||
iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }
|
||||
iteratorValue(iterator) { _fn(_sequence.iteratorValue(iterator)) }
|
||||
}
|
||||
|
||||
class WhereSequence is Sequence {
|
||||
@ -120,7 +120,7 @@ class WhereSequence is Sequence {
|
||||
|
||||
iterate(iterator) {
|
||||
while (iterator = _sequence.iterate(iterator)) {
|
||||
if (_fn.call(_sequence.iteratorValue(iterator))) break
|
||||
if (_fn(_sequence.iteratorValue(iterator))) break
|
||||
}
|
||||
return iterator
|
||||
}
|
||||
@ -160,12 +160,12 @@ class StringCodePointSequence is Sequence {
|
||||
class List is Sequence {
|
||||
addAll(other) {
|
||||
for (element in other) {
|
||||
add(element)
|
||||
@add(element)
|
||||
}
|
||||
return other
|
||||
}
|
||||
|
||||
toString { "[%(join(", "))]" }
|
||||
toString { "[%(@join(", "))]" }
|
||||
|
||||
+(other) {
|
||||
var result = this[0..-1]
|
||||
@ -184,7 +184,7 @@ class Map {
|
||||
var first = true
|
||||
var result = "{"
|
||||
|
||||
for (key in keys) {
|
||||
for (key in @keys) {
|
||||
if (!first) result = result + ", "
|
||||
first = false
|
||||
result = result + "%(key): %(this[key])"
|
||||
@ -216,35 +216,35 @@ class Range is Sequence {}
|
||||
|
||||
class System {
|
||||
static print() {
|
||||
writeString_("\n")
|
||||
@writeString_("\n")
|
||||
}
|
||||
|
||||
static print(obj) {
|
||||
writeObject_(obj)
|
||||
writeString_("\n")
|
||||
return obj
|
||||
static print(object) {
|
||||
@writeObject_(object)
|
||||
@writeString_("\n")
|
||||
return object
|
||||
}
|
||||
|
||||
static printAll(sequence) {
|
||||
for (object in sequence) writeObject_(object)
|
||||
writeString_("\n")
|
||||
for (object in sequence) @writeObject_(object)
|
||||
@writeString_("\n")
|
||||
}
|
||||
|
||||
static write(obj) {
|
||||
writeObject_(obj)
|
||||
return obj
|
||||
static write(object) {
|
||||
@writeObject_(object)
|
||||
return object
|
||||
}
|
||||
|
||||
static writeAll(sequence) {
|
||||
for (object in sequence) writeObject_(object)
|
||||
for (object in sequence) @writeObject_(object)
|
||||
}
|
||||
|
||||
static writeObject_(obj) {
|
||||
var string = obj.toString
|
||||
static writeObject_(object) {
|
||||
var string = object.toString
|
||||
if (string is String) {
|
||||
writeString_(string)
|
||||
@writeString_(string)
|
||||
} else {
|
||||
writeString_("[invalid toString]")
|
||||
@writeString_("[invalid toString]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,19 +7,19 @@ static const char* coreModuleSource =
|
||||
"class Num {}\n"
|
||||
"\n"
|
||||
"class Sequence {\n"
|
||||
" all(f) {\n"
|
||||
" all(fn) {\n"
|
||||
" var result = true\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" result = fn(element)\n"
|
||||
" if (!result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" any(f) {\n"
|
||||
" any(fn) {\n"
|
||||
" var result = false\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" result = fn(element)\n"
|
||||
" if (result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
@ -40,54 +40,54 @@ static const char* coreModuleSource =
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" count(f) {\n"
|
||||
" count(fn) {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" if (f.call(element)) result = result + 1\n"
|
||||
" if (fn(element)) result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" each(f) {\n"
|
||||
" each(fn) {\n"
|
||||
" for (element in this) {\n"
|
||||
" f.call(element)\n"
|
||||
" fn(element)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" isEmpty { iterate(null) ? false : true }\n"
|
||||
" isEmpty { @iterate(null) ? false : true }\n"
|
||||
"\n"
|
||||
" map(transformation) { MapSequence.new(this, transformation) }\n"
|
||||
"\n"
|
||||
" where(predicate) { WhereSequence.new(this, predicate) }\n"
|
||||
"\n"
|
||||
" reduce(acc, f) {\n"
|
||||
" reduce(accumulator, fn) {\n"
|
||||
" for (element in this) {\n"
|
||||
" acc = f.call(acc, element)\n"
|
||||
" accumulator = fn(accumulator, element)\n"
|
||||
" }\n"
|
||||
" return acc\n"
|
||||
" return accumulator\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" reduce(f) {\n"
|
||||
" var iter = iterate(null)\n"
|
||||
" if (!iter) Fiber.abort(\"Can't reduce an empty sequence.\")\n"
|
||||
" reduce(fn) {\n"
|
||||
" var iterator = @iterate(null)\n"
|
||||
" if (!iterator) Fiber.abort(\"Can't reduce an empty sequence.\")\n"
|
||||
"\n"
|
||||
" // Seed with the first element.\n"
|
||||
" var result = iteratorValue(iter)\n"
|
||||
" while (iter = iterate(iter)) {\n"
|
||||
" result = f.call(result, iteratorValue(iter))\n"
|
||||
" var result = @iteratorValue(iterator)\n"
|
||||
" while (iterator = @iterate(iterator)) {\n"
|
||||
" result = fn(result, @iteratorValue(iterator))\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" join() { join(\"\") }\n"
|
||||
" join() { @join(\"\") }\n"
|
||||
"\n"
|
||||
" join(sep) {\n"
|
||||
" join(separator) {\n"
|
||||
" var first = true\n"
|
||||
" var result = \"\"\n"
|
||||
"\n"
|
||||
" for (element in this) {\n"
|
||||
" if (!first) result = result + sep\n"
|
||||
" if (!first) result = result + separator\n"
|
||||
" first = false\n"
|
||||
" result = result + element.toString\n"
|
||||
" }\n"
|
||||
@ -111,7 +111,7 @@ static const char* coreModuleSource =
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) { _sequence.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }\n"
|
||||
" iteratorValue(iterator) { _fn(_sequence.iteratorValue(iterator)) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class WhereSequence is Sequence {\n"
|
||||
@ -122,7 +122,7 @@ static const char* coreModuleSource =
|
||||
"\n"
|
||||
" iterate(iterator) {\n"
|
||||
" while (iterator = _sequence.iterate(iterator)) {\n"
|
||||
" if (_fn.call(_sequence.iteratorValue(iterator))) break\n"
|
||||
" if (_fn(_sequence.iteratorValue(iterator))) break\n"
|
||||
" }\n"
|
||||
" return iterator\n"
|
||||
" }\n"
|
||||
@ -162,12 +162,12 @@ static const char* coreModuleSource =
|
||||
"class List is Sequence {\n"
|
||||
" addAll(other) {\n"
|
||||
" for (element in other) {\n"
|
||||
" add(element)\n"
|
||||
" @add(element)\n"
|
||||
" }\n"
|
||||
" return other\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" toString { \"[%(join(\", \"))]\" }\n"
|
||||
" toString { \"[%(@join(\", \"))]\" }\n"
|
||||
"\n"
|
||||
" +(other) {\n"
|
||||
" var result = this[0..-1]\n"
|
||||
@ -186,7 +186,7 @@ static const char* coreModuleSource =
|
||||
" var first = true\n"
|
||||
" var result = \"{\"\n"
|
||||
"\n"
|
||||
" for (key in keys) {\n"
|
||||
" for (key in @keys) {\n"
|
||||
" if (!first) result = result + \", \"\n"
|
||||
" first = false\n"
|
||||
" result = result + \"%(key): %(this[key])\"\n"
|
||||
@ -218,35 +218,35 @@ 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"
|
||||
" return obj\n"
|
||||
" static print(object) {\n"
|
||||
" @writeObject_(object)\n"
|
||||
" @writeString_(\"\n\")\n"
|
||||
" return object\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static printAll(sequence) {\n"
|
||||
" for (object in sequence) writeObject_(object)\n"
|
||||
" writeString_(\"\n\")\n"
|
||||
" for (object in sequence) @writeObject_(object)\n"
|
||||
" @writeString_(\"\n\")\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static write(obj) {\n"
|
||||
" writeObject_(obj)\n"
|
||||
" return obj\n"
|
||||
" static write(object) {\n"
|
||||
" @writeObject_(object)\n"
|
||||
" return object\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static writeAll(sequence) {\n"
|
||||
" for (object in sequence) writeObject_(object)\n"
|
||||
" for (object in sequence) @writeObject_(object)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static writeObject_(obj) {\n"
|
||||
" var string = obj.toString\n"
|
||||
" static writeObject_(object) {\n"
|
||||
" var string = object.toString\n"
|
||||
" if (string is String) {\n"
|
||||
" writeString_(string)\n"
|
||||
" @writeString_(string)\n"
|
||||
" } else {\n"
|
||||
" writeString_(\"[invalid toString]\")\n"
|
||||
" @writeString_(\"[invalid toString]\")\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
@ -11,12 +11,9 @@ class Tree {
|
||||
}
|
||||
}
|
||||
|
||||
check {
|
||||
if (_left == null) {
|
||||
return _item
|
||||
}
|
||||
|
||||
return _item + _left.check - _right.check
|
||||
check() {
|
||||
if (_left == null) return _item
|
||||
return _item + _left.check() - _right.check()
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +24,7 @@ var stretchDepth = maxDepth + 1
|
||||
var start = System.clock
|
||||
|
||||
System.print("stretch tree of depth %(stretchDepth) check: " +
|
||||
"%(Tree.new(0, stretchDepth).check)")
|
||||
"%(Tree.new(0, stretchDepth).check())")
|
||||
|
||||
var longLivedTree = Tree.new(0, maxDepth)
|
||||
|
||||
@ -41,7 +38,7 @@ var depth = minDepth
|
||||
while (depth < stretchDepth) {
|
||||
var check = 0
|
||||
for (i in 1..iterations) {
|
||||
check = check + Tree.new(i, depth).check + Tree.new(-i, depth).check
|
||||
check = check + Tree.new(i, depth).check() + Tree.new(-i, depth).check()
|
||||
}
|
||||
|
||||
System.print("%(iterations * 2) trees of depth %(depth) check: %(check)")
|
||||
@ -50,5 +47,5 @@ while (depth < stretchDepth) {
|
||||
}
|
||||
|
||||
System.print(
|
||||
"long lived tree of depth %(maxDepth) check: %(longLivedTree.check)")
|
||||
"long lived tree of depth %(maxDepth) check: %(longLivedTree.check())")
|
||||
System.print("elapsed: %(System.clock - start)")
|
||||
|
||||
@ -79,7 +79,7 @@ class Constraint {
|
||||
|
||||
// Activate this constraint and attempt to satisfy it.
|
||||
addConstraint() {
|
||||
addToGraph()
|
||||
@addToGraph()
|
||||
ThePlanner.incrementalAdd(this)
|
||||
}
|
||||
|
||||
@ -89,16 +89,16 @@ class Constraint {
|
||||
// there is one, or nil, if there isn't.
|
||||
// Assume: I am not already satisfied.
|
||||
satisfy(mark) {
|
||||
chooseMethod(mark)
|
||||
if (!isSatisfied) {
|
||||
@chooseMethod(mark)
|
||||
if (!@isSatisfied) {
|
||||
if (_strength == REQUIRED) {
|
||||
System.print("Could not satisfy a required constraint!")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
markInputs(mark)
|
||||
var out = output
|
||||
@markInputs(mark)
|
||||
var out = @output
|
||||
var overridden = out.determinedBy
|
||||
if (overridden != null) overridden.markUnsatisfied()
|
||||
out.determinedBy = this
|
||||
@ -108,8 +108,8 @@ class Constraint {
|
||||
}
|
||||
|
||||
destroyConstraint() {
|
||||
if (isSatisfied) ThePlanner.incrementalRemove(this)
|
||||
removeFromGraph()
|
||||
if (@isSatisfied) ThePlanner.incrementalRemove(this)
|
||||
@removeFromGraph()
|
||||
}
|
||||
|
||||
// Normal constraints are not input constraints. An input constraint
|
||||
@ -124,7 +124,7 @@ class UnaryConstraint is Constraint {
|
||||
super(strength)
|
||||
_satisfied = false
|
||||
_myOutput = myOutput
|
||||
addConstraint()
|
||||
@addConstraint()
|
||||
}
|
||||
|
||||
// Adds this constraint to the constraint graph.
|
||||
@ -136,7 +136,7 @@ class UnaryConstraint is Constraint {
|
||||
// Decides if this constraint can be satisfied and records that decision.
|
||||
chooseMethod(mark) {
|
||||
_satisfied = (_myOutput.mark != mark) &&
|
||||
Strength.stronger(strength, _myOutput.walkStrength)
|
||||
Strength.stronger(@strength, _myOutput.walkStrength)
|
||||
}
|
||||
|
||||
// Returns true if this constraint is satisfied in the current solution.
|
||||
@ -153,9 +153,9 @@ class UnaryConstraint is Constraint {
|
||||
// 'stay', the value for the current output of this constraint. Assume
|
||||
// this constraint is satisfied.
|
||||
recalculate() {
|
||||
_myOutput.walkStrength = strength
|
||||
_myOutput.stay = !isInput
|
||||
if (_myOutput.stay) execute() // Stay optimization.
|
||||
_myOutput.walkStrength = @strength
|
||||
_myOutput.stay = !@isInput
|
||||
if (_myOutput.stay) @execute() // Stay optimization.
|
||||
}
|
||||
|
||||
// Records that this constraint is unsatisfied.
|
||||
@ -213,7 +213,7 @@ class BinaryConstraint is Constraint {
|
||||
_v1 = v1
|
||||
_v2 = v2
|
||||
_direction = NONE
|
||||
addConstraint()
|
||||
@addConstraint()
|
||||
}
|
||||
|
||||
direction { _direction }
|
||||
@ -226,7 +226,7 @@ class BinaryConstraint is Constraint {
|
||||
chooseMethod(mark) {
|
||||
if (_v1.mark == mark) {
|
||||
if (_v2.mark != mark &&
|
||||
Strength.stronger(strength, _v2.walkStrength)) {
|
||||
Strength.stronger(@strength, _v2.walkStrength)) {
|
||||
_direction = FORWARD
|
||||
} else {
|
||||
_direction = NONE
|
||||
@ -235,7 +235,7 @@ class BinaryConstraint is Constraint {
|
||||
|
||||
if (_v2.mark == mark) {
|
||||
if (_v1.mark != mark &&
|
||||
Strength.stronger(strength, _v1.walkStrength)) {
|
||||
Strength.stronger(@strength, _v1.walkStrength)) {
|
||||
_direction = BACKWARD
|
||||
} else {
|
||||
_direction = NONE
|
||||
@ -243,13 +243,13 @@ class BinaryConstraint is Constraint {
|
||||
}
|
||||
|
||||
if (Strength.weaker(_v1.walkStrength, _v2.walkStrength)) {
|
||||
if (Strength.stronger(strength, _v1.walkStrength)) {
|
||||
if (Strength.stronger(@strength, _v1.walkStrength)) {
|
||||
_direction = BACKWARD
|
||||
} else {
|
||||
_direction = NONE
|
||||
}
|
||||
} else {
|
||||
if (Strength.stronger(strength, _v2.walkStrength)) {
|
||||
if (Strength.stronger(@strength, _v2.walkStrength)) {
|
||||
_direction = FORWARD
|
||||
} else {
|
||||
_direction = BACKWARD
|
||||
@ -269,7 +269,7 @@ class BinaryConstraint is Constraint {
|
||||
|
||||
// Mark the input variable with the given mark.
|
||||
markInputs(mark) {
|
||||
input.mark = mark
|
||||
@input.mark = mark
|
||||
}
|
||||
|
||||
// Returns the current input variable
|
||||
@ -282,11 +282,11 @@ class BinaryConstraint is Constraint {
|
||||
// 'stay', the value for the current output of this
|
||||
// constraint. Assume this constraint is satisfied.
|
||||
recalculate() {
|
||||
var ihn = input
|
||||
var out = output
|
||||
out.walkStrength = Strength.weakest(strength, ihn.walkStrength)
|
||||
var ihn = @input
|
||||
var out = @output
|
||||
out.walkStrength = Strength.weakest(@strength, ihn.walkStrength)
|
||||
out.stay = ihn.stay
|
||||
if (out.stay) execute()
|
||||
if (out.stay) @execute()
|
||||
}
|
||||
|
||||
// Record the fact that this constraint is unsatisfied.
|
||||
@ -295,7 +295,7 @@ class BinaryConstraint is Constraint {
|
||||
}
|
||||
|
||||
inputsKnown(mark) {
|
||||
var i = input
|
||||
var i = @input
|
||||
return i.mark == mark || i.stay || i.determinedBy == null
|
||||
}
|
||||
|
||||
@ -337,11 +337,11 @@ class ScaleConstraint is BinaryConstraint {
|
||||
|
||||
// Enforce this constraint. Assume that it is satisfied.
|
||||
execute() {
|
||||
if (direction == FORWARD) {
|
||||
v2.value = v1.value * _scale.value + _offset.value
|
||||
if (@direction == FORWARD) {
|
||||
@v2.value = @v1.value * _scale.value + _offset.value
|
||||
} else {
|
||||
// TODO: Is this the same semantics as ~/?
|
||||
v1.value = ((v2.value - _offset.value) / _scale.value).floor
|
||||
@v1.value = ((@v2.value - _offset.value) / _scale.value).floor
|
||||
}
|
||||
}
|
||||
|
||||
@ -349,11 +349,11 @@ class ScaleConstraint is BinaryConstraint {
|
||||
// 'stay', the value for the current output of this constraint. Assume
|
||||
// this constraint is satisfied.
|
||||
recalculate() {
|
||||
var ihn = input
|
||||
var out = output
|
||||
out.walkStrength = Strength.weakest(strength, ihn.walkStrength)
|
||||
var ihn = @input
|
||||
var out = @output
|
||||
out.walkStrength = Strength.weakest(@strength, ihn.walkStrength)
|
||||
out.stay = ihn.stay && _scale.stay && _offset.stay
|
||||
if (out.stay) execute()
|
||||
if (out.stay) @execute()
|
||||
}
|
||||
}
|
||||
|
||||
@ -365,7 +365,7 @@ class EqualityConstraint is BinaryConstraint {
|
||||
|
||||
// Enforce this constraint. Assume that it is satisfied.
|
||||
execute() {
|
||||
output.value = input.value
|
||||
@output.value = @input.value
|
||||
}
|
||||
}
|
||||
|
||||
@ -448,7 +448,7 @@ class Planner {
|
||||
// the algorithm to avoid getting into an infinite loop even if the
|
||||
// constraint graph has an inadvertent cycle.
|
||||
incrementalAdd(constraint) {
|
||||
var mark = newMark()
|
||||
var mark = @newMark()
|
||||
var overridden = constraint.satisfy(mark)
|
||||
while (overridden != null) {
|
||||
overridden = overridden.satisfy(mark)
|
||||
@ -468,11 +468,11 @@ class Planner {
|
||||
var out = constraint.output
|
||||
constraint.markUnsatisfied()
|
||||
constraint.removeFromGraph()
|
||||
var unsatisfied = removePropagateFrom(out)
|
||||
var unsatisfied = @removePropagateFrom(out)
|
||||
var strength = REQUIRED
|
||||
while (true) {
|
||||
for (u in unsatisfied) {
|
||||
if (u.strength == strength) incrementalAdd(u)
|
||||
if (u.strength == strength) @incrementalAdd(u)
|
||||
}
|
||||
strength = strength.nextWeaker
|
||||
if (strength == WEAKEST) break
|
||||
@ -500,7 +500,7 @@ class Planner {
|
||||
// any constraint.
|
||||
// Assume: [sources] are all satisfied.
|
||||
makePlan(sources) {
|
||||
var mark = newMark()
|
||||
var mark = @newMark()
|
||||
var plan = Plan.new()
|
||||
var todo = sources
|
||||
while (todo.count > 0) {
|
||||
@ -508,7 +508,7 @@ class Planner {
|
||||
if (constraint.output.mark != mark && constraint.inputsKnown(mark)) {
|
||||
plan.addConstraint(constraint)
|
||||
constraint.output.mark = mark
|
||||
addConstraintsConsumingTo(constraint.output, todo)
|
||||
@addConstraintsConsumingTo(constraint.output, todo)
|
||||
}
|
||||
}
|
||||
return plan
|
||||
@ -522,7 +522,7 @@ class Planner {
|
||||
// if not in plan already and eligible for inclusion.
|
||||
if (constraint.isInput && constraint.isSatisfied) sources.add(constraint)
|
||||
}
|
||||
return makePlan(sources)
|
||||
return @makePlan(sources)
|
||||
}
|
||||
|
||||
// Recompute the walkabout strengths and stay flags of all variables
|
||||
@ -541,12 +541,12 @@ class Planner {
|
||||
while (todo.count > 0) {
|
||||
var d = todo.removeAt(-1)
|
||||
if (d.output.mark == mark) {
|
||||
incrementalRemove(constraint)
|
||||
@incrementalRemove(constraint)
|
||||
return false
|
||||
}
|
||||
|
||||
d.recalculate()
|
||||
addConstraintsConsumingTo(d.output, todo)
|
||||
@addConstraintsConsumingTo(d.output, todo)
|
||||
}
|
||||
|
||||
return true
|
||||
@ -602,7 +602,7 @@ var total = 0
|
||||
// constraint so it cannot be accomodated. The cost in this case is,
|
||||
// of course, very low. Typical situations lie somewhere between these
|
||||
// two extremes.
|
||||
var chainTest = Fn.new {|n|
|
||||
def chainTest(n) {
|
||||
ThePlanner = Planner.new()
|
||||
var prev = null
|
||||
var first = null
|
||||
@ -627,7 +627,7 @@ var chainTest = Fn.new {|n|
|
||||
}
|
||||
}
|
||||
|
||||
var change = Fn.new {|v, newValue|
|
||||
def change(v, newValue) {
|
||||
var edit = EditConstraint.new(v, PREFERRED)
|
||||
var plan = ThePlanner.extractPlanFromConstraints([edit])
|
||||
for (i in 0...10) {
|
||||
@ -642,7 +642,7 @@ var change = Fn.new {|v, newValue|
|
||||
// other by a simple linear transformation (scale and offset). The
|
||||
// time is measured to change a variable on either side of the
|
||||
// mapping and to change the scale and offset factors.
|
||||
var projectionTest = Fn.new {|n|
|
||||
def projectionTest(n) {
|
||||
ThePlanner = Planner.new()
|
||||
var scale = Variable.new("scale", 10)
|
||||
var offset = Variable.new("offset", 1000)
|
||||
@ -658,22 +658,22 @@ var projectionTest = Fn.new {|n|
|
||||
ScaleConstraint.new(src, scale, offset, dst, REQUIRED)
|
||||
}
|
||||
|
||||
change.call(src, 17)
|
||||
change(src, 17)
|
||||
total = total + dst.value
|
||||
if (dst.value != 1170) System.print("Projection 1 failed")
|
||||
|
||||
change.call(dst, 1050)
|
||||
change(dst, 1050)
|
||||
|
||||
total = total + src.value
|
||||
if (src.value != 5) System.print("Projection 2 failed")
|
||||
|
||||
change.call(scale, 5)
|
||||
change(scale, 5)
|
||||
for (i in 0...n - 1) {
|
||||
total = total + dests[i].value
|
||||
if (dests[i].value != i * 5 + 1000) System.print("Projection 3 failed")
|
||||
}
|
||||
|
||||
change.call(offset, 2000)
|
||||
change(offset, 2000)
|
||||
for (i in 0...n - 1) {
|
||||
total = total + dests[i].value
|
||||
if (dests[i].value != i * 5 + 2000) System.print("Projection 4 failed")
|
||||
@ -682,8 +682,8 @@ var projectionTest = Fn.new {|n|
|
||||
|
||||
var start = System.clock
|
||||
for (i in 0...40) {
|
||||
chainTest.call(100)
|
||||
projectionTest.call(100)
|
||||
chainTest(100)
|
||||
projectionTest(100)
|
||||
}
|
||||
|
||||
System.print(total)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
class Fib {
|
||||
static get(n) {
|
||||
if (n < 2) return n
|
||||
return get(n - 1) + get(n - 2)
|
||||
return @get(n - 1) + @get(n - 2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,10 +7,10 @@ var start = System.clock
|
||||
for (i in 0...100000) {
|
||||
fibers.add(Fiber.new {
|
||||
sum = sum + i
|
||||
if (i < 99999) fibers[i + 1].call()
|
||||
if (i < 99999) fibers[i + 1]()
|
||||
})
|
||||
}
|
||||
|
||||
fibers[0].call()
|
||||
fibers[0]()
|
||||
System.print(sum)
|
||||
System.print("elapsed: %(System.clock - start)")
|
||||
|
||||
@ -4,7 +4,7 @@ class Toggle {
|
||||
}
|
||||
|
||||
value { _state }
|
||||
activate {
|
||||
activate() {
|
||||
_state = !_state
|
||||
return this
|
||||
}
|
||||
@ -17,10 +17,10 @@ class NthToggle is Toggle {
|
||||
_count = 0
|
||||
}
|
||||
|
||||
activate {
|
||||
activate() {
|
||||
_count = _count + 1
|
||||
if (_count >= _countMax) {
|
||||
super.activate
|
||||
super.activate()
|
||||
_count = 0
|
||||
}
|
||||
|
||||
@ -34,16 +34,16 @@ var val = true
|
||||
var toggle = Toggle.new(val)
|
||||
|
||||
for (i in 0...n) {
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate.value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
val = toggle.activate().value
|
||||
}
|
||||
|
||||
System.print(toggle.value)
|
||||
@ -52,16 +52,16 @@ val = true
|
||||
var ntoggle = NthToggle.new(val, 3)
|
||||
|
||||
for (i in 0...n) {
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate.value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
val = ntoggle.activate().value
|
||||
}
|
||||
|
||||
System.print(ntoggle.value)
|
||||
|
||||
@ -3,5 +3,5 @@ var fiber = Fiber.new {
|
||||
}
|
||||
|
||||
System.print("before") // expect: before
|
||||
fiber.call() // expect: fiber
|
||||
fiber() // expect: fiber
|
||||
System.print("after") // expect: after
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
var fiber
|
||||
|
||||
fiber = Fiber.new {
|
||||
fiber.call() // expect runtime error: Fiber has already been called.
|
||||
fiber() // expect runtime error: Fiber has already been called.
|
||||
}
|
||||
|
||||
fiber.call()
|
||||
fiber()
|
||||
|
||||
@ -2,5 +2,5 @@ var fiber = Fiber.new {
|
||||
System.print("call")
|
||||
}
|
||||
|
||||
fiber.call() // expect: call
|
||||
fiber.call() // expect runtime error: Cannot call a finished fiber.
|
||||
fiber() // expect: call
|
||||
fiber() // expect runtime error: Cannot call a finished fiber.
|
||||
|
||||
@ -4,4 +4,4 @@ var fiber = Fiber.new {
|
||||
}
|
||||
|
||||
fiber.try()
|
||||
fiber.call() // expect runtime error: Cannot call an aborted fiber.
|
||||
fiber() // expect runtime error: Cannot call an aborted fiber.
|
||||
|
||||
@ -2,11 +2,11 @@ var a
|
||||
var b
|
||||
|
||||
a = Fiber.new {
|
||||
b.call() // expect runtime error: Fiber has already been called.
|
||||
b() // expect runtime error: Fiber has already been called.
|
||||
}
|
||||
|
||||
b = Fiber.new {
|
||||
a.call()
|
||||
a()
|
||||
}
|
||||
|
||||
b.call()
|
||||
b()
|
||||
|
||||
@ -2,4 +2,4 @@ var fiber = Fiber.new {
|
||||
System.print("fiber") // expect: fiber
|
||||
}
|
||||
|
||||
System.print(fiber.call()) // expect: null
|
||||
System.print(fiber()) // expect: null
|
||||
|
||||
@ -3,4 +3,4 @@ var fiber = Fiber.new {
|
||||
return "result" // expect: fiber
|
||||
}
|
||||
|
||||
System.print(fiber.call()) // expect: result
|
||||
System.print(fiber()) // expect: result
|
||||
|
||||
@ -6,7 +6,7 @@ var fiber = Fiber.new {
|
||||
System.print("called")
|
||||
}
|
||||
|
||||
fiber.transfer() // expect: transferred
|
||||
System.print("main") // expect: main
|
||||
fiber.call() // expect: null
|
||||
// expect: called
|
||||
fiber.transfer() // expect: transferred
|
||||
System.print("main") // expect: main
|
||||
fiber() // expect: null
|
||||
// expect: called
|
||||
|
||||
@ -4,6 +4,6 @@ var fiber = Fiber.new {
|
||||
|
||||
// The first value passed to the fiber is ignored, since there's no yield call
|
||||
// to return it.
|
||||
System.print("before") // expect: before
|
||||
fiber.call("ignored") // expect: fiber
|
||||
System.print("after") // expect: after
|
||||
System.print("before") // expect: before
|
||||
fiber("ignored") // expect: fiber
|
||||
System.print("after") // expect: after
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
var fiber
|
||||
|
||||
fiber = Fiber.new {
|
||||
fiber.call(2) // expect runtime error: Fiber has already been called.
|
||||
fiber(2) // expect runtime error: Fiber has already been called.
|
||||
}
|
||||
|
||||
fiber.call(1)
|
||||
fiber(1)
|
||||
|
||||
@ -2,5 +2,5 @@ var fiber = Fiber.new {
|
||||
System.print("call")
|
||||
}
|
||||
|
||||
fiber.call(1) // expect: call
|
||||
fiber.call(2) // expect runtime error: Cannot call a finished fiber.
|
||||
fiber(1) // expect: call
|
||||
fiber(2) // expect runtime error: Cannot call a finished fiber.
|
||||
|
||||
@ -4,4 +4,4 @@ var fiber = Fiber.new {
|
||||
}
|
||||
|
||||
fiber.try()
|
||||
fiber.call("value") // expect runtime error: Cannot call an aborted fiber.
|
||||
fiber("value") // expect runtime error: Cannot call an aborted fiber.
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var A = Fiber.new {
|
||||
B.call(3) // expect runtime error: Fiber has already been called.
|
||||
var a = Fiber.new {
|
||||
b(3) // expect runtime error: Fiber has already been called.
|
||||
}
|
||||
|
||||
var B = Fiber.new {
|
||||
A.call(2)
|
||||
var b = Fiber.new {
|
||||
a(2)
|
||||
}
|
||||
|
||||
B.call(1)
|
||||
b(1)
|
||||
|
||||
@ -6,7 +6,7 @@ var fiber = Fiber.new {
|
||||
System.print("called")
|
||||
}
|
||||
|
||||
fiber.transfer() // expect: transferred
|
||||
System.print("main") // expect: main
|
||||
fiber.call("value") // expect: value
|
||||
// expect: called
|
||||
fiber.transfer() // expect: transferred
|
||||
System.print("main") // expect: main
|
||||
fiber("value") // expect: value
|
||||
// expect: called
|
||||
|
||||
@ -5,7 +5,7 @@ var fiber = Fiber.new {
|
||||
}
|
||||
|
||||
System.print(fiber.isDone) // expect: false
|
||||
fiber.call() // expect: 1
|
||||
fiber() // expect: 1
|
||||
System.print(fiber.isDone) // expect: false
|
||||
fiber.call() // expect: 2
|
||||
fiber() // expect: 2
|
||||
System.print(fiber.isDone) // expect: true
|
||||
|
||||
@ -4,12 +4,12 @@ var b = Fiber.new {
|
||||
|
||||
var a = Fiber.new {
|
||||
System.print("begin fiber a")
|
||||
b.call()
|
||||
b()
|
||||
System.print("end fiber a")
|
||||
}
|
||||
|
||||
System.print("begin main")
|
||||
a.call()
|
||||
a()
|
||||
System.print("end main")
|
||||
|
||||
// expect: begin main
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var F = Fiber.new {
|
||||
var f = Fiber.new {
|
||||
System.print(1) // expect: 1
|
||||
System.print(F.transfer()) // expect: null
|
||||
System.print(f.transfer()) // expect: null
|
||||
System.print(2) // expect: 2
|
||||
}
|
||||
|
||||
F.call()
|
||||
// F remembers its original caller so transfers back to main.
|
||||
f()
|
||||
// f remembers its original caller so transfers back to main.
|
||||
System.print(3) // expect: 3
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
var A = Fiber.new {
|
||||
var a = Fiber.new {
|
||||
System.print(2)
|
||||
B.transfer()
|
||||
b.transfer()
|
||||
System.print("nope")
|
||||
}
|
||||
|
||||
var B = Fiber.new {
|
||||
var b = Fiber.new {
|
||||
System.print(1)
|
||||
A.transfer()
|
||||
a.transfer()
|
||||
System.print(3)
|
||||
}
|
||||
|
||||
B.call()
|
||||
b()
|
||||
// expect: 1
|
||||
// expect: 2
|
||||
// expect: 3
|
||||
// B remembers its original caller so returns to main.
|
||||
// b remembers its original caller so returns to main.
|
||||
System.print(4) // expect: 4
|
||||
|
||||
@ -13,11 +13,11 @@ var fiber = Fiber.new {
|
||||
|
||||
fiber.transfer() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber.call("call 1") // expect: call 1
|
||||
fiber("call 1") // expect: call 1
|
||||
|
||||
System.print("main 2") // expect: main 2
|
||||
// Transfer back into the fiber so it has a NULL caller.
|
||||
fiber.transfer()
|
||||
|
||||
fiber.call() // expect: null
|
||||
fiber() // expect: null
|
||||
System.print("main 3") // expect: main 3
|
||||
|
||||
@ -2,5 +2,5 @@ var a = Fiber.new {
|
||||
System.print("run")
|
||||
}
|
||||
|
||||
a.call() // expect: run
|
||||
a.transfer() // expect runtime error: Cannot transfer to a finished fiber.
|
||||
a() // expect: run
|
||||
a.transfer() // expect runtime error: Cannot transfer to a finished fiber.
|
||||
|
||||
@ -4,6 +4,6 @@ var fiber = Fiber.new {
|
||||
System.print("transferred")
|
||||
}
|
||||
|
||||
fiber.call() // expect: called
|
||||
fiber.transfer() // expect: null
|
||||
// expect: transferred
|
||||
fiber() // expect: called
|
||||
fiber.transfer() // expect: null
|
||||
// expect: transferred
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
var F = Fiber.new {
|
||||
var f = Fiber.new {
|
||||
System.print(1) // expect: 1
|
||||
System.print(F.transfer("value")) // expect: value
|
||||
System.print(f.transfer("value")) // expect: value
|
||||
System.print(2) // expect: 2
|
||||
}
|
||||
|
||||
F.call()
|
||||
f()
|
||||
System.print(3) // expect: 3
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
var A = Fiber.new {
|
||||
var a = Fiber.new {
|
||||
System.print(2)
|
||||
B.transfer("ignored")
|
||||
b.transfer("ignored")
|
||||
System.print("nope")
|
||||
}
|
||||
|
||||
var B = Fiber.new {
|
||||
var b = Fiber.new {
|
||||
System.print(1)
|
||||
A.transfer("ignored")
|
||||
a.transfer("ignored")
|
||||
System.print(3)
|
||||
}
|
||||
|
||||
B.call()
|
||||
b()
|
||||
// expect: 1
|
||||
// expect: 2
|
||||
// expect: 3
|
||||
|
||||
@ -2,5 +2,5 @@ var a = Fiber.new {
|
||||
System.print("run")
|
||||
}
|
||||
|
||||
a.call() // expect: run
|
||||
a() // expect: run
|
||||
a.transfer("blah") // expect runtime error: Cannot transfer to a finished fiber.
|
||||
|
||||
@ -4,6 +4,6 @@ var fiber = Fiber.new {
|
||||
System.print("transferred")
|
||||
}
|
||||
|
||||
fiber.call() // expect: called
|
||||
fiber() // expect: called
|
||||
fiber.transfer("value") // expect: value
|
||||
// expect: transferred
|
||||
|
||||
@ -4,4 +4,4 @@ fiber = Fiber.new {
|
||||
fiber.try() // expect runtime error: Fiber has already been called.
|
||||
}
|
||||
|
||||
fiber.call()
|
||||
fiber()
|
||||
|
||||
@ -6,7 +6,7 @@ a = Fiber.new {
|
||||
}
|
||||
|
||||
b = Fiber.new {
|
||||
a.call()
|
||||
a()
|
||||
}
|
||||
|
||||
b.call()
|
||||
b()
|
||||
|
||||
@ -6,9 +6,9 @@ var fiber = Fiber.new {
|
||||
System.print("fiber 3")
|
||||
}
|
||||
|
||||
fiber.call() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber.call() // expect: fiber 2
|
||||
System.print("main 2") // expect: main 2
|
||||
fiber.call() // expect: fiber 3
|
||||
System.print("main 3") // expect: main 3
|
||||
fiber() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber() // expect: fiber 2
|
||||
System.print("main 2") // expect: main 2
|
||||
fiber() // expect: fiber 3
|
||||
System.print("main 3") // expect: main 3
|
||||
|
||||
@ -4,9 +4,9 @@ var fiber = Fiber.new {
|
||||
System.print(Fiber.yield())
|
||||
}
|
||||
|
||||
fiber.call() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber.call("call 1") // expect: call 1
|
||||
System.print("main 2") // expect: main 2
|
||||
fiber.call() // expect: null
|
||||
System.print("main 3") // expect: main 3
|
||||
fiber() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber("call 1") // expect: call 1
|
||||
System.print("main 2") // expect: main 2
|
||||
fiber() // expect: null
|
||||
System.print("main 3") // expect: main 3
|
||||
|
||||
@ -9,11 +9,11 @@ var b = Fiber.new {
|
||||
System.print("b")
|
||||
System.print(Fiber.yield())
|
||||
|
||||
a.call()
|
||||
a()
|
||||
a.transfer("value")
|
||||
}
|
||||
|
||||
b.call() // expect: b
|
||||
b() // expect: b
|
||||
b.transfer()
|
||||
// expect: null
|
||||
// expect: a
|
||||
|
||||
@ -6,9 +6,9 @@ var fiber = Fiber.new {
|
||||
System.print("fiber 3")
|
||||
}
|
||||
|
||||
System.print(fiber.call()) // expect: fiber 1
|
||||
// expect: yield 1
|
||||
System.print(fiber.call()) // expect: fiber 2
|
||||
// expect: yield 2
|
||||
System.print(fiber.call()) // expect: fiber 3
|
||||
// expect: null
|
||||
System.print(fiber()) // expect: fiber 1
|
||||
// expect: yield 1
|
||||
System.print(fiber()) // expect: fiber 2
|
||||
// expect: yield 2
|
||||
System.print(fiber()) // expect: fiber 3
|
||||
// expect: null
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
var f0 = Fn.new { System.print("zero") }
|
||||
var f1 = Fn.new {|a| System.print("one %(a)") }
|
||||
var f2 = Fn.new {|a, b| System.print("two %(a) %(b)") }
|
||||
var f3 = Fn.new {|a, b, c| System.print("three %(a) %(b) %(c)") }
|
||||
def f0() { System.print("zero") }
|
||||
def f1(a) { System.print("one %(a)") }
|
||||
def f2(a, b) { System.print("two %(a) %(b)") }
|
||||
def f3(a, b, c) { System.print("three %(a) %(b) %(c)") }
|
||||
|
||||
f0.call("a") // expect: zero
|
||||
f0.call("a", "b") // expect: zero
|
||||
f0("a") // expect: zero
|
||||
f0("a", "b") // expect: zero
|
||||
|
||||
f1.call("a", "b") // expect: one a
|
||||
f1.call("a", "b", "c") // expect: one a
|
||||
f1("a", "b") // expect: one a
|
||||
f1("a", "b", "c") // expect: one a
|
||||
|
||||
f2.call("a", "b", "c") // expect: two a b
|
||||
f2.call("a", "b", "c", "d") // expect: two a b
|
||||
f2("a", "b", "c") // expect: two a b
|
||||
f2("a", "b", "c", "d") // expect: two a b
|
||||
|
||||
f3.call("a", "b", "c", "d") // expect: three a b c
|
||||
f3.call("a", "b", "c", "d", "e") // expect: three a b c
|
||||
f3("a", "b", "c", "d") // expect: three a b c
|
||||
f3("a", "b", "c", "d", "e") // expect: three a b c
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
var f2 = Fn.new {|a, b| System.print(a + b) }
|
||||
f2.call("a") // expect runtime error: Function expects more arguments.
|
||||
def f2(a, b) { System.print(a + b) }
|
||||
f2("a") // expect runtime error: Function expects more arguments.
|
||||
|
||||
@ -11,6 +11,6 @@ System.print(Fn.new { 123 } != false) // expect: true
|
||||
System.print(Fn.new { 123 } != "fn 123") // expect: true
|
||||
|
||||
// Equal by identity.
|
||||
var f = Fn.new { 123 }
|
||||
def f() { 123 }
|
||||
System.print(f == f) // expect: true
|
||||
System.print(f != f) // expect: false
|
||||
|
||||
@ -1,14 +1,7 @@
|
||||
var a = [1, 4, 2, 1, 5]
|
||||
var b = ["W", "o", "r", "l", "d"]
|
||||
var max = Fn.new {|a, b| a > b ? a : b }
|
||||
var sum = Fn.new {|a, b| a + b }
|
||||
|
||||
System.print(a.reduce(max)) // expect: 5
|
||||
System.print(a.reduce(10, max)) // expect: 10
|
||||
System.print(a.reduce {|a, b| a > b ? a : b }) // expect: 5
|
||||
System.print(a.reduce(10) {|a, b| a > b ? a : b }) // expect: 10
|
||||
|
||||
System.print(a.reduce(sum)) // expect: 13
|
||||
System.print(a.reduce(-1, sum)) // expect: 12
|
||||
|
||||
// sum also concatenates strings
|
||||
System.print(b.reduce("Hello ", sum)) // expect: Hello World
|
||||
System.print(b.reduce(sum)) // expect: World
|
||||
System.print(a.reduce {|a, b| a + b }) // expect: 13
|
||||
System.print(a.reduce(-1) {|a, b| a + b }) // expect: 12
|
||||
|
||||
@ -7,4 +7,4 @@ Fn.new {
|
||||
|
||||
System.print(a = "arg") // expect: arg
|
||||
System.print(a) // expect: arg
|
||||
}.call()
|
||||
}()
|
||||
|
||||
@ -1 +1,2 @@
|
||||
unknown = "what" // expect error
|
||||
unknown = "what"
|
||||
// expect error
|
||||
@ -5,5 +5,5 @@ for (i in [1, 2, 3]) {
|
||||
break
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: 5
|
||||
|
||||
@ -5,5 +5,5 @@ while (true) {
|
||||
break
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: i
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
class foo {
|
||||
construct new() {}
|
||||
|
||||
static callFoo {
|
||||
System.print(foo)
|
||||
}
|
||||
|
||||
callFoo {
|
||||
System.print(foo)
|
||||
}
|
||||
|
||||
foo { "instance foo method" }
|
||||
static foo { "static foo method" }
|
||||
}
|
||||
|
||||
foo.callFoo // expect: static foo method
|
||||
foo.new().callFoo // expect: instance foo method
|
||||
@ -16,10 +16,10 @@ var g = null
|
||||
}
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: local
|
||||
// expect: after f
|
||||
|
||||
g.call()
|
||||
g()
|
||||
// expect: after f
|
||||
// expect: after g
|
||||
|
||||
@ -4,6 +4,6 @@ Fn.new {|param|
|
||||
f = Fn.new {
|
||||
System.print(param)
|
||||
}
|
||||
}.call("param")
|
||||
}("param")
|
||||
|
||||
f.call() // expect: param
|
||||
f() // expect: param
|
||||
|
||||
@ -9,5 +9,5 @@ Fn.new {
|
||||
Fn.new {
|
||||
System.print(b) // expect: b
|
||||
System.print(a) // expect: a
|
||||
}.call()
|
||||
}.call()
|
||||
}()
|
||||
}()
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
var F = null
|
||||
var f
|
||||
|
||||
class Foo {
|
||||
construct new() {}
|
||||
|
||||
method(param) {
|
||||
F = Fn.new {
|
||||
f = Fn.new {
|
||||
System.print(param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new().method("param")
|
||||
F.call() // expect: param
|
||||
f() // expect: param
|
||||
|
||||
@ -7,4 +7,4 @@ var f = null
|
||||
}
|
||||
}
|
||||
|
||||
f.call() // expect: local
|
||||
f() // expect: local
|
||||
|
||||
@ -11,11 +11,11 @@ Fn.new {
|
||||
System.print(b)
|
||||
System.print(c)
|
||||
}
|
||||
}.call()
|
||||
}.call()
|
||||
}.call()
|
||||
}()
|
||||
}()
|
||||
}()
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: a
|
||||
// expect: b
|
||||
// expect: c
|
||||
|
||||
@ -2,5 +2,5 @@
|
||||
var local = "local"
|
||||
Fn.new {
|
||||
System.print(local) // expect: local
|
||||
}.call()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -8,6 +8,6 @@ var f = null
|
||||
}
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: a
|
||||
// expect: a
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
// Since a is out of scope, the local slot will be reused by b. Make sure
|
||||
// that f still closes over a.
|
||||
var b = "b"
|
||||
f.call() // expect: a
|
||||
f() // expect: a
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7,5 +7,5 @@
|
||||
System.print(foo) // expect: shadow
|
||||
}
|
||||
System.print(foo) // expect: closure
|
||||
}.call()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -15,5 +15,5 @@ var closure
|
||||
if (false) Fn.new { b }
|
||||
}
|
||||
|
||||
System.print(closure.call()) // expect: a
|
||||
System.print(closure()) // expect: a
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
class Foo {
|
||||
this new { // expect error
|
||||
construct new { // expect error
|
||||
System.print("ok")
|
||||
}
|
||||
}
|
||||
|
||||
2
test/language/def/empty_body.wren
Normal file
2
test/language/def/empty_body.wren
Normal file
@ -0,0 +1,2 @@
|
||||
def f() {}
|
||||
System.print(f()) // expect: null
|
||||
4
test/language/def/newline_body.wren
Normal file
4
test/language/def/newline_body.wren
Normal file
@ -0,0 +1,4 @@
|
||||
def f() {
|
||||
// Hi.
|
||||
}
|
||||
System.print(f()) // expect: null
|
||||
4
test/language/def/newline_in_expression_block.wren
Normal file
4
test/language/def/newline_in_expression_block.wren
Normal file
@ -0,0 +1,4 @@
|
||||
def f() { System.print("ok") // expect error
|
||||
}
|
||||
|
||||
f()
|
||||
2
test/language/def/no_newline_before_close.wren
Normal file
2
test/language/def/no_newline_before_close.wren
Normal file
@ -0,0 +1,2 @@
|
||||
def f() {
|
||||
System.print("ok") } // expect error
|
||||
50
test/language/def/parameters.wren
Normal file
50
test/language/def/parameters.wren
Normal file
@ -0,0 +1,50 @@
|
||||
def f0() { 0 }
|
||||
System.print(f0()) // expect: 0
|
||||
|
||||
def f1(a) { a }
|
||||
System.print(f1(1)) // expect: 1
|
||||
|
||||
def f2(a, b) { a + b }
|
||||
System.print(f2(1, 2)) // expect: 3
|
||||
|
||||
def f3(a, b, c) { a + b + c }
|
||||
System.print(f3(1, 2, 3)) // expect: 6
|
||||
|
||||
def f4(a, b, c, d) { a + b + c + d }
|
||||
System.print(f4(1, 2, 3, 4)) // expect: 10
|
||||
|
||||
def f5(a, b, c, d, e) { a + b + c + d + e }
|
||||
System.print(f5(1, 2, 3, 4, 5)) // expect: 15
|
||||
|
||||
def f6(a, b, c, d, e, f) { a + b + c + d + e + f }
|
||||
System.print(f6(1, 2, 3, 4, 5, 6)) // expect: 21
|
||||
|
||||
def f7(a, b, c, d, e, f, g) { a + b + c + d + e + f + g }
|
||||
System.print(f7(1, 2, 3, 4, 5, 6, 7)) // expect: 28
|
||||
|
||||
def f8(a, b, c, d, e, f, g, h) { a + b + c + d + e + f + g + h }
|
||||
System.print(f8(1, 2, 3, 4, 5, 6, 7, 8)) // expect: 36
|
||||
|
||||
def f9(a, b, c, d, e, f, g, h, i) { a + b + c + d + e + f + g + h + i }
|
||||
System.print(f9(1, 2, 3, 4, 5, 6, 7, 8, 9)) // expect: 45
|
||||
|
||||
def f10(a, b, c, d, e, f, g, h, i, j) { a + b + c + d + e + f + g + h + i + j }
|
||||
System.print(f10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) // expect: 55
|
||||
|
||||
def f11(a, b, c, d, e, f, g, h, i, j, k) { a + b + c + d + e + f + g + h + i + j + k }
|
||||
System.print(f11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)) // expect: 66
|
||||
|
||||
def f12(a, b, c, d, e, f, g, h, i, j, k, l) { a + b + c + d + e + f + g + h + i + j + k + l }
|
||||
System.print(f12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) // expect: 78
|
||||
|
||||
def f13(a, b, c, d, e, f, g, h, i, j, k, l, m) { a + b + c + d + e + f + g + h + i + j + k + l + m }
|
||||
System.print(f13(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)) // expect: 91
|
||||
|
||||
def f14(a, b, c, d, e, f, g, h, i, j, k, l, m, n) { a + b + c + d + e + f + g + h + i + j + k + l + m + n }
|
||||
System.print(f14(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)) // expect: 105
|
||||
|
||||
def f15(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) { a + b + c + d + e + f + g + h + i + j + k + l + m + n + o }
|
||||
System.print(f15(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) // expect: 120
|
||||
|
||||
def f16(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) { a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p }
|
||||
System.print(f16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) // expect: 136
|
||||
29
test/language/def/syntax.wren
Normal file
29
test/language/def/syntax.wren
Normal file
@ -0,0 +1,29 @@
|
||||
// Single expression body.
|
||||
def f() { System.print("ok") } // expect: ok
|
||||
f()
|
||||
|
||||
// Curly body.
|
||||
def g() {
|
||||
System.print("ok") // expect: ok
|
||||
}
|
||||
g()
|
||||
|
||||
// Multiple statements.
|
||||
def h() {
|
||||
System.print("1") // expect: 1
|
||||
System.print("2") // expect: 2
|
||||
}
|
||||
h()
|
||||
|
||||
// Extra newlines.
|
||||
def i() {
|
||||
|
||||
|
||||
System.print("1") // expect: 1
|
||||
|
||||
|
||||
System.print("2") // expect: 2
|
||||
|
||||
|
||||
}
|
||||
i()
|
||||
@ -17,9 +17,9 @@ var closure
|
||||
}
|
||||
}
|
||||
|
||||
fiber.call() // expect: before
|
||||
closure.call() // expect: before
|
||||
fiber.call()
|
||||
closure.call() // expect: after
|
||||
fiber.call() // expect: after
|
||||
closure.call() // expect: final
|
||||
fiber() // expect: before
|
||||
closure() // expect: before
|
||||
fiber()
|
||||
closure() // expect: after
|
||||
fiber() // expect: after
|
||||
closure() // expect: final
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
class Foo {
|
||||
construct new() { _field = "Foo field" }
|
||||
|
||||
closeOverGet {
|
||||
closeOverGet() {
|
||||
return Fn.new { _field }
|
||||
}
|
||||
|
||||
closeOverSet {
|
||||
closeOverSet() {
|
||||
return Fn.new { _field = "new value" }
|
||||
}
|
||||
}
|
||||
|
||||
var foo = Foo.new()
|
||||
System.print(foo.closeOverGet.call()) // expect: Foo field
|
||||
foo.closeOverSet.call()
|
||||
System.print(foo.closeOverGet.call()) // expect: new value
|
||||
System.print(foo.closeOverGet()()) // expect: Foo field
|
||||
foo.closeOverSet()()
|
||||
System.print(foo.closeOverGet()()) // expect: new value
|
||||
|
||||
@ -4,7 +4,7 @@ for (i in [1, 2, 3]) {
|
||||
list.add(Fn.new { System.print(i) })
|
||||
}
|
||||
|
||||
for (f in list) f.call()
|
||||
for (f in list) f()
|
||||
// expect: 1
|
||||
// expect: 2
|
||||
// expect: 3
|
||||
|
||||
@ -5,7 +5,7 @@ for (i in [1, 2, 3]) {
|
||||
list.add(Fn.new { System.print(j) })
|
||||
}
|
||||
|
||||
for (f in list) f.call()
|
||||
for (f in list) f()
|
||||
// expect: 2
|
||||
// expect: 3
|
||||
// expect: 4
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var f = Fn.new {
|
||||
def f() {
|
||||
System.print("evaluate sequence")
|
||||
return [1, 2, 3]
|
||||
}
|
||||
|
||||
for (i in f.call()) System.print(i)
|
||||
for (i in f()) System.print(i)
|
||||
// expect: evaluate sequence
|
||||
// expect: 1
|
||||
// expect: 2
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var f = Fn.new {
|
||||
def f() {
|
||||
for (i in [1, 2, 3]) {
|
||||
return Fn.new { System.print(i) }
|
||||
}
|
||||
}
|
||||
|
||||
var g = f.call()
|
||||
g.call()
|
||||
var g = f()
|
||||
g()
|
||||
// expect: 1
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
var f = Fn.new {
|
||||
def f() {
|
||||
for (i in [1, 2, 3]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
System.print(f.call())
|
||||
System.print(f())
|
||||
// expect: 1
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
var f = Fn.new {}
|
||||
System.print(f.call()) // expect: null
|
||||
System.print(f()) // expect: null
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
var f = Fn.new {
|
||||
// Hi.
|
||||
}
|
||||
System.print(f.call()) // expect: null
|
||||
System.print(f()) // expect: null
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
Fn.new { System.print("ok") // expect error
|
||||
}.call()
|
||||
}()
|
||||
|
||||
@ -1,50 +1,50 @@
|
||||
var f0 = Fn.new { 0 }
|
||||
System.print(f0.call()) // expect: 0
|
||||
System.print(f0()) // expect: 0
|
||||
|
||||
var f1 = Fn.new {|a| a }
|
||||
System.print(f1.call(1)) // expect: 1
|
||||
System.print(f1(1)) // expect: 1
|
||||
|
||||
var f2 = Fn.new {|a, b| a + b }
|
||||
System.print(f2.call(1, 2)) // expect: 3
|
||||
System.print(f2(1, 2)) // expect: 3
|
||||
|
||||
var f3 = Fn.new {|a, b, c| a + b + c }
|
||||
System.print(f3.call(1, 2, 3)) // expect: 6
|
||||
System.print(f3(1, 2, 3)) // expect: 6
|
||||
|
||||
var f4 = Fn.new {|a, b, c, d| a + b + c + d }
|
||||
System.print(f4.call(1, 2, 3, 4)) // expect: 10
|
||||
System.print(f4(1, 2, 3, 4)) // expect: 10
|
||||
|
||||
var f5 = Fn.new {|a, b, c, d, e| a + b + c + d + e }
|
||||
System.print(f5.call(1, 2, 3, 4, 5)) // expect: 15
|
||||
System.print(f5(1, 2, 3, 4, 5)) // expect: 15
|
||||
|
||||
var f6 = Fn.new {|a, b, c, d, e, f| a + b + c + d + e + f }
|
||||
System.print(f6.call(1, 2, 3, 4, 5, 6)) // expect: 21
|
||||
System.print(f6(1, 2, 3, 4, 5, 6)) // expect: 21
|
||||
|
||||
var f7 = Fn.new {|a, b, c, d, e, f, g| a + b + c + d + e + f + g }
|
||||
System.print(f7.call(1, 2, 3, 4, 5, 6, 7)) // expect: 28
|
||||
System.print(f7(1, 2, 3, 4, 5, 6, 7)) // expect: 28
|
||||
|
||||
var f8 = Fn.new {|a, b, c, d, e, f, g, h| a + b + c + d + e + f + g + h }
|
||||
System.print(f8.call(1, 2, 3, 4, 5, 6, 7, 8)) // expect: 36
|
||||
System.print(f8(1, 2, 3, 4, 5, 6, 7, 8)) // expect: 36
|
||||
|
||||
var f9 = Fn.new {|a, b, c, d, e, f, g, h, i| a + b + c + d + e + f + g + h + i }
|
||||
System.print(f9.call(1, 2, 3, 4, 5, 6, 7, 8, 9)) // expect: 45
|
||||
System.print(f9(1, 2, 3, 4, 5, 6, 7, 8, 9)) // expect: 45
|
||||
|
||||
var f10 = Fn.new {|a, b, c, d, e, f, g, h, i, j| a + b + c + d + e + f + g + h + i + j }
|
||||
System.print(f10.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) // expect: 55
|
||||
System.print(f10(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)) // expect: 55
|
||||
|
||||
var f11 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k| a + b + c + d + e + f + g + h + i + j + k }
|
||||
System.print(f11.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)) // expect: 66
|
||||
System.print(f11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)) // expect: 66
|
||||
|
||||
var f12 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k, l| a + b + c + d + e + f + g + h + i + j + k + l }
|
||||
System.print(f12.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) // expect: 78
|
||||
System.print(f12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)) // expect: 78
|
||||
|
||||
var f13 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k, l, m| a + b + c + d + e + f + g + h + i + j + k + l + m }
|
||||
System.print(f13.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)) // expect: 91
|
||||
System.print(f13(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)) // expect: 91
|
||||
|
||||
var f14 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k, l, m, n| a + b + c + d + e + f + g + h + i + j + k + l + m + n }
|
||||
System.print(f14.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)) // expect: 105
|
||||
System.print(f14(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)) // expect: 105
|
||||
|
||||
var f15 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k, l, m, n, o| a + b + c + d + e + f + g + h + i + j + k + l + m + n + o }
|
||||
System.print(f15.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) // expect: 120
|
||||
System.print(f15(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)) // expect: 120
|
||||
|
||||
var f16 = Fn.new {|a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p| a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p }
|
||||
System.print(f16.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) // expect: 136
|
||||
System.print(f16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)) // expect: 136
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
// Single expression body.
|
||||
Fn.new { System.print("ok") }.call() // expect: ok
|
||||
Fn.new { System.print("ok") }() // expect: ok
|
||||
|
||||
// Curly body.
|
||||
Fn.new {
|
||||
System.print("ok") // expect: ok
|
||||
}.call()
|
||||
}()
|
||||
|
||||
// Multiple statements.
|
||||
Fn.new {
|
||||
System.print("1") // expect: 1
|
||||
System.print("2") // expect: 2
|
||||
}.call()
|
||||
}()
|
||||
|
||||
// Extra newlines.
|
||||
Fn.new {
|
||||
@ -22,4 +22,4 @@ Fn.new {
|
||||
System.print("2") // expect: 2
|
||||
|
||||
|
||||
}.call()
|
||||
}()
|
||||
|
||||
11
test/language/implicit_call/local.wren
Normal file
11
test/language/implicit_call/local.wren
Normal file
@ -0,0 +1,11 @@
|
||||
Fn.new {
|
||||
def f1(arg) { System.print(arg) }
|
||||
|
||||
f1("string") // expect: string
|
||||
|
||||
def f2(block) { System.print(block()) }
|
||||
f2 { "block" } // expect: block
|
||||
|
||||
def f3(a, b, c) { System.print("%(a) %(b) %(c())") }
|
||||
f3(1, 2) { 3 } // expect: 1 2 3
|
||||
}()
|
||||
8
test/language/implicit_call/module_variable.wren
Normal file
8
test/language/implicit_call/module_variable.wren
Normal file
@ -0,0 +1,8 @@
|
||||
def f1(arg) { System.print(arg) }
|
||||
f1("string") // expect: string
|
||||
|
||||
def f2(block) { System.print(block()) }
|
||||
f2 { "block" } // expect: block
|
||||
|
||||
def f3(a, b, c) { System.print("%(a) %(b) %(c())") }
|
||||
f3(1, 2) { 3 } // expect: 1 2 3
|
||||
27
test/language/implicit_call/this.wren
Normal file
27
test/language/implicit_call/this.wren
Normal file
@ -0,0 +1,27 @@
|
||||
class CallArg {
|
||||
static test() {
|
||||
this("string") // expect: string
|
||||
}
|
||||
|
||||
static call(arg) { System.print(arg) }
|
||||
}
|
||||
|
||||
class CallBlock {
|
||||
static test() {
|
||||
this { "block" } // expect: block
|
||||
}
|
||||
|
||||
static call(block) { System.print(block()) }
|
||||
}
|
||||
|
||||
class CallBoth {
|
||||
static test() {
|
||||
this(1, 2) { 3 } // expect: 1 2 3
|
||||
}
|
||||
|
||||
static call(a, b, c) { System.print("%(a) %(b) %(c())") }
|
||||
}
|
||||
|
||||
CallArg.test()
|
||||
CallBlock.test()
|
||||
CallBoth.test()
|
||||
@ -1,25 +0,0 @@
|
||||
class Foo {
|
||||
construct new() {}
|
||||
|
||||
getter {
|
||||
System.print("getter")
|
||||
}
|
||||
|
||||
setter=(value) {
|
||||
System.print("setter")
|
||||
}
|
||||
|
||||
method(a) {
|
||||
System.print("method")
|
||||
}
|
||||
|
||||
test {
|
||||
getter // expect: getter
|
||||
setter = "value" // expect: setter
|
||||
method("arg") // expect: method
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new().test
|
||||
|
||||
// TODO: Need to decide how these interact with globals.
|
||||
@ -1,19 +0,0 @@
|
||||
class Foo {
|
||||
construct new() {}
|
||||
|
||||
bar { "getter" }
|
||||
|
||||
test {
|
||||
System.print(bar) // expect: getter
|
||||
|
||||
{
|
||||
System.print(bar) // expect: getter
|
||||
var bar = "local"
|
||||
System.print(bar) // expect: local
|
||||
}
|
||||
|
||||
System.print(bar) // expect: getter
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new().test
|
||||
@ -1,22 +0,0 @@
|
||||
class Foo {
|
||||
construct new() {}
|
||||
|
||||
bar=(value) {
|
||||
System.print("setter")
|
||||
return value
|
||||
}
|
||||
|
||||
test {
|
||||
bar = "value" // expect: setter
|
||||
|
||||
{
|
||||
bar = "value" // expect: setter
|
||||
var bar = "local"
|
||||
bar = "value" // no expectation
|
||||
}
|
||||
|
||||
bar = "value" // expect: setter
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new().test
|
||||
@ -1,51 +0,0 @@
|
||||
class Outer {
|
||||
construct new() {}
|
||||
|
||||
getter {
|
||||
System.print("outer getter")
|
||||
}
|
||||
|
||||
setter=(value) {
|
||||
System.print("outer setter")
|
||||
}
|
||||
|
||||
method(a) {
|
||||
System.print("outer method")
|
||||
}
|
||||
|
||||
test {
|
||||
getter // expect: outer getter
|
||||
setter = "value" // expect: outer setter
|
||||
method("arg") // expect: outer method
|
||||
|
||||
class Inner {
|
||||
construct new() {}
|
||||
|
||||
getter {
|
||||
System.print("inner getter")
|
||||
}
|
||||
|
||||
setter=(value) {
|
||||
System.print("inner setter")
|
||||
}
|
||||
|
||||
method(a) {
|
||||
System.print("inner method")
|
||||
}
|
||||
|
||||
test {
|
||||
getter // expect: inner getter
|
||||
setter = "value" // expect: inner setter
|
||||
method("arg") // expect: inner method
|
||||
}
|
||||
}
|
||||
|
||||
Inner.new().test
|
||||
|
||||
getter // expect: outer getter
|
||||
setter = "value" // expect: outer setter
|
||||
method("arg") // expect: outer method
|
||||
}
|
||||
}
|
||||
|
||||
Outer.new().test
|
||||
@ -1,11 +1,11 @@
|
||||
class Foo {
|
||||
construct new() { _field = "Foo field" }
|
||||
|
||||
closeOverFooGet {
|
||||
closeOverFooGet() {
|
||||
return Fn.new { Fn.new { _field } }
|
||||
}
|
||||
|
||||
closeOverFooSet {
|
||||
closeOverFooSet() {
|
||||
return Fn.new { Fn.new { _field = "new foo value" } }
|
||||
}
|
||||
}
|
||||
@ -16,21 +16,21 @@ class Bar is Foo {
|
||||
_field = "Bar field"
|
||||
}
|
||||
|
||||
closeOverBarGet {
|
||||
closeOverBarGet() {
|
||||
return Fn.new { Fn.new { _field } }
|
||||
}
|
||||
|
||||
closeOverBarSet {
|
||||
closeOverBarSet() {
|
||||
return Fn.new { Fn.new { _field = "new bar value" } }
|
||||
}
|
||||
}
|
||||
|
||||
var bar = Bar.new()
|
||||
System.print(bar.closeOverFooGet.call().call()) // expect: Foo field
|
||||
System.print(bar.closeOverBarGet.call().call()) // expect: Bar field
|
||||
bar.closeOverFooSet.call().call()
|
||||
System.print(bar.closeOverFooGet.call().call()) // expect: new foo value
|
||||
System.print(bar.closeOverBarGet.call().call()) // expect: Bar field
|
||||
bar.closeOverBarSet.call().call()
|
||||
System.print(bar.closeOverFooGet.call().call()) // expect: new foo value
|
||||
System.print(bar.closeOverBarGet.call().call()) // expect: new bar value
|
||||
System.print(bar.closeOverFooGet()()()) // expect: Foo field
|
||||
System.print(bar.closeOverBarGet()()()) // expect: Bar field
|
||||
bar.closeOverFooSet()()()
|
||||
System.print(bar.closeOverFooGet()()()) // expect: new foo value
|
||||
System.print(bar.closeOverBarGet()()()) // expect: Bar field
|
||||
bar.closeOverBarSet()()()
|
||||
System.print(bar.closeOverFooGet()()()) // expect: new foo value
|
||||
System.print(bar.closeOverBarGet()()()) // expect: new bar value
|
||||
|
||||
@ -3,6 +3,6 @@ var fiber = Fiber.new {
|
||||
Fiber.yield("result")
|
||||
}
|
||||
|
||||
System.print("outer %(fiber.call()) string")
|
||||
System.print("outer %(fiber()) string")
|
||||
// expect: in fiber
|
||||
// expect: outer result string
|
||||
|
||||
18
test/language/module_variable/assignment.wren
Normal file
18
test/language/module_variable/assignment.wren
Normal file
@ -0,0 +1,18 @@
|
||||
var variable = "before"
|
||||
System.print(variable) // expect: before
|
||||
variable = "after"
|
||||
System.print(variable) // expect: after
|
||||
|
||||
class Foo {
|
||||
static method {
|
||||
variable = "method"
|
||||
}
|
||||
}
|
||||
|
||||
Foo.method
|
||||
System.print(variable) // expect: method
|
||||
|
||||
Fn.new {
|
||||
variable = "fn"
|
||||
}()
|
||||
System.print(variable) // expect: fn
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user