Пример #1
0
        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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #6
0
        public void ShouldRaiseErrorForEmptyAddress()
        {
            LineOfCode result = parser.Parse("@");

            result.Type.Should().Be(InstructionType.Invalid);
            result.Error.Should().Be("Empty addresses are not permitted.");
        }
Пример #7
0
        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.");
        }
Пример #8
0
        public void ShouldRaiseErrorForEmptyLabel()
        {
            LineOfCode result = parser.Parse("()");

            result.Type.Should().Be(InstructionType.Invalid);
            result.Error.Should().Be("Empty labels are not permitted.");
        }
Пример #9
0
        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.");
        }
Пример #10
0
        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.");
        }
Пример #11
0
        public void ShouldTrimLabel()
        {
            LineOfCode result = parser.Parse("(  LOOP  )");

            result.Type.Should().Be(InstructionType.Label);
            result.Label.Should().Be("LOOP");
        }
Пример #12
0
        public void ShouldOutputNullForLabels()
        {
            LineOfCode line = new LineOfCode {
                Type = InstructionType.Label
            };

            classUnderTest.ConvertToBinary(line, symbolTable).Should().BeNull();
        }
Пример #13
0
        public void ShouldOutputCorrectBinaryForAddressesExpressedAsSymbols()
        {
            LineOfCode line = new LineOfCode {
                Type = InstructionType.AInstruction, AddressSymbol = "counter"
            };

            classUnderTest.ConvertToBinary(line, symbolTable).Should().Be("0000000000010010");
        }
Пример #14
0
        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);
        }
Пример #15
0
        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);
        }
Пример #18
0
        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");
        }
Пример #20
0
        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.");
        }
Пример #22
0
        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");
        }
Пример #23
0
        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");
        }
Пример #24
0
        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");
        }
Пример #25
0
        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);
        }
Пример #27
0
    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());
    }