public Capture(IdenType type, int index) { Debug.Assert(index >= 0); this.index = index; this.type = type; }
List <Capture> GetMatchesOrdinal(ref int max) { var match = new List <Capture>(); var strCmp = Context.IgnoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; IdenType idenType = IdenType.Argument; foreach (IListEnumerable list in this.literals) { int id = 0; foreach (string name in list) { int length = name.Length; if (length >= max && String.Compare( this.expr, this.curPos, name, 0, length, strCmp) == 0) { if (length != max) { match.Clear(); } match.Add(new Capture(idenType, id)); max = length; } id++; } idenType++; } return(match); }
List <Capture> GetMatchesCulture(ref int max) { CultureInfo culture = Context.Culture; var matches = new List <Capture>(); #if SILVERLIGHT var compare = Context.IgnoreCase? CompareOptions.IgnoreCase : CompareOptions.None; #else bool ignCase = Context.IgnoreCase; #endif IdenType idenType = IdenType.Argument; foreach (IListEnumerable list in this.literals) { int id = 0; foreach (string name in list) { int length = name.Length; if (length >= max && #if SILVERLIGHT String.Compare(this.expr, this.curPos, name, 0, length, culture, compare) == 0) #else String.Compare(this.expr, this.curPos, name, 0, length, ignCase, culture) == 0) #endif { if (length != max) { matches.Clear(); } matches.Add(new Capture(idenType, id)); max = length; } id++; } idenType++; } return(matches); }
public override int doFinalize() { int errCount = 0; Ident parentIdent = (this.Parent is Ident ? (Ident)this.Parent : default(Ident)); //Check what we have here (possible outcomes: variableacces, arrayaccess, functioncall, namespaceaccess) #region typeDetection type = IdenType.NamespaceAccess; var fncCalls = this.getAllChildrenOf <FunctionCall>(); var arrAccess = this.getAllChildrenOf <ArrayAccess>(); if (this.Parent is Template && !(this.Parent.Parent is Ident)) { type = IdenType.TemplateVar; } else if (this.Parent is SqfCall && ((SqfCall)this.Parent).Name == this) { type = IdenType.SqfCommandName; } else if (this.IsSelfReference) { type = IdenType.ThisVar; } else if (fncCalls.Count > 0) { type = IdenType.FunctionCall; } else if (arrAccess.Count > 0) { type = IdenType.ArrayAccess; } else if (IsNamespaceAccess()) { type = IdenType.NamespaceAccess; } else if (parentIdent == null && this.Access == AccessType.NA) { if (this.Parent is Interfaces.iClass || (this.Parent is Interfaces.iFunction && ((Interfaces.iFunction) this.Parent).ReturnType.ident == this) || this.Parent is Value || this.Parent is Variable) { type = IdenType.NamespaceAccess; } else { type = IdenType.VariableAccess; } } else if (parentIdent != null && ( (parentIdent.Access == AccessType.Namespace && this.Access == AccessType.NA) || this.Access == AccessType.Instance || (parentIdent.Access == AccessType.Instance && this.Access == AccessType.NA) )) { var ntr = HelperClasses.NamespaceResolver.createNSR(this); if (ntr == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0012, this.Line, this.Pos, this.File)); errCount++; return(errCount); } if (ntr.Reference is Interfaces.iClass) { type = IdenType.NamespaceAccess; } else { type = IdenType.VariableAccess; } } else if (this.Access == AccessType.Namespace) { type = IdenType.NamespaceAccess; } else if (this.Access == AccessType.Instance && parentIdent == null) { type = IdenType.VariableAccess; } else { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.UNKNOWN, this.Line, this.Pos, this.File)); errCount++; } #endregion //And process it then ((unless its a simple ident, then we do not want to process ... here any further)) if ( this.IsSimpleIdentifier && ( (this.Parent is Interfaces.iName && ((Interfaces.iName) this.Parent).Name == this) || (this.Parent is Interfaces.iHasType && !(this.Parent is Expression) && ((Interfaces.iHasType) this.Parent).ReferencedType.ident == this) ) && !(this.Parent is AssignContainer) && !(this.Parent is NewInstance) && !(this.Parent is Interfaces.iHasType && ((Interfaces.iHasType) this.Parent).ReferencedType.ident == this) ) { this.ReferencedObject = this.Parent; if (this.Parent is Interfaces.iHasType) { this.ReferencedType = ((Interfaces.iHasType) this.Parent).ReferencedType; } else //todo: try to replace with proper refObject type { this.ReferencedType = new VarTypeObject(this, (this.Parent is Interfaces.iTemplate ? ((Interfaces.iTemplate) this.Parent).TemplateObject : null)); } } else { switch (type) { #region ThisVar case IdenType.ThisVar: { Interfaces.iClass curObject = this.getFirstOf <Interfaces.iClass>(); this.ReferencedObject = (pBaseLangObject)curObject; this.ReferencedType = curObject.VTO; var fnc = this.getFirstOf <Interfaces.iFunction>(); if (fnc.FunctionEncapsulation == Encapsulation.Static) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0055, this.Line, this.Pos, this.File)); errCount++; } } break; #endregion #region TemplateVar case IdenType.TemplateVar: { this.ReferencedObject = (pBaseLangObject)this.getFirstOf <Interfaces.iClass>(); this.ReferencedType = ((Interfaces.iClass) this.ReferencedObject).VTO; } break; #endregion #region SqfCommandName case IdenType.SqfCommandName: { this.ReferencedObject = this.Parent; this.ReferencedType = ((SqfCall)this.Parent).ReferencedType; } break; #endregion #region VariableAccess & ArrayAccess case IdenType.VariableAccess: case IdenType.ArrayAccess: { var nsr = HelperClasses.NamespaceResolver.createNSR(this); if (nsr != null && nsr.IsValid && (nsr.Reference is oosEnum.EnumEntry || nsr.Reference is oosEnum)) { if (nsr.Reference is oosEnum.EnumEntry) { var entry = (oosEnum.EnumEntry)nsr.Reference; this.ReferencedObject = entry; this.ReferencedType = ((oosEnum)entry.Parent).ReferencedType; break; } else if (nsr.Reference is oosEnum) { var e = (oosEnum)nsr.Reference; this.ReferencedObject = e; this.ReferencedType = e.ReferencedType; break; } } var variable = HelperClasses.NamespaceResolver.getVariableReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(this, true), true, this); if (variable == null) { variable = HelperClasses.NamespaceResolver.getVariableReferenceOfFQN(this, false, this); } if (variable == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0012, this.Line, this.Pos, this.File)); errCount++; } else { this.ReferencedObject = variable; //Set type to variable type this.ReferencedType = variable.varType; if (type == IdenType.ArrayAccess) { if (variable.ReferencedType.IsObject) { //Check if given object is implementing the ArrayAccess operator if (variable.ReferencedType.ident.LastIdent.ReferencedObject is Interfaces.iClass) { Interfaces.iClass classRef = (Interfaces.iClass)variable.ReferencedType.ident.LastIdent.ReferencedObject; Interfaces.iOperatorFunction opFnc = classRef.getOperatorFunction(OverridableOperator.ArrayAccess); if (opFnc == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0005, this.Line, this.Pos, this.File)); errCount++; } else { this.ReferencedType = opFnc.ReturnType; if (variable.TemplateObject != null) { var templateList = ((pBaseLangObject)opFnc).getAllParentsOf <Interfaces.iTemplate>(); foreach (var it in templateList) { var tmp = HelperClasses.ArgList.resolveVarTypeObject(opFnc.ReturnType, it.TemplateObject, variable.TemplateObject); if (tmp != opFnc.ReturnType) { this.ReferencedType = tmp; break; } } } } } else { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.UNKNOWN, this.Line, this.Pos, this.File)); errCount++; } } else { //just check if this is an array type switch (this.ReferencedType.varType) { case VarType.BoolArray: this.ReferencedType = new VarTypeObject(this.ReferencedType); this.ReferencedType.varType = VarType.Bool; break; case VarType.ScalarArray: this.ReferencedType = new VarTypeObject(this.ReferencedType); this.ReferencedType.varType = VarType.Scalar; break; default: Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0006, this.Line, this.Pos, this.File)); errCount++; break; } } } } } break; #endregion #region FunctionCall case IdenType.FunctionCall: { List <Interfaces.iFunction> fncList; var fncCall = fncCalls[0]; var newInstance = this.getFirstOf <NewInstance>(true, typeof(Ident)); var fqn = this.FullyQualifiedName; if (parentIdent != null && parentIdent.ReferencedObject is Variable) { //if (((Variable)parentIdent.ReferencedObject).ReferencedType.IsObject) // fqn = ((Interfaces.iClass)((Variable)parentIdent.ReferencedObject).ReferencedType.ident.LastIdent.ReferencedObject).Name.LastIdent.FullyQualifiedName + "." + this.originalValue; //else parentIdent.ReferencedObject.finalize(); fqn = parentIdent.ReferencedType.ident.LastIdent.ReferencedType.ident.LastIdent.FullyQualifiedName + "." + this.originalValue; } if (newInstance == null) { fncList = HelperClasses.NamespaceResolver.getFunctionReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(fqn)); } else { fncList = HelperClasses.NamespaceResolver.getFunctionReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(fqn + "." + this.originalValue)); } if (fncList.Count == 0) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0001, this.Line, this.Pos, this.File)); errCount++; } else { //Search the correct function in the possible matches Interfaces.iFunction fnc = null; foreach (var it in fncList) { if (HelperClasses.ArgList.matchesArglist(it.ArgList, fncCall.ArgList, (parentIdent != null && parentIdent.ReferencedObject is Variable ? (Variable)parentIdent.ReferencedObject : null))) { fnc = it; break; } } //Raise new linker issue if we could not locate a matching function if (fnc == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0002, this.Line, this.Pos, this.File)); errCount++; } else { if (fnc is Function && ((Function)fnc).IsConstructor && this.getFirstOf <NewInstance>() == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0026, this.Line, this.Pos, this.File)); errCount++; } //Ref the object to the function this.ReferencedObject = (pBaseLangObject)fnc; //Ref the type to the return type this.ReferencedType = fnc.ReturnType; //As last step make sure we got the correct encapsulation here var enc = fnc.FunctionEncapsulation; if (enc != Encapsulation.Static && enc != Encapsulation.Public) { var parentClass = this.getFirstOf <Interfaces.iClass>(); HelperClasses.NamespaceResolver fncNsr = fnc.Name; if (enc == Encapsulation.Private) { //Private encapsulation just requires checking the current class we are operating in if (!fncNsr.isInNamespace(parentClass == null ? null : parentClass.Name)) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0003, this.Line, this.Pos, this.File)); errCount++; } } else { //Protected we need to check ALL extended classes ... var classes = parentClass.ExtendedClasses; bool flag = false; foreach (var it in classes) { if (fncNsr.isInNamespace(it)) { flag = true; break; } } if (!flag) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0004, this.Line, this.Pos, this.File)); errCount++; } } } } } } break; #endregion #region NamespaceAccess case IdenType.NamespaceAccess: { if (this.IsAnonymousIdent) { this.ReferencedObject = getClassTemplate(); this.ReferencedObject = null; } else { var nsr = HelperClasses.NamespaceResolver.createNSR(this); if (nsr == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0046, this.Line, this.Pos, this.File)); errCount++; } else { var reference = nsr.Reference; this.ReferencedObject = reference; if (reference is Interfaces.iClass) { this.ReferencedType = ((Interfaces.iClass)reference).VTO; } else if (reference is Interfaces.iFunction) { this.ReferencedType = ((Interfaces.iFunction)reference).ReturnType; } else { this.ReferencedType = null; } } } } break; #endregion } } return(errCount); }
public override int doFinalize() { int errCount = 0; Ident parentIdent = (this.Parent is Ident ? (Ident)this.Parent : default(Ident)); //Check what we have here (possible outcomes: variableacces, arrayaccess, functioncall, namespaceaccess) #region typeDetection type = IdenType.NamespaceAccess; var fncCalls = this.getAllChildrenOf<FunctionCall>(); var arrAccess = this.getAllChildrenOf<ArrayAccess>(); if (this.Parent is Template) { type = IdenType.TemplateVar; } else if (this.Parent is SqfCall && ((SqfCall)this.Parent).Name == this) { type = IdenType.SqfCommandName; } else if (this.IsSelfReference) { type = IdenType.ThisVar; } else if (fncCalls.Count > 0) { type = IdenType.FunctionCall; } else if (arrAccess.Count > 0) { type = IdenType.ArrayAccess; } else if (parentIdent == null && this.Access == AccessType.NA) { if (this.Parent is Interfaces.iClass || (this.Parent is Interfaces.iFunction && ((Interfaces.iFunction)this.Parent).ReturnType.ident == this)) type = IdenType.NamespaceAccess; else type = IdenType.VariableAccess; } else if (parentIdent != null && ( (parentIdent.Access == AccessType.Namespace && this.Access == AccessType.NA) || this.Access == AccessType.Instance || (parentIdent.Access == AccessType.Instance && this.Access == AccessType.NA) )) { var ntr = HelperClasses.NamespaceResolver.createNSR(this); if (ntr.Reference is Interfaces.iClass) type = IdenType.NamespaceAccess; else type = IdenType.VariableAccess; } else if (this.Access == AccessType.Namespace) { type = IdenType.NamespaceAccess; } else if (this.Access == AccessType.Instance && parentIdent == null) { type = IdenType.VariableAccess; } else { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.UNKNOWN, this.Line, this.Pos)); errCount++; } #endregion //And process it then ((unless its a simple ident, then we do not want to process ... here any further)) if (this.IsSimpleIdentifier && ((this.Parent is Interfaces.iName && ((Interfaces.iName)this.Parent).Name == this) || (this.Parent is Interfaces.iHasType && !(this.Parent is Expression) && ((Interfaces.iHasType)this.Parent).ReferencedType.ident == this)) && !(this.Parent is AssignContainer)) { this.referencedObject = this.Parent; if (this.Parent is Interfaces.iHasType) this.referencedType = ((Interfaces.iHasType)this.Parent).ReferencedType; else //todo: try to replace with proper refObject type this.referencedType = new VarTypeObject(this, true, (this.Parent is Interfaces.iTemplate ? ((Interfaces.iTemplate)this.Parent).TemplateObject : null) ); } else { switch (type) { #region ThisVar case IdenType.ThisVar: { Interfaces.iClass curObject = this.getFirstOf<Interfaces.iClass>(); this.referencedObject = (pBaseLangObject)curObject; this.referencedType = curObject.VTO; } break; #endregion #region TemplateVar case IdenType.TemplateVar: { this.referencedObject = (pBaseLangObject)this.getFirstOf<Interfaces.iClass>(); this.referencedType = ((Interfaces.iClass)this.referencedObject).VTO; } break; #endregion #region SqfCommandName case IdenType.SqfCommandName: { this.referencedObject = this.Parent; this.referencedType = ((SqfCall)this.Parent).ReferencedType; } break; #endregion #region VariableAccess & ArrayAccess case IdenType.VariableAccess: case IdenType.ArrayAccess: { var variable = HelperClasses.NamespaceResolver.getVariableReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(this,true), true, this); if (variable == null) { variable = HelperClasses.NamespaceResolver.getVariableReferenceOfFQN(this, false, this); } if (variable == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0012, this.Line, this.Pos)); errCount++; } this.referencedObject = variable; //Set type to variable type this.referencedType = variable.varType; if (type == IdenType.ArrayAccess) { if (variable.ReferencedType.IsObject) { //Check if given object is implementing the ArrayAccess operator if (variable.ReferencedType.ident.LastIdent.referencedObject is Interfaces.iClass) { Interfaces.iClass classRef = (Interfaces.iClass)variable.ReferencedType.ident.LastIdent.referencedObject; Interfaces.iOperatorFunction opFnc = classRef.getOperatorFunction(OverridableOperator.ArrayAccess); if (opFnc == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0005, this.Line, this.Pos)); errCount++; } else { this.referencedType = opFnc.ReturnType; if (variable.TemplateObject != null) { var templateList = ((pBaseLangObject)opFnc).getAllParentsOf<Interfaces.iTemplate>(); foreach (var it in templateList) { var tmp = HelperClasses.ArgList.resolveVarTypeObject(opFnc.ReturnType, it.TemplateObject, variable.TemplateObject); if (tmp != opFnc.ReturnType) { this.referencedType = tmp; break; } } } } } else { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.UNKNOWN, this.Line, this.Pos)); errCount++; } } else { //just check if this is an array type switch (this.referencedType.varType) { case VarType.BoolArray: this.referencedType = new VarTypeObject(this.referencedType); this.referencedType.varType = VarType.Bool; break; case VarType.ScalarArray: this.referencedType = new VarTypeObject(this.referencedType); this.referencedType.varType = VarType.Scalar; break; case VarType.StringArray: this.referencedType = new VarTypeObject(this.referencedType); this.referencedType.varType = VarType.String; break; default: Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0006, this.Line, this.Pos)); errCount++; break; } } } } break; #endregion #region FunctionCall case IdenType.FunctionCall: { List<Interfaces.iFunction> fncList; var fncCall = fncCalls[0]; var newInstance = this.getFirstOf<NewInstance>(); var fqn = this.FullyQualifiedName; if (parentIdent != null && parentIdent.ReferencedObject is Variable) { //if (((Variable)parentIdent.ReferencedObject).ReferencedType.IsObject) // fqn = ((Interfaces.iClass)((Variable)parentIdent.ReferencedObject).ReferencedType.ident.LastIdent.ReferencedObject).Name.LastIdent.FullyQualifiedName + "." + this.originalValue; //else fqn = parentIdent.ReferencedType.ident.LastIdent.referencedType.ident.LastIdent.FullyQualifiedName + "." + this.originalValue; } if (newInstance == null) { fncList = HelperClasses.NamespaceResolver.getFunctionReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(fqn)); } else { fncList = HelperClasses.NamespaceResolver.getFunctionReferenceOfFQN(HelperClasses.NamespaceResolver.createNSR(fqn + "::" + this.originalValue)); } if (fncList.Count == 0) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.UNKNOWN, this.Line, this.Pos)); errCount++; } else { //Search the correct function in the possible matches Interfaces.iFunction fnc = null; foreach (var it in fncList) { if (HelperClasses.ArgList.matchesArglist(it.ArgList, fncCall.ArgList, (parentIdent.ReferencedObject is Variable ? (Variable)parentIdent.ReferencedObject : null))) { fnc = it; break; } } //Raise new linker issue if we could not locate a matching function if (fnc == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0002, this.Line, this.Pos)); errCount++; } else { if(fnc is Function && ((Function)fnc).IsConstructor && this.getFirstOf<NewInstance>() == null) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0026, this.Line, this.Pos)); errCount++; } //Ref the object to the function this.referencedObject = (pBaseLangObject)fnc; //Ref the type to the return type this.referencedType = fnc.ReturnType; //As last step make sure we got the correct encapsulation here var enc = fnc.FunctionEncapsulation; if (enc != Encapsulation.Static && enc != Encapsulation.Public) { var parentClass = this.getFirstOf<Interfaces.iClass>(); HelperClasses.NamespaceResolver fncNsr = fnc.Name; if (enc == Encapsulation.Private) { //Private encapsulation just requires checking the current class we are operating in if (!fncNsr.isInNamespace(parentClass.Name)) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0003, this.Line, this.Pos)); errCount++; } } else { //Protected we need to check ALL extended classes ... var classes = parentClass.ExtendedClasses; bool flag = false; foreach (var it in classes) { if (fncNsr.isInNamespace(it)) { flag = true; break; } } if (!flag) { Logger.Instance.log(Logger.LogLevel.ERROR, ErrorStringResolver.resolve(ErrorStringResolver.LinkerErrorCode.LNK0004, this.Line, this.Pos)); errCount++; } } } } } } break; #endregion #region NamespaceAccess case IdenType.NamespaceAccess: { var nsr = HelperClasses.NamespaceResolver.createNSR(this, this.IsAnonymousIdent); var reference = nsr.Reference; this.referencedObject = reference; if (reference is Interfaces.iClass) this.referencedType = ((Interfaces.iClass)reference).VTO; else if (reference is Interfaces.iFunction) this.referencedType = ((Interfaces.iFunction)reference).ReturnType; else this.referencedType = null; } break; #endregion } } return errCount; }
Exception AmbiguousMatchException(int pos, List <Capture> matches) { Debug.Assert(matches != null); Debug.Assert(matches.Count > 0); var names = new List <string>(matches.Count); foreach (Capture match in matches) { IdenType idenType = IdenType.Argument; foreach (var list in this.literals) { if (idenType == match.Type) { int i = 0, id = match.Index; foreach (string name in list) { if (i++ == id) { names.Add(name); break; } } } idenType++; } } Debug.Assert(matches.Count == names.Count); var buf = new StringBuilder( Resource.errAmbiguousMatch); for (int i = 0; i < matches.Count; i++) { string type = string.Empty; switch (matches[i].Type) { case IdenType.Argument: type = Resource.sArgument; break; case IdenType.Constant: type = Resource.sConstant; break; case IdenType.Function: type = Resource.sFunction; break; } buf .Append(' ') .Append(type.ToLowerInvariant()) .Append(" \"") .Append(names[i]) .Append('\"'); if (i + 1 == matches.Count) { buf.Append(' ').Append(Resource.sAnd); } else { buf.Append(i == matches.Count ? '.' : ','); } } int len = names[0].Length; return(new SyntaxException( buf.ToString(), this.expr, pos, len)); }