mirror of
https://github.com/wren-lang/wren.git
synced 2026-01-11 06:08:41 +01:00
Logical "||" operator.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
build/
|
||||
|
||||
# XCode user-specific stuff.
|
||||
xcuserdata/
|
||||
xcuserdata/
|
||||
*.xccheckout
|
||||
@ -32,6 +32,7 @@ typedef enum
|
||||
TOKEN_PLUS,
|
||||
TOKEN_MINUS,
|
||||
TOKEN_PIPE,
|
||||
TOKEN_PIPEPIPE,
|
||||
TOKEN_AMP,
|
||||
TOKEN_AMPAMP,
|
||||
TOKEN_BANG,
|
||||
@ -384,7 +385,18 @@ static void readRawToken(Parser* parser)
|
||||
}
|
||||
return;
|
||||
|
||||
case '|': makeToken(parser, TOKEN_PIPE); return;
|
||||
case '|':
|
||||
if (peekChar(parser) == '|')
|
||||
{
|
||||
nextChar(parser);
|
||||
makeToken(parser, TOKEN_PIPEPIPE);
|
||||
}
|
||||
else
|
||||
{
|
||||
makeToken(parser, TOKEN_PIPE);
|
||||
}
|
||||
return;
|
||||
|
||||
case '&':
|
||||
if (peekChar(parser) == '&')
|
||||
{
|
||||
@ -512,6 +524,7 @@ static void nextToken(Parser* parser)
|
||||
case TOKEN_PLUS:
|
||||
case TOKEN_MINUS:
|
||||
case TOKEN_PIPE:
|
||||
case TOKEN_PIPEPIPE:
|
||||
case TOKEN_AMP:
|
||||
case TOKEN_AMPAMP:
|
||||
case TOKEN_BANG:
|
||||
@ -1000,6 +1013,17 @@ void and(Compiler* compiler, int allowAssignment)
|
||||
patchJump(compiler, jump);
|
||||
}
|
||||
|
||||
void or(Compiler* compiler, int allowAssignment)
|
||||
{
|
||||
// Skip the right argument if the left is true.
|
||||
emit(compiler, CODE_OR);
|
||||
int jump = emit(compiler, 255);
|
||||
|
||||
parsePrecedence(compiler, 0, PREC_LOGIC);
|
||||
|
||||
patchJump(compiler, jump);
|
||||
}
|
||||
|
||||
void infixOp(Compiler* compiler, int allowAssignment)
|
||||
{
|
||||
GrammarRule* rule = &rules[compiler->parser->previous.type];
|
||||
@ -1073,6 +1097,7 @@ GrammarRule rules[] =
|
||||
/* TOKEN_PLUS */ INFIX_OPERATOR(PREC_TERM, "+ "),
|
||||
/* TOKEN_MINUS */ OPERATOR(PREC_TERM, "- "),
|
||||
/* TOKEN_PIPE */ UNUSED,
|
||||
/* TOKEN_PIPEPIPE */ INFIX(PREC_LOGIC, or),
|
||||
/* TOKEN_AMP */ UNUSED,
|
||||
/* TOKEN_AMPAMP */ INFIX(PREC_LOGIC, and),
|
||||
/* TOKEN_BANG */ PREFIX_OPERATOR("!"),
|
||||
|
||||
27
src/vm.c
27
src/vm.c
@ -577,6 +577,14 @@ int dumpInstruction(VM* vm, ObjFn* fn, int i)
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_OR:
|
||||
{
|
||||
int offset = bytecode[i++];
|
||||
printf("OR %d\n", offset);
|
||||
printf("%04d | offset %d\n", i, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_IS:
|
||||
printf("CODE_IS\n");
|
||||
break;
|
||||
@ -908,6 +916,25 @@ Value interpret(VM* vm, ObjFn* fn)
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_OR:
|
||||
{
|
||||
int offset = READ_ARG();
|
||||
Value condition = PEEK();
|
||||
|
||||
// False is the only falsey value.
|
||||
if (IS_FALSE(condition))
|
||||
{
|
||||
// Discard the condition and evaluate the right hand side.
|
||||
POP();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Short-circuit the right hand side.
|
||||
ip += offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CODE_IS:
|
||||
{
|
||||
Value classObj = POP();
|
||||
|
||||
4
src/vm.h
4
src/vm.h
@ -83,6 +83,10 @@ typedef enum
|
||||
// continue.
|
||||
CODE_AND,
|
||||
|
||||
// If the top of the stack is non-false, jump [arg] forward. Otherwise, pop
|
||||
// and continue.
|
||||
CODE_OR,
|
||||
|
||||
// Pop [a] then [b] and push true if [b] is an instance of [a].
|
||||
CODE_IS,
|
||||
|
||||
|
||||
@ -18,3 +18,9 @@ io.write(true) && // expect: true
|
||||
// Swallow a trailing newline.
|
||||
io.write(true &&
|
||||
true) // expect: true
|
||||
|
||||
// Only false is falsy.
|
||||
io.write(0 && true) // expect: true
|
||||
io.write(null && true) // expect: true
|
||||
io.write("" && true) // expect: true
|
||||
io.write(false && true) // expect: false
|
||||
|
||||
@ -44,3 +44,8 @@ if (true) class Foo {} // no error
|
||||
// Definition in else arm.
|
||||
if (false) null else var a = io.write("ok") // expect: ok
|
||||
if (true) null else class Foo {} // no error
|
||||
|
||||
// Only false is falsy.
|
||||
if (0) io.write(0) // expect: 0
|
||||
if (null) io.write(null) // expect: null
|
||||
if ("") io.write("empty") // expect: empty
|
||||
|
||||
26
test/or.wren
Normal file
26
test/or.wren
Normal file
@ -0,0 +1,26 @@
|
||||
// Note: These tests implicitly depend on ints being truthy.
|
||||
// Also rely on io.write() returning its argument.
|
||||
|
||||
// Return the first true argument.
|
||||
io.write(1 || true) // expect: 1
|
||||
io.write(false || 1) // expect: 1
|
||||
io.write(false || false || true) // expect: true
|
||||
|
||||
// Return the last argument if all are false.
|
||||
io.write(false || false) // expect: false
|
||||
io.write(false || false || false) // expect: false
|
||||
|
||||
// Short-circuit at the first true argument.
|
||||
io.write(false) || // expect: false
|
||||
io.write(true) || // expect: true
|
||||
io.write(true) // should not print
|
||||
|
||||
// Swallow a trailing newline.
|
||||
io.write(true ||
|
||||
true) // expect: true
|
||||
|
||||
// Only false is falsy.
|
||||
io.write(0 || true) // expect: 0
|
||||
io.write(null || true) // expect: null
|
||||
io.write(("" || true) == "") // expect: true
|
||||
io.write(false || true) // expect: true
|
||||
Reference in New Issue
Block a user