public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, BooleanCombination boolComb, bool outputUsed) { if (!outputUsed) { throw new ParserException(boolComb, "Cannot have this expression here."); } ByteBuffer rightBuffer = new ByteBuffer(); Expression[] expressions = boolComb.Expressions; bcc.CompileExpression(parser, rightBuffer, expressions[expressions.Length - 1], true); for (int i = expressions.Length - 2; i >= 0; --i) { ByteBuffer leftBuffer = new ByteBuffer(); bcc.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); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, BracketIndex bracketIndex, bool outputUsed) { if (!outputUsed) { throw new ParserException(bracketIndex, "This expression does nothing."); } bcc.CompileExpression(parser, buffer, bracketIndex.Root, true); bcc.CompileExpression(parser, buffer, bracketIndex.Index, true); buffer.Add(bracketIndex.BracketToken, OpCode.INDEX); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, NullCoalescer nullCoalescer, bool outputUsed) { ByteCodeCompiler.EnsureUsed(nullCoalescer, outputUsed); bcc.CompileExpression(parser, buffer, nullCoalescer.PrimaryExpression, true); ByteBuffer secondaryExpression = new ByteBuffer(); bcc.CompileExpression(parser, secondaryExpression, nullCoalescer.SecondaryExpression, true); buffer.Add(nullCoalescer.FirstToken, OpCode.POP_IF_NULL_OR_JUMP, secondaryExpression.Size); buffer.Concat(secondaryExpression); }
public static void Compile( ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, CoreFunctionInvocation coreFuncInvocation, Expression[] argsOverrideOrNull, Token tokenOverrideOrNull, bool outputUsed) { Token token = tokenOverrideOrNull ?? coreFuncInvocation.FirstToken; Expression[] args = argsOverrideOrNull ?? coreFuncInvocation.Args; if (coreFuncInvocation.FunctionId == (int)CoreFunctionID.TYPE_IS) { ByteCodeCompiler.EnsureUsed(coreFuncInvocation, outputUsed); bcc.CompileExpression(parser, buffer, args[0], true); int typeCount = args.Length - 1; int[] actualArgs = new int[typeCount + 3]; actualArgs[0] = coreFuncInvocation.FunctionId; actualArgs[1] = 1; // output used actualArgs[2] = typeCount; for (int i = typeCount - 1; i >= 0; --i) { IntegerConstant typeArg = args[args.Length - 1 - i] as IntegerConstant; if (typeArg == null) { throw new ParserException(coreFuncInvocation, "typeis requires type enum values."); } actualArgs[3 + i] = typeArg.Value + 1; } buffer.Add(token, OpCode.CORE_FUNCTION, actualArgs); return; } foreach (Expression arg in args) { bcc.CompileExpression(parser, buffer, arg, true); } if (coreFuncInvocation.FunctionId == (int)CoreFunctionID.INT_QUEUE_WRITE_16) { buffer.Add(token, OpCode.CORE_FUNCTION, coreFuncInvocation.FunctionId, outputUsed ? 1 : 0, args.Length - 1); return; } buffer.Add(token, OpCode.CORE_FUNCTION, coreFuncInvocation.FunctionId, outputUsed ? 1 : 0); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ForEachLoop forEachLoop) { bcc.CompileExpression(parser, buffer, forEachLoop.IterationExpression, true); buffer.Add( forEachLoop.IterationExpression.FirstToken, OpCode.VERIFY_TYPE_IS_ITERABLE, forEachLoop.ListLocalId.ID, forEachLoop.IndexLocalId.ID); ByteBuffer body = new ByteBuffer(); ByteBuffer body2 = new ByteBuffer(); bcc.Compile(parser, body2, forEachLoop.Code); body.Add( forEachLoop.FirstToken, OpCode.ITERATION_STEP, body2.Size + 1, forEachLoop.IterationVariableId.ID, forEachLoop.IndexLocalId.ID, forEachLoop.ListLocalId.ID); body2.Add(null, OpCode.JUMP, -body2.Size - 2); body.Concat(body2); body.ResolveBreaks(); body.ResolveContinues(); buffer.Concat(body); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Ternary ternary, bool outputUsed) { ByteCodeCompiler.EnsureUsed(ternary, outputUsed); bcc.CompileExpression(parser, buffer, ternary.Condition, true); ByteBuffer trueBuffer = new ByteBuffer(); bcc.CompileExpression(parser, trueBuffer, ternary.TrueValue, true); ByteBuffer falseBuffer = new ByteBuffer(); bcc.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); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, IfStatement ifStatement) { bcc.CompileExpression(parser, buffer, ifStatement.Condition, true); ByteBuffer trueCode = new ByteBuffer(); bcc.Compile(parser, trueCode, ifStatement.TrueCode); ByteBuffer falseCode = new ByteBuffer(); bcc.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); } }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, NegativeSign negativeSign, bool outputUsed) { if (!outputUsed) { throw new ParserException(negativeSign, "This expression does nothing."); } bcc.CompileExpression(parser, buffer, negativeSign.Root, true); buffer.Add(negativeSign.FirstToken, OpCode.NEGATIVE_SIGN); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, BooleanNot boolNot, bool outputUsed) { if (!outputUsed) { throw new ParserException(boolNot, "Cannot have this expression here."); } bcc.CompileExpression(parser, buffer, boolNot.Root, true); buffer.Add(boolNot.FirstToken, OpCode.BOOLEAN_NOT); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ListSlice listSlice, bool outputUsed) { ByteCodeCompiler.EnsureUsed(listSlice, outputUsed); bcc.CompileExpression(parser, buffer, listSlice.Root, true); Expression step = listSlice.Items[2]; bool isStep1 = step is IntegerConstant && ((IntegerConstant)step).Value == 1; int serializeThese = isStep1 ? 2 : 3; for (int i = 0; i < serializeThese; ++i) { Expression item = listSlice.Items[i]; if (item != null) { bcc.CompileExpression(parser, buffer, item, true); } } bool firstIsPresent = listSlice.Items[0] != null; bool secondIsPresent = listSlice.Items[1] != null; buffer.Add(listSlice.BracketToken, OpCode.LIST_SLICE, new int[] { firstIsPresent ? 1 : 0, secondIsPresent ? 1 : 0, isStep1 ? 0 : 1 }); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, DoWhileLoop doWhileLoop) { ByteBuffer loopBody = new ByteBuffer(); bcc.Compile(parser, loopBody, doWhileLoop.Code); loopBody.ResolveContinues(true); // continues should jump to the condition, hence the true. ByteBuffer condition = new ByteBuffer(); bcc.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); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ListDefinition listDef, bool outputUsed) { if (!outputUsed) { throw new ParserException(listDef, "List allocation made without storing it. This is likely a mistake."); } foreach (Expression item in listDef.Items) { bcc.CompileExpression(parser, buffer, item, true); } List <int> args = new List <int>() { listDef.Items.Length }; listDef.ResolvedType.ListItemType.BuildEncoding(args); buffer.Add(listDef.FirstToken, OpCode.DEF_LIST, args.ToArray()); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, WhileLoop whileLoop) { ByteBuffer loopBody = new ByteBuffer(); bcc.Compile(parser, loopBody, whileLoop.Code); ByteBuffer condition = new ByteBuffer(); bcc.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); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Cast castExpression, bool outputUsed) { if (!outputUsed) { throw new ParserException(castExpression, "The output of a cast must be used."); } // This should have been filtered out before now. if (castExpression.Expression.ResolvedType == castExpression.ResolvedType) { throw new Exception(); } bcc.CompileExpression(parser, buffer, castExpression.Expression, true); List <int> args = new List <int>(); EncodeTypeInfoToIntBuffer(args, castExpression.ResolvedType, castExpression.DoIntFloatConversions); buffer.Add(castExpression.FirstToken, OpCode.CAST, args.ToArray()); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ReturnStatement returnStatement) { if (returnStatement.Owner is ConstructorDefinition) { if (returnStatement.Expression != null) { throw new ParserException(returnStatement, "Cannot return a value from a constructor."); } } if (returnStatement.Expression == null || returnStatement.Expression is NullConstant) { buffer.Add(returnStatement.FirstToken, OpCode.RETURN, 0); } else { bcc.CompileExpression(parser, buffer, returnStatement.Expression, true); buffer.Add(returnStatement.FirstToken, OpCode.RETURN, 1); } }
public static void Compile( ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, CniFunctionInvocation cniFuncInvocation, Expression[] argsOverrideOrNull, Token throwTokenOverrideOrNull, bool outputUsed) { CniFunction cniFunc = cniFuncInvocation.CniFunction; Expression[] args = argsOverrideOrNull ?? cniFuncInvocation.Args; foreach (Expression arg in args) { bcc.CompileExpression(parser, buffer, arg, true); } Token throwToken = throwTokenOverrideOrNull ?? cniFuncInvocation.FirstToken; buffer.Add(throwToken, OpCode.CNI_INVOKE, cniFunc.ID, cniFunc.ArgCount, outputUsed ? 1 : 0); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ForLoop forLoop) { bcc.Compile(parser, buffer, forLoop.Init); ByteBuffer codeBuffer = new ByteBuffer(); bcc.Compile(parser, codeBuffer, forLoop.Code); codeBuffer.ResolveContinues(true); // resolve continues as jump-to-end before you add the step instructions. bcc.Compile(parser, codeBuffer, forLoop.Step); ByteBuffer forBuffer = new ByteBuffer(); bcc.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 static void CompileImpl(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Expression root, Token dotToken, Token fieldToken, bool outputUsed) { if (!outputUsed) { throw new ParserException(root.FirstToken, "This expression does nothing."); } bcc.CompileExpression(parser, buffer, root, true); int rawNameId = parser.GetId(fieldToken.Value); int localeId = parser.GetLocaleId(root.Owner.FileScope.CompilationScope.Locale); int localeScopedNameId = rawNameId * parser.GetLocaleCount() + localeId; ClassDefinition cd = root.ClassOwner; int classId = cd == null ? -1 : cd.ClassID; buffer.Add( dotToken, OpCode.DEREF_DOT, rawNameId, localeScopedNameId, classId, root.CompilationScope.ScopeNumId, -1, 0); }
// Shared code for functions/constructors/lambdas internal static void CompileFunctionArgs( ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, IList <Token> argNames, IList <Expression> argValues, List <int> offsetsForOptionalArgs, VariableId[] variableIds) { int bufferStartSize = buffer.Size; for (int i = 0; i < argNames.Count; ++i) { if (argValues[i] != null) { bcc.CompileExpression(parser, buffer, argValues[i], true); buffer.Add(argNames[i], OpCode.ASSIGN_LOCAL, i); offsetsForOptionalArgs.Add(buffer.Size - bufferStartSize); } } // Arguments that are actually closure variables and not plain locals need to be converted. for (int i = 0; i < argValues.Count; ++i) { VariableId varId = variableIds[i]; if (varId.UsedByClosure) { // It's simple to copy all passed args at function invocation time to locals, which, on // its own, is incorrect. Therefore add bytecode that will dereference those local ID's and // assign them to the proper closure ID. This eliminates the need to make a dinstinction in // CALL_FUNCTION between local and closure args. buffer.Add(null, OpCode.LOCAL, i); buffer.Add(null, OpCode.ASSIGN_CLOSURE, varId.ClosureID); } } }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ThrowStatement throwStatement) { bcc.CompileExpression(parser, buffer, throwStatement.Expression, true); buffer.Add(throwStatement.FirstToken, OpCode.THROW); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, IsComparison isComp, bool outputUsed) { ByteCodeCompiler.EnsureUsed(isComp.IsToken, outputUsed); bcc.CompileExpression(parser, buffer, isComp.Expression, true); buffer.Add(isComp.IsToken, OpCode.IS_COMPARISON, isComp.ClassDefinition.ClassID); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, FunctionCall funCall, bool outputUsed) { bool argCountIsNegativeOne = false; FunctionDefinition ownerFunction = funCall.Owner as FunctionDefinition; if (ownerFunction != null && ownerFunction.NameToken.Value == "_LIB_CORE_invoke" && ownerFunction.FileScope.CompilationScope.Dependencies.Length == 0) { argCountIsNegativeOne = true; } Expression root = funCall.Root; if (root is FunctionReference) { FunctionReference verifiedFunction = (FunctionReference)root; FunctionDefinition fd = verifiedFunction.FunctionDefinition; if (parser.InlinableLibraryFunctions.Contains(fd)) { CompileInlinedLibraryFunctionCall(bcc, parser, buffer, funCall, fd, outputUsed); } else { bcc.CompileExpressionList(parser, buffer, funCall.Args, true); if (fd.Owner is ClassDefinition) { ClassDefinition cd = (ClassDefinition)fd.Owner; if (fd.Modifiers.HasStatic) { buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.STATIC_METHOD, funCall.Args.Length, fd.FunctionID, outputUsed ? 1 : 0, cd.ClassID); } else { buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.LOCAL_METHOD, funCall.Args.Length, fd.FunctionID, outputUsed ? 1 : 0, cd.ClassID, verifiedFunction.FunctionDefinition.MemberID); } } else { // vanilla function buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.NORMAL_FUNCTION, funCall.Args.Length, fd.FunctionID, outputUsed ? 1 : 0, 0); } } } else if (root is DotField) { DotField ds = (DotField)root; Expression dotRoot = ds.Root; int globalNameId = parser.GetId(ds.FieldToken.Value); bcc.CompileExpression(parser, buffer, dotRoot, true); bcc.CompileExpressionList(parser, buffer, funCall.Args, true); int localeId = parser.GetLocaleId(ds.Owner.FileScope.CompilationScope.Locale); buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.FIELD_INVOCATION, funCall.Args.Length, 0, outputUsed ? 1 : 0, globalNameId, localeId); } else if (root is BaseMethodReference) { BaseMethodReference bmr = (BaseMethodReference)root; FunctionDefinition fd = bmr.ClassToWhichThisMethodRefers.GetMethod(bmr.FieldToken.Value, true); if (fd == null) { throw new ParserException(bmr.DotToken, "This method does not exist on any base class."); } bcc.CompileExpressionList(parser, buffer, funCall.Args, true); buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.LOCAL_METHOD, funCall.Args.Length, fd.FunctionID, outputUsed ? 1 : 0, bmr.ClassToWhichThisMethodRefers.ClassID, -1); } else { bcc.CompileExpression(parser, buffer, root, true); bcc.CompileExpressionList(parser, buffer, funCall.Args, true); buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.POINTER_PROVIDED, argCountIsNegativeOne ? -1 : funCall.Args.Length, 0, outputUsed ? 1 : 0, 0); } }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, SwitchStatement switchStatement) { bool isInt = switchStatement.UsesIntegers; bcc.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 (isInt) { integersToChunkIds[((IntegerConstant)expression).Value] = chunkId; } else { stringsToChunkIds[((StringConstant)expression).Value] = chunkId; } } } chunkIdsToOffsets[chunkId] = chunkBuffer.Size; bcc.Compile(parser, chunkBuffer, chunk.Code); } chunkBuffer.ResolveBreaks(); int defaultOffsetLength = defaultChunkId == -1 ? chunkBuffer.Size : chunkIdsToOffsets[defaultChunkId]; List <int> args = new List <int>() { defaultOffsetLength }; if (isInt) { foreach (int caseValue in integersToChunkIds.Keys.OrderBy(_ => _)) { int chunkId = integersToChunkIds[caseValue]; int offset = chunkIdsToOffsets[chunkId]; args.Add(caseValue); args.Add(offset); } } else { foreach (string caseValue in stringsToChunkIds.Keys.OrderBy(_ => _)) { int chunkId = stringsToChunkIds[caseValue]; int offset = chunkIdsToOffsets[chunkId]; args.Add(parser.GetStringConstant(caseValue)); args.Add(offset); } } buffer.Add( switchStatement.FirstToken, isInt ? OpCode.SWITCH_INT : OpCode.SWITCH_STRING, args.ToArray()); buffer.Concat(chunkBuffer); }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Assignment assignment) { Expression target = assignment.Target; Expression value = assignment.Value; ResolvedType targetAssignmentType = target.ResolvedType; if (targetAssignmentType == null) { throw new Exception(); // should be ANY if no type is set. } if (value.ResolvedType == ResolvedType.ANY && targetAssignmentType != ResolvedType.ANY) { value = new Cast(value.FirstToken, targetAssignmentType, value, value.Owner, false); } if (assignment.Op == Ops.EQUALS) { if (assignment.Target is Variable) { Variable varTarget = (Variable)assignment.Target; bcc.CompileExpression(parser, buffer, value, true); VariableId varId = varTarget.VarId; if (varId.UsedByClosure) { buffer.Add(assignment.OpToken, OpCode.ASSIGN_CLOSURE, varId.ClosureID); } else { buffer.Add(assignment.OpToken, OpCode.ASSIGN_LOCAL, varId.ID); } } else if (assignment.Target is BracketIndex) { BracketIndex bi = (BracketIndex)assignment.Target; bcc.CompileExpression(parser, buffer, bi.Root, true); bcc.CompileExpression(parser, buffer, bi.Index, true); bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.ASSIGN_INDEX, 0); } else if (assignment.Target is DotField) { DotField dotStep = (DotField)assignment.Target; if (dotStep.Root is ThisKeyword) { bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.ASSIGN_THIS_FIELD, parser.GetId(dotStep.FieldToken.Value)); } else { bcc.CompileExpression(parser, buffer, dotStep.Root, true); bcc.CompileExpression(parser, buffer, value, true); int nameId = parser.GetId(dotStep.FieldToken.Value); int localeScopedNameId = nameId * parser.GetLocaleCount() + parser.GetLocaleId(dotStep.Owner.FileScope.CompilationScope.Locale); buffer.Add( assignment.OpToken, OpCode.ASSIGN_FIELD, nameId, 0, localeScopedNameId, assignment.ClassOwner == null ? -1 : assignment.ClassOwner.ClassID, assignment.CompilationScope.ScopeNumId, -1, 0); } } else if (assignment.Target is FieldReference) { bcc.CompileExpression(parser, buffer, value, true); FieldReference fieldReference = (FieldReference)assignment.Target; if (fieldReference.Field.Modifiers.HasStatic) { buffer.Add( assignment.OpToken, OpCode.ASSIGN_STATIC_FIELD, ((ClassDefinition)fieldReference.Field.Owner).ClassID, fieldReference.Field.StaticMemberID); } else { buffer.Add( assignment.OpToken, OpCode.ASSIGN_THIS_FIELD, fieldReference.Field.MemberID); } } else { throw new Exception("This shouldn't happen."); } } else { Ops op = assignment.Op; if (assignment.Target is Variable) { Variable varTarget = (Variable)assignment.Target; VariableId varId = varTarget.VarId; bool isClosure = varId.UsedByClosure; int scopeId = isClosure ? varId.ClosureID : varId.ID; buffer.Add(varTarget.FirstToken, isClosure ? OpCode.DEREF_CLOSURE : OpCode.LOCAL, scopeId); bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.BINARY_OP, (int)op); buffer.Add(assignment.Target.FirstToken, isClosure ? OpCode.ASSIGN_CLOSURE : OpCode.ASSIGN_LOCAL, scopeId); } else if (assignment.Target is DotField) { DotField dotExpr = (DotField)assignment.Target; int fieldId = parser.GetId(dotExpr.FieldToken.Value); int localeScopedStepId = parser.GetLocaleCount() * fieldId + parser.GetLocaleId(dotExpr.Owner.FileScope.CompilationScope.Locale); bcc.CompileExpression(parser, buffer, dotExpr.Root, true); if (!(dotExpr.Root is ThisKeyword)) { buffer.Add(null, OpCode.DUPLICATE_STACK_TOP, 1); } buffer.Add( dotExpr.DotToken, OpCode.DEREF_DOT, fieldId, localeScopedStepId, assignment.ClassOwner == null ? -1 : assignment.ClassOwner.ClassID, assignment.CompilationScope.ScopeNumId, -1, 0); bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.BINARY_OP, (int)op); if (dotExpr.Root is ThisKeyword) { buffer.Add(assignment.OpToken, OpCode.ASSIGN_THIS_FIELD, fieldId); } else { int localeScopedNameId = fieldId * parser.GetLocaleCount() + parser.GetLocaleId(dotExpr.Owner.FileScope.CompilationScope.Locale); buffer.Add( assignment.OpToken, OpCode.ASSIGN_FIELD, fieldId, 0, localeScopedNameId, assignment.ClassOwner == null ? -1 : assignment.ClassOwner.ClassID, assignment.CompilationScope.ScopeNumId, -1, 0); } } else if (assignment.Target is BracketIndex) { BracketIndex indexExpr = (BracketIndex)assignment.Target; bcc.CompileExpression(parser, buffer, indexExpr.Root, true); bcc.CompileExpression(parser, buffer, indexExpr.Index, true); buffer.Add(null, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(indexExpr.BracketToken, OpCode.INDEX); bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.BINARY_OP, (int)op); buffer.Add(assignment.OpToken, OpCode.ASSIGN_INDEX, 0); } else if (assignment.Target is FieldReference) { FieldReference fieldRef = (FieldReference)assignment.Target; FieldReferenceEncoder.Compile(parser, buffer, fieldRef, true); bcc.CompileExpression(parser, buffer, value, true); buffer.Add(assignment.OpToken, OpCode.BINARY_OP, (int)op); if (fieldRef.Field.Modifiers.HasStatic) { buffer.Add( assignment.OpToken, OpCode.ASSIGN_STATIC_FIELD, ((ClassDefinition)fieldRef.Field.Owner).ClassID, fieldRef.Field.StaticMemberID); } else { buffer.Add( assignment.OpToken, OpCode.ASSIGN_THIS_FIELD, fieldRef.Field.MemberID); } } else { throw new ParserException(assignment.OpToken, "Assignment is not allowed on this sort of expression."); } } }
public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Increment increment, bool outputUsed) { if (!outputUsed) { throw new Exception("This should have been optimized into a += or -="); } if (increment.Root is Variable) { // OpCode re-use be damned. This should be not one, but two top-level op codes. // INCREMENT_INLINE and INCREMENT_POP (depending on whether outputUsed is true) // In fact, the code here in its current form is actually WRONG because someString++ will have // a '1' appended to it when it really should be an error if the variable is not an integer. // Same for the others below. Ideally the DUPLICATE_STACK_TOP op should be removed. Variable variable = (Variable)increment.Root; VariableId varId = variable.VarId; bool isClosureVar = varId.UsedByClosure; int scopeId = isClosureVar ? varId.ClosureID : varId.ID; bcc.CompileExpression(parser, buffer, increment.Root, true); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(variable.FirstToken, isClosureVar ? OpCode.ASSIGN_CLOSURE : OpCode.ASSIGN_LOCAL, scopeId); } else { buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(variable.FirstToken, isClosureVar ? OpCode.ASSIGN_CLOSURE : OpCode.ASSIGN_LOCAL, scopeId); } } else if (increment.Root is BracketIndex) { BracketIndex bracketIndex = (BracketIndex)increment.Root; bcc.CompileExpression(parser, buffer, bracketIndex.Root, true); bcc.CompileExpression(parser, buffer, bracketIndex.Index, true); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(bracketIndex.BracketToken, OpCode.INDEX); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_INDEX, 1); } else { buffer.Add(increment.IncrementToken, OpCode.STACK_INSERTION_FOR_INCREMENT); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_INDEX, 0); } } else if (increment.Root is DotField) { DotField dotStep = (DotField)increment.Root; bcc.CompileExpression(parser, buffer, dotStep.Root, true); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); int nameId = parser.GetId(dotStep.FieldToken.Value); int localeScopedNameId = nameId * parser.GetLocaleCount() + parser.GetLocaleId(dotStep.Owner.FileScope.CompilationScope.Locale); int originClassId = increment.ClassOwner == null ? -1 : increment.ClassOwner.ClassID; int originAssemblyId = increment.CompilationScope.ScopeNumId; buffer.Add( dotStep.DotToken, OpCode.DEREF_DOT, nameId, localeScopedNameId, originClassId, increment.CompilationScope.ScopeNumId, -1, 0); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_FIELD, nameId, 1, localeScopedNameId, originClassId, originAssemblyId, -1, 0); } else { buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_FIELD, nameId, 0, localeScopedNameId, originClassId, originAssemblyId, -1, 0); buffer.Add(increment.IncrementToken, OpCode.STACK_SWAP_POP); } } else if (increment.Root is FieldReference) { FieldReference fr = (FieldReference)increment.Root; bool isStatic = fr.Field.Modifiers.HasStatic; ClassDefinition cd = (ClassDefinition)fr.Field.Owner; int memberId = isStatic ? fr.Field.StaticMemberID : fr.Field.MemberID; bcc.CompileExpression(parser, buffer, fr, true); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); } else { buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)Ops.ADDITION : (int)Ops.SUBTRACTION); } Token token = increment.IsPrefix ? increment.FirstToken : fr.FirstToken; if (isStatic) { buffer.Add(token, OpCode.ASSIGN_STATIC_FIELD, ((ClassDefinition)fr.Field.Owner).ClassID, memberId); } else { buffer.Add(token, OpCode.ASSIGN_THIS_FIELD, memberId); } } else { throw new ParserException(increment.IncrementToken, "Cannot apply " + (increment.IsIncrement ? "++" : "--") + " to this sort of expression."); } }