public bool TryGetNext(out LineOfCode lineOfCode) { if (!_sourceCode.TryGetNextLine(_currentIndex, out var currentLineSpan)) { lineOfCode = default; return(false); } _currentIndex += currentLineSpan.Length; var leftTrimmedSpan = currentLineSpan.TrimStart(); if (leftTrimmedSpan.StartsWith("///")) { lineOfCode = new LineOfCode(LineOfCodeType.XmlComment, currentLineSpan); } else if (leftTrimmedSpan.StartsWith("[ContractAnnotation(")) { lineOfCode = new LineOfCode(LineOfCodeType.ContractAnnotation, currentLineSpan); } else if (leftTrimmedSpan.StartsWith("[DoesNotReturn]")) { lineOfCode = new LineOfCode(LineOfCodeType.DoesNotReturnAnnotation, currentLineSpan); } else if (leftTrimmedSpan.IsEmpty) { lineOfCode = new LineOfCode(LineOfCodeType.WhiteSpace, currentLineSpan); } else { lineOfCode = new LineOfCode(LineOfCodeType.Other, currentLineSpan); } return(true); }
public void ShouldHandleCommentsOnTheSameLineAsCode() { LineOfCode loc = classUnderTest.Parse("push constant 4000 // test THIS and THAT context save"); loc.Error.Should().BeNull(); loc.Value.Should().Be(4000); }
public void ShouldLeaveSegmentAndValueEmptyForArithmeticInstructions() { LineOfCode lineOfCode = classUnderTest.Parse("add"); lineOfCode.Segment.Should().BeNull(); lineOfCode.Value.Should().BeNull(); }
public void ShouldNotIncrementProgramCounterForLabelsAndWhitespace() { LineOfCode whitespace = new LineOfCode { Type = InstructionType.Whitespace }; LineOfCode comp1 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode comp2 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode label1 = new LineOfCode { Type = InstructionType.Label, Label = "LOOP" }; LineOfCode comp3 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode comp4 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode label2 = new LineOfCode { Type = InstructionType.Label, Label = "FINISH" }; LineOfCode comp5 = new LineOfCode { Type = InstructionType.CInstruction }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(whitespace, comp1, comp2, whitespace, label1, comp3, comp4, whitespace, whitespace, label2, comp5); dict["LOOP"].Should().Be(2); dict["FINISH"].Should().Be(4); }
public void ShouldDistinguishBetweenVariablesAndLabels() { LineOfCode referenceToVariable = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "counter" }; LineOfCode comp1 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode comp2 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode referenceToLabel = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "FINISH" }; LineOfCode comp3 = new LineOfCode { Type = InstructionType.CInstruction }; LineOfCode label2 = new LineOfCode { Type = InstructionType.Label, Label = "FINISH" }; LineOfCode comp4 = new LineOfCode { Type = InstructionType.CInstruction }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(referenceToVariable, comp1, comp2, referenceToLabel, comp3, label2, comp4); dict["counter"].Should().Be(16); dict["FINISH"].Should().Be(5); }
public void ShouldRaiseErrorForEmptyAddress() { LineOfCode result = parser.Parse("@"); result.Type.Should().Be(InstructionType.Invalid); result.Error.Should().Be("Empty addresses are not permitted."); }
public void ShouldRaiseErrorForInvalidLabel() { LineOfCode result = parser.Parse("(SOMETHING"); result.Type.Should().Be(InstructionType.Invalid); result.Error.Should().Be("The given key '(SOMETHING' was not present in the dictionary."); }
public void ShouldRaiseErrorForEmptyLabel() { LineOfCode result = parser.Parse("()"); result.Type.Should().Be(InstructionType.Invalid); result.Error.Should().Be("Empty labels are not permitted."); }
public void ShouldRaiseErrorForInvalidComp() { LineOfCode result = parser.Parse("M=Z+1"); result.Type.Should().Be(InstructionType.Invalid); result.Error.Should().Be("The given key 'Z+1' was not present in the dictionary."); }
public void ShouldRaiseErrorForInvalidJump() { LineOfCode result = parser.Parse("A=M+1;JUMP"); result.Type.Should().Be(InstructionType.Invalid); result.Error.Should().Be("Requested value 'JUMP' was not found."); }
public void ShouldTrimLabel() { LineOfCode result = parser.Parse("( LOOP )"); result.Type.Should().Be(InstructionType.Label); result.Label.Should().Be("LOOP"); }
public void ShouldOutputNullForLabels() { LineOfCode line = new LineOfCode { Type = InstructionType.Label }; classUnderTest.ConvertToBinary(line, symbolTable).Should().BeNull(); }
public void ShouldOutputCorrectBinaryForAddressesExpressedAsSymbols() { LineOfCode line = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "counter" }; classUnderTest.ConvertToBinary(line, symbolTable).Should().Be("0000000000010010"); }
public void ShouldSetCorrectJumpDetailsWithDest() { LineOfCode result = parser.Parse("AMD=D|A;JEQ"); result.Comp.Should().Be(Comp.DOrA); result.Type.Should().Be(InstructionType.CInstruction); result.Dest.Should().Be(Dest.AMD); result.Jump.Should().Be(Jump.JEQ); }
public void ShouldSetCorrectJumpDetailsWithoutDest() { LineOfCode result = parser.Parse("D&M;JGE"); result.Comp.Should().Be(Comp.DAndM); result.Type.Should().Be(InstructionType.CInstruction); result.Dest.Should().Be(Dest.NotStored); result.Jump.Should().Be(Jump.JGE); }
public void ShouldSetAddressOfVariables() { LineOfCode variable = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "counter" }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(line1, line2, variable, line3); dict.Should().ContainKey("counter"); dict["counter"].Should().Be(16); }
public void ShouldSetAddressOfLabels() { LineOfCode label = new LineOfCode { Type = InstructionType.Label, Label = "LOOP" }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(line1, line2, label, line3); dict.Should().ContainKey("LOOP"); dict["LOOP"].Should().Be(2); }
public void ShouldOutputCorrectBinaryForCInstructions() { LineOfCode line = new LineOfCode { Type = InstructionType.CInstruction, Dest = Dest.AM, Comp = Comp.DMinusA, Jump = Jump.JEQ }; classUnderTest.ConvertToBinary(line, symbolTable).Should().Be("1110010011101010"); }
public void ShouldIgnoreAInstructionsWithANumericAddress() { LineOfCode variable1 = new LineOfCode { Type = InstructionType.AInstruction, Address = 123 }; LineOfCode variable2 = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "temp" }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(variable1, variable2); dict.Should().NotContainKey("123"); }
public void ShouldTranslateFunctionReturn() { LineOfCode loc = new LineOfCode { VmCode = "return", Instruction = InstructionType.Return, FunctionName = "myFunction" }; classUnderTest.Translate(loc) .Should().Contain("endFrame"); }
public void ShouldMarkAsErrorIfThereAreDuplicateLabels() { LineOfCode label1 = new LineOfCode { Type = InstructionType.Label, Label = "LOOP" }; LineOfCode label2 = new LineOfCode { Type = InstructionType.Label, Label = "LOOP" }; symbolTableBuilder.BuildSymbolTable(line1, line2, label1, line3, label2); label2.Type.Should().Be(InstructionType.Invalid); label2.Error.Should().Be("Duplicated label."); }
public void ShouldTranslateFunctionWithASingleLocalVariable() { LineOfCode loc = new LineOfCode { VmCode = "function myFunction 1", Instruction = InstructionType.Function, FunctionName = "myFunction", FileName = "Foo", Value = 1 }; classUnderTest.Translate(loc) .Should().Be("// function myFunction 1\n(myFunction)\n@SP\nA=M\nM=0\n@SP\nM=M+1\n"); }
public void ShouldTranslateFunctionWithMoreThanOneLocalVariable() { LineOfCode loc = new LineOfCode { VmCode = "function myFunction 3", Instruction = InstructionType.Function, FunctionName = "myFunction", FileName = "Foo", Value = 3 }; classUnderTest.Translate(loc) .Should().Be("// function myFunction 3\n(myFunction)\n@3\nD=A\n(myFunction.init)\n@SP\nA=M\nM=0\n@SP\nM=M+1\nD=D-1\[email protected]\nD;JNE\n"); }
public void ShouldTranslateFunctionWithNoLocalVariables() { LineOfCode loc = new LineOfCode { VmCode = "function myFunction 0", Instruction = InstructionType.Function, FunctionName = "myFunction", FileName = "Foo", Value = 0 }; classUnderTest.Translate(loc) .Should().Be("// function myFunction 0\n(myFunction)\n"); }
public void ShouldTranslateFunctionCall() { LineOfCode loc = new LineOfCode { VmCode = "call myFunction 2", Instruction = InstructionType.Call, FunctionName = "myFunction", FileName = "Foo", Value = 2, LineNumber = 123 }; classUnderTest.Translate(loc) .Should().Contain("@myFunction.return.123"); }
public void ShouldUsePreviouslyAssignedAddressInSubsequentVariableReferences() { LineOfCode variable1 = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "counter" }; LineOfCode variable2 = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "temp" }; LineOfCode variable3 = new LineOfCode { Type = InstructionType.AInstruction, AddressSymbol = "i" }; Dictionary <string, int> dict = symbolTableBuilder.BuildSymbolTable(variable1, variable2, line3, variable1, variable3); dict.Should().ContainKey("counter").And.ContainKey("temp").And.ContainKey("i"); dict["counter"].Should().Be(16); dict["temp"].Should().Be(17); dict["i"].Should().Be(18); }
public static Memory <char> Cleanup(string sourceCode, SourceFileMergeOptions options) { if (options.RemoveCallerArgumentExpressions) { sourceCode = sourceCode.Replace("[CallerArgumentExpression(\"parameter\")] ", string.Empty); } if (options.RemoveValidatedNotNull) { sourceCode = sourceCode.Replace("[ValidatedNotNull] ", string.Empty); } if (options.RemoveNotNullWhen) { sourceCode = sourceCode.Replace("[NotNullWhen(true)] ", string.Empty); sourceCode = sourceCode.Replace("[NotNullWhen(false)] ", string.Empty); } var sink = new ArrayTextSink(new char[sourceCode.Length]); var parser = new LineOfCodeParser(sourceCode); LineOfCode previousLineOfCode = default; while (parser.TryGetNext(out var currentLineOfCode)) { var isEmptyLineAfterXmlComment = previousLineOfCode.Type == LineOfCodeType.XmlComment && currentLineOfCode.Type == LineOfCodeType.WhiteSpace; var isContractAnnotationThatShouldBeRemoved = options.RemoveContractAnnotations && currentLineOfCode.Type == LineOfCodeType.ContractAnnotation; var isDoesNotReturnThatShouldBeRemoved = options.RemoveDoesNotReturn && currentLineOfCode.Type == LineOfCodeType.DoesNotReturnAnnotation; if (isEmptyLineAfterXmlComment) { // Break point parking spot } if (!isEmptyLineAfterXmlComment && !isContractAnnotationThatShouldBeRemoved && !isDoesNotReturnThatShouldBeRemoved) { sink.Append(currentLineOfCode.Span); } previousLineOfCode = currentLineOfCode; } return(sink.ToMemory()); }