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); }
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); }
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); }
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)); }
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)); }
public static void DebugPopLocalVariableNames(this CompilerIO self, byte count) { if (self.mode == Mode.Debug) { self.EmitInstruction(Instruction.DebugPopLocalVariableNameMultiple); self.EmitByte(count); } }
public static void DebugEmitPopTypes(this CompilerIO self, byte count) { if (self.mode == Mode.Debug) { self.EmitInstruction(Instruction.DebugPopTypeMultiple); self.EmitByte(count); } }
public static void DebugEmitPushType(this CompilerIO self, ValueType type) { if (self.mode == Mode.Debug) { self.EmitInstruction(Instruction.DebugPushType); self.EmitType(type); } }
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); } }
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 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); } } }
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))); }
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); }
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); }
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); } }
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()); }
public static void BeginLoop(this CompilerIO self, Slice labelSlice) { self.loopNesting.PushBack(labelSlice); }
public static Scope BeginScope(this CompilerIO self) { self.scopeDepth += 1; return(new Scope(self.localVariables.count)); }
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()); }