Esempio n. 1
0
        private static ValueType ParseTypeRecursive(this CompilerIO self, string error, Slice slice, int recursionLevel)
        {
            if (recursionLevel > 8)
            {
                self.AddSoftError(slice, "Type is nested too deeply");
                return(new ValueType(TypeKind.Unit));
            }

            var type = new Option <ValueType>();

            if (self.parser.Match(TokenKind.Bool))
            {
                type = Option.Some(new ValueType(TypeKind.Bool));
            }
            else if (self.parser.Match(TokenKind.Int))
            {
                type = Option.Some(new ValueType(TypeKind.Int));
            }
            else if (self.parser.Match(TokenKind.Float))
            {
                type = Option.Some(new ValueType(TypeKind.Float));
            }
            else if (self.parser.Match(TokenKind.String))
            {
                type = Option.Some(new ValueType(TypeKind.String));
            }
            else if (self.parser.Match(TokenKind.OpenCurlyBrackets))
            {
                type = self.ParseTupleType(slice, recursionLevel + 1);
            }
            else if (self.parser.Match(TokenKind.Identifier))
            {
                type = self.ParseStructOrClassType(recursionLevel + 1);
            }
            else if (self.parser.Match(TokenKind.Function))
            {
                type = self.ParseFunctionType(slice, recursionLevel + 1);
            }
            else if (self.parser.Match(TokenKind.OpenSquareBrackets))
            {
                type = self.ParseArrayType(slice, recursionLevel + 1);
            }
            else if (self.parser.Match(TokenKind.Ampersand))
            {
                type = self.ParseReferenceType(slice, recursionLevel + 1);
            }

            if (type.isSome)
            {
                return(type.value);
            }

            slice = Slice.FromTo(slice, self.parser.previousToken.slice);

            self.AddSoftError(slice, error);
            return(new ValueType(TypeKind.Unit));
        }
Esempio n. 2
0
        public static void EndScope(this CompilerIO self, Scope scope, int sizeLeftOnStack)
        {
            self.scopeDepth -= 1;

            for (var i = scope.localVariablesStartIndex; i < self.localVariables.count; i++)
            {
                var variable = self.localVariables.buffer[i];
                if (!variable.IsUsed)
                {
                    self.AddSoftError(variable.slice, "Unused variable '{0}'", CompilerHelper.GetSlice(self, variable.slice));
                }
                if (variable.IsMutable && !variable.IsChanged)
                {
                    self.AddSoftError(variable.slice, "Mutable variable '{0}' never changes", CompilerHelper.GetSlice(self, variable.slice));
                }
            }

            var localCount = self.localVariables.count - scope.localVariablesStartIndex;

            if (localCount == 0)
            {
                return;
            }

            var localVarsSize = 0;

            for (var i = scope.localVariablesStartIndex; i < self.localVariables.count; i++)
            {
                var type = self.localVariables.buffer[i].type;
                localVarsSize += type.GetSize(self.chunk);
            }

            if (sizeLeftOnStack > 0)
            {
                self.EmitInstruction(Instruction.Move);
                self.EmitByte((byte)localVarsSize);
                self.EmitByte((byte)sizeLeftOnStack);
            }
            else
            {
                self.EmitPop(localVarsSize);
            }

            self.localVariables.count -= localCount;

            self.DebugEmitPopTypes((byte)localCount);
            self.DebugPopLocalVariableNames((byte)localCount);
        }
Esempio n. 3
0
        public static bool CheckStructBuild(this CompilerIO self, StructTypeBuilder.Result result, Slice slice, string name)
        {
            switch (result)
            {
            case StructTypeBuilder.Result.Success:
                return(true);

            case StructTypeBuilder.Result.TooManyStructs:
                self.AddSoftError(slice, "Too many struct declarations");
                return(false);

            case StructTypeBuilder.Result.DuplicatedName:
                self.AddSoftError(slice, "There's already a struct named '{0}'", name);
                return(false);

            default:
                return(false);
            }
        }
Esempio n. 4
0
        public static bool CheckFunctionBuild(this CompilerIO self, FunctionTypeBuilder.Result result, Slice slice)
        {
            switch (result)
            {
            case FunctionTypeBuilder.Result.Success:
                return(true);

            case FunctionTypeBuilder.Result.TooManyFunctions:
                self.AddSoftError(slice, "Too many function declarations");
                return(false);

            case FunctionTypeBuilder.Result.ParametersTooBig:
                self.AddSoftError(slice, "Function parameters size is too big. Max is {0}", byte.MaxValue);
                return(false);

            default:
                return(false);
            }
        }
Esempio n. 5
0
        public static bool CheckTupleBuild(this CompilerIO self, TupleTypeBuilder.Result result, Slice slice)
        {
            switch (result)
            {
            case TupleTypeBuilder.Result.Success:
                return(true);

            case TupleTypeBuilder.Result.TooManyTuples:
                self.AddSoftError(slice, "Too many tuple declarations");
                return(false);

            case TupleTypeBuilder.Result.ElementsTooBig:
                self.AddSoftError(slice, "Tuple elements size is too big. Max is {0}", byte.MaxValue);
                return(false);

            default:
                return(false);
            }
        }
Esempio n. 6
0
        private static Option <ValueType> ParseReferenceType(this CompilerIO self, Slice slice, int recursionLevel)
        {
            var isMutable = self.parser.Match(TokenKind.Mut);

            slice = Slice.FromTo(slice, self.parser.previousToken.slice);
            var referredType = self.ParseTypeRecursive("Expected referred type", slice, recursionLevel);

            if (referredType.IsReference)
            {
                self.AddSoftError(slice, "Can not declare reference of reference");
                return(Option.None);
            }

            return(Option.Some(referredType.ToReferenceType(isMutable)));
        }
Esempio n. 7
0
        private static Option <ValueType> ParseArrayType(this CompilerIO self, Slice slice, int recursionLevel)
        {
            slice = Slice.FromTo(slice, self.parser.previousToken.slice);
            var elementType = self.ParseTypeRecursive("Expected array element type", slice, recursionLevel);

            self.parser.Consume(TokenKind.CloseSquareBrackets, "Expected ']' after array type");
            slice = Slice.FromTo(slice, self.parser.previousToken.slice);

            if (elementType.IsArray)
            {
                self.AddSoftError(slice, "Can not declare array of arrays");
                return(Option.None);
            }

            return(Option.Some(elementType.ToArrayType()));
        }
        public static int EndFunctionDeclaration(this CompilerIO self, FunctionTypeBuilder builder, Slice slice, bool isPublic, bool hasBody)
        {
            var name          = CompilerHelper.GetSlice(self, slice);
            var result        = builder.Build(out var index);
            var functionIndex = -1;

            if (self.CheckFunctionBuild(result, slice))
            {
                switch (self.chunk.AddFunction(name, isPublic, index, hasBody, slice, self.functionsStartIndex, out functionIndex))
                {
                case ByteCodeChunk.AddFunctionResult.AlreadyDefined:
                    self.AddSoftError(slice, "Function '{0}' is already defined", name);
                    break;

                case ByteCodeChunk.AddFunctionResult.VisibilityMismatch:
                {
                    if (self.ResolveToFunctionIndex(slice, out int prototypeIndex))
                    {
                        var prototypeIsPublic = self.chunk.functions.buffer[prototypeIndex].isPublic;

                        self.AddSoftError(
                            slice,
                            "Visibility mismatch between function '{0}' prototype and its body. Expected {1}. Got {2}",
                            name,
                            prototypeIsPublic ? "'pub'" : "no 'pub'",
                            isPublic ? "'pub'" : "no 'pub'"
                            );
                    }
                    else
                    {
                        self.AddSoftError(slice, "Visibility mismatch between function '{0}' prototype and its body", name);
                    }
                    break;
                }

                case ByteCodeChunk.AddFunctionResult.TypeMismatch:
                {
                    if (self.ResolveToFunctionIndex(slice, out int prototypeIndex))
                    {
                        var typeIndex     = self.chunk.functions.buffer[prototypeIndex].typeIndex;
                        var prototypeType = new ValueType(TypeKind.Function, typeIndex);
                        var functionType  = new ValueType(TypeKind.Function, index);

                        self.AddSoftError(
                            slice,
                            "Type mismatch between function '{0}' prototype and its body. Expected {1}. Got {2}",
                            name,
                            prototypeType.ToString(self.chunk),
                            functionType.ToString(self.chunk)
                            );
                    }
                    else
                    {
                        self.AddSoftError(slice, "Type mismatch between function '{0}' prototype and its body", name);
                    }
                    break;
                }

                default:
                    break;
                }
            }

            if (functionIndex < 0)
            {
                functionIndex = self.chunk.functions.count;
                if (self.chunk.functionTypes.count < ushort.MaxValue)
                {
                    self.chunk.functionTypes.PushBack(new FunctionType(new Slice(), new ValueType(TypeKind.Unit), 0));
                }
                var typeIndex = self.chunk.functionTypes.count - 1;

                self.chunk.functions.PushBack(new Function(name, isPublic, -slice.index, (ushort)typeIndex));
            }

            return(functionIndex);
        }