private void CompileBooleanCombination(Parser parser, ByteBuffer buffer, BooleanCombination boolComb, bool outputUsed) { if (!outputUsed) throw new ParserException(boolComb.FirstToken, "Cannot have this expression here."); ByteBuffer rightBuffer = new ByteBuffer(); Expression[] expressions = boolComb.Expressions; this.CompileExpression(parser, rightBuffer, expressions[expressions.Length - 1], true); for (int i = expressions.Length - 2; i >= 0; --i) { ByteBuffer leftBuffer = new ByteBuffer(); this.CompileExpression(parser, leftBuffer, expressions[i], true); Token op = boolComb.Ops[i]; if (op.Value == "&&") { leftBuffer.Add(op, OpCode.JUMP_IF_FALSE_NO_POP, rightBuffer.Size); } else { leftBuffer.Add(op, OpCode.JUMP_IF_TRUE_NO_POP, rightBuffer.Size); } leftBuffer.Concat(rightBuffer); rightBuffer = leftBuffer; } buffer.Concat(rightBuffer); }
private void CompileTernary(Parser parser, ByteBuffer buffer, Ternary ternary, bool outputUsed) { EnsureUsed(ternary.FirstToken, outputUsed); this.CompileExpression(parser, buffer, ternary.Condition, true); ByteBuffer trueBuffer = new ByteBuffer(); this.CompileExpression(parser, trueBuffer, ternary.TrueValue, true); ByteBuffer falseBuffer = new ByteBuffer(); this.CompileExpression(parser, falseBuffer, ternary.FalseValue, true); trueBuffer.Add(null, OpCode.JUMP, falseBuffer.Size); buffer.Add(ternary.Condition.FirstToken, OpCode.JUMP_IF_FALSE, trueBuffer.Size); buffer.Concat(trueBuffer); buffer.Concat(falseBuffer); }
private void CompileNullCoalescer(Parser parser, ByteBuffer buffer, NullCoalescer nullCoalescer, bool outputUsed) { EnsureUsed(nullCoalescer.FirstToken, outputUsed); this.CompileExpression(parser, buffer, nullCoalescer.PrimaryExpression, true); ByteBuffer secondaryExpression = new ByteBuffer(); this.CompileExpression(parser, secondaryExpression, nullCoalescer.SecondaryExpression, true); buffer.Add(nullCoalescer.FirstToken, OpCode.POP_IF_NULL_OR_JUMP, secondaryExpression.Size); buffer.Concat(secondaryExpression); }
private void CompileDoWhileLoop(Parser parser, ByteBuffer buffer, DoWhileLoop doWhileLoop) { ByteBuffer loopBody = new ByteBuffer(); this.Compile(parser, loopBody, doWhileLoop.Code); loopBody.ResolveContinues(true); // continues should jump to the condition, hence the true. ByteBuffer condition = new ByteBuffer(); this.CompileExpression(parser, condition, doWhileLoop.Condition, true); loopBody.Concat(condition); loopBody.Add(doWhileLoop.Condition.FirstToken, OpCode.JUMP_IF_TRUE, -loopBody.Size - 1); loopBody.ResolveBreaks(); buffer.Concat(loopBody); }
private void CompileFunctionDefinition(Parser parser, ByteBuffer buffer, FunctionDefinition funDef, bool isMethod) { if (funDef.FunctionID == 13) { } ByteBuffer tBuffer = new ByteBuffer(); List<int> offsetsForOptionalArgs = new List<int>(); this.CompileFunctionArgs(parser, tBuffer, funDef.ArgNames, funDef.DefaultValues, offsetsForOptionalArgs); Compile(parser, tBuffer, funDef.Code); int offset = tBuffer.Size; int minArgCount = 0; for (int i = 0; i < funDef.DefaultValues.Length; ++i) { if (funDef.DefaultValues[i] != null) { break; } minArgCount++; } List<int> args = new List<int>() { funDef.FunctionID, parser.GetId(funDef.NameToken.Value), // local var to save in minArgCount, funDef.ArgNames.Length, // max number of args supplied isMethod ? (funDef.IsStaticMethod ? 2 : 1) : 0, // type (0 - function, 1 - method, 2 - static method) isMethod ? ((ClassDefinition)funDef.FunctionOrClassOwner).ClassID : 0, funDef.LocalScopeSize, tBuffer.Size, offsetsForOptionalArgs.Count }; args.AddRange(offsetsForOptionalArgs); buffer.Add( funDef.FirstToken, OpCode.FUNCTION_DEFINITION, args.ToArray()); buffer.Concat(tBuffer); }
private void CompileForLoop(Parser parser, ByteBuffer buffer, ForLoop forLoop) { this.Compile(parser, buffer, forLoop.Init); ByteBuffer codeBuffer = new ByteBuffer(); this.Compile(parser, codeBuffer, forLoop.Code); codeBuffer.ResolveContinues(true); // resolve continues as jump-to-end before you add the step instructions. this.Compile(parser, codeBuffer, forLoop.Step); ByteBuffer forBuffer = new ByteBuffer(); this.CompileExpression(parser, forBuffer, forLoop.Condition, true); forBuffer.Add(forLoop.Condition.FirstToken, OpCode.JUMP_IF_FALSE, codeBuffer.Size + 1); // +1 to go past the jump I'm about to add. forBuffer.Concat(codeBuffer); forBuffer.Add(null, OpCode.JUMP, -forBuffer.Size - 1); forBuffer.ResolveBreaks(); buffer.Concat(forBuffer); }
private void CompileWhileLoop(Parser parser, ByteBuffer buffer, WhileLoop whileLoop) { ByteBuffer loopBody = new ByteBuffer(); this.Compile(parser, loopBody, whileLoop.Code); ByteBuffer condition = new ByteBuffer(); this.CompileExpression(parser, condition, whileLoop.Condition, true); condition.Add(whileLoop.Condition.FirstToken, OpCode.JUMP_IF_FALSE, loopBody.Size + 1); condition.Concat(loopBody); condition.Add(null, OpCode.JUMP, -condition.Size - 1); condition.ResolveBreaks(); condition.ResolveContinues(); buffer.Concat(condition); }
private void CompileIfStatement(Parser parser, ByteBuffer buffer, IfStatement ifStatement) { this.CompileExpression(parser, buffer, ifStatement.Condition, true); ByteBuffer trueCode = new ByteBuffer(); this.Compile(parser, trueCode, ifStatement.TrueCode); ByteBuffer falseCode = new ByteBuffer(); this.Compile(parser, falseCode, ifStatement.FalseCode); if (falseCode.Size == 0) { if (trueCode.Size == 0) buffer.Add(ifStatement.Condition.FirstToken, OpCode.POP); else { buffer.Add(ifStatement.Condition.FirstToken, OpCode.JUMP_IF_FALSE, trueCode.Size); buffer.Concat(trueCode); } } else { trueCode.Add(null, OpCode.JUMP, falseCode.Size); buffer.Add(ifStatement.Condition.FirstToken, OpCode.JUMP_IF_FALSE, trueCode.Size); buffer.Concat(trueCode); buffer.Concat(falseCode); } }
private void CompileConstructor(Parser parser, ByteBuffer buffer, ConstructorDefinition constructor) { // TODO: throw parser exception in the resolver if a return appears with any value ByteBuffer tBuffer = new ByteBuffer(); ClassDefinition cd = (ClassDefinition)constructor.FunctionOrClassOwner; List<int> offsetsForOptionalArgs = new List<int>(); this.CompileFunctionArgs(parser, tBuffer, constructor.ArgNames, constructor.DefaultValues, offsetsForOptionalArgs); int minArgs = 0; int maxArgs = constructor.ArgNames.Length; for (int i = 0; i < constructor.ArgNames.Length; ++i) { if (constructor.DefaultValues[i] == null) { minArgs++; } else { break; } } if (constructor.BaseToken != null) { this.CompileExpressionList(parser, tBuffer, constructor.BaseArgs, true); tBuffer.Add( constructor.BaseToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.BASE_CONSTRUCTOR, constructor.BaseArgs.Length, cd.BaseClass.Constructor.FunctionID, 0, cd.BaseClass.ClassID); } this.Compile(parser, tBuffer, constructor.Code); tBuffer.Add(null, OpCode.RETURN, 0); bool isStatic = constructor == cd.StaticConstructor; List<int> args = new List<int>() { constructor.FunctionID, -1, minArgs, maxArgs, isStatic ? 4 : 3, cd.ClassID, constructor.LocalScopeSize, tBuffer.Size, offsetsForOptionalArgs.Count, }; args.AddRange(offsetsForOptionalArgs); buffer.Add(constructor.FirstToken, OpCode.FUNCTION_DEFINITION, args.ToArray()); buffer.Concat(tBuffer); }
private void CompileClass(Parser parser, ByteBuffer buffer, ClassDefinition classDefinition) { bool hasStaticFieldsWithStartingValues = classDefinition.Fields .Where<FieldDeclaration>(fd => fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) .Count() > 0; if (hasStaticFieldsWithStartingValues) { if (classDefinition.StaticConstructor == null) { classDefinition.StaticConstructor = new ConstructorDefinition(null, new Token[0], new Expression[0], new Expression[0], new Executable[0], null, classDefinition); } List<Executable> staticFieldInitializers = new List<Executable>(); foreach (FieldDeclaration fd in classDefinition.Fields) { if (fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) { Executable assignment = new Assignment(new FieldReference(fd.FirstToken, fd, classDefinition), fd.NameToken, "=", fd.DefaultValue, classDefinition); staticFieldInitializers.Add(assignment); } } staticFieldInitializers.AddRange(classDefinition.StaticConstructor.Code); classDefinition.StaticConstructor.Code = staticFieldInitializers.ToArray(); } if (classDefinition.StaticConstructor != null) { // All static field initializers are added here. this.CompileConstructor(parser, buffer, classDefinition.StaticConstructor); } this.CompileConstructor(parser, buffer, classDefinition.Constructor); foreach (FunctionDefinition fd in classDefinition.Methods) { int pc = buffer.Size; fd.FinalizedPC = pc; this.CompileFunctionDefinition(parser, buffer, fd, true); } int classId = classDefinition.ClassID; int baseClassId = classDefinition.BaseClass != null ? classDefinition.BaseClass.ClassID : -1; int nameId = parser.GetId(classDefinition.NameToken.Value); int constructorId = classDefinition.Constructor.FunctionID; int staticConstructorId = classDefinition.StaticConstructor != null ? classDefinition.StaticConstructor.FunctionID : -1; int staticFieldCount = classDefinition.Fields.Where<FieldDeclaration>(fd => fd.IsStaticField).Count(); FieldDeclaration[] regularFields = classDefinition.Fields.Where<FieldDeclaration>(fd => !fd.IsStaticField).ToArray(); FunctionDefinition[] regularMethods = classDefinition.Methods.Where<FunctionDefinition>(fd => !fd.IsStaticMethod).ToArray(); List<int> members = new List<int>(); List<FieldDeclaration> fieldsWithComplexValues = new List<FieldDeclaration>(); foreach (FieldDeclaration fd in regularFields) { int memberId = fd.MemberID; int fieldNameId = parser.GetId(fd.NameToken.Value); int initInstruction; int literalId = 0; if (fd.DefaultValue is ListDefinition && ((ListDefinition)fd.DefaultValue).Items.Length == 0) { initInstruction = 1; } else if (fd.DefaultValue is DictionaryDefinition && ((DictionaryDefinition)fd.DefaultValue).Keys.Length == 0) { initInstruction = 2; } else { initInstruction = 0; literalId = parser.GetLiteralId(fd.DefaultValue); if (literalId == -1) { literalId = parser.GetNullConstant(); fieldsWithComplexValues.Add(fd); } } members.AddRange(new int[] { 0, // flag for field memberId, fieldNameId, initInstruction, literalId}); } foreach (FunctionDefinition fd in regularMethods) { int memberId = fd.MemberID; int methodNameId = parser.GetId(fd.NameToken.Value); int functionId = fd.FunctionID; members.AddRange(new int[] { 1, // flag for method memberId, methodNameId, functionId, 0, // ignored value. It's just here to keep spacing consistent. }); } ByteBuffer initializer = null; if (fieldsWithComplexValues.Count > 0) { initializer = new ByteBuffer(); foreach (FieldDeclaration complexField in fieldsWithComplexValues) { this.CompileExpression(parser, initializer, complexField.DefaultValue, true); initializer.Add(complexField.FirstToken, OpCode.ASSIGN_THIS_STEP, complexField.MemberID); } initializer.Add(null, OpCode.RETURN, 0); } List<int> args = new List<int>() { classId, baseClassId, nameId, constructorId, initializer == null ? 0 : initializer.Size, // jump amount after initialization staticConstructorId, staticFieldCount, }; args.AddRange(members); buffer.Add(classDefinition.FirstToken, OpCode.CLASS_DEFINITION, args.ToArray()); if (initializer != null) { buffer.Concat(initializer); } }
private void CompileSwitchStatement(Parser parser, ByteBuffer buffer, SwitchStatement switchStatement) { this.CompileExpression(parser, buffer, switchStatement.Condition, true); ByteBuffer chunkBuffer = new ByteBuffer(); Dictionary<int, int> chunkIdsToOffsets = new Dictionary<int, int>(); Dictionary<int, int> integersToChunkIds = new Dictionary<int,int>(); Dictionary<string, int> stringsToChunkIds = new Dictionary<string,int>(); int defaultChunkId = -1; foreach (SwitchStatement.Chunk chunk in switchStatement.Chunks) { int chunkId = chunk.ID; if (chunk.Cases.Length == 1 && chunk.Cases[0] == null) { defaultChunkId = chunkId; } else { foreach (Expression expression in chunk.Cases) { if (switchStatement.UsesIntegers) { integersToChunkIds[((IntegerConstant)expression).Value] = chunkId; } else { stringsToChunkIds[((StringConstant)expression).Value] = chunkId; } } } chunkIdsToOffsets[chunkId] = chunkBuffer.Size; this.Compile(parser, chunkBuffer, chunk.Code); } chunkBuffer.ResolveBreaks(); int switchId = parser.RegisterByteCodeSwitch(switchStatement.FirstToken, chunkIdsToOffsets, integersToChunkIds, stringsToChunkIds, switchStatement.UsesIntegers); int defaultOffsetLength = defaultChunkId == -1 ? chunkBuffer.Size : chunkIdsToOffsets[defaultChunkId]; buffer.Add(switchStatement.FirstToken, switchStatement.UsesIntegers ? OpCode.SWITCH_INT : OpCode.SWITCH_STRING, switchId, defaultOffsetLength); buffer.Concat(chunkBuffer); }
private void CompileForEachLoop(Parser parser, ByteBuffer buffer, ForEachLoop forEachLoop) { buffer.Add(null, OpCode.LITERAL, parser.GetIntConstant(0)); buffer.Add(null, OpCode.LITERAL, parser.GetIntConstant(forEachLoop.IterationVariableId)); this.CompileExpression(parser, buffer, forEachLoop.IterationExpression, true); buffer.Add(forEachLoop.IterationExpression.FirstToken, OpCode.VERIFY_TYPE_IS_ITERABLE); ByteBuffer body = new ByteBuffer(); ByteBuffer body2 = new Crayon.ByteBuffer(); this.Compile(parser, body2, forEachLoop.Code); body.Add(forEachLoop.FirstToken, OpCode.ITERATION_STEP, body2.Size + 1); body2.Add(null, OpCode.JUMP, -body2.Size - 2); body.Concat(body2); body.ResolveBreaks(); body.ResolveContinues(); buffer.Concat(body); buffer.Add(null, OpCode.POP); // list buffer.Add(null, OpCode.POP); // var ID buffer.Add(null, OpCode.POP); // index }