mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 06:08:41 +01:00
Compare commits
8 Commits
0.1.0
...
functional
| Author | SHA1 | Date | |
|---|---|---|---|
| f54f8df4d6 | |||
| 22b9ed8f6f | |||
| a45a43606f | |||
| edcacb830b | |||
| a25ea70e89 | |||
| 6c0cbe36bb | |||
| f1fd944c6b | |||
| 3848286cf7 |
@ -149,102 +149,108 @@ tightest to loosest, is:
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td><code>()</code> <code>[]</code> <code>.</code></td>
|
||||
<td>Grouping, <a href="method-calls.html">Subscript, Method call</a></td>
|
||||
<td><code>.</code></td>
|
||||
<td><a href="method-calls.html">Method call</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2</td>
|
||||
<td><code>()</code> <code>{}</code> <code>[]</code></td>
|
||||
<td><a href="functions.html">Call, Block argument</a>, <a href="method-calls.html#subscripts">Subscript</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td><code>-</code> <code>!</code> <code>~</code></td>
|
||||
<td><a href="method-calls.html#operators">Negate, Not, Complement</a></td>
|
||||
<td>Right</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td><code>*</code> <code>/</code> <code>%</code></td>
|
||||
<td><a href="method-calls.html#operators">Multiply, Divide, Modulo</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
<td><code>+</code> <code>-</code></td>
|
||||
<td><a href="method-calls.html#operators">Add, Subtract</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>5</td>
|
||||
<td>6</td>
|
||||
<td><code>..</code> <code>...</code></td>
|
||||
<td><a href="method-calls.html#operators">Inclusive range, Exclusive range</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>6</td>
|
||||
<td>7</td>
|
||||
<td><code><<</code> <code>>></code></td>
|
||||
<td><a href="method-calls.html#operators">Left shift, Right shift</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>7</td>
|
||||
<td>8</td>
|
||||
<td><code><</code> <code><=</code> <code>></code> <code>>=</code></td>
|
||||
<td><a href="method-calls.html#operators">Comparison</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
<td><code>==</code></td>
|
||||
<td><a href="method-calls.html#operators">Equals</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>8</td>
|
||||
<td>10</td>
|
||||
<td><code>!=</code></td>
|
||||
<td><a href="method-calls.html#operators">Not equal</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>9</td>
|
||||
<td>11</td>
|
||||
<td><code>&</code></td>
|
||||
<td><a href="method-calls.html#operators">Bitwise and</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>10</td>
|
||||
<td>12</td>
|
||||
<td><code>^</code></td>
|
||||
<td><a href="method-calls.html#operators">Bitwise xor</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>11</td>
|
||||
<td>13</td>
|
||||
<td><code>|</code></td>
|
||||
<td><a href="method-calls.html#operators">Bitwise or</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>12</td>
|
||||
<td>14</td>
|
||||
<td><code>is</code></td>
|
||||
<td><a href="method-calls.html#operators">Type test</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>13</td>
|
||||
<td>15</td>
|
||||
<td><code>&&</code></td>
|
||||
<td><a href="control-flow.html#logical-operators">Logical and</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>14</td>
|
||||
<td>16</td>
|
||||
<td><code>||</code></td>
|
||||
<td><a href="control-flow.html#logical-operators">Logical or</a></td>
|
||||
<td>Left</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>15</td>
|
||||
<td>17</td>
|
||||
<td><code>?:</code></td>
|
||||
<td><a href="control-flow.html#the-conditional-operator-">Conditional</a></td>
|
||||
<td>Right</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>16</td>
|
||||
<td>18</td>
|
||||
<td><code>=</code></td>
|
||||
<td><a href="variables.html#assignment">Assignment</a>, <a href="method-calls.html#setters">Setter</a></td>
|
||||
<td>Right</td>
|
||||
|
||||
@ -71,5 +71,7 @@ then it isn't an assignment. Instead, it's calling a [setter method][].
|
||||
|
||||
[setter method]: method-calls.html#setters
|
||||
|
||||
**TODO: Implicit definition at top level.**
|
||||
|
||||
<a class="right" href="functions.html">Functions →</a>
|
||||
<a href="control-flow.html">← Control Flow</a>
|
||||
|
||||
@ -9,9 +9,9 @@ foreign class File {
|
||||
return new_(fd)
|
||||
}
|
||||
|
||||
static open(path, fn) {
|
||||
static open(path, function) {
|
||||
var file = open(path)
|
||||
var fiber = Fiber.new { fn.call(file) }
|
||||
var fiber = Fiber.new { function(file) }
|
||||
|
||||
// Poor man's finally. Can we make this more elegant?
|
||||
var result = fiber.try()
|
||||
|
||||
@ -11,9 +11,9 @@ static const char* ioModuleSource =
|
||||
" return new_(fd)\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static open(path, fn) {\n"
|
||||
" static open(path, function) {\n"
|
||||
" var file = open(path)\n"
|
||||
" var fiber = Fiber.new { fn.call(file) }\n"
|
||||
" var fiber = Fiber.new { function(file) }\n"
|
||||
"\n"
|
||||
" // Poor man's finally. Can we make this more elegant?\n"
|
||||
" var result = fiber.try()\n"
|
||||
|
||||
@ -3,7 +3,7 @@ class Scheduler {
|
||||
if (__scheduled == null) __scheduled = []
|
||||
|
||||
__scheduled.add(Fiber.new {
|
||||
callable.call()
|
||||
callable()
|
||||
runNextScheduled_()
|
||||
})
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ static const char* schedulerModuleSource =
|
||||
" if (__scheduled == null) __scheduled = []\n"
|
||||
"\n"
|
||||
" __scheduled.add(Fiber.new {\n"
|
||||
" callable.call()\n"
|
||||
" callable()\n"
|
||||
" 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 function = compile_(source)
|
||||
// TODO: Include compile errors.
|
||||
if (fn == null) Fiber.abort("Could not compile source code.")
|
||||
if (function == null) Fiber.abort("Could not compile source code.")
|
||||
|
||||
Fiber.new(fn).call()
|
||||
Fiber.new(function)()
|
||||
}
|
||||
|
||||
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 function = compile_(source)\n"
|
||||
" // TODO: Include compile errors.\n"
|
||||
" if (fn == null) Fiber.abort(\"Could not compile source code.\")\n"
|
||||
" if (function == null) Fiber.abort(\"Could not compile source code.\")\n"
|
||||
"\n"
|
||||
" Fiber.new(fn).call()\n"
|
||||
" Fiber.new(function)()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static compile_(source)\n"
|
||||
|
||||
@ -82,6 +82,7 @@ typedef enum
|
||||
TOKEN_CONSTRUCT,
|
||||
TOKEN_ELSE,
|
||||
TOKEN_FALSE,
|
||||
TOKEN_FN,
|
||||
TOKEN_FOR,
|
||||
TOKEN_FOREIGN,
|
||||
TOKEN_IF,
|
||||
@ -491,6 +492,7 @@ static Keyword keywords[] =
|
||||
{"construct", 9, TOKEN_CONSTRUCT},
|
||||
{"else", 4, TOKEN_ELSE},
|
||||
{"false", 5, TOKEN_FALSE},
|
||||
{"fn", 2, TOKEN_FN},
|
||||
{"for", 3, TOKEN_FOR},
|
||||
{"foreign", 7, TOKEN_FOREIGN},
|
||||
{"if", 2, TOKEN_IF},
|
||||
@ -1493,7 +1495,8 @@ typedef enum
|
||||
PREC_TERM, // + -
|
||||
PREC_FACTOR, // * / %
|
||||
PREC_UNARY, // unary - ! ~
|
||||
PREC_CALL, // . () []
|
||||
PREC_APPLY, // () {} []
|
||||
PREC_CALL, // .
|
||||
PREC_PRIMARY
|
||||
} Precedence;
|
||||
|
||||
@ -1767,6 +1770,39 @@ static void callMethod(Compiler* compiler, int numArgs, const char* name,
|
||||
emitShortArg(compiler, (Code)(CODE_CALL_0 + numArgs), symbol);
|
||||
}
|
||||
|
||||
// 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 an (optional) argument list for a method call with [methodSignature]
|
||||
// and then calls it.
|
||||
static void methodCall(Compiler* compiler, Code instruction,
|
||||
@ -1789,37 +1825,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?
|
||||
@ -1892,6 +1901,21 @@ static void loadCoreVariable(Compiler* compiler, const char* name)
|
||||
emitShortArg(compiler, CODE_LOAD_MODULE_VAR, symbol);
|
||||
}
|
||||
|
||||
// Parses an optional parenthesized parameter list. Updates `type` and `arity`
|
||||
// in [signature] to match what was parsed.
|
||||
static void parameterList(Compiler* compiler, Signature* signature)
|
||||
{
|
||||
consume(compiler, TOKEN_LEFT_PAREN, "Expect '(' before parameters.");
|
||||
|
||||
signature->type = SIG_METHOD;
|
||||
|
||||
// Allow an empty parameter list.
|
||||
if (match(compiler, TOKEN_RIGHT_PAREN)) return;
|
||||
|
||||
finishParameterList(compiler, signature);
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
|
||||
}
|
||||
|
||||
// A parenthesized expression.
|
||||
static void grouping(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
@ -1899,6 +1923,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 +2003,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)
|
||||
{
|
||||
@ -1975,6 +2033,25 @@ static void boolean(Compiler* compiler, bool allowAssignment)
|
||||
compiler->parser->previous.type == TOKEN_FALSE ? CODE_FALSE : CODE_TRUE);
|
||||
}
|
||||
|
||||
// A function literal.
|
||||
static void function(Compiler* compiler, bool allowAssignment)
|
||||
{
|
||||
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);
|
||||
|
||||
endCompiler(&fnCompiler, "fn", 2);
|
||||
}
|
||||
|
||||
// Walks the compiler chain to find the compiler for the nearest class
|
||||
// enclosing this one. Returns NULL if not currently inside a class definition.
|
||||
static Compiler* getEnclosingClassCompiler(Compiler* compiler)
|
||||
@ -2155,13 +2232,13 @@ static void name(Compiler* compiler, bool allowAssignment)
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 a parameter list follows a resolved name, then it will be treated as an
|
||||
// infix call operator on it. So "foo(arg)" gets parsed to "foo.call(arg)" if
|
||||
// foo resolves to a variable and "this.foo(arg)" if we're in a class.
|
||||
//
|
||||
// This makes the *semantics* slightly context-sensitive but keeps the syntax
|
||||
// context free: "foo(arg)" is always *meaningful* regardless of how "foo" is
|
||||
// resolved, it just means one of two things.
|
||||
|
||||
// If we're inside a method and the name is lowercase, treat it as a method
|
||||
// on this.
|
||||
@ -2177,14 +2254,8 @@ static void name(Compiler* compiler, bool allowAssignment)
|
||||
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.
|
||||
// If it's not a self-send or a closure, 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);
|
||||
|
||||
@ -2312,7 +2383,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 '.'.");
|
||||
@ -2464,22 +2535,6 @@ void subscriptSignature(Compiler* compiler, Signature* signature)
|
||||
maybeSetter(compiler, signature);
|
||||
}
|
||||
|
||||
// Parses an optional parenthesized parameter list. Updates `type` and `arity`
|
||||
// in [signature] to match what was parsed.
|
||||
static void parameterList(Compiler* compiler, Signature* signature)
|
||||
{
|
||||
// The parameter list is optional.
|
||||
if (!match(compiler, TOKEN_LEFT_PAREN)) return;
|
||||
|
||||
signature->type = SIG_METHOD;
|
||||
|
||||
// Allow an empty parameter list.
|
||||
if (match(compiler, TOKEN_RIGHT_PAREN)) return;
|
||||
|
||||
finishParameterList(compiler, signature);
|
||||
consume(compiler, TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
|
||||
}
|
||||
|
||||
// Compiles a method signature for a named method or setter.
|
||||
void namedSignature(Compiler* compiler, Signature* signature)
|
||||
{
|
||||
@ -2489,7 +2544,10 @@ void namedSignature(Compiler* compiler, Signature* signature)
|
||||
if (maybeSetter(compiler, signature)) return;
|
||||
|
||||
// Regular named method with an optional parameter list.
|
||||
parameterList(compiler, signature);
|
||||
if (peek(compiler) == TOKEN_LEFT_PAREN)
|
||||
{
|
||||
parameterList(compiler, signature);
|
||||
}
|
||||
}
|
||||
|
||||
// Compiles a method signature for a constructor.
|
||||
@ -2531,14 +2589,14 @@ void constructorSignature(Compiler* compiler, Signature* signature)
|
||||
|
||||
GrammarRule rules[] =
|
||||
{
|
||||
/* TOKEN_LEFT_PAREN */ PREFIX(grouping),
|
||||
/* TOKEN_LEFT_PAREN */ { grouping, call, NULL, PREC_APPLY, NULL },
|
||||
/* TOKEN_RIGHT_PAREN */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACKET */ { list, subscript, subscriptSignature, PREC_CALL, NULL },
|
||||
/* TOKEN_LEFT_BRACKET */ { list, subscript, subscriptSignature, PREC_APPLY, NULL },
|
||||
/* TOKEN_RIGHT_BRACKET */ UNUSED,
|
||||
/* TOKEN_LEFT_BRACE */ PREFIX(map),
|
||||
/* TOKEN_LEFT_BRACE */ { map, blockArgument, NULL, PREC_APPLY, NULL },
|
||||
/* TOKEN_RIGHT_BRACE */ UNUSED,
|
||||
/* TOKEN_COLON */ UNUSED,
|
||||
/* TOKEN_DOT */ INFIX(PREC_CALL, call),
|
||||
/* TOKEN_DOT */ INFIX(PREC_CALL, dot),
|
||||
/* TOKEN_DOTDOT */ INFIX_OPERATOR(PREC_RANGE, ".."),
|
||||
/* TOKEN_DOTDOTDOT */ INFIX_OPERATOR(PREC_RANGE, "..."),
|
||||
/* TOKEN_COMMA */ UNUSED,
|
||||
@ -2569,6 +2627,7 @@ GrammarRule rules[] =
|
||||
/* TOKEN_CONSTRUCT */ { NULL, NULL, constructorSignature, PREC_NONE, NULL },
|
||||
/* TOKEN_ELSE */ UNUSED,
|
||||
/* TOKEN_FALSE */ PREFIX(boolean),
|
||||
/* TOKEN_FN */ PREFIX(function),
|
||||
/* TOKEN_FOR */ UNUSED,
|
||||
/* TOKEN_FOREIGN */ UNUSED,
|
||||
/* TOKEN_IF */ UNUSED,
|
||||
@ -2600,6 +2659,19 @@ static GrammarRule* getRule(TokenType type)
|
||||
return &rules[type];
|
||||
}
|
||||
|
||||
// Completes parsing an expression after the prefix part has been parsed.
|
||||
// Parses any trailing infix expressions.
|
||||
static void parseInfix(Compiler* compiler, bool allowAssignment,
|
||||
Precedence precedence)
|
||||
{
|
||||
while (precedence <= rules[compiler->parser->current.type].precedence)
|
||||
{
|
||||
nextToken(compiler->parser);
|
||||
GrammarFn infix = rules[compiler->parser->previous.type].infix;
|
||||
infix(compiler, allowAssignment);
|
||||
}
|
||||
}
|
||||
|
||||
// The main entrypoint for the top-down operator precedence parser.
|
||||
void parsePrecedence(Compiler* compiler, bool allowAssignment,
|
||||
Precedence precedence)
|
||||
@ -2614,13 +2686,7 @@ void parsePrecedence(Compiler* compiler, bool allowAssignment,
|
||||
}
|
||||
|
||||
prefix(compiler, allowAssignment);
|
||||
|
||||
while (precedence <= rules[compiler->parser->current.type].precedence)
|
||||
{
|
||||
nextToken(compiler->parser);
|
||||
GrammarFn infix = rules[compiler->parser->previous.type].infix;
|
||||
infix(compiler, allowAssignment);
|
||||
}
|
||||
parseInfix(compiler, allowAssignment, precedence);
|
||||
}
|
||||
|
||||
// Parses an expression. Unlike statements, expressions leave a resulting value
|
||||
@ -3234,6 +3300,45 @@ static void classDefinition(Compiler* compiler, bool isForeign)
|
||||
popScope(compiler);
|
||||
}
|
||||
|
||||
static void functionDefinition(Compiler* compiler)
|
||||
{
|
||||
// If we don't have a name after "fn", then this isn't a function declaration,
|
||||
// it's an anonymous function expression appearing in an expressions
|
||||
// statement. In that case, we need to parse it like an expression to allow
|
||||
// other code to follow it, like:
|
||||
//
|
||||
// fn (param) { param }("call with argument")
|
||||
if (peek(compiler) != TOKEN_NAME)
|
||||
{
|
||||
function(compiler, true);
|
||||
parseInfix(compiler, true, PREC_LOWEST);
|
||||
emit(compiler, CODE_POP);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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 an "import" statement.
|
||||
static void import(Compiler* compiler)
|
||||
{
|
||||
@ -3302,6 +3407,10 @@ void definition(Compiler* compiler)
|
||||
{
|
||||
classDefinition(compiler, false);
|
||||
}
|
||||
else if (match(compiler, TOKEN_FN))
|
||||
{
|
||||
functionDefinition(compiler);
|
||||
}
|
||||
else if (match(compiler, TOKEN_FOREIGN))
|
||||
{
|
||||
consume(compiler, TOKEN_CLASS, "Expect 'class' after 'foreign'.");
|
||||
|
||||
@ -235,14 +235,6 @@ DEF_PRIMITIVE(fiber_yield1)
|
||||
return false;
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(fn_new)
|
||||
{
|
||||
if (!validateFn(vm, args[1], "Argument")) return false;
|
||||
|
||||
// The block argument is already a function, so just return it.
|
||||
RETURN_VAL(args[1]);
|
||||
}
|
||||
|
||||
DEF_PRIMITIVE(fn_arity)
|
||||
{
|
||||
RETURN_NUM(AS_FN(args[0])->arity);
|
||||
@ -1161,7 +1153,6 @@ void wrenInitializeCore(WrenVM* vm)
|
||||
PRIMITIVE(vm->fiberClass, "try()", fiber_try);
|
||||
|
||||
vm->fnClass = AS_CLASS(wrenFindVariable(vm, coreModule, "Fn"));
|
||||
PRIMITIVE(vm->fnClass->obj.classObj, "new(_)", fn_new);
|
||||
|
||||
PRIMITIVE(vm->fnClass, "arity", fn_arity);
|
||||
fnCall(vm, "call()");
|
||||
|
||||
@ -8,7 +8,7 @@ class Sequence {
|
||||
all(f) {
|
||||
var result = true
|
||||
for (element in this) {
|
||||
result = f.call(element)
|
||||
result = f(element)
|
||||
if (!result) return result
|
||||
}
|
||||
return result
|
||||
@ -17,7 +17,7 @@ class Sequence {
|
||||
any(f) {
|
||||
var result = false
|
||||
for (element in this) {
|
||||
result = f.call(element)
|
||||
result = f(element)
|
||||
if (result) return result
|
||||
}
|
||||
return result
|
||||
@ -41,14 +41,14 @@ class Sequence {
|
||||
count(f) {
|
||||
var result = 0
|
||||
for (element in this) {
|
||||
if (f.call(element)) result = result + 1
|
||||
if (f(element)) result = result + 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
each(f) {
|
||||
for (element in this) {
|
||||
f.call(element)
|
||||
f(element)
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ class Sequence {
|
||||
|
||||
reduce(acc, f) {
|
||||
for (element in this) {
|
||||
acc = f.call(acc, element)
|
||||
acc = f(acc, element)
|
||||
}
|
||||
return acc
|
||||
}
|
||||
@ -72,7 +72,7 @@ class Sequence {
|
||||
// Seed with the first element.
|
||||
var result = iteratorValue(iter)
|
||||
while (iter = iterate(iter)) {
|
||||
result = f.call(result, iteratorValue(iter))
|
||||
result = f(result, iteratorValue(iter))
|
||||
}
|
||||
|
||||
return result
|
||||
@ -103,24 +103,24 @@ class Sequence {
|
||||
}
|
||||
|
||||
class MapSequence is Sequence {
|
||||
construct new(sequence, fn) {
|
||||
construct new(sequence, function) {
|
||||
_sequence = sequence
|
||||
_fn = fn
|
||||
_function = function
|
||||
}
|
||||
|
||||
iterate(iterator) { _sequence.iterate(iterator) }
|
||||
iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }
|
||||
iteratorValue(iterator) { _function.call(_sequence.iteratorValue(iterator)) }
|
||||
}
|
||||
|
||||
class WhereSequence is Sequence {
|
||||
construct new(sequence, fn) {
|
||||
construct new(sequence, function) {
|
||||
_sequence = sequence
|
||||
_fn = fn
|
||||
_function = function
|
||||
}
|
||||
|
||||
iterate(iterator) {
|
||||
while (iterator = _sequence.iterate(iterator)) {
|
||||
if (_fn.call(_sequence.iteratorValue(iterator))) break
|
||||
if (_function.call(_sequence.iteratorValue(iterator))) break
|
||||
}
|
||||
return iterator
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ static const char* coreModuleSource =
|
||||
" all(f) {\n"
|
||||
" var result = true\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" result = f(element)\n"
|
||||
" if (!result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
@ -19,7 +19,7 @@ static const char* coreModuleSource =
|
||||
" any(f) {\n"
|
||||
" var result = false\n"
|
||||
" for (element in this) {\n"
|
||||
" result = f.call(element)\n"
|
||||
" result = f(element)\n"
|
||||
" if (result) return result\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
@ -43,14 +43,14 @@ static const char* coreModuleSource =
|
||||
" count(f) {\n"
|
||||
" var result = 0\n"
|
||||
" for (element in this) {\n"
|
||||
" if (f.call(element)) result = result + 1\n"
|
||||
" if (f(element)) result = result + 1\n"
|
||||
" }\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" each(f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" f.call(element)\n"
|
||||
" f(element)\n"
|
||||
" }\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
@ -62,7 +62,7 @@ static const char* coreModuleSource =
|
||||
"\n"
|
||||
" reduce(acc, f) {\n"
|
||||
" for (element in this) {\n"
|
||||
" acc = f.call(acc, element)\n"
|
||||
" acc = f(acc, element)\n"
|
||||
" }\n"
|
||||
" return acc\n"
|
||||
" }\n"
|
||||
@ -74,7 +74,7 @@ static const char* coreModuleSource =
|
||||
" // Seed with the first element.\n"
|
||||
" var result = iteratorValue(iter)\n"
|
||||
" while (iter = iterate(iter)) {\n"
|
||||
" result = f.call(result, iteratorValue(iter))\n"
|
||||
" result = f(result, iteratorValue(iter))\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
@ -105,24 +105,24 @@ static const char* coreModuleSource =
|
||||
"}\n"
|
||||
"\n"
|
||||
"class MapSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" construct new(sequence, function) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" _function = function\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) { _sequence.iterate(iterator) }\n"
|
||||
" iteratorValue(iterator) { _fn.call(_sequence.iteratorValue(iterator)) }\n"
|
||||
" iteratorValue(iterator) { _function.call(_sequence.iteratorValue(iterator)) }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class WhereSequence is Sequence {\n"
|
||||
" construct new(sequence, fn) {\n"
|
||||
" construct new(sequence, function) {\n"
|
||||
" _sequence = sequence\n"
|
||||
" _fn = fn\n"
|
||||
" _function = function\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" iterate(iterator) {\n"
|
||||
" while (iterator = _sequence.iterate(iterator)) {\n"
|
||||
" if (_fn.call(_sequence.iteratorValue(iterator))) break\n"
|
||||
" if (_function.call(_sequence.iteratorValue(iterator))) break\n"
|
||||
" }\n"
|
||||
" return iterator\n"
|
||||
" }\n"
|
||||
|
||||
@ -68,8 +68,6 @@ var ORDERED = [
|
||||
WEAKEST, WEAK_DEFAULT, NORMAL, STRONG_DEFAULT, PREFERRED, STRONG_REFERRED
|
||||
]
|
||||
|
||||
var ThePlanner
|
||||
|
||||
class Constraint {
|
||||
construct new(strength) {
|
||||
_strength = strength
|
||||
@ -410,7 +408,7 @@ class Variable {
|
||||
|
||||
// Removes all traces of c from this variable.
|
||||
removeConstraint(constraint) {
|
||||
_constraints = _constraints.where { |c| c != constraint }
|
||||
_constraints = _constraints.where {|c| c != constraint }
|
||||
if (_determinedBy == constraint) _determinedBy = null
|
||||
}
|
||||
}
|
||||
@ -611,7 +609,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|
|
||||
fn chainTest(n) {
|
||||
ThePlanner = Planner.new()
|
||||
var prev = null
|
||||
var first = null
|
||||
@ -636,7 +634,7 @@ var chainTest = Fn.new {|n|
|
||||
}
|
||||
}
|
||||
|
||||
var change = Fn.new {|v, newValue|
|
||||
fn change(v, newValue) {
|
||||
var edit = EditConstraint.new(v, PREFERRED)
|
||||
var plan = ThePlanner.extractPlanFromConstraints([edit])
|
||||
for (i in 0...10) {
|
||||
@ -647,11 +645,13 @@ var change = Fn.new {|v, newValue|
|
||||
edit.destroyConstraint
|
||||
}
|
||||
|
||||
var ThePlanner
|
||||
|
||||
// This test constructs a two sets of variables related to each
|
||||
// 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|
|
||||
fn projectionTest(n) {
|
||||
ThePlanner = Planner.new()
|
||||
var scale = Variable.new("scale", 10)
|
||||
var offset = Variable.new("offset", 1000)
|
||||
@ -667,22 +667,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")
|
||||
@ -691,8 +691,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)
|
||||
|
||||
@ -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)")
|
||||
|
||||
@ -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
|
||||
|
||||
@ -5,5 +5,5 @@ 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
|
||||
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,15 +1,15 @@
|
||||
var A = Fiber.new {
|
||||
System.print("transferred to A")
|
||||
B.transferError("error!")
|
||||
var a = Fiber.new {
|
||||
System.print("transferred to a")
|
||||
b.transferError("error!")
|
||||
}
|
||||
|
||||
var B = Fiber.new {
|
||||
System.print("started B")
|
||||
A.transfer()
|
||||
var b = Fiber.new {
|
||||
System.print("started b")
|
||||
a.transfer()
|
||||
System.print("should not get here")
|
||||
}
|
||||
|
||||
B.try()
|
||||
// expect: started B
|
||||
// expect: transferred to A
|
||||
System.print(B.error) // expect: error!
|
||||
b.try()
|
||||
// expect: started b
|
||||
// expect: transferred to a
|
||||
System.print(b.error) // expect: error!
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
var A = Fiber.new {
|
||||
B.transferError(123)
|
||||
var a = Fiber.new {
|
||||
b.transferError(123)
|
||||
}
|
||||
|
||||
var B = Fiber.new {
|
||||
A.transfer()
|
||||
var b = Fiber.new {
|
||||
a.transfer()
|
||||
}
|
||||
|
||||
B.try()
|
||||
System.print(B.error) // expect: 123
|
||||
b.try()
|
||||
System.print(b.error) // expect: 123
|
||||
|
||||
@ -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() // 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() // 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.transfer("blah") // expect runtime error: Cannot transfer to a finished fiber.
|
||||
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
|
||||
fiber() // expect: fiber 1
|
||||
System.print("main 1") // expect: main 1
|
||||
fiber.call() // expect: fiber 2
|
||||
fiber() // expect: fiber 2
|
||||
System.print("main 2") // expect: main 2
|
||||
fiber.call() // expect: fiber 3
|
||||
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
|
||||
System.print(fiber()) // expect: fiber 1
|
||||
// expect: yield 1
|
||||
System.print(fiber.call()) // expect: fiber 2
|
||||
System.print(fiber()) // expect: fiber 2
|
||||
// expect: yield 2
|
||||
System.print(fiber.call()) // expect: fiber 3
|
||||
System.print(fiber()) // expect: fiber 3
|
||||
// expect: null
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
System.print(Fn.new {}.arity) // expect: 0
|
||||
System.print(Fn.new {|a| a}.arity) // expect: 1
|
||||
System.print(Fn.new {|a, b| a}.arity) // expect: 2
|
||||
System.print(Fn.new {|a, b, c| a}.arity) // expect: 3
|
||||
System.print(Fn.new {|a, b, c, d| a}.arity) // expect: 4
|
||||
System.print(fn () {}.arity) // expect: 0
|
||||
System.print(fn (a) {a}.arity) // expect: 1
|
||||
System.print(fn (a, b) {a}.arity) // expect: 2
|
||||
System.print(fn (a, b, c) {a}.arity) // expect: 3
|
||||
System.print(fn (a, b, c, d) {a}.arity) // expect: 4
|
||||
|
||||
@ -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)") }
|
||||
fn f0() { System.print("zero") }
|
||||
fn f1(a) { System.print("one %(a)") }
|
||||
fn f2(a, b) { System.print("two %(a) %(b)") }
|
||||
fn 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.
|
||||
fn f2(a, b) { System.print(a + b) }
|
||||
f2("a") // expect runtime error: Function expects more arguments.
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
// Not structurally equal.
|
||||
System.print(Fn.new { 123 } == Fn.new { 123 }) // expect: false
|
||||
System.print(Fn.new { 123 } != Fn.new { 123 }) // expect: true
|
||||
System.print(fn () { 123 } == fn () { 123 }) // expect: false
|
||||
System.print(fn () { 123 } != fn () { 123 }) // expect: true
|
||||
|
||||
// Not equal to other types.
|
||||
System.print(Fn.new { 123 } == 1) // expect: false
|
||||
System.print(Fn.new { 123 } == false) // expect: false
|
||||
System.print(Fn.new { 123 } == "fn 123") // expect: false
|
||||
System.print(Fn.new { 123 } != 1) // expect: true
|
||||
System.print(Fn.new { 123 } != false) // expect: true
|
||||
System.print(Fn.new { 123 } != "fn 123") // expect: true
|
||||
System.print(fn () { 123 } == 1) // expect: false
|
||||
System.print(fn () { 123 } == false) // expect: false
|
||||
System.print(fn () { 123 } == "fn 123") // expect: false
|
||||
System.print(fn () { 123 } != 1) // expect: true
|
||||
System.print(fn () { 123 } != false) // expect: true
|
||||
System.print(fn () { 123 } != "fn 123") // expect: true
|
||||
|
||||
// Equal by identity.
|
||||
var f = Fn.new { 123 }
|
||||
fn f() { 123 }
|
||||
System.print(f == f) // expect: true
|
||||
System.print(f != f) // expect: false
|
||||
|
||||
@ -1 +0,0 @@
|
||||
Fn.new(3) // expect runtime error: Argument must be a function.
|
||||
@ -1 +1 @@
|
||||
System.print(Fn.new {}) // expect: <fn>
|
||||
System.print(fn () {}) // expect: <fn>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
System.print(Fn.new { 0 } is Fn) // expect: true
|
||||
System.print(Fn.new { 0 } is Object) // expect: true
|
||||
System.print(Fn.new { 0 } is String) // expect: false
|
||||
System.print(Fn.new { 0 }.type == Fn) // expect: true
|
||||
System.print(fn () { 0 } is Fn) // expect: true
|
||||
System.print(fn () { 0 } is Object) // expect: true
|
||||
System.print(fn () { 0 } is String) // expect: false
|
||||
System.print(fn () { 0 }.type == Fn) // expect: true
|
||||
|
||||
@ -1,14 +1,8 @@
|
||||
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
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
System.print(Num is Class) // expect: true
|
||||
System.print(true is Bool) // expect: true
|
||||
System.print(Fn.new { 1 } is Fn) // expect: true
|
||||
System.print(fn () { 1 } is Fn) // expect: true
|
||||
System.print(123 is Num) // expect: true
|
||||
System.print(null is Null) // expect: true
|
||||
System.print("s" is String) // expect: true
|
||||
@ -8,7 +8,7 @@ System.print("s" is String) // expect: true
|
||||
System.print(Num is Bool) // expect: false
|
||||
System.print(null is Class) // expect: false
|
||||
System.print(true is Fn) // expect: false
|
||||
System.print(Fn.new { 1 } is Num) // expect: false
|
||||
System.print(fn () { 1 } is Num) // expect: false
|
||||
System.print("s" is Null) // expect: false
|
||||
System.print(123 is String) // expect: false
|
||||
|
||||
@ -16,7 +16,7 @@ System.print(123 is String) // expect: false
|
||||
System.print(Num is Object) // expect: true
|
||||
System.print(null is Object) // expect: true
|
||||
System.print(true is Object) // expect: true
|
||||
System.print(Fn.new { 1 } is Object) // expect: true
|
||||
System.print(fn () { 1 } is Object) // expect: true
|
||||
System.print("s" is Object) // expect: true
|
||||
System.print(123 is Object) // expect: true
|
||||
|
||||
@ -24,7 +24,7 @@ System.print(123 is Object) // expect: true
|
||||
System.print(Num is Class) // expect: true
|
||||
System.print(null is Class) // expect: false
|
||||
System.print(true is Class) // expect: false
|
||||
System.print(Fn.new { 1 } is Class) // expect: false
|
||||
System.print(fn () { 1 } is Class) // expect: false
|
||||
System.print("s" is Class) // expect: false
|
||||
System.print(123 is Class) // expect: false
|
||||
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
var a = "a"
|
||||
var b = "b"
|
||||
b is a = "value" // expect error
|
||||
@ -1,4 +1,4 @@
|
||||
Fn.new {
|
||||
fn () {
|
||||
var a = "before"
|
||||
System.print(a) // expect: before
|
||||
|
||||
@ -7,4 +7,4 @@ Fn.new {
|
||||
|
||||
System.print(a = "arg") // expect: arg
|
||||
System.print(a) // expect: arg
|
||||
}.call()
|
||||
}()
|
||||
|
||||
@ -1 +1,4 @@
|
||||
unknown = "what" // expect error
|
||||
unknown = "what"
|
||||
// Error on last line since the variable is assumed to be implicitly defined
|
||||
// until we hit the end and don't find it.
|
||||
// expect error
|
||||
3
test/language/block_argument/empty_body.wren
Normal file
3
test/language/block_argument/empty_body.wren
Normal file
@ -0,0 +1,3 @@
|
||||
fn block(arg) { arg }
|
||||
var f = block {}
|
||||
System.print(f()) // expect: null
|
||||
5
test/language/block_argument/newline_body.wren
Normal file
5
test/language/block_argument/newline_body.wren
Normal file
@ -0,0 +1,5 @@
|
||||
fn block(arg) { arg }
|
||||
var f = block {
|
||||
// Hi.
|
||||
}
|
||||
System.print(f()) // expect: null
|
||||
@ -0,0 +1,3 @@
|
||||
fn block(arg) { arg }
|
||||
block { System.print("ok") // expect error
|
||||
}()
|
||||
@ -0,0 +1,3 @@
|
||||
fn block(arg) { arg }
|
||||
block {
|
||||
System.print("ok") } // expect error
|
||||
2
test/language/block_argument/no_parameters.wren
Normal file
2
test/language/block_argument/no_parameters.wren
Normal file
@ -0,0 +1,2 @@
|
||||
fn block(arg) { arg }
|
||||
block {|| null } // expect error
|
||||
52
test/language/block_argument/parameters.wren
Normal file
52
test/language/block_argument/parameters.wren
Normal file
@ -0,0 +1,52 @@
|
||||
fn block(arg) { arg }
|
||||
|
||||
var f0 = block { 0 }
|
||||
System.print(f0.call()) // expect: 0
|
||||
|
||||
var f1 = block {|a| a }
|
||||
System.print(f1.call(1)) // expect: 1
|
||||
|
||||
var f2 = block {|a, b| a + b }
|
||||
System.print(f2.call(1, 2)) // expect: 3
|
||||
|
||||
var f3 = block {|a, b, c| a + b + c }
|
||||
System.print(f3.call(1, 2, 3)) // expect: 6
|
||||
|
||||
var f4 = block {|a, b, c, d| a + b + c + d }
|
||||
System.print(f4.call(1, 2, 3, 4)) // expect: 10
|
||||
|
||||
var f5 = block {|a, b, c, d, e| a + b + c + d + e }
|
||||
System.print(f5.call(1, 2, 3, 4, 5)) // expect: 15
|
||||
|
||||
var f6 = block {|a, b, c, d, e, f| a + b + c + d + e + f }
|
||||
System.print(f6.call(1, 2, 3, 4, 5, 6)) // expect: 21
|
||||
|
||||
var f7 = block {|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
|
||||
|
||||
var f8 = block {|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
|
||||
|
||||
var f9 = block {|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
|
||||
|
||||
var f10 = block {|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
|
||||
|
||||
var f11 = block {|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
|
||||
|
||||
var f12 = block {|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
|
||||
|
||||
var f13 = block {|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
|
||||
|
||||
var f14 = block {|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
|
||||
|
||||
var f15 = block {|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
|
||||
|
||||
var f16 = block {|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
|
||||
@ -1,19 +1,21 @@
|
||||
fn block(arg) { arg }
|
||||
|
||||
// Single expression body.
|
||||
Fn.new { System.print("ok") }.call() // expect: ok
|
||||
System.print(block { "ok" }()) // expect: ok
|
||||
|
||||
// Curly body.
|
||||
Fn.new {
|
||||
block {
|
||||
System.print("ok") // expect: ok
|
||||
}.call()
|
||||
}()
|
||||
|
||||
// Multiple statements.
|
||||
Fn.new {
|
||||
block {
|
||||
System.print("1") // expect: 1
|
||||
System.print("2") // expect: 2
|
||||
}.call()
|
||||
}()
|
||||
|
||||
// Extra newlines.
|
||||
Fn.new {
|
||||
block {
|
||||
|
||||
|
||||
System.print("1") // expect: 1
|
||||
@ -22,4 +24,4 @@ Fn.new {
|
||||
System.print("2") // expect: 2
|
||||
|
||||
|
||||
}.call()
|
||||
}()
|
||||
@ -1,9 +1,9 @@
|
||||
var f
|
||||
for (i in [1, 2, 3]) {
|
||||
var j = 4
|
||||
f = Fn.new { System.print(i + j) }
|
||||
f = fn () { System.print(i + j) }
|
||||
break
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: 5
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var f
|
||||
while (true) {
|
||||
var i = "i"
|
||||
f = Fn.new { System.print(i) }
|
||||
f = fn () { System.print(i) }
|
||||
break
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: i
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
var done = false
|
||||
while (!done) {
|
||||
Fn.new {
|
||||
fn () {
|
||||
break // expect error
|
||||
}
|
||||
done = true
|
||||
|
||||
@ -3,23 +3,23 @@ var g = null
|
||||
|
||||
{
|
||||
var local = "local"
|
||||
f = Fn.new {
|
||||
f = fn () {
|
||||
System.print(local)
|
||||
local = "after f"
|
||||
System.print(local)
|
||||
}
|
||||
|
||||
g = Fn.new {
|
||||
g = fn () {
|
||||
System.print(local)
|
||||
local = "after g"
|
||||
System.print(local)
|
||||
}
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: local
|
||||
// expect: after f
|
||||
|
||||
g.call()
|
||||
g()
|
||||
// expect: after f
|
||||
// expect: after g
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
var f = null
|
||||
|
||||
Fn.new {|param|
|
||||
f = Fn.new {
|
||||
fn (param) {
|
||||
f = fn () {
|
||||
System.print(param)
|
||||
}
|
||||
}.call("param")
|
||||
}("param")
|
||||
|
||||
f.call() // expect: param
|
||||
f() // expect: param
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
// would crash because it walked to the end of the upvalue list (correct), but
|
||||
// then didn't handle not finding the variable.
|
||||
|
||||
Fn.new {
|
||||
fn () {
|
||||
var a = "a"
|
||||
var b = "b"
|
||||
Fn.new {
|
||||
fn () {
|
||||
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 () {
|
||||
System.print(param)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new().method("param")
|
||||
F.call() // expect: param
|
||||
F() // expect: param
|
||||
|
||||
@ -2,9 +2,9 @@ var f = null
|
||||
|
||||
{
|
||||
var local = "local"
|
||||
f = Fn.new {
|
||||
f = fn () {
|
||||
System.print(local)
|
||||
}
|
||||
}
|
||||
|
||||
f.call() // expect: local
|
||||
f() // expect: local
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
var f = null
|
||||
|
||||
Fn.new {
|
||||
fn () {
|
||||
var a = "a"
|
||||
Fn.new {
|
||||
fn () {
|
||||
var b = "b"
|
||||
Fn.new {
|
||||
fn () {
|
||||
var c = "c"
|
||||
f = Fn.new {
|
||||
f = fn () {
|
||||
System.print(a)
|
||||
System.print(b)
|
||||
System.print(c)
|
||||
}
|
||||
}.call()
|
||||
}.call()
|
||||
}.call()
|
||||
}()
|
||||
}()
|
||||
}()
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: a
|
||||
// expect: b
|
||||
// expect: c
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
var local = "local"
|
||||
Fn.new {
|
||||
fn () {
|
||||
System.print(local) // expect: local
|
||||
}.call()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -2,12 +2,12 @@ var f = null
|
||||
|
||||
{
|
||||
var a = "a"
|
||||
f = Fn.new {
|
||||
f = fn () {
|
||||
System.print(a)
|
||||
System.print(a)
|
||||
}
|
||||
}
|
||||
|
||||
f.call()
|
||||
f()
|
||||
// expect: a
|
||||
// expect: a
|
||||
|
||||
@ -3,14 +3,14 @@
|
||||
|
||||
{
|
||||
var a = "a"
|
||||
f = Fn.new { System.print(a) }
|
||||
f = fn () { System.print(a) }
|
||||
}
|
||||
|
||||
{
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
{
|
||||
var foo = "closure"
|
||||
Fn.new {
|
||||
fn () {
|
||||
{
|
||||
System.print(foo) // expect: closure
|
||||
var foo = "shadow"
|
||||
System.print(foo) // expect: shadow
|
||||
}
|
||||
System.print(foo) // expect: closure
|
||||
}.call()
|
||||
}()
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
{
|
||||
var a = "a"
|
||||
if (false) Fn.new { a }
|
||||
if (false) fn () { a }
|
||||
}
|
||||
|
||||
// If we get here, we didn't segfault when a went out of scope.
|
||||
|
||||
@ -11,9 +11,9 @@ var closure
|
||||
|
||||
{
|
||||
var b = "b"
|
||||
closure = Fn.new { a }
|
||||
if (false) Fn.new { b }
|
||||
closure = fn () { a }
|
||||
if (false) fn () { b }
|
||||
}
|
||||
|
||||
System.print(closure.call()) // expect: a
|
||||
System.print(closure()) // expect: a
|
||||
}
|
||||
|
||||
@ -12,14 +12,14 @@ var closure
|
||||
a = "final"
|
||||
}
|
||||
|
||||
closure = Fn.new {
|
||||
closure = fn () {
|
||||
System.print(a)
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return Fn.new { _field }
|
||||
closeOverGet() {
|
||||
return fn () { _field }
|
||||
}
|
||||
|
||||
closeOverSet {
|
||||
return Fn.new { _field = "new value" }
|
||||
closeOverSet() {
|
||||
return fn () { _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
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
class Foo {
|
||||
static bar {
|
||||
Fn.new { _field = "wat" } // expect error
|
||||
fn () { _field = "wat" } // expect error
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
var list = []
|
||||
|
||||
for (i in [1, 2, 3]) {
|
||||
list.add(Fn.new { System.print(i) })
|
||||
list.add(fn () { System.print(i) })
|
||||
}
|
||||
|
||||
for (f in list) f.call()
|
||||
for (f in list) f()
|
||||
// expect: 1
|
||||
// expect: 2
|
||||
// expect: 3
|
||||
|
||||
@ -2,10 +2,10 @@ var list = []
|
||||
|
||||
for (i in [1, 2, 3]) {
|
||||
var j = i + 1
|
||||
list.add(Fn.new { System.print(j) })
|
||||
list.add(fn () { 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 {
|
||||
fn 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 {
|
||||
fn f() {
|
||||
for (i in [1, 2, 3]) {
|
||||
return Fn.new { System.print(i) }
|
||||
return fn () { System.print(i) }
|
||||
}
|
||||
}
|
||||
|
||||
var g = f.call()
|
||||
g.call()
|
||||
var g = f()
|
||||
g()
|
||||
// expect: 1
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
var f = Fn.new {
|
||||
fn f() {
|
||||
for (i in [1, 2, 3]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
System.print(f.call())
|
||||
System.print(f())
|
||||
// expect: 1
|
||||
|
||||
31
test/language/function/declaration_syntax.wren
Normal file
31
test/language/function/declaration_syntax.wren
Normal file
@ -0,0 +1,31 @@
|
||||
// Single expression body.
|
||||
fn a() { "ok" }
|
||||
System.print(a()) // expect: ok
|
||||
|
||||
// Curly body.
|
||||
fn b() {
|
||||
System.print("ok") // expect: ok
|
||||
}
|
||||
b()
|
||||
|
||||
// Multiple statements.
|
||||
fn c() {
|
||||
System.print("1") // expect: 1
|
||||
System.print("2") // expect: 2
|
||||
}
|
||||
c()
|
||||
|
||||
// Extra newlines.
|
||||
fn d() {
|
||||
|
||||
|
||||
System.print("1") // expect: 1
|
||||
|
||||
|
||||
System.print("2") // expect: 2
|
||||
|
||||
|
||||
}
|
||||
d()
|
||||
|
||||
// TODO: Newlines before/after parameters.
|
||||
@ -1,2 +1,2 @@
|
||||
var f = Fn.new {}
|
||||
System.print(f.call()) // expect: null
|
||||
fn f() {}
|
||||
System.print(f()) // expect: null
|
||||
|
||||
25
test/language/function/expression_syntax.wren
Normal file
25
test/language/function/expression_syntax.wren
Normal file
@ -0,0 +1,25 @@
|
||||
// Single expression body.
|
||||
System.print(fn () { "ok" }()) // expect: ok
|
||||
|
||||
// Curly body.
|
||||
fn () {
|
||||
System.print("ok") // expect: ok
|
||||
}()
|
||||
|
||||
// Multiple statements.
|
||||
fn () {
|
||||
System.print("1") // expect: 1
|
||||
System.print("2") // expect: 2
|
||||
}()
|
||||
|
||||
// Extra newlines.
|
||||
fn () {
|
||||
|
||||
|
||||
System.print("1") // expect: 1
|
||||
|
||||
|
||||
System.print("2") // expect: 2
|
||||
|
||||
|
||||
}()
|
||||
@ -1,4 +1,4 @@
|
||||
var f = Fn.new {
|
||||
fn f() {
|
||||
// Hi.
|
||||
}
|
||||
System.print(f.call()) // expect: null
|
||||
System.print(f()) // expect: null
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
Fn.new { System.print("ok") // expect error
|
||||
}.call()
|
||||
fn () { System.print("ok") // expect error
|
||||
}()
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
Fn.new {
|
||||
fn () {
|
||||
System.print("ok") } // expect error
|
||||
@ -1 +0,0 @@
|
||||
Fn.new {|| null } // expect error
|
||||
@ -1,50 +1,50 @@
|
||||
var f0 = Fn.new { 0 }
|
||||
System.print(f0.call()) // expect: 0
|
||||
fn f0() { 0 }
|
||||
System.print(f0()) // expect: 0
|
||||
|
||||
var f1 = Fn.new {|a| a }
|
||||
System.print(f1.call(1)) // expect: 1
|
||||
fn f1(a) { a }
|
||||
System.print(f1(1)) // expect: 1
|
||||
|
||||
var f2 = Fn.new {|a, b| a + b }
|
||||
System.print(f2.call(1, 2)) // expect: 3
|
||||
fn f2(a, b) { a + b }
|
||||
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
|
||||
fn f3(a, b, c) { a + b + c }
|
||||
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
|
||||
fn f4(a, b, c, d) { a + b + c + d }
|
||||
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
|
||||
fn f5(a, b, c, d, e) { a + b + c + d + e }
|
||||
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
|
||||
fn f6(a, b, c, d, e, f) { a + b + c + d + e + f }
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
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
|
||||
fn 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
|
||||
|
||||
11
test/language/implicit_receiver/block_argument.wren
Normal file
11
test/language/implicit_receiver/block_argument.wren
Normal file
@ -0,0 +1,11 @@
|
||||
class Foo {
|
||||
construct new() {
|
||||
method { "block" }
|
||||
}
|
||||
|
||||
method(a) {
|
||||
System.print("method %(a())")
|
||||
}
|
||||
}
|
||||
|
||||
Foo.new() // expect: method block
|
||||
@ -2,7 +2,7 @@ var ClosureType
|
||||
|
||||
{
|
||||
var a = "a"
|
||||
ClosureType = Fn.new { System.print(a) }.type
|
||||
ClosureType = fn () { System.print(a) }.type
|
||||
}
|
||||
|
||||
class Subclass is ClosureType {} // expect runtime error: Class 'Subclass' cannot inherit from built-in class 'Fn'.
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
class Foo {
|
||||
construct new() { _field = "Foo field" }
|
||||
|
||||
closeOverFooGet {
|
||||
return Fn.new { Fn.new { _field } }
|
||||
closeOverFooGet() {
|
||||
return fn () { fn () { _field } }
|
||||
}
|
||||
|
||||
closeOverFooSet {
|
||||
return Fn.new { Fn.new { _field = "new foo value" } }
|
||||
closeOverFooSet() {
|
||||
return fn () { fn () { _field = "new foo value" } }
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,21 +16,21 @@ class Bar is Foo {
|
||||
_field = "Bar field"
|
||||
}
|
||||
|
||||
closeOverBarGet {
|
||||
return Fn.new { Fn.new { _field } }
|
||||
closeOverBarGet() {
|
||||
return fn () { fn () { _field } }
|
||||
}
|
||||
|
||||
closeOverBarSet {
|
||||
return Fn.new { Fn.new { _field = "new bar value" } }
|
||||
closeOverBarSet() {
|
||||
return fn () { fn () { _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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user