internal ScriptLogic(ScopeTable ti) { string type; string length; var primaryScopeColumn = from ScopeColumn ci in ti.Columns where ci.Primary select ci; var nonPrimaryScopeColumn = from ScopeColumn ci in ti.Columns where (ci.Primary == false) select ci; _tableName = ti.Name; foreach (var ci in primaryScopeColumn) { type = Runtime.GetSqlType(ci.Type); length = Runtime.GetLength(ci.Type.ToString(), ci.Length); if (string.IsNullOrEmpty(_clusterKeys)) { _clusterKeys = "[" + ci.Name + "]"; } else { _clusterKeys += ",[" + ci.Name + "]"; } _selectFields += "t.[" + ci.Name + "],"; if (string.IsNullOrEmpty(_allColumnsParamWithType)) _allColumnsParamWithType = "@" + ci.Name + " " + type + length; else _allColumnsParamWithType += ",@" + ci.Name + " " + type + length; if (string.IsNullOrEmpty(_allColumnsParam)) _allColumnsParam = "@" + ci.Name; else _allColumnsParam += ",@" + ci.Name; } foreach (var ci in nonPrimaryScopeColumn) { type = Runtime.GetSqlType(ci.Type); length = Runtime.GetLength(ci.Type.ToString(), ci.Length); _selectFields += "c.[" + ci.Name + "],"; if (string.IsNullOrEmpty(_allColumnsParamWithType)) _allColumnsParamWithType = "@" + ci.Name + " " + type + length; else _allColumnsParamWithType += ",@" + ci.Name + " " + type + length; if (string.IsNullOrEmpty(_allColumnsParam)) _allColumnsParam = "@" + ci.Name; else _allColumnsParam += ",@" + ci.Name; } _selectFields = _selectFields.TrimEnd(char.Parse(",")); }
/// <summary> /// 节点转字符串 /// </summary> /// <param name="node">待转化节点</param> /// <returns>返回该节点之下的所有叶子节点组成的字符串</returns> private static string nodeToString(ParseTreeNode node) { String str = ""; if (node.IsLeaf) { if (node.TSymbol == TerminalType.ID) { ScopeTable scope = Constant.check(node.StringValue); if (scope == null) { ErrorInfo error = new ErrorInfo(node.LineNum, "符号表中没有" + node.StringValue + "!"); Constant.outputAppend(error.ToString()); //计算出错 return("<>"); } else if (scope.type != "int" && scope.type != "real") { string[] arr1 = scope.value.Split(','); str += "["; for (int i = 0; i < arr1.Length; i++) { str += arr1[i] + ","; } str += "]"; return(str); } return(scope.value); } else if (node.StringValue == "<>") { return("!="); } return(node.StringValue); } else { for (int i = 0; i < node.Childs.Count; i++) { str += nodeToString(node.Childs[i]); } } return(str); }
/// <summary> /// 增||改 /// </summary> /// <param name="scopeTable">层数表</param> public static void update(ScopeTable scopeTable) { if (check(scopeTable.name) == null) { // 增 scopeTables.Add(scopeTable); } else //改 { for (int i = 0; i < Constant.scopeTables.Count; i++) { if (Constant.scopeTables[i].name == scopeTable.name) { Constant.scopeTables[i].type = scopeTable.type; Constant.scopeTables[i].value = scopeTable.value; } } } }
/// <summary> ///Statement节点分析函数 /// </summary> /// <param name="node">Statement节点</param> public static void StatementAnalysis(ParseTreeNode node) { //判断是不是断点 if (node.Childs[0].TSymbol == TerminalType.BREAKPOINT) { string debugString; debugString = "-------\n"; foreach (ScopeTable scope in Constant.scopeTables) { if (String.IsNullOrEmpty(scope.value)) { debugString += "符号表中名为" + scope.name + "的表项值为空\n"; //Constant.deBugAppend("符号表中名为" + scope.name + "的表项值为空"); } else { debugString += "符号表中名为" + scope.name + "的表项值为" + scope.value + "\n"; //Constant.deBugAppend("符号表中名为" + scope.name + "的表项值为" + scope.value); } } debugString += "-------\n"; Constant.deBugAppend(debugString); //Constant.deBugAppend("-------"); //foreach (ScopeTable scope in Constant.scopeTables) { // if (String.IsNullOrEmpty(scope.value)) // { // Constant.deBugAppend("符号表中名为" + scope.name + "的表项值为空"); // } // else { // Constant.deBugAppend("符号表中名为" + scope.name + "的表项值为" + scope.value); // } //} //Constant.deBugAppend("-------"); //如果是断点则阻塞线程 Constant.mreReset(); return; } //判断是否能运行 Constant._mre.WaitOne(); if (node.IsLeaf) { //是叶子节点直接退出 return; } else if (node.Childs[0].NSymbol == NEnum.if_stmt) // if-stmt-> if-stmt - block else -stmt - block //i f语句 { ParseTreeNode ifStmt = node.Childs[0]; ParseTreeNode ifStmtBlock = ifStmt.Childs[0]; //if-stmt-block -> if (exp) stmt-block // if语句子块 ParseTreeNode exp = ifStmtBlock.Childs[2]; //if条件为真 if (expJudge(exp)) { //遇到stmtBlock ParseTreeNode stmtBlock = ifStmtBlock.Childs[4]; //stmt - block->{statement} | { stmt - sequence } // 语句块 if (stmtBlock.Childs.Count == 4) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); //判断是否能运行 Constant._mre.WaitOne(); Constant.currentScopeDecrease(); stmtBlock.Childs.RemoveAt(1); } if (stmtBlock.Childs[1].NSymbol == NEnum.statement) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); //判断是否能运行 Constant._mre.WaitOne(); Constant.currentScopeDecrease(); } else if (!stmtBlock.Childs[1].IsLeaf) { Constant.currentScopeIncrease(); ParseTreeNode stmtSequence = stmtBlock.Childs[1]; //stmt-sequence -> statement stmt-sequence | ε // 语句序列 while (stmtSequence.Childs.Count >= 2) { for (int j = 0; j < stmtSequence.Childs.Count - 1; j++) { StatementAnalysis(stmtSequence.Childs[j]); //判断是否能运行 Constant._mre.WaitOne(); } stmtSequence = stmtSequence.Childs[stmtSequence.Childs.Count - 1]; } if (stmtSequence.NSymbol == NEnum.statement) { StatementAnalysis(stmtSequence); //判断是否能运行 Constant._mre.WaitOne(); } else { StatementAnalysis(stmtSequence.Childs[0]); //判断是否能运行 Constant._mre.WaitOne(); } Constant.currentScopeDecrease(); } } //if条件未假 else if (ifStmt.Childs.Count == 2) //else-stmt-block -> else stmt-block | ε { if (ifStmt.Childs[1].Childs[0].TSymbol == TerminalType.EMPTY) { //是空直接退出 return; } //遇到stmtBlock ParseTreeNode elseStmtBlock = ifStmt.Childs[1]; ParseTreeNode stmtBlock = elseStmtBlock.Childs[1]; //stmt - block->{statement }| { stmt - sequence } // 语句块 if (stmtBlock.Childs.Count == 4) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); //判断是否能运行 Constant._mre.WaitOne(); Constant.currentScopeDecrease(); stmtBlock.Childs.RemoveAt(1); } if (stmtBlock.Childs[1].NSymbol == NEnum.statement) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); //判断是否能运行 Constant._mre.WaitOne(); Constant.currentScopeDecrease(); } else if (!stmtBlock.Childs[1].IsLeaf) { Constant.currentScopeIncrease(); ParseTreeNode stmtSequence = stmtBlock.Childs[1]; //stmt-sequence -> statement stmt-sequence | ε // 语句序列 while (stmtSequence.Childs.Count >= 2) { for (int j = 0; j < stmtSequence.Childs.Count - 1; j++) { StatementAnalysis(stmtSequence.Childs[j]); //判断是否能运行 Constant._mre.WaitOne(); } stmtSequence = stmtSequence.Childs[stmtSequence.Childs.Count - 1]; } if (stmtSequence.NSymbol == NEnum.statement) { StatementAnalysis(stmtSequence); //判断是否能运行 Constant._mre.WaitOne(); } else { StatementAnalysis(stmtSequence.Childs[0]); //判断是否能运行 Constant._mre.WaitOne(); } Constant.currentScopeDecrease(); } } } else if (node.Childs[0].NSymbol == NEnum.while_stmt) { //while-stmt -> while ( exp ) stmt-block // while语句子快 ParseTreeNode whileStmt = node.Childs[0]; while (expJudge(whileStmt.Childs[2])) { //遇到stmtBlock ParseTreeNode stmtBlock = whileStmt.Childs[4]; //stmt - block->{statement} | { stmt - sequence } // 语句块 if (stmtBlock.Childs.Count == 4) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); //判断是否能运行 Constant._mre.WaitOne(); Constant.currentScopeDecrease(); stmtBlock.Childs.RemoveAt(1); } if (stmtBlock.Childs[1].NSymbol == NEnum.statement) { Constant.currentScopeIncrease(); StatementAnalysis(stmtBlock.Childs[1]); Constant._mre.WaitOne(); Constant.currentScopeDecrease(); } else if (!stmtBlock.Childs[1].IsLeaf) { Constant.currentScopeIncrease(); ParseTreeNode stmtSequence = stmtBlock.Childs[1]; //stmt-sequence -> statement stmt-sequence | ε // 语句序列 while (stmtSequence.Childs.Count >= 2) { for (int j = 0; j < stmtSequence.Childs.Count - 1; j++) { StatementAnalysis(stmtSequence.Childs[j]); //判断是否能运行 Constant._mre.WaitOne(); } stmtSequence = stmtSequence.Childs[stmtSequence.Childs.Count - 1]; } if (stmtSequence.NSymbol == NEnum.statement) { StatementAnalysis(stmtSequence); Constant._mre.WaitOne(); } else { StatementAnalysis(stmtSequence.Childs[0]); Constant._mre.WaitOne(); } Constant.currentScopeDecrease(); } } } else if (node.Childs[0].NSymbol == NEnum.assign_stmt) //赋值语句 assign-stmt -> variable = exp ; variable -> identifier [ [ exp ] ] { ParseTreeNode assignStmt = node.Childs[0]; ParseTreeNode variable = assignStmt.Childs[0]; if (variable.Childs.Count == 1) //一般变量赋值 { string name = variable.Childs[0].StringValue; //查找并赋值 ScopeTable scopeTable = Constant.check(name); if (scopeTable == null) { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "符号表中没有" + name + "!"); Constant.outputAppend(error.ToString()); return; } if (IsNumberic(expToValue(assignStmt.Childs[2]))) { //声明的为整数时,还需将非整数转化成整数 if (scopeTable.type == "int") { string num = expToValue(assignStmt.Childs[2]); if (Regex.IsMatch(num, @"^[+-]?[0-9]+$")) { string value = int.Parse(num).ToString(); scopeTable.value = value; Constant.update(scopeTable); } else { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "赋值类型错误!"); Constant.outputAppend(error.ToString()); return; } } else //real类型可以直接存入 { scopeTable.value = expToValue(assignStmt.Childs[2]); Constant.update(scopeTable); } } else //返回错误 { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "赋值类型错误!"); Constant.outputAppend(error.ToString()); return; } } else //数组赋值 没有考虑一维数组以外的情况 { //数组名 string name = variable.Childs[0].StringValue; //插入数组位置 int leng = int.Parse(variable.Childs[2].StringValue); //查找 ScopeTable scopeTable = Constant.check(name); if (scopeTable == null) { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "符号表中没有" + name + "!"); Constant.outputAppend(error.ToString()); return; } //判断是否越界 string type = scopeTable.type; string a = type.Substring(type.IndexOf('[') + 1, type.IndexOf(']') - type.IndexOf('[') - 1); int length = int.Parse(a); if (leng >= length) { ErrorInfo error = new ErrorInfo(variable.Childs[0].LineNum, "数组越界错误!"); Constant.outputAppend(error.ToString()); return; } else { //value= 0,0,0 string value = scopeTable.value; string[] arr1 = value.Split(','); // 以','字符对字符串进行分割,返回字符串数组 if (IsNumberic(expToValue(assignStmt.Childs[2]))) { //声明的为整数时,还需将非整数转化成整数 if (scopeTable.type.IndexOf("int") != -1) { string num = expToValue(assignStmt.Childs[2]); if (Regex.IsMatch(num, @"^[+-]?[0-9]+$")) { string value2 = int.Parse(num).ToString(); arr1[leng] = value2; scopeTable.value = String.Join(",", arr1); Constant.update(scopeTable); } else { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "赋值类型错误!"); Constant.outputAppend(error.ToString()); return; } } else //real类型可以直接存入 { arr1[leng] = expToValue(assignStmt.Childs[2]); scopeTable.value = String.Join(",", arr1); Constant.update(scopeTable); } } else //返回错误 { ErrorInfo error = new ErrorInfo(assignStmt.Childs[1].LineNum, "赋值类型错误!"); Constant.outputAppend(error.ToString()); return; } } } } else if (node.Childs[0].NSymbol == NEnum.read_stmt) //read-stmt -> read variable ; // read语句 { Constant.mreReset(); Constant._mre.WaitOne(); string num = Constant.readstr; ParseTreeNode readStmt = node.Childs[0]; ScopeTable scopeTable = Constant.check(readStmt.Childs[1].Childs[0].StringValue); if (scopeTable.type == "int") { if (Regex.IsMatch(num, @"^[+-]?[0-9]+$")) { scopeTable.value = num; } else { ErrorInfo error = new ErrorInfo(readStmt.Childs[1].Childs[0].LineNum, "赋值类型错误!"); Constant.outputAppend(error.ToString()); return; } } else { scopeTable.value = num; } Constant.update(scopeTable); } else if (node.Childs[0].NSymbol == NEnum.write_stmt) //write-stmt -> write exp ; // write语句 { ParseTreeNode writeStmt = node.Childs[0]; ParseTreeNode exp = writeStmt.Childs[1]; Constant.outputAppend(expToValue(exp)); } else if (node.Childs[0].NSymbol == NEnum.declare_stmt) //declare-stmt语句 (int | real) ( (identifier [= exp ]) | (identifier [ exp ]) ) ; { ParseTreeNode declareStmt = node.Childs[0]; //声明,且赋值 int a=3; //作废 if (declareStmt.Childs.Count > 3) { if (IsNumberic(expToValue(declareStmt.Childs[3]))) { //声明的为整数时,还需将非整数转化成整数 if (declareStmt.Childs[0].StringValue == "int") { string num = expToValue(declareStmt.Childs[3]); if (Regex.IsMatch(num, @"^[+-]?[0-9]+$")) { string value = int.Parse(num).ToString(); ScopeTable scopeTable = new ScopeTable(declareStmt.Childs[1].StringValue, declareStmt.Childs[0].StringValue, value, Constant.currentScope); Constant.scopeTables.Add(scopeTable); } else { ErrorInfo error = new ErrorInfo(0, "声明类型错误!"); } } else //real类型可以直接存入 { ScopeTable scopeTable = new ScopeTable(declareStmt.Childs[1].StringValue, declareStmt.Childs[0].StringValue, expToValue(declareStmt.Childs[3]), Constant.currentScope); Constant.scopeTables.Add(scopeTable); } } else //返回错误 { ErrorInfo error = new ErrorInfo(0, "声明类型错误!"); } } else if ((declareStmt.Childs[1].Childs.Count < 2)) //只申明,未赋值 int a ; { ScopeTable scopeTable = new ScopeTable(declareStmt.Childs[1].Childs[0].StringValue, declareStmt.Childs[0].StringValue, null, Constant.currentScope); Constant.scopeTables.Add(scopeTable); } else if (declareStmt.Childs[1].Childs.Count > 2) //申明一个数组 int a[2]; a int[3] 0,0,0 Constant.currentScope); { int length = 0; try { length = int.Parse(declareStmt.Childs[1].Childs[2].StringValue); } catch { ErrorInfo error = new ErrorInfo(declareStmt.Childs[0].LineNum, "数组索引必须为整数!"); Constant.outputAppend(error.ToString()); return; } if (length == 1) { ErrorInfo error = new ErrorInfo(declareStmt.Childs[0].LineNum, "不能声明大小为1的数组!"); Constant.outputAppend(error.ToString()); return; } string value = ""; for (int i = 1; i < length; i++) { value += "0,"; } value += "0"; string n = declareStmt.Childs[1].Childs[0].StringValue; string t = declareStmt.Childs[0].StringValue + declareStmt.Childs[1].Childs[1].StringValue + declareStmt.Childs[1].Childs[2].StringValue + declareStmt.Childs[1].Childs[3].StringValue; ScopeTable scopeTable = new ScopeTable(n, t, value, Constant.currentScope); Constant.scopeTables.Add(scopeTable); } } }
internal ScriptLogic(ScopeTable ti) { string type; string length; var primaryScopeColumn = from ScopeColumn ci in ti.Columns where ci.Primary select ci; var nonPrimaryScopeColumn = from ScopeColumn ci in ti.Columns where (ci.Primary == false) select ci; _tableName = ti.Name; foreach (var ci in primaryScopeColumn) { type = Runtime.GetSqlType(ci.Type); length = Runtime.GetLength(ci.Type.ToString(), ci.Length); if (string.IsNullOrEmpty(_clusterKeys)) { _clusterKeys = "[" + ci.Name + "]"; } else { _clusterKeys += ",[" + ci.Name + "]"; } _selectFields += "t.[" + ci.Name + "],"; if (string.IsNullOrEmpty(_allColumnsParamWithType)) { _allColumnsParamWithType = "@" + ci.Name + " " + type + length; } else { _allColumnsParamWithType += ",@" + ci.Name + " " + type + length; } if (string.IsNullOrEmpty(_allColumnsParam)) { _allColumnsParam = "@" + ci.Name; } else { _allColumnsParam += ",@" + ci.Name; } } foreach (var ci in nonPrimaryScopeColumn) { type = Runtime.GetSqlType(ci.Type); length = Runtime.GetLength(ci.Type.ToString(), ci.Length); _selectFields += "c.[" + ci.Name + "],"; if (string.IsNullOrEmpty(_allColumnsParamWithType)) { _allColumnsParamWithType = "@" + ci.Name + " " + type + length; } else { _allColumnsParamWithType += ",@" + ci.Name + " " + type + length; } if (string.IsNullOrEmpty(_allColumnsParam)) { _allColumnsParam = "@" + ci.Name; } else { _allColumnsParam += ",@" + ci.Name; } } _selectFields = _selectFields.TrimEnd(char.Parse(",")); }
private void compute(ComputationContext ctx) { foreach (TypeDefinition trait in this.AssociatedTraits) { trait.computeAncestors(ctx, new HashSet <TypeDefinition>()); } computeAncestors(ctx, new HashSet <TypeDefinition>()); IEnumerable <INode> owned_nodes = this.ChildrenNodes.Concat(this.AssociatedTraits.SelectMany(it => it.ChildrenNodes)); owned_nodes.WhereType <ISurfable>().ForEach(it => it.Surfed(ctx)); // -- if (this.Modifier.HasMutable && (!this.Modifier.HasHeapOnly || this.NestedFunctions.Any(it => it.IsCopyInitConstructor(ctx)))) { // creating counterparts of mutable methods // todo: this should be implemented differently -- instead of creating methods, creating expressions // copy-cons, mutable call, return obj // on demand, in-place, when const non-existing method is called HashSet <string> const_functions = this.NestedFunctions.Where(f => !f.Modifier.HasMutable).Concat( this.Inheritance.OrderedAncestorsIncludingObject.SelectMany(it => it.TargetType.NestedFunctions .Where(f => !f.Modifier.HasMutable && !f.Modifier.HasPrivate))) .Select(it => it.Name.Name) .ToHashSet(); foreach (FunctionDefinition func in this.NestedFunctions.Where(it => it.Modifier.HasMutable).StoreReadOnly()) { string const_name = NameFactory.UnmutableName(func.Name.Name); if (const_functions.Contains(const_name)) { continue; } if (!ctx.Env.IsOfUnitType(func.ResultTypeName)) { continue; } INameReference result_typename = NameFactory.ItNameReference(); if (this.Modifier.HasHeapOnly) { result_typename = NameFactory.PointerNameReference(result_typename); } var instructions = new List <IExpression>(); if (this.Modifier.HasHeapOnly) { instructions.Add(VariableDeclaration.CreateStatement("cp", null, ExpressionFactory.HeapConstructor(NameFactory.ItNameReference(), NameReference.CreateThised()))); } else { // explicit typename is needed, because otherwise we would get a reference to this, not value (copy) instructions.Add(VariableDeclaration.CreateStatement("cp", NameFactory.ItNameReference(), NameReference.CreateThised())); } instructions.Add(FunctionCall.Create(NameReference.Create("cp", func.Name.Name), func.Parameters.Select(it => NameReference.Create(it.Name.Name)).ToArray())); instructions.Add(Return.Create(NameReference.Create("cp"))); FunctionDefinition const_func = FunctionBuilder.Create(const_name, func.Name.Parameters, result_typename, Block.CreateStatement(instructions)) .SetModifier(EntityModifier.AutoGenerated) // native methods have parameters with forbidden read .Parameters(func.Parameters.Select(it => it.CloneAsReadable())); this.AddNode(const_func); const_func.Surfed(ctx); } } if (this.Modifier.HasEnum) { // finally we are at point when we know from which offset we can start setting ids for enum cases FunctionDefinition zero_constructor = this.NestedFunctions.Single(it => it.IsZeroConstructor() && it.Modifier.HasStatic); if (zero_constructor.IsComputed) { throw new System.Exception("Internal error -- we cannot alter the body after the function was already computed"); } int enum_ord = this.InstanceOf.PrimaryAncestors(ctx).Select(it => it.TargetType) .Sum(it => it.NestedFields.Count(f => f.Modifier.HasEnum)); foreach (VariableDeclaration decl in this.NestedFields.Where(it => it.Modifier.HasEnum)) { zero_constructor.UserBody.Append(decl.CreateFieldInitCall(NatLiteral.Create($"{enum_ord++}"))); } } // base method -> derived (here) method var virtual_mapping = new VirtualTable(isPartial: false); foreach (EntityInstance parent_instance in this.Inheritance.MinimalParentsIncludingObject .Concat(this.AssociatedTraits.SelectMany(it => it.Inheritance.MinimalParentsIncludingObject)) .Distinct(EntityInstance.Comparer) .Reverse()) { virtual_mapping.OverrideWith(parent_instance.TargetType.InheritanceVirtualTable); } IEnumerable <FunctionDefinition> all_nested_functions = this.AllNestedFunctions .Concat(this.AssociatedTraits.SelectMany(it => it.AllNestedFunctions)); // derived (here) method -> base methods Dictionary <FunctionDefinition, List <FunctionDefinition> > derivation_mapping = all_nested_functions .Where(it => it.Modifier.HasOverride) .ToDictionary(it => it, it => new List <FunctionDefinition>()); var inherited_member_instances = new HashSet <EntityInstance>(EntityInstance.Comparer); var missing_func_implementations = new List <FunctionDefinition>(); foreach (EntityInstance ancestor in this.Inheritance.OrderedAncestorsIncludingObject .Concat(this.AssociatedTraits.SelectMany(it => it.Inheritance.OrderedAncestorsIncludingObject)) .Distinct(EntityInstance.Comparer)) { // special case are properties -- properties are in fact not inherited, their accessors are // however user sees properties, so we get members here (including properties), but when we compute // what function overrode which, we use really functions, and only having them in hand we check if // they are property accessors IEnumerable <EntityInstance> members = (ancestor.TargetType.AvailableEntities ?? Enumerable.Empty <EntityInstance>()) .Where(it => it.Target is IMember); foreach (EntityInstance entity_instance in members .Where(it => it.Target.Modifier.HasPublic || it.Target.Modifier.HasProtected) .Where(it => !(it.Target is FunctionDefinition func) || !func.IsAnyConstructor())) { EntityInstance translated = entity_instance.TranslateThrough(ancestor); inherited_member_instances.Add(translated); } foreach (FunctionDerivation deriv_info in TypeDefinitionExtension.PairDerivations(ctx, ancestor, all_nested_functions)) { if (deriv_info.Derived == null) { // we can skip implementation or abstract signature of the function in the abstract type if (deriv_info.Base.Modifier.RequiresOverride && !this.Modifier.IsAbstract) { missing_func_implementations.Add(deriv_info.Base); } } else { { if (deriv_info.Base.IsPropertyAccessor(out Property base_property)) { EntityInstance base_prop_instance = base_property.InstanceOf.TranslateThrough(ancestor); inherited_member_instances.Remove(base_prop_instance); } EntityInstance base_instance = deriv_info.Base.InstanceOf.TranslateThrough(ancestor); inherited_member_instances.Remove(base_instance); } if (deriv_info.Derived.Modifier.HasOverride) { derivation_mapping[deriv_info.Derived].Add(deriv_info.Base); // user does not have to repeat "pinned" all the time, but for easier tracking of pinned methods // we add it automatically if (deriv_info.Base.Modifier.HasPinned) { deriv_info.Derived.SetModifier(deriv_info.Derived.Modifier | EntityModifier.Pinned); } if (deriv_info.Base.Modifier.HasHeapOnly != deriv_info.Derived.Modifier.HasHeapOnly) { ctx.AddError(ErrorCode.HeapRequirementChangedOnOverride, deriv_info.Derived); } } else if (!deriv_info.Base.Modifier.IsSealed) { ctx.AddError(ErrorCode.MissingOverrideModifier, deriv_info.Derived); } if (!deriv_info.Base.Modifier.IsSealed) { virtual_mapping.Update(deriv_info.Base, deriv_info.Derived); // the rationale for keeping the same access level is this // narrowing is pretty easy to skip by downcasting // expanding looks like a good idea, but... -- the author of original type // maybe had better understanding why given function is private/protected and not protected/public // it is better to keep it safe, despite little annoyance (additional wrapper), than finding out // how painful is violating that "good reason" because it was too easy to type "public" if (!deriv_info.Base.Modifier.SameAccess(deriv_info.Derived.Modifier)) { ctx.AddError(ErrorCode.AlteredAccessLevel, deriv_info.Derived.Modifier); } } else if (deriv_info.Derived.Modifier.HasOverride) { ctx.AddError(ErrorCode.CannotOverrideSealedMethod, deriv_info.Derived); } } } } foreach (FunctionDefinition missing_impl in missing_func_implementations) { if (!isDerivedByAncestors(missing_impl)) { ctx.AddError(ErrorCode.BaseFunctionMissingImplementation, this, missing_impl); } } // here we eliminate "duplicate" entries -- if we have some method in ancestor A // and this method is overridden in ancestor B, then we would like to have // only method B listed, not both foreach (EntityInstance inherited in inherited_member_instances.ToArray()) { IEntity target = inherited.Target; if (target is Property prop) { target = prop.Getter; } if (target is FunctionDefinition func && isDerivedByAncestors(func)) { inherited_member_instances.Remove(inherited); } } this.InheritanceVirtualTable = virtual_mapping; this.DerivationTable = new DerivationTable(ctx, this, derivation_mapping); this.availableEntities = ScopeTable.Combine(this.AvailableEntities, inherited_member_instances); foreach (FunctionDefinition func in derivation_mapping.Where(it => !it.Value.Any()).Select(it => it.Key)) { ctx.AddError(ErrorCode.NothingToOverride, func); } this.isEvaluated = true; }