public OperatorOperands(Function function, ByteCode.ByteCode byteCode, int label, Variable a) { Function = function; ByteCode = byteCode; Label = label; A = a; }
public static Variable GetVariable(List <NumeratedVariable> locals, ByteCode.ByteCode byteCode, Token token) { if (token == null) { return(null); } var operand = locals.Find(p => p.Variable.Name == token.StringValue)?.Variable; if (operand == null) { if (token.Constant != null) { operand = token.Constant.ToVariable(byteCode.Program); } else if ((operand = byteCode.Header.GetGlobalVariable(token.StringValue)) != null) { return(operand); } else { throw new CompileException(CompileErrorType.UndefinedReference, token); } } return(operand); }
public OperatorOperands(Function function, ByteCode.ByteCode byteCode, int label, Variable a, Variable b, ExpressionLineItem lineItem) { LineItem = lineItem; Function = function; ByteCode = byteCode; Label = label; A = a; B = b; }
public static List <Instruction> GetInstructions(Function func, ByteCode.ByteCode byteCode, ref int localVarIndex, List <ExpressionLineItem> list, out List <Variable> registers, List <NumeratedVariable> locals) { var currentIndex = 0; var instructions = new List <Instruction>(); registers = new List <Variable>(); foreach (var item in list) { OperatorResult result = null; Variable operand1 = item.RegOperand1 == -1 ? GetVariable(locals, byteCode, item.Operand1.CodeToken) : registers[item.RegOperand1]; Variable operand2 = null; if (!item.IsUnary) { operand2 = item.RegOperand2 == -1 ? GetVariable(locals, byteCode, item.Operand2.CodeToken) : registers[item.RegOperand2]; result = item.Operator.BinaryFunc(new OperatorOperands(func, byteCode, -1, operand1, operand2, item)); } else { if (item.FunctionCall != null) { var funcToCall = func.Program.ByteCode.Header .GetFunction(item.FunctionCall.StringValue, item.NearToken); if (funcToCall == null) { throw new CompileException(CompileErrorType.UndefinedReference, item.FunctionCall); } if (operand1 == null) { if (funcToCall.Parameters.Count != 0) { throw new CompileException(CompileErrorType.WrongParameterCount, item.FunctionCall, funcToCall.Token); } instructions.Add(new InstructionCall(funcToCall, func, byteCode, -1)); } else if (operand1.VariableType != VariableType.Tuple) { //if variadic we dont care about types if (funcToCall.IsVariadic) { var countAttribute = (VarCountAttribute)funcToCall.Attributes.Find(p => p.Type == AttributeType.VarCount); var restrictAttributes = funcToCall.Attributes.FindAll(p => p.Type == AttributeType.VarRestrict) .Select(p => (VarRestrictAttribute)p) .ToList(); //User can specify parameters count in a variadic function if (countAttribute != null) { if (!countAttribute.CheckCount(1)) { throw new CompileException(CompileErrorType.WrongParameterCount, item.FunctionCall); } } foreach (var attribute in restrictAttributes) { if (!attribute.CheckValues(new List <Variable>() { operand1 })) { throw new CompileException(CompileErrorType.IncompatibleTypes, item.FunctionCall); } } instructions.Add(new InstructionPushI( -byteCode.Header.GetTypeIndex(operand1.Type) - 1, func, byteCode, -1)); instructions.Add(new InstructionPush(operand1, func, byteCode, -1)); //just one variable instructions.Add(new InstructionPushI(-1 - 1, func, byteCode, -1)); } else { if (funcToCall.Parameters.Count != 1) { throw new CompileException(CompileErrorType.WrongParameterCount, item.FunctionCall, funcToCall.Token); } if (funcToCall.Parameters[0].Type != operand1.Type) { //not equals, but can we cast? if (!Type.CanCastAssignment(funcToCall.Parameters[0].Type, operand1.Type)) { throw new CompileException(CompileErrorType.IncompatibleTypes, item.FunctionCall, funcToCall.Token); } //casting var varCast = new Variable(funcToCall.Parameters[0].Type, $"_castedReg{localVarIndex}", func.Scope, null, localVarIndex++, VariableType.Variable); instructions.Add(new InstructionCast(varCast, operand1, func, byteCode, -1)); operand1 = varCast; } instructions.Add(new InstructionPush(operand1, func, byteCode, -1)); } instructions.Add(new InstructionCall(funcToCall, func, byteCode, -1)); } else { //if variadic we dont care about types if (funcToCall.IsVariadic) { var countAttribute = (VarCountAttribute)funcToCall.Attributes.Find(p => p.Type == AttributeType.VarCount); var restrictAttributes = funcToCall.Attributes.FindAll(p => p.Type == AttributeType.VarRestrict) .Select(p => (VarRestrictAttribute)p) .ToList(); //User can specify parameters count in a variadic function if (countAttribute != null) { if (!countAttribute.CheckCount(operand1.Tuple.Count)) { throw new CompileException(CompileErrorType.WrongParameterCount, item.FunctionCall); } } foreach (var attribute in restrictAttributes) { if (!attribute.CheckValues(operand1.Tuple)) { throw new CompileException(CompileErrorType.IncompatibleTypes, item.FunctionCall); } } foreach (var variable in operand1.Tuple.ToArray().Reverse()) { instructions.Add(new InstructionPushI(-byteCode.Header.GetTypeIndex(variable.Type) - 1, func, byteCode, -1)); instructions.Add(new InstructionPush(variable, func, byteCode, -1)); } instructions.Add(new InstructionPushI(-operand1.Tuple.Count - 1, func, byteCode, -1)); } else { if (funcToCall.Parameters.Count != operand1.Tuple.Count) { throw new CompileException(CompileErrorType.WrongParameterCount, item.FunctionCall, funcToCall.Token); } for (int i = 0; i < operand1.Tuple.Count; i++) { if (funcToCall.Parameters[i].Type != operand1.Tuple[i].Type) { //not equals, but can we cast? if (!Type.CanCastAssignment(funcToCall.Parameters[i].Type, operand1.Tuple[i].Type)) { throw new CompileException(CompileErrorType.IncompatibleTypes, item.FunctionCall, funcToCall.Token); } //casting var varCast = new Variable(funcToCall.Parameters[i].Type, $"__castedReg{localVarIndex}", func.Scope, null, localVarIndex++, VariableType.Variable); instructions.Add(new InstructionCast(varCast, operand1.Tuple[i], func, byteCode, -1)); operand1.Tuple[i] = varCast; } } for (int i = 0; i < operand1.Tuple.Count; i++) { instructions.Add(new InstructionPush(operand1.Tuple[i], func, byteCode, -1)); } //I dunno what is it, just comment it. //registers.RemoveRange(registers.Count - funcToCall.Parameters.Count + 1, funcToCall.Parameters.Count- 1); //localVarIndex -= funcToCall.Parameters.Count - 1; /*for (int i = currentIndex + 1; i < list.Count; i++) * { * if (list[i].RegOperand1 != -1) list[i].RegOperand1 -= funcToCall.Parameters.Count - 1; * if (list[i].RegOperand2 != -1) list[i].RegOperand2 -= funcToCall.Parameters.Count - 1; * }*/ } instructions.Add(new InstructionCall(funcToCall, func, byteCode, -1)); } if (funcToCall.ReturnType != null) { registers.Add(new Variable(funcToCall.ReturnType, $"__reg{localVarIndex}", func.Scope, null, localVarIndex++, VariableType.Variable)); //pop out result instructions.Add(new InstructionPop(registers.Last(), func, byteCode, -1)); } else if (currentIndex != list.Count - 1) { throw new CompileException(CompileErrorType.WrongUsageOfVoidFunc, item.NearToken, funcToCall.Token); } } else if (item.UnaryOperator != null) { result = item.UnaryOperator.UnaryFunc(new OperatorOperands(func, byteCode, -1, operand1)); } else if (item.Indexer != null) { var array = GetVariable(locals, byteCode, item.Indexer); if (array.Type.ID != TypeID.Array) { throw new CompileException(CompileErrorType.ExpectedArrayType, item.NearToken); } var resultType = (array.Type as ArrayType).BaseType; var arrayDim = (array.Type as ArrayType).Dimensions; var indexes = new List <Variable>(); if (operand1.VariableType == VariableType.Tuple) { if (operand1.Tuple.Count != arrayDim) { throw new CompileException(CompileErrorType.WrongIndicesCount, item.NearToken); } foreach (var variable in operand1.Tuple) { if (variable.Type.ID != TypeID.Integer && variable.Type.ID != TypeID.UInteger) { throw new CompileException(CompileErrorType.ExpectedIntegerIndex, item.NearToken); } } indexes.AddRange(operand1.Tuple); } else { if (arrayDim != 1) { throw new CompileException(CompileErrorType.WrongIndicesCount, item.NearToken); } if (operand1.Type.ID != TypeID.Integer && operand1.Type.ID != TypeID.UInteger) { throw new CompileException(CompileErrorType.ExpectedIntegerIndex, item.NearToken); } indexes.Add(operand1); } var resultVar = new Variable(resultType, $"__reg{localVarIndex}", func.Scope, null, localVarIndex++, VariableType.ArrayItem) { Array = array, ArrayItem = indexes }; registers.Add(resultVar); instructions.Add(new InstructionVget(resultVar, array, indexes, func, byteCode, -1)); } } if (item.FunctionCall == null && item.Indexer == null) { if (result.Error != null) { throw new CompileException(result.Error.ErrorType, item.NearToken); } if (result.UsedCasts != null && result.UsedCasts.Count != 0) { instructions.AddRange(result.UsedCasts); foreach (var cast in result.UsedCasts) { cast.Result.Index = localVarIndex++; //registers.Add(cast.Dest); } } var resultVar = new Variable(result.ResultType, $"__reg{localVarIndex}", func.Scope, null, localVarIndex++, result.Instruction == null ? VariableType.Tuple : VariableType.Variable); if (result.Instruction != null) { instructions.Add(result.Instruction); (result.Instruction as ArithmeticInstruction).Result = resultVar; } else { resultVar.Tuple = result.ResultTuple; } registers.Add(resultVar); } currentIndex++; } registers.AddRange(instructions.FindAll(p => p is InstructionCast) .Select(p => ((InstructionCast)p).Result)); registers = registers.OrderBy(p => p.Index).ToList(); return(instructions); }