public bool MatchEnvEmpty(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { PhoneticShapeNode leftNode = null; PhoneticShapeNode rightNode = null; switch (dir) { case Direction.LEFT: rightNode = node; leftNode = node.GetNext(Direction.LEFT); break; case Direction.RIGHT: rightNode = node.GetNext(Direction.RIGHT); leftNode = node; break; } // in case this is an epenthesis rule, we want to ensure that the segment to the right // of where we're going to do the epenthesis is not a boundary marker, unless the // environment calls for one. if (mode == ModeType.SYNTHESIS && m_env.RightEnvironment != null && m_env.RightEnvironment.Count > 0) { if (rightNode.Type == PhoneticShapeNode.NodeType.BOUNDARY && m_env.RightEnvironment.First.Type != PhoneticPatternNode.NodeType.BDRY_CTXT) return false; } // there is a small difference between legacy HC and HC.NET in matching environments when the // analysis target is empty and one of the environments is empty. In this case, legacy HC does // not try to skip the initial optional segments when matching the right environment. I think // this will cause HC.NET to overproduce a little more during analysis, which isn't that big of a // deal if (!m_env.IsMatch(leftNode, rightNode, mode, instantiatedVars)) return false; // remove ambiguous variables instantiatedVars.RemoveAmbiguousVariables(); return true; }
bool FindNextMatchLHS(PhoneticShapeNode node, Direction dir, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { VariableValues instantiatedVars = new VariableValues(m_alphaVars); if (m_lhs.Count == 0) { // epenthesis rules always match the LHS match = new Match(instantiatedVars); match.Add(node); return true; } else { IList<Match> matches; if (m_lhs.IsMatch(node, dir, ModeType.SYNTHESIS, instantiatedVars, out matches)) { match = matches[0]; return true; } } } match = null; return false; }
bool FindNextMatchRHS(PhoneticShapeNode node, Direction dir, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { if (node.Type == PhoneticShapeNode.NodeType.BOUNDARY) continue; if (m_analysisTarget.Count == 0) { // if the analysis target is empty (deletion rule), // just check environment VariableValues instantiatedVars = new VariableValues(m_rule.m_alphaVars); if (MatchEnvEmpty(node, dir, ModeType.ANALYSIS, instantiatedVars)) { match = new Match(instantiatedVars); match.Add(node); return true; } } else { // analysis target is non-empty, check everything if (MatchAnalysisTarget(node, dir, out match)) return true; } } match = null; return false; }
bool MatchAnalysisTarget(PhoneticShapeNode node, Direction dir, out Match match) { // check analysis target IList<Match> matches; VariableValues instantiatedVars = new VariableValues(m_rule.m_alphaVars); if (!m_analysisTarget.IsMatch(node, dir, ModeType.ANALYSIS, instantiatedVars, out matches)) { match = null; return false; } match = matches[0]; // check vacuous unapplication // even if the subrule matches, we do not want to successfully unapply if no real changes are // going to be made to the phonetic shape if (!CheckVacuousUnapplication(match, dir)) { match = null; return false; } // finally, check environment if (!MatchEnvNonempty(match.EntireMatch, dir, ModeType.ANALYSIS, match.VariableValues)) { match = null; return false; } return true; }
bool FindNextMatch(PhoneticShapeNode node, Direction dir, PhoneticPattern ptemp, ModeType mode, out Match match) { for (; node != node.Owner.GetLast(dir); node = node.GetNext(dir)) { if (mode == ModeType.ANALYSIS && node.Type == PhoneticShapeNode.NodeType.BOUNDARY) continue; IList<Match> matches; if (ptemp.IsMatch(node, dir, mode, out matches)) { match = matches[0]; return true; } } match = null; return false; }
/// <summary> /// Checks if the specified phonetic shape node matches this boundary context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList<Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { // only match boundaries in synthesis mode if (mode == ModeType.SYNTHESIS) { switch (node.Type) { case PhoneticShapeNode.NodeType.BOUNDARY: Boundary bdry = node as Boundary; // check if string representations match if (m_bdryDef.StrRep != bdry.BoundaryDefinition.StrRep) return new List<Match>(); // move to next node IList<Match> matches = MatchNext(node, dir, mode, instantiatedVars); foreach (Match match in matches) match.Add(node, m_partition); return matches; case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (dir == margin.MarginType) // we are at the end of the phonetic shape, so it does not match return new List<Match>(); else return Match(GetNextShapeNode(node, dir), dir, mode, instantiatedVars); } return new List<Match>(); } else { PhoneticPatternNode n = GetNext(dir); if (n == null) { // this was the last node in the pattern, so we have a match List<Match> matches = new List<Match>(); matches.Add(new Match(Owner, instantiatedVars)); return matches; } else { return n.Match(node, dir, mode, instantiatedVars); } } }
/// <summary> /// Checks if the specified phonetic shape node matches this margin context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList<Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { switch (node.Type) { case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (m_marginType != margin.MarginType) return new List<Match>(); // move to next node return MatchNext(node, dir, mode, instantiatedVars); case PhoneticShapeNode.NodeType.BOUNDARY: return Match(GetNextShapeNode(node, dir), dir, mode, instantiatedVars); } return new List<Match>(); }
/// <summary> /// Checks if the specified phonetic shape node matches this simple context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList<Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { switch (node.Type) { case PhoneticShapeNode.NodeType.BOUNDARY: // only check boundaries in synthesis mode when the pattern is a target, // otherwise skip if (mode == ModeType.SYNTHESIS) { if (Owner.IsTarget) { return new List<Match>(); } else { IList<Match> bdryMatches = Match(GetNextShapeNode(node, dir), dir, mode, instantiatedVars); foreach (Match match in bdryMatches) match.Add(node, m_partition); return bdryMatches; } } else { return Match(GetNextShapeNode(node, dir), dir, mode, instantiatedVars); } case PhoneticShapeNode.NodeType.MARGIN: Margin margin = node as Margin; if (dir == margin.MarginType) // we are at the end of the shape, so no match return new List<Match>(); else return Match(GetNextShapeNode(node, dir), dir, mode, instantiatedVars); case PhoneticShapeNode.NodeType.SEGMENT: Segment seg = node as Segment; if (mode == ModeType.SYNTHESIS && Owner.IsTarget) { // check segment to see if it has already been altered by another // subrule, only matters for simultaneously applying rules if (!seg.IsClean) return new List<Match>(); } VariableValues tempVars = instantiatedVars.Clone(); if (m_featSys.HasFeatures) { if (!IsFeatureMatch(seg, tempVars, mode)) return new List<Match>(); } else { if (!IsSegmentMatch(seg)) return new List<Match>(); } // move to the next node IList<Match> segMatches = MatchNext(node, dir, mode, tempVars); foreach (Match match in segMatches) match.Add(node, m_partition); return segMatches; } return new List<Match>(); }
/// <summary> /// Checks if the specified phonetic shape node matches this margin context. /// </summary> /// <param name="node">The phonetic shape node.</param> /// <param name="dir">The direction.</param> /// <param name="mode">The mode.</param> /// <param name="instantiatedVars">The instantiated variables.</param> /// <returns>All matches.</returns> internal override IList<Match> Match(PhoneticShapeNode node, Direction dir, ModeType mode, VariableValues instantiatedVars) { if (node.Type == PhoneticShapeNode.NodeType.MARGIN) { Margin margin = node as Margin; if (m_marginType != margin.MarginType) return new List<Match>(); // move to next node return MatchNext(node, dir, mode, instantiatedVars); } return new List<Match>(); }