feat: add logical OR operator with short-circuit evaluation and token support
Add TOKEN_PIPEPIPE token for '||' syntax, implement or() parsing function with CODE_OR bytecode, and add VM interpreter logic that short-circuits on truthy left operand. Update .gitignore to exclude *.xccheckout files, extend test coverage for falsy behavior in and.wren and if.wren, and add comprehensive or.wren test suite verifying short-circuit semantics and truthiness rules.
This commit is contained in:
+26
-1
@@ -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("!"),
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user