For loop on arrays working, untested, read more

Needed: break and continue support, extensive tests, other iterables
This commit is contained in:
2026-05-24 18:13:18 +10:00
parent 813da3e1aa
commit f11bc95833
10 changed files with 241 additions and 58 deletions
+23
View File
@@ -0,0 +1,23 @@
```toy
for (var name in array) {
//
}
```
pushStack name
pushStack array
pushStack counter //tracks the index for each loop
OPCODE iterable:
pushScope
declare name = array.next() if next is not null else jump to end
(user code)
popScope
jump to beginning
popStack counter, array, name
+28 -9
View File
@@ -195,9 +195,24 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j
return 4;
case TOY_OPCODE_ELIMINATE:
printf(MARKER "ELIMINATE\n", MARKER_VALUE(pc, unsigned char));
printf(MARKER "ELIMINATE %u\n", MARKER_VALUE(pc, unsigned char), (unsigned int)bytecode[pc + 1]);
return 4;
case TOY_OPCODE_ITERATE:
printf(MARKER TOY_CC_DEBUG "ITERATE on [-2] based on type, with [-1] as counter, then delegate to: JUMP %s%s (%s%d) (GOTO %u)\n" TOY_CC_RESET, MARKER_VALUE(pc, unsigned char),
bytecode[pc + 1] == TOY_OP_PARAM_JUMP_ABSOLUTE ? "absolute" : "relative",
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_ALWAYS ? "" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_TRUE ? " if true" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_FALSE ? " if false" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_NULL ? " if null" :
"if <unknown>"
,
(*(int*)(bytecode + pc + 4)) > 0 ? "+" : "", //show a + sign when positive
(*(int*)(bytecode + pc + 4)),
(*(int*)(bytecode + pc + 4)) + pc + 8
);
return 8;
case TOY_OPCODE_ADD:
printf(MARKER "ADD %s\n", MARKER_VALUE(pc, unsigned char), bytecode[pc + 1] == TOY_OPCODE_ASSIGN ? "and ASSIGN" : "");
return 4;
@@ -262,18 +277,22 @@ int inspect_instruction(unsigned char* bytecode, unsigned int pc, unsigned int j
printf(MARKER TOY_CC_DEBUG "JUMP %s%s (%s%d) (GOTO %u)\n" TOY_CC_RESET, MARKER_VALUE(pc, unsigned char),
bytecode[pc + 1] == TOY_OP_PARAM_JUMP_ABSOLUTE ? "absolute" : "relative",
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_ALWAYS ? "" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_TRUE ? " if true" : " if false",
bytecode[pc + 4] > 0 ? "+" : "", //show a + sign when positive
bytecode[pc + 4],
bytecode[pc + 4] + pc + 8
);
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_TRUE ? " if true" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_FALSE ? " if false" :
bytecode[pc + 2] == TOY_OP_PARAM_JUMP_IF_NULL ? " if null" :
"if <unknown>"
,
(*(int*)(bytecode + pc + 4)) > 0 ? "+" : "", //show a + sign when positive
(*(int*)(bytecode + pc + 4)),
(*(int*)(bytecode + pc + 4)) + pc + 8
);
return 8;
case TOY_OPCODE_ESCAPE:
printf(MARKER TOY_CC_DEBUG "ESCAPE relative %s%d (GOTO %u) and pop %d\n" TOY_CC_RESET, MARKER_VALUE(pc, unsigned char),
bytecode[pc + 4] > 0 ? "+" : "", //show a + sign when positive
bytecode[pc + 4],
bytecode[pc + 4] + pc + 12,
(*(int*)(bytecode + pc + 4)) > 0 ? "+" : "", //show a + sign when positive
(*(int*)(bytecode + pc + 4)),
(*(int*)(bytecode + pc + 4)) + pc + 12,
bytecode[pc + 8]
);
return 12;
+5 -7
View File
@@ -1,12 +1,10 @@
var array = ["foo", "bar"];
fn a(x) {
print x;
for (var i in array) {
print i;
break;
}
fn b() {
return 42;
}
a(b(), b());
print "done";
+67 -7
View File
@@ -226,6 +226,7 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast); //for
static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast);
static unsigned char* collateBytecodeBody(Toy_Bytecode* mb);
static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment); //forward declare for chaining of var declarations
static unsigned int writeInstructionAccess(Toy_Bytecode** mb, Toy_AstVarAccess ast);
static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke ast, bool chainedInvoke);
static unsigned int writeInstructionValue(Toy_Bytecode** mb, Toy_AstValue ast) {
@@ -456,7 +457,7 @@ static unsigned int writeInstructionBinaryShortCircuit(Toy_Bytecode** mb, Toy_As
//if the lhs value isn't needed, pop it
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 1);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
@@ -719,12 +720,71 @@ static unsigned int writeInstructionWhileThen(Toy_Bytecode** mb, Toy_AstWhileThe
}
static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) {
//URGENT: WIP
(void)mb;
(void)ast;
//check the operands
if (ast.condBranch->type != TOY_AST_ITERABLE || ast.condBranch->iterable.left->type != TOY_AST_VAR_DECLARE || ast.condBranch->iterable.right->type != TOY_AST_VAR_ACCESS) {
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid conditional found in a 'for' loop\n" TOY_CC_RESET);
(*mb)->panic = true;
return 0;
}
(*mb)->panic = true;
return 1;
//set up the iterable, and the counter
writeInstructionAccess(mb, ast.condBranch->iterable.right->varAccess);
EMIT_BYTE(mb, code, TOY_OPCODE_READ);
EMIT_BYTE(mb, code, TOY_VALUE_INTEGER);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_INT(mb, code, 0); //start from zero
unsigned int beginAddr = CURRENT_ADDRESS(mb, code);
//access [-1] from [-2], incrementing [-1] afterwards
//then delegate to JUMP
EMIT_BYTE(mb, code, TOY_OPCODE_ITERATE);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_IF_NULL);
EMIT_BYTE(mb, code, 0);
unsigned int thenParamAddr = SKIP_INT(mb, code); //parameter to be written later
//push scope (built-into the keyword)
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_PUSH);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
(*mb)->currentScopeDepth++;
//delcare the iterator with the given string
EMIT_BYTE(mb, code, TOY_OPCODE_DECLARE);
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.valueType);
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.name->info.length); //quick optimisation to skip a 'strlen()' call
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.constant); //check for constness
emitString(mb, ast.condBranch->iterable.left->varDeclare.name);
//write the body
writeBytecodeFromAst(mb, ast.thenBranch);
//pop scope after each iteration
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_POP);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
(*mb)->currentScopeDepth--;
//jump to begin to repeat the conditional test
EMIT_BYTE(mb, code, TOY_OPCODE_JUMP);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_ALWAYS);
EMIT_BYTE(mb, code, 0);
EMIT_INT(mb, code, beginAddr - (CURRENT_ADDRESS(mb, code) + 4)); //this sets a negative value
//end of the loop, overwrite the parameter
OVERWRITE_INT(mb, code, thenParamAddr, CURRENT_ADDRESS(mb, code) - (thenParamAddr + 4));
return 0;
}
static unsigned int writeInstructionBreak(Toy_Bytecode** mb, Toy_AstBreak ast) {
@@ -1163,7 +1223,7 @@ static unsigned int writeInstructionStackPop(Toy_Bytecode** mb, Toy_AstStackPop
//dead simple
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 1);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
+2 -1
View File
@@ -12,9 +12,9 @@ typedef enum Toy_OpcodeType {
TOY_OPCODE_ACCESS,
TOY_OPCODE_INVOKE, //for calling functions
TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds
TOY_OPCODE_ITERABLE, //for operating on all members of a compound
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
TOY_OPCODE_ELIMINATE, //remove the top of the stack
TOY_OPCODE_ITERATE, //for operating on all members of a compound
//arithmetic instructions
TOY_OPCODE_ADD,
@@ -67,5 +67,6 @@ typedef enum Toy_OpParamJumpConditional {
TOY_OP_PARAM_JUMP_ALWAYS = 0,
TOY_OP_PARAM_JUMP_IF_TRUE = 1,
TOY_OP_PARAM_JUMP_IF_FALSE = 2,
TOY_OP_PARAM_JUMP_IF_NULL = 3,
} Toy_OpParamJumpConditional;
+39 -21
View File
@@ -122,7 +122,6 @@ static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag attribute(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
//precedence definitions
static ParsingTuple parsingRulesetTable[] = {
@@ -157,7 +156,7 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_FUNCTION,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IF,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IMPORT,
{PREC_CALL,NULL,iterable},// TOY_TOKEN_KEYWORD_IN,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IN,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_OF,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PASS,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PRINT,
@@ -761,19 +760,6 @@ static Toy_AstFlag attribute(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
}
}
static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//infix must advance
advance(parser);
Toy_Ast* expr = NULL;
parsePrecedence(bucketHandle, parser, &expr, PREC_CALL);
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr);
//TODO: check for var declare without assignment
return TOY_AST_FLAG_NONE;
}
//grammar rules
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule) {
//'step over' the token to parse
@@ -785,7 +771,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
if (prefix == NULL) {
//make a nice error message
if (Toy_private_findKeywordByType(parser->previous.type)) {
printError(parser, parser->previous, "Found reserved keyword instead");
printError(parser, parser->previous, "Expected expression, found reserved keyword instead");
}
else {
printError(parser, parser->previous, "Expected expression");
@@ -906,20 +892,52 @@ static void makeWhileStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
}
static void makeForStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
Toy_Ast* declBranch = NULL;
Toy_Ast* condBranch = NULL;
Toy_Ast* thenBranch = NULL;
//for (condBranch)
consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'for' keyword");
makeExpr(bucketHandle, parser, &condBranch);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
consume(parser, TOY_TOKEN_KEYWORD_VAR, "Expected 'var' in 'for' conditional");
//TODO: check for an iterable node
//WARN: duped from var declare
consume(parser, TOY_TOKEN_NAME, "Expected variable name after 'var' keyword");
if (parser->previous.length > 255) {
printError(parser, parser->previous, "Can't have a variable name longer than 255 characters");
Toy_private_emitAstError(bucketHandle, rootHandle);
return;
}
Toy_Token nameToken = parser->previous;
//read the type specifier if present
Toy_ValueType varType = TOY_VALUE_ANY;
bool constant = false;
if (match(parser, TOY_TOKEN_OPERATOR_COLON)) {
varType = readType(parser);
if (match(parser, TOY_TOKEN_KEYWORD_CONST)) {
constant = true;
}
}
//build the name string & emit a var declare
Toy_String* nameStr = Toy_toStringLength(bucketHandle, nameToken.lexeme, nameToken.length);
Toy_private_emitAstVariableDeclaration(bucketHandle, &declBranch, nameStr, varType, constant, NULL);
//continue to the 'in' keyword
consume(parser, TOY_TOKEN_KEYWORD_IN, "Expected 'in' inside 'for' condition");
parsePrecedence(bucketHandle, parser, &condBranch, PREC_CALL);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
//{ thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
Toy_private_emitAstForThen(bucketHandle, rootHandle, condBranch, thenBranch);
//finalize everything
Toy_private_emitAstIterable(bucketHandle, &declBranch, condBranch);
Toy_private_emitAstForThen(bucketHandle, rootHandle, declBranch, thenBranch);
}
static void makeBreakStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
@@ -1125,7 +1143,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
return;
}
//TODO: import
//import?
//print
else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) {
+63 -4
View File
@@ -33,6 +33,9 @@ static inline void fixAlignment(Toy_VM* vm) {
vm->programCounter = (vm->programCounter + 3) & ~3;
}
//forward declarations for delegations
static void processJump(Toy_VM* vm);
//instruction handlers
static void processRead(Toy_VM* vm) {
Toy_ValueType type = READ_BYTE(vm);
@@ -470,9 +473,51 @@ static void processDuplicate(Toy_VM* vm) {
}
static void processEliminate(Toy_VM* vm) {
//discard the stack top
Toy_Value value = Toy_popStack(&vm->stack);
Toy_freeValue(value);
//discard the stack top, X times
unsigned int x = (unsigned int)READ_BYTE(vm);
for (unsigned int i = 0; i < x; i++) {
Toy_Value value = Toy_popStack(&vm->stack);
Toy_freeValue(value);
}
}
static void processIterate(Toy_VM* vm) {
//ITERATE on [-2] based on type, with [-1] as counter
//then delegate to processJump
Toy_Value counter = Toy_popStack(&vm->stack);
Toy_Value compound = Toy_popStack(&vm->stack);
if (!TOY_VALUE_IS_INTEGER(counter)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown counter type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(counter.type));
exit(-1);
}
if (TOY_VALUE_IS_ARRAY(compound)) {
Toy_Array* array = TOY_VALUE_AS_ARRAY(compound);
unsigned int index = (unsigned int)TOY_VALUE_AS_INTEGER(counter);
//check out-of-bounds
if (index >= array->count) {
Toy_freeValue(counter);
Toy_freeValue(compound);
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL()); //force a jump
processJump(vm);
return;
}
//get the desired element
Toy_Value value = Toy_copyValue(&vm->memoryBucket, array->data[index]);
//push everything back onto the stack (iterating the counter)
Toy_pushStack(&vm->stack, compound);
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(index + 1));
Toy_pushStack(&vm->stack, value);
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown iterable type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(compound.type));
exit(-1);
}
}
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
@@ -682,6 +727,17 @@ static void processJump(Toy_VM* vm) {
Toy_freeValue(value);
return;
}
case TOY_OP_PARAM_JUMP_IF_NULL: {
Toy_Value value = Toy_popStack(&vm->stack);
if (TOY_VALUE_IS_NULL(value)) {
Toy_freeValue(value);
break;
}
Toy_freeValue(value);
return;
}
}
//do the jump
@@ -997,6 +1053,10 @@ static unsigned int process(Toy_VM* vm) {
processEliminate(vm);
break;
case TOY_OPCODE_ITERATE:
processIterate(vm);
break;
//arithmetic instructions
case TOY_OPCODE_ADD:
case TOY_OPCODE_SUBTRACT:
@@ -1060,7 +1120,6 @@ static unsigned int process(Toy_VM* vm) {
processIndex(vm);
break;
case TOY_OPCODE_ITERABLE: //tmp
case TOY_OPCODE_UNUSED:
case TOY_OPCODE_PASS:
case TOY_OPCODE_ERROR:
@@ -0,0 +1,5 @@
//TODO: empty test script
//TODO: test iteration on arrays, tables, closures
//TODO: test break, continue
+9 -9
View File
@@ -139,7 +139,7 @@ int test_compiler_expressions(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 27)) != 0 ||
*((unsigned char*)(buffer + 28)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 29)) != 0 ||
*((unsigned char*)(buffer + 29)) != 1 ||
*((unsigned char*)(buffer + 30)) != 0 ||
*((unsigned char*)(buffer + 31)) != 0 ||
@@ -197,7 +197,7 @@ int test_compiler_expressions(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 27)) != 0 ||
*((unsigned char*)(buffer + 28)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 29)) != 0 ||
*((unsigned char*)(buffer + 29)) != 1 ||
*((unsigned char*)(buffer + 30)) != 0 ||
*((unsigned char*)(buffer + 31)) != 0 ||
@@ -257,7 +257,7 @@ int test_compiler_expressions(Toy_Bucket** bucketHandle) {
*(int*)(buffer + 28) != 42 ||
*((unsigned char*)(buffer + 32)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 33)) != 0 ||
*((unsigned char*)(buffer + 33)) != 1 ||
*((unsigned char*)(buffer + 34)) != 0 ||
*((unsigned char*)(buffer + 35)) != 0 ||
@@ -317,7 +317,7 @@ int test_compiler_expressions(Toy_Bucket** bucketHandle) {
*(float*)(buffer + 28) != 3.1415f ||
*((unsigned char*)(buffer + 32)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 33)) != 0 ||
*((unsigned char*)(buffer + 33)) != 1 ||
*((unsigned char*)(buffer + 34)) != 0 ||
*((unsigned char*)(buffer + 35)) != 0 ||
@@ -389,7 +389,7 @@ int test_compiler_expressions(Toy_Bucket** bucketHandle) {
*(unsigned int*)(code + 4) != 0 || //the jump index
*((unsigned char*)(code + 8)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(code + 9)) != 0 ||
*((unsigned char*)(code + 9)) != 1 ||
*((unsigned char*)(code + 10)) != 0 ||
*((unsigned char*)(code + 11)) != 0 ||
@@ -499,7 +499,7 @@ int test_compiler_binary(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 43)) != 0 ||
*((unsigned char*)(buffer + 44)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 45)) != 0 ||
*((unsigned char*)(buffer + 45)) != 1 ||
*((unsigned char*)(buffer + 46)) != 0 ||
*((unsigned char*)(buffer + 47)) != 0 ||
@@ -569,7 +569,7 @@ int test_compiler_binary(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 43)) != 0 ||
*((unsigned char*)(buffer + 44)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 45)) != 0 ||
*((unsigned char*)(buffer + 45)) != 1 ||
*((unsigned char*)(buffer + 46)) != 0 ||
*((unsigned char*)(buffer + 47)) != 0 ||
@@ -639,7 +639,7 @@ int test_compiler_binary(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 43)) != 0 ||
*((unsigned char*)(buffer + 44)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 45)) != 0 ||
*((unsigned char*)(buffer + 45)) != 1 ||
*((unsigned char*)(buffer + 46)) != 0 ||
*((unsigned char*)(buffer + 47)) != 0 ||
@@ -735,7 +735,7 @@ int test_compiler_binary(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 67)) != 0 ||
*((unsigned char*)(buffer + 68)) != TOY_OPCODE_ELIMINATE ||
*((unsigned char*)(buffer + 69)) != 0 ||
*((unsigned char*)(buffer + 69)) != 1 ||
*((unsigned char*)(buffer + 70)) != 0 ||
*((unsigned char*)(buffer + 71)) != 0 ||