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)); }
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); }
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); } }
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); } }
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); } }
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))); }
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); }