Exemple #1
0
		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);
		}
Exemple #2
0
		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);
		}
Exemple #3
0
		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);
		}
Exemple #4
0
		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);
		}
Exemple #5
0
		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);
		}
Exemple #6
0
		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);
		}
Exemple #7
0
		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);
		}
Exemple #8
0
		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);
			}
		}
Exemple #9
0
		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);
		}
Exemple #10
0
		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);
			}
		}
Exemple #11
0
		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);
		}
Exemple #12
0
		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
		}