public static bool ResolveToLocalVariableIndex(this CompilerIO self, Slice slice, out int index)
        {
            var source = self.parser.tokenizer.source;

            for (var i = self.localVariables.count - 1; i >= 0; i--)
            {
                var local = self.localVariables.buffer[i];
                if (CompilerHelper.AreEqual(source, slice, local.slice))
                {
                    index = i;
                    return(true);
                }
            }

            if (self.loopNesting.count > 0 || CompilerHelper.AreEqual(source, slice, "it"))
            {
                for (var i = self.localVariables.count - 1; i >= 0; i--)
                {
                    if (self.localVariables.buffer[i].IsIteration)
                    {
                        index = i;
                        return(true);
                    }
                }
            }

            index = 0;
            return(false);
        }
Ejemplo n.º 2
0
        private static Option <ValueType> ParseStructOrClassType(this CompilerIO self, int recursionLevel)
        {
            var source = self.parser.tokenizer.source;
            var slice  = self.parser.previousToken.slice;

            for (var i = 0; i < self.chunk.structTypes.count; i++)
            {
                var structName = self.chunk.structTypes.buffer[i].name;
                if (CompilerHelper.AreEqual(source, slice, structName))
                {
                    return(Option.Some(new ValueType(TypeKind.Struct, i)));
                }
            }

            for (var i = 0; i < self.chunk.nativeClassTypes.count; i++)
            {
                var className = self.chunk.nativeClassTypes.buffer[i].name;
                if (CompilerHelper.AreEqual(source, slice, className))
                {
                    return(Option.Some(new ValueType(TypeKind.NativeClass, i)));
                }
            }

            return(Option.None);
        }
Ejemplo n.º 3
0
 public static void DebugEmitPushFrame(this CompilerIO self)
 {
     if (self.mode == Mode.Debug)
     {
         self.EmitInstruction(Instruction.DebugPushFrame);
     }
 }
        public static void EndStructDeclaration(this CompilerIO self, StructTypeBuilder builder, Slice slice, bool isPublic)
        {
            var name   = CompilerHelper.GetSlice(self, slice);
            var result = builder.Build(name, isPublic, self.structTypesStartIndex, out var index);

            self.CheckStructBuild(result, slice, name);
        }
        // VARIABLES
        public static int AddLocalVariable(this CompilerIO self, Slice slice, ValueType type, VariableFlags flags)
        {
            self.DebugPushLocalVariableName(
                (flags & VariableFlags.Iteration) != 0 ?
                "it" :
                CompilerHelper.GetSlice(self, slice)
                );

            byte stackIndex = 0;

            if (self.localVariables.count > 0)
            {
                var lastVar = self.localVariables.buffer[self.localVariables.count - 1];
                stackIndex = (byte)(lastVar.stackIndex + lastVar.type.GetSize(self.chunk));
            }

            if (self.parser.tokenizer.source[slice.index] == '_')
            {
                flags |= VariableFlags.Used | VariableFlags.Changed;
            }

            self.localVariables.PushBack(new LocalVariable(
                                             slice,
                                             stackIndex,
                                             type,
                                             flags
                                             ));

            return(self.localVariables.count - 1);
        }
Ejemplo n.º 6
0
        private static Option <ValueType> ParseFunctionType(this CompilerIO self, Slice slice, int recursionLevel)
        {
            var builder = self.chunk.BeginFunctionType();

            self.parser.Consume(TokenKind.OpenParenthesis, "Expected '(' after function type");
            if (!self.parser.Check(TokenKind.CloseParenthesis))
            {
                do
                {
                    slice = Slice.FromTo(slice, self.parser.previousToken.slice);
                    var paramType = self.ParseTypeRecursive("Expected function parameter type", slice, recursionLevel);
                    builder.WithParam(paramType);
                } while (self.parser.Match(TokenKind.Comma));
            }
            self.parser.Consume(TokenKind.CloseParenthesis, "Expected ')' after function type parameter list");
            if (self.parser.Match(TokenKind.Colon))
            {
                slice = Slice.FromTo(slice, self.parser.previousToken.slice);
                builder.returnType = self.ParseTypeRecursive("Expected function return type", slice, recursionLevel);
            }

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

            var result = builder.Build(out var typeIndex);

            if (!self.CheckFunctionBuild(result, slice))
            {
                return(Option.None);
            }

            var type = new ValueType(TypeKind.Function, typeIndex);

            return(Option.Some(type));
        }
