예제 #1
0
        public DefinedType(ParseInfo parseInfo, Scope scope, DeltinScriptParser.Type_defineContext typeContext, List <IApplyBlock> applyMethods) : base(typeContext.name.Text)
        {
            this.translateInfo = parseInfo.TranslateInfo;
            if (translateInfo.IsCodeType(Name))
            {
                parseInfo.Script.Diagnostics.Error($"A type with the name '{Name}' already exists.", DocRange.GetRange(typeContext.name));
            }

            DefinedAt = new LanguageServer.Location(parseInfo.Script.Uri, DocRange.GetRange(typeContext.name));
            translateInfo.AddSymbolLink(this, DefinedAt);

            if (typeContext.CLASS() != null)
            {
                TypeKind       = TypeKind.Class;
                TypeKindString = "class";
            }
            else if (typeContext.STRUCT() != null)
            {
                TypeKind       = TypeKind.Struct;
                TypeKindString = "struct";
            }
            else
            {
                throw new NotImplementedException();
            }

            staticScope = translateInfo.GlobalScope.Child(TypeKindString + " " + Name);
            objectScope = staticScope.Child(TypeKindString + " " + Name);

            // Get the variables defined in the type.
            foreach (var definedVariable in typeContext.define())
            {
                Var newVar = Var.CreateVarFromContext(VariableDefineType.InClass, parseInfo, definedVariable);
                newVar.Finalize(UseScope(newVar.Static));
                if (!newVar.Static)
                {
                    objectVariables.Add(newVar);
                }
            }

            // Todo: Static methods/macros.
            foreach (var definedMethod in typeContext.define_method())
            {
                var newMethod = new DefinedMethod(parseInfo, UseScope(false), definedMethod);
                applyMethods.Add(newMethod);
            }

            foreach (var macroContext in typeContext.define_macro())
            {
                DeltinScript.GetMacro(parseInfo, UseScope(false), macroContext, applyMethods);
            }

            // Get the constructors.
            if (typeContext.constructor().Length > 0)
            {
                Constructors = new Constructor[typeContext.constructor().Length];
                for (int i = 0; i < Constructors.Length; i++)
                {
                    Constructors[i] = new DefinedConstructor(parseInfo, this, typeContext.constructor(i));
                    applyMethods.Add((DefinedConstructor)Constructors[i]);
                }
            }
            else
            {
                // If there are no constructors, create a default constructor.
                Constructors = new Constructor[] {
                    new Constructor(this, new Location(parseInfo.Script.Uri, DocRange.GetRange(typeContext.name)), AccessLevel.Public)
                };
            }
        }
        public override void ResolveElements()
        {
            if (elementsResolved)
            {
                return;
            }

            // Get the type being extended.
            if (typeContext.TERNARY_ELSE() != null)
            {
                // If there is no type name, error.
                if (typeContext.extends == null)
                {
                    parseInfo.Script.Diagnostics.Error("Expected type name.", DocRange.GetRange(typeContext.TERNARY_ELSE()));
                }
                else
                {
                    // Get the type being inherited.
                    CodeType inheriting = parseInfo.TranslateInfo.GetCodeType(typeContext.extends.Text, parseInfo.Script.Diagnostics, DocRange.GetRange(typeContext.extends));

                    // GetCodeType will return null if the type is not found.
                    if (inheriting != null)
                    {
                        inheriting.Call(parseInfo.Script, DocRange.GetRange(typeContext.extends));

                        Inherit(inheriting, parseInfo.Script.Diagnostics, DocRange.GetRange(typeContext.extends));
                        (Extends as ClassType)?.ResolveElements();
                    }
                }
            }

            base.ResolveElements();

            // Give DefinedMethod and GetMacro a scope to use in case of the static attribute.
            foreach (var definedMethod in typeContext.define_method())
            {
                var newMethod = new DefinedMethod(parseInfo, operationalScope, staticScope, definedMethod, this);

                // Copy to serving scopes.
                if (newMethod.Static)
                {
                    staticScope.CopyMethod(newMethod);
                }
                else
                {
                    serveObjectScope.CopyMethod(newMethod);
                }
            }

            // Get the macros.
            foreach (var macroContext in typeContext.define_macro())
            {
                var newMacro = DeltinScript.GetMacro(parseInfo, operationalScope, staticScope, macroContext);

                // Copy to serving scopes.
                if (newMacro is IMethod asMethod)
                {
                    if (newMacro.Static)
                    {
                        staticScope.CopyMethod(asMethod);
                    }
                    else
                    {
                        serveObjectScope.CopyMethod(asMethod);
                    }
                }
                else
                {
                    if (newMacro.Static)
                    {
                        staticScope.CopyVariable(newMacro);
                    }
                    else
                    {
                        serveObjectScope.CopyVariable(newMacro);
                    }
                }
            }

            // Get the variables defined in the type.
            foreach (var definedVariable in typeContext.define())
            {
                Var newVar = new ClassVariable(operationalScope, staticScope, new DefineContextHandler(parseInfo, definedVariable));

                // Copy to serving scopes.
                if (!newVar.Static)
                {
                    ObjectVariables.Add(new ObjectVariable(newVar));
                    serveObjectScope.CopyVariable(newVar);
                }
                // Add to static scope.
                else
                {
                    staticVariables.Add(newVar);
                    staticScope.CopyVariable(newVar);
                    operationalScope.CopyVariable(newVar);
                }
            }

            // Get the constructors.
            if (typeContext.constructor().Length > 0)
            {
                Constructors = new Constructor[typeContext.constructor().Length];
                for (int i = 0; i < Constructors.Length; i++)
                {
                    Constructors[i] = new DefinedConstructor(parseInfo, operationalScope, this, typeContext.constructor(i));
                }
            }
            else
            {
                // If there are no constructors, create a default constructor.
                Constructors = new Constructor[] {
                    new Constructor(this, new Location(parseInfo.Script.Uri, DocRange.GetRange(typeContext.name)), AccessLevel.Public)
                };
            }

            // If the extend token exists, add completion that only contains all extendable classes.
            if (typeContext.TERNARY_ELSE() != null)
            {
                parseInfo.Script.AddCompletionRange(new CompletionRange(
                                                        // Get the completion items of all types.
                                                        parseInfo.TranslateInfo.types
                                                        .Where(t => t is ClassType ct && ct.CanBeExtended)
                                                        .Select(t => t.GetCompletion())
                                                        .ToArray(),
                                                        // Get the completion range.
                                                        DocRange.GetRange(typeContext.TERNARY_ELSE(), parseInfo.Script.NextToken(typeContext.TERNARY_ELSE())),
                                                        // This completion takes priority.
                                                        CompletionRangeKind.ClearRest
                                                        ));
            }
            parseInfo.Script.AddCodeLensRange(new ReferenceCodeLensRange(this, parseInfo, CodeLensSourceType.Type, DefinedAt.range));
        }