private void VisitFunction(Function function) { Debug.Assert(function.OutParams.Count == 1); for (QKeyValue kv = function.Attributes; kv != null; kv = kv.Next) { if (kv.Key != CivlAttributes.WITNESS) { continue; } if (kv.Params.Count == 3 && kv.Params[0] is string witnessedVariableName && kv.Params[1] is string firstActionName && kv.Params[2] is string secondActionName) { witnessedVariable = ctc.sharedVariables.Find(v => v.Name == witnessedVariableName); if (witnessedVariable == null) { ctc.Error(kv, $"Could not find shared variable {witnessedVariableName}"); } else if (!function.OutParams[0].TypedIdent.Type.Equals(witnessedVariable.TypedIdent.Type)) { ctc.Error(function, "Result type does not match witnessed variable"); } firstAction = ctc.FindAtomicAction(firstActionName); secondAction = ctc.FindAtomicAction(secondActionName); if (firstAction == null) { ctc.Error(kv, $"Could not find atomic action {firstActionName}"); } if (secondAction == null) { ctc.Error(kv, $"Could not find atomic action {firstActionName}"); } if (firstAction != null && secondAction != null) { CheckInParams(function.InParams); } allWitnessFunctions.Add(new WitnessFunction(function, witnessedVariable, firstAction, secondAction, args)); }