Ejemplo n.º 7
0
        private static Option <ValueType> ParseTupleType(this CompilerIO self, Slice slice, int recursionLevel)
        {
            var source            = self.parser.tokenizer.source;
            var builder           = self.chunk.BeginTupleType();
            var elementStartIndex = self.chunk.tupleElementTypes.count;

            while (
                !self.parser.Check(TokenKind.CloseCurlyBrackets) &&
                !self.parser.Check(TokenKind.End)
                )
            {
                slice = Slice.FromTo(slice, self.parser.previousToken.slice);
                var elementType = self.ParseTypeRecursive("Expected tuple element type", slice, recursionLevel);
                if (!self.parser.Check(TokenKind.CloseCurlyBrackets))
                {
                    self.parser.Consume(TokenKind.Comma, "Expected ',' after element type");
                }
                builder.WithElement(elementType);
            }
            self.parser.Consume(TokenKind.CloseCurlyBrackets, "Expected '}' after tuple elements");

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

            var result = builder.Build(out var tupleTypeIndex);

            if (!self.CheckTupleBuild(result, slice))
            {
                return(Option.None);
            }

            var type = new ValueType(TypeKind.Tuple, tupleTypeIndex);

            return(Option.Some(type));
        }
Ejemplo n.º 8
0
 public static void DebugPopLocalVariableNames(this CompilerIO self, byte count)
 {
     if (self.mode == Mode.Debug)
     {
         self.EmitInstruction(Instruction.DebugPopLocalVariableNameMultiple);
         self.EmitByte(count);
     }
 }
Ejemplo n.º 9
0
 public static void DebugEmitPopTypes(this CompilerIO self, byte count)
 {
     if (self.mode == Mode.Debug)
     {
         self.EmitInstruction(Instruction.DebugPopTypeMultiple);
         self.EmitByte(count);
     }
 }
Ejemplo n.º 10
0
 public static void DebugEmitPushType(this CompilerIO self, ValueType type)
 {
     if (self.mode == Mode.Debug)
     {
         self.EmitInstruction(Instruction.DebugPushType);
         self.EmitType(type);
     }
 }
Ejemplo n.º 11
0
 public static void DebugPushLocalVariableName(this CompilerIO self, string name)
 {
     if (self.mode == Mode.Debug)
     {
         var stringIndex = self.chunk.AddStringLiteral(name);
         self.EmitInstruction(Instruction.DebugPushLocalVariableName);
         self.EmitUShort((ushort)stringIndex);
     }
 }
Ejemplo n.º 12
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));
        }
Ejemplo n.º 13
0
        public static void EndLoop(this CompilerIO self)
        {
            self.loopNesting.count -= 1;

            for (var i = self.loopBreaks.count - 1; i >= 0; i--)
            {
                var loopBreak = self.loopBreaks.buffer[i];
                if (loopBreak.nesting == self.loopNesting.count)
                {
                    self.EndEmitForwardJump(loopBreak.jump);
                    self.loopBreaks.SwapRemove(i);
                }
            }
        }
Ejemplo n.º 14
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)));
        }
Ejemplo n.º 15
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);
        }
Ejemplo n.º 16
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()));
        }
        // NATIVE FUNCTIONS
        public static bool ResolveToNativeFunctionIndex(this CompilerIO self, Slice slice, out int index)
        {
            var source = self.parser.tokenizer.source;

            for (var i = 0; i < self.chunk.nativeFunctions.count; i++)
            {
                var f = self.chunk.nativeFunctions.buffer[i];
                if (CompilerHelper.AreEqual(source, slice, f.name))
                {
                    index = i;
                    return(true);
                }
            }

            index = 0;
            return(false);
        }
Ejemplo n.º 18
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);
            }
        }
Ejemplo n.º 19
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);
            }
        }
Ejemplo n.º 20
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);
            }
        }
        public static bool ResolveToStructTypeIndex(this CompilerIO self, Slice slice, out int index)
        {
            var source = self.parser.tokenizer.source;

            for (var i = 0; i < self.chunk.structTypes.count; i++)
            {
                var s = self.chunk.structTypes.buffer[i];
                if (
                    CompilerHelper.IsStructTypeVisible(self.chunk, i, self.structTypesStartIndex) &&
                    CompilerHelper.AreEqual(source, slice, s.name)
                    )
                {
                    index = i;
                    return(true);
                }
            }

            index = 0;
            return(false);
        }
        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);
        }
 // FUNCTIONS
 public static FunctionTypeBuilder BeginFunctionDeclaration(this CompilerIO self)
 {
     return(self.chunk.BeginFunctionType());
 }
Ejemplo n.º 24
0
 public static void BeginLoop(this CompilerIO self, Slice labelSlice)
 {
     self.loopNesting.PushBack(labelSlice);
 }
Ejemplo n.º 25
0
 public static Scope BeginScope(this CompilerIO self)
 {
     self.scopeDepth += 1;
     return(new Scope(self.localVariables.count));
 }
Ejemplo n.º 26
0
        public static ValueType ParseType(this CompilerIO self, string error)
        {
            var slice = self.parser.currentToken.slice;

            return(self.ParseTypeRecursive(error, slice, 0));
        }
 // STRUCTS
 public static StructTypeBuilder BeginStructDeclaration(this CompilerIO self)
 {
     return(self.chunk.BeginStructType());
 }