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 void writeOut(System.IO.StreamWriter sw, SqfConfigObjects.SqfConfigFile cfg) { string variableName = this.Name.WriteOutValue; if (this.ReferencedObject is Interfaces.iFunction) { Interfaces.iFunction fnc = (Interfaces.iFunction) this.ReferencedObject; bool flag = false; if (fnc is NativeInstruction) { var nIns = (NativeInstruction)fnc; List <string> stringList = new List <string>(); if (!string.IsNullOrEmpty(variableName)) { stringList.Add(variableName); } foreach (var it in this.children) { using (MemoryStream memStream = new MemoryStream()) { StreamWriter memStreamWriter = new StreamWriter(memStream); it.writeOut(memStreamWriter, cfg); memStreamWriter.Flush(); memStream.Seek(0, SeekOrigin.Begin); stringList.Add(new StreamReader(memStream).ReadToEnd()); } } sw.Write(nIns.getCode(stringList.ToArray())); } else { if (fnc.FunctionEncapsulation == Encapsulation.Static || fnc.IsConstructor) { sw.Write('['); } else { sw.Write('[' + variableName); flag = true; } foreach (var it in this.children) { if (flag) { sw.Write(", "); } else { flag = true; } it.writeOut(sw, cfg); } if (fnc is Function) { if (fnc.IsVirtual) { sw.Write(']' + (!fnc.IsAsync ? " call (" : " spawn (") + '(' + variableName + ')' + ((Function)fnc).SqfVariableName + ')'); } else { sw.Write(']' + (!fnc.IsAsync ? " call " : " spawn ") + ((Function)fnc).SqfVariableName); } if (((Function)fnc).IsThrowing && this.getFirstOf <TryCatch>() == null) { Ident ident = this.getFirstOf <Ident>(); Logger.Instance.log(Logger.LogLevel.WARNING, "Function '" + fnc.Name.FullyQualifiedName + "' is throwing but not catched. line " + ident.Line + ", pos " + ident.Pos + ", file '" + ident.File + '\''); } } else { throw new Exception(); } } } else { throw new Exception(); } }