/// <summary> /// /// </summary> /// <param name="classIndex"></param> /// <param name="function"></param> /// <param name="si"></param> /// <param name="isStatic"></param> /// <returns> /// the key means the function index of thr procedure, not that it may be different from argument classIndex if /// the procedure comes from its base class /// </returns> private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetMemberFunctions(int classIndex, string function, ScopeInfo si, bool isStatic) { ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex]; List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > functionList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >(); // first search its own functions if (cn.vtable == null) { return(functionList); } foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList) { if (pn.isConstructor || pn.name != function || pn.isStatic != isStatic) { continue; } // here we have found a function with the same name // check if it is accessible if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access) { functionList.Add(new KeyValuePair <int, ProtoCore.DSASM.ProcedureNode>(classIndex, pn)); } } // continue to search its base class foreach (int baseClass in cn.baseList) { functionList.AddRange(GetMemberFunctions(baseClass, function, si, isStatic)); } return(functionList); }
public void VerifyMethodExists(string className, string methodName, bool doAssert = true) { int classIndex = testCore.ClassTable.IndexOf(className); if (classIndex == ProtoCore.DSASM.Constants.kInvalidIndex) { if (doAssert) { Assert.Fail(string.Format("\tFailed to find type \"{0}\" \n{1}", className, mErrorMessage)); } return; } ProtoCore.DSASM.ClassNode thisClass = testCore.ClassTable.ClassNodes[classIndex]; if (!thisClass.vtable.procList.Exists(memberFunc => String.Compare(memberFunc.name, methodName) == 0)) { if (doAssert) { Assert.Fail(string.Format("\tMethod \"{0}.{1}\" doesn't exist \n{2}", className, methodName, mErrorMessage)); } } else if (!doAssert) { Assert.Fail(string.Format("\tMethod \"{0}.{1}\" does exist \n{2}", className, methodName, mErrorMessage)); } }
public void Reserve(int size) { for (int n = 0; n < size; ++n) { ProtoCore.DSASM.ClassNode cnode = new ProtoCore.DSASM.ClassNode { Name = ProtoCore.DSDefinitions.Keyword.Invalid, Size = 0, Rank = 0, Symbols = null, ProcTable = null }; classNodes.Add(cnode); } }
public void Reserve(int size) { for (int n = 0; n < size; ++n) { ProtoCore.DSASM.ClassNode cnode = new ProtoCore.DSASM.ClassNode { name = ProtoCore.DSDefinitions.Kw.kw_invalid, size = 0, rank = 0, symbols = null, vtable = null }; classNodes.Add(cnode); } }
/// <summary> /// Return all the members of a class /// </summary> /// <param name="classIndex"></param> /// <param name="si"></param> /// <param name="searchingBase">if searchingBase == true, the MemberType.FromBase of the returned members will be set </param> /// <param name="isStatic"></param> /// <param name="includeConstructor"></param> /// <returns></returns> private static List <KeyValuePair <MemberType, string> > GetClassMembers(int classIndex, ScopeInfo si, bool searchingBase, bool isStatic, bool includeConstructor) { List <KeyValuePair <MemberType, string> > members = new List <KeyValuePair <MemberType, string> >(); ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex]; // 1. search the member variable if (cn.symbols != null && !searchingBase) // when searching base, no need to populate the member variable, it has already been added in code gen { foreach (ProtoCore.DSASM.SymbolNode sn in cn.symbols.symbolList.Values.Where(x => x.functionIndex == ProtoCore.DSASM.Constants.kInvalidIndex)) { if (GetAccessLevel(si.ClassScope, sn.classScope) >= sn.access && isStatic == sn.isStatic && !sn.name.StartsWith("%") /* block the internally generated members*/) { KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Fields | AccessToMemberType(sn.access) | StaticToMemberType(isStatic) | BaseToMemberType(sn.classScope != classIndex), sn.name); members.Add(member); } } } // 2. search the member functions and constructors if (cn.vtable != null) { foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList) { // get static members if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access && isStatic == pn.isStatic && pn.isConstructor == false && !pn.name.StartsWith("%") && pn.isAutoGenerated != true) { KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Methods | AccessToMemberType(pn.access) | StaticToMemberType(pn.isStatic) | BaseToMemberType(searchingBase) | ConstructorToMemberType(pn.isConstructor), pn.name); members.Add(member); } // get constructor if (GetAccessLevel(si.ClassScope, classIndex) >= pn.access && true == pn.isConstructor && includeConstructor == true && !pn.name.StartsWith("%") && pn.isAutoGenerated != true) { KeyValuePair <MemberType, string> member = new KeyValuePair <MemberType, string>(MemberType.Methods | AccessToMemberType(pn.access) | StaticToMemberType(pn.isStatic) | BaseToMemberType(searchingBase) | ConstructorToMemberType(pn.isConstructor), pn.name); members.Add(member); } } } // 3. search base class if (cn.baseList != null) // Note, for nonstatic members it is been copied to the derived class, hence they have been added already { foreach (int baseIndex in cn.baseList) { // searching base will be set to true since we are searching the base class now members.AddRange(GetClassMembers(baseIndex, si, true, isStatic, false)); } } return(members); }
protected void EmitReturnStatement(Node node, ProtoCore.Type inferedType) { // Check the returned type against the declared return type if (null != localProcedure && core.IsFunctionCodeBlock(codeBlock)) { if (localProcedure.isConstructor) { Debug.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != inferedType.UID); ProtoCore.DSASM.ClassNode typeNode = core.ClassTable.ClassNodes[inferedType.UID]; Debug.Assert(null != typeNode); } } }
private static List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > GetConstructors(int classIndex, string function, ScopeInfo si) { ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex]; ProtoCore.DSASM.AccessSpecifier access = GetAccessLevel(si.ClassScope, classIndex); List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> > functionList = new List <KeyValuePair <int, ProtoCore.DSASM.ProcedureNode> >(); if (cn.vtable == null) { return(functionList); } foreach (ProtoCore.DSASM.ProcedureNode pn in cn.vtable.procList) { if (pn.name == function && pn.isConstructor && access >= pn.access) { functionList.Add(new KeyValuePair <int, ProtoCore.DSASM.ProcedureNode>(classIndex, pn)); } } // no need to search base constructors, return(functionList); }
private static ProtoCore.DSASM.SymbolNode GetMemberVariable(int classIndex, string field, ScopeInfo si, bool isStatic) { if (field.IndexOfAny(new char[] { '[', ']' }) != -1) { string[] tokens = TokenizeArrayIndexers(field); field = tokens[0]; } // one search is enough, because the code gen will copy all the accessible base // class member variabs to the current class table, life easier ProtoCore.DSASM.ClassNode cn = compileState.ClassTable.ClassNodes[classIndex]; if (cn.symbols == null) { return(null); } for (int ix = cn.symbols.symbolList.Values.Count - 1; ix >= 0; --ix) { // we should search in reverse order because in code gen // the base class member variable is added first // hence we shoud search the its own variable first ProtoCore.DSASM.SymbolNode sn = cn.symbols.symbolList[ix]; if (sn.functionIndex != ProtoCore.DSASM.Constants.kInvalidIndex || sn.name != field || isStatic != sn.isStatic) { continue; } // here we have found a variable with the same name if (GetAccessLevel(si.ClassScope, sn.classScope) >= sn.access) { return(sn); } } return(null); }
private void EmitClassDeclNode(AssociativeNode node, ref ProtoCore.Type inferedType, ProtoCore.DSASM.AssociativeSubCompilePass subPass = ProtoCore.DSASM.AssociativeSubCompilePass.kNone) { ClassDeclNode classDecl = node as ClassDeclNode; // Handling n-pass on class declaration if (ProtoCore.DSASM.AssociativeCompilePass.kClassName == compilePass) { ProtoCore.DSASM.ClassNode cnode = new ProtoCore.DSASM.ClassNode(); cnode.name = classDecl.className; cnode.size = classDecl.varlist.Count; cnode.IsImportedClass = classDecl.IsImportedClass; cnode.typeSystem = core.TypeSystem; globalClassIndex = core.ClassTable.Append(cnode); CodeRangeTable.AddClassBlockRangeEntry(globalClassIndex, classDecl.line, classDecl.col, classDecl.endLine, classDecl.endCol, core.CurrentDSFileName); } else if (ProtoCore.DSASM.AssociativeCompilePass.kClassHeirarchy == compilePass) { // Class heirarchy pass // Populating each class entry with their respective base classes globalClassIndex = core.ClassTable.IndexOf(classDecl.className); ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[globalClassIndex]; if (null != classDecl.superClass) { for (int n = 0; n < classDecl.superClass.Count; ++n) { int baseClass = core.ClassTable.IndexOf(classDecl.superClass[n]); if (ProtoCore.DSASM.Constants.kInvalidIndex != baseClass) { cnode.baseList.Add(baseClass); cnode.coerceTypes.Add(baseClass, (int)ProtoCore.DSASM.ProcedureDistance.kCoerceBaseClass); } } } } else if (ProtoCore.DSASM.AssociativeCompilePass.kClassMemVar == compilePass) { // Class member variable pass // Populating each class entry symbols with their respective member variables globalClassIndex = core.ClassTable.IndexOf(classDecl.className); ProtoCore.DSASM.ClassNode cnode = core.ClassTable.ClassNodes[globalClassIndex]; // Handle member vars from base class if (null != classDecl.superClass) { for (int n = 0; n < classDecl.superClass.Count; ++n) { int baseClass = core.ClassTable.IndexOf(classDecl.superClass[n]); if (ProtoCore.DSASM.Constants.kInvalidIndex != baseClass) { // Append the members variables of every class that this class inherits from foreach (ProtoCore.DSASM.SymbolNode symnode in core.ClassTable.ClassNodes[baseClass].symbols.symbolList.Values) { // It is a member variables if (ProtoCore.DSASM.Constants.kGlobalScope == symnode.functionIndex) { Debug.Assert(!symnode.isArgument); int symbolIndex = AllocateMemberVariable(globalClassIndex, symnode.isStatic ? symnode.classScope : baseClass, symnode.name, symnode.datatype, symnode.access, symnode.isStatic); if (symbolIndex != ProtoCore.DSASM.Constants.kInvalidIndex) cnode.size += ProtoCore.DSASM.Constants.kPointerSize; } } } else { Debug.Assert(false, "n-pass compile error, fixme Jun...."); } } } // This list will store all static properties initialization // expression (say x = 1). List<BinaryExpressionNode> staticPropertyInitList = new List<BinaryExpressionNode>(); foreach (VarDeclNode vardecl in classDecl.varlist) { IdentifierNode varIdent = null; if (vardecl.NameNode is IdentifierNode) { varIdent = vardecl.NameNode as IdentifierNode; } else if (vardecl.NameNode is BinaryExpressionNode) { BinaryExpressionNode bNode = vardecl.NameNode as BinaryExpressionNode; varIdent = bNode.LeftNode as IdentifierNode; if (vardecl.IsStatic) staticPropertyInitList.Add(bNode); else cnode.defaultArgExprList.Add(bNode); } else { Debug.Assert(false, "Check generated AST"); } // It is possible that fail to allocate variable. In that // case we should remove initializing expression from // cnode's defaultArgExprList ProtoCore.Type datatype = vardecl.ArgumentType; if (string.IsNullOrEmpty(vardecl.ArgumentType.Name)) datatype.UID = (int)PrimitiveType.kTypeVar; else { datatype.UID = core.TypeSystem.GetType(vardecl.ArgumentType.Name); if (datatype.UID == ProtoCore.DSASM.Constants.kInvalidIndex) datatype.UID = (int)PrimitiveType.kTypeVar; } datatype.Name = core.TypeSystem.GetType(datatype.UID); int symbolIndex = ProtoCore.DSASM.Constants.kInvalidIndex; if (varIdent is ProtoCore.AST.AssociativeAST.TypedIdentifierNode) symbolIndex = AllocateTypedMemberVariable(globalClassIndex, globalClassIndex, varIdent.Value, datatype, vardecl.access, vardecl.IsStatic); else symbolIndex = AllocateMemberVariable(globalClassIndex, globalClassIndex, varIdent.Value, datatype, vardecl.access, vardecl.IsStatic); if (symbolIndex != ProtoCore.DSASM.Constants.kInvalidIndex && !classDecl.IsExternLib) { ProtoCore.DSASM.SymbolNode memVar = vardecl.IsStatic ? core.CodeBlockList[0].symbolTable.symbolList[symbolIndex] : core.ClassTable.ClassNodes[globalClassIndex].symbols.symbolList[symbolIndex]; EmitGetterForMemVar(classDecl, memVar); EmitSetterForMemVar(classDecl, memVar); } } classOffset = 0; // Now we are going to create a static function __init_static_properties() // which will initialize all static properties. We will emit a // call to this function after all classes have been compiled. if (staticPropertyInitList.Count > 0) { FunctionDefinitionNode initFunc = new FunctionDefinitionNode() { Name = ProtoCore.DSASM.Constants.kStaticPropertiesInitializer, Singnature = new ArgumentSignatureNode(), Pattern = null, ReturnType = new ProtoCore.Type { Name = core.TypeSystem.GetType((int)PrimitiveType.kTypeNull), UID = (int)PrimitiveType.kTypeNull }, FunctionBody = new CodeBlockNode(), IsExternLib = false, IsDNI = false, ExternLibName = null, access = ProtoCore.DSASM.AccessSpecifier.kPublic, IsStatic = true }; classDecl.funclist.Add(initFunc); staticPropertyInitList.ForEach(bNode => initFunc.FunctionBody.Body.Add(bNode)); initFunc.FunctionBody.Body.Add(new BinaryExpressionNode() { LeftNode = new IdentifierNode() { Value = ProtoCore.DSDefinitions.Kw.kw_return, Name = ProtoCore.DSDefinitions.Kw.kw_return, datatype = core.TypeSystem.BuildTypeObject(PrimitiveType.kTypeReturn, false) }, Optr = ProtoCore.DSASM.Operator.assign, RightNode = new NullNode() }); } } else if (ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncSig == compilePass) { // Class member variable pass // Populating each class entry vtables with their respective member variables signatures globalClassIndex = core.ClassTable.IndexOf(classDecl.className); foreach (AssociativeNode funcdecl in classDecl.funclist) { DfsTraverse(funcdecl, ref inferedType); } if (!classDecl.IsExternLib) { ProtoCore.DSASM.ProcedureTable vtable = core.ClassTable.ClassNodes[globalClassIndex].vtable; if (vtable.IndexOfExact(classDecl.className, new List<ProtoCore.Type>()) == ProtoCore.DSASM.Constants.kInvalidIndex) { ConstructorDefinitionNode defaultConstructor = new ConstructorDefinitionNode(); defaultConstructor.Name = classDecl.className; defaultConstructor.localVars = 0; defaultConstructor.Signature = new ArgumentSignatureNode(); defaultConstructor.Pattern = null; defaultConstructor.ReturnType = new ProtoCore.Type { Name = "var", UID = 0 }; defaultConstructor.FunctionBody = new CodeBlockNode(); defaultConstructor.baseConstr = null; defaultConstructor.access = ProtoCore.DSASM.AccessSpecifier.kPublic; defaultConstructor.IsExternLib = false; defaultConstructor.ExternLibName = null; DfsTraverse(defaultConstructor, ref inferedType); classDecl.funclist.Add(defaultConstructor); } } } else if (ProtoCore.DSASM.AssociativeCompilePass.kClassMemFuncBody == compilePass) { // Class member variable pass // Populating the function body of each member function defined in the class vtables globalClassIndex = core.ClassTable.IndexOf(classDecl.className); foreach (AssociativeNode funcdecl in classDecl.funclist) { // reset the inferedtype between functions inferedType = new ProtoCore.Type(); DfsTraverse(funcdecl, ref inferedType, false, null, subPass); } } // Reset the class index core.ClassIndex = globalClassIndex = ProtoCore.DSASM.Constants.kGlobalScope; }