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 CompileIncrement(Parser 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; int scopeId = variable.LocalScopeId; this.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)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(variable.FirstToken, 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)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(variable.FirstToken, OpCode.ASSIGN_LOCAL, scopeId); } } else if (increment.Root is BracketIndex) { BracketIndex bracketIndex = (BracketIndex)increment.Root; this.CompileExpression(parser, buffer, bracketIndex.Root, true); this.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)BinaryOps.ADDITION : (int)BinaryOps.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)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_INDEX, 0); } } else if (increment.Root is DotStep) { DotStep dotStep = (DotStep)increment.Root; this.CompileExpression(parser, buffer, dotStep.Root, true); buffer.Add(increment.IncrementToken, OpCode.DUPLICATE_STACK_TOP, 1); buffer.Add(dotStep.DotToken, OpCode.DEREF_DOT, parser.GetId(dotStep.StepToken.Value)); if (increment.IsPrefix) { buffer.Add(increment.IncrementToken, OpCode.LITERAL, parser.GetIntConstant(1)); buffer.Add(increment.IncrementToken, OpCode.BINARY_OP, increment.IsIncrement ? (int)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_STEP, parser.GetId(dotStep.StepToken.Value), 1); } 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)BinaryOps.ADDITION : (int)BinaryOps.SUBTRACTION); buffer.Add(increment.IncrementToken, OpCode.ASSIGN_STEP, parser.GetId(dotStep.StepToken.Value), 0); buffer.Add(increment.IncrementToken, OpCode.STACK_SWAP_POP); } } else { throw new ParserException(increment.IncrementToken, "Cannot apply " + (increment.IsIncrement ? "++" : "--") + " to this sort of expression."); } }
private void CompileAssignment(Parser parser, ByteBuffer buffer, Assignment assignment) { if (assignment.AssignmentOp == "=") { if (assignment.Target is Variable) { Variable varTarget = (Variable)assignment.Target; this.CompileExpression(parser, buffer, assignment.Value, true); int scopeId = varTarget.LocalScopeId; if (scopeId == -1) { throw new Exception(); // this should not happen. } buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_LOCAL, scopeId); } else if (assignment.Target is BracketIndex) { BracketIndex bi = (BracketIndex)assignment.Target; // TODO: optimization opportunity: special op code when index is a string or int constant. this.CompileExpression(parser, buffer, bi.Root, true); this.CompileExpression(parser, buffer, bi.Index, true); this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_INDEX, 0); } else if (assignment.Target is DotStep) { DotStep dotStep = (DotStep)assignment.Target; if (dotStep.Root is ThisKeyword) { this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_THIS_STEP, parser.GetId(dotStep.StepToken.Value)); } else { this.CompileExpression(parser, buffer, dotStep.Root, true); this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_STEP, parser.GetId(dotStep.StepToken.Value), 0); } } else if (assignment.Target is FieldReference) { this.CompileExpression(parser, buffer, assignment.Value, true); FieldReference fieldReference = (FieldReference)assignment.Target; if (fieldReference.Field.IsStaticField) { buffer.Add( assignment.AssignmentOpToken, OpCode.ASSIGN_STATIC_FIELD, ((ClassDefinition)fieldReference.Field.FunctionOrClassOwner).ClassID, fieldReference.Field.StaticMemberID); } else { // TODO: "this.foo = value" throw new NotImplementedException(); } } else { throw new Exception("This shouldn't happen."); } } else { BinaryOps op = this.ConvertOpString(assignment.AssignmentOpToken); if (assignment.Target is Variable) { Variable varTarget = (Variable)assignment.Target; int scopeId = varTarget.LocalScopeId; if (scopeId == -1) { throw new Exception(); // all variables should have local ID's allocated or errors thrown by now. } this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.BINARY_OP, (int)op); buffer.Add(assignment.Target.FirstToken, OpCode.ASSIGN_LOCAL, scopeId); throw new NotImplementedException(); // TODO: redo this } else if (assignment.Target is DotStep) { DotStep dotExpr = (DotStep)assignment.Target; int stepId = parser.GetId(dotExpr.StepToken.Value); this.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, stepId); this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.BINARY_OP, (int)op); if (dotExpr.Root is ThisKeyword) { buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_THIS_STEP, stepId); } else { buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_STEP, stepId, 0); } } else if (assignment.Target is BracketIndex) { BracketIndex indexExpr = (BracketIndex)assignment.Target; this.CompileExpression(parser, buffer, indexExpr.Root, true); this.CompileExpression(parser, buffer, indexExpr.Index, true); buffer.Add(null, OpCode.DUPLICATE_STACK_TOP, 2); buffer.Add(indexExpr.BracketToken, OpCode.INDEX); this.CompileExpression(parser, buffer, assignment.Value, true); buffer.Add(assignment.AssignmentOpToken, OpCode.BINARY_OP, (int)op); buffer.Add(assignment.AssignmentOpToken, OpCode.ASSIGN_INDEX, 0); } else { throw new ParserException(assignment.AssignmentOpToken, "Assignment is not allowed on this sort of expression."); } } }
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 CompileFunctionCall(Parser parser, ByteBuffer buffer, FunctionCall funCall, bool outputUsed) { Expression root = funCall.Root; if (root is FunctionReference) { FunctionReference verifiedFunction = (FunctionReference)root; FunctionDefinition fd = verifiedFunction.FunctionDefinition; this.CompileExpressionList(parser, buffer, funCall.Args, true); if (fd.FunctionOrClassOwner is ClassDefinition) { ClassDefinition cd = (ClassDefinition)fd.FunctionOrClassOwner; if (fd.IsStaticMethod) { 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); } } 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 DotStep) { DotStep ds = (DotStep)root; Expression dotRoot = ds.Root; int globalNameId = parser.GetId(ds.StepToken.Value); this.CompileExpression(parser, buffer, dotRoot, true); this.CompileExpressionList(parser, buffer, funCall.Args, true); buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.FIELD_INVOCATION, funCall.Args.Length, 0, outputUsed ? 1 : 0, globalNameId); } else if (root is BaseMethodReference) { BaseMethodReference bmr = (BaseMethodReference)root; FunctionDefinition fd = bmr.ClassToWhichThisMethodRefers.GetMethod(bmr.StepToken.Value, true); if (fd == null) { throw new ParserException(bmr.DotToken, "This method does not exist on any base class."); } this.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); } else { this.CompileExpression(parser, buffer, root, true); this.CompileExpressionList(parser, buffer, funCall.Args, true); buffer.Add( funCall.ParenToken, OpCode.CALL_FUNCTION, (int)FunctionInvocationType.POINTER_PROVIDED, funCall.Args.Length, 0, outputUsed ? 1 : 0, 0); } }
private void CompileVariable(Parser parser, ByteBuffer buffer, Variable variable, bool outputUsed) { if (!outputUsed) throw new ParserException(variable.FirstToken, "This expression does nothing."); int nameId = parser.GetId(variable.Name); Token token = variable.FirstToken; if (variable.LocalScopeId == -1) { throw new ParserException(token, "Variable used but not declared."); } else { buffer.Add(token, OpCode.LOCAL, variable.LocalScopeId, nameId); } }
private void CompileDotStep(Parser parser, ByteBuffer buffer, DotStep dotStep, bool outputUsed) { if (!outputUsed) throw new ParserException(dotStep.FirstToken, "This expression does nothing."); this.CompileExpression(parser, buffer, dotStep.Root, true); int primitiveMethodId = Constants.GetPrimitiveFieldId(dotStep.StepToken.Value); buffer.Add(dotStep.DotToken, OpCode.DEREF_DOT, parser.GetId(dotStep.StepToken.Value), primitiveMethodId); }