internal override Expression ResolveNames(Parser parser, System.Collections.Generic.Dictionary <string, Executable> lookup, string[] imports) { FunctionDefinition funcDef; // used in multiple places. FieldDeclaration fieldDec; this.Root = this.Root.ResolveNames(parser, lookup, imports); Expression root = this.Root; string field = this.StepToken.Value; if (root is PartialNamespaceReference) { // already a fully qualified namespace, therefore imports don't matter. string fullyQualifiedName = ((PartialNamespaceReference)root).Name + "." + field; if (lookup.ContainsKey(fullyQualifiedName)) { return(Resolver.ConvertStaticReferenceToExpression(lookup[fullyQualifiedName], this.FirstToken, this.FunctionOrClassOwner)); } throw new ParserException(this.FirstToken, "Could not find class or function by the name of: '" + fullyQualifiedName + "'"); } if (root is ClassReference) { ClassDefinition cd = ((ClassReference)root).ClassDefinition; funcDef = cd.GetMethod(field, false); if (funcDef != null) { if (!funcDef.IsStaticMethod) { string className = cd.NameToken.Value; string functionName = funcDef.NameToken.Value; throw new ParserException(this.DotToken, "'" + className + "." + functionName + "' is not a static method, but it is being used as though it is static."); } return(new FunctionReference(this.FirstToken, funcDef, this.FunctionOrClassOwner)); } fieldDec = cd.GetField(field, false); if (fieldDec != null) { if (!fieldDec.IsStaticField) { throw new ParserException(this.DotToken, "Cannot make a static reference to a non-static field."); } return(new FieldReference(this.FirstToken, fieldDec, this.FunctionOrClassOwner)); } // TODO: nested classes, enums, constants // TODO: show spelling suggestions. throw new ParserException(this.StepToken, "No static fields or methods named '" + field + "' on the class " + cd.NameToken.Value + "."); } if (root is BaseKeyword) { ClassDefinition thisClass = null; if (this.FunctionOrClassOwner != null) { if (this.FunctionOrClassOwner is FunctionDefinition) { thisClass = this.FunctionOrClassOwner.FunctionOrClassOwner as ClassDefinition; } else { thisClass = this.FunctionOrClassOwner as ClassDefinition; } } if (thisClass == null) { throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes."); } ClassDefinition cd = thisClass.BaseClass; if (cd == null) { throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes that extend from another class."); } FunctionDefinition fd = cd.GetMethod(field, true); if (fd == null) { throw new ParserException(this.DotToken, "Cannot find a method by that name in the base class chain."); } if (fd.IsStaticMethod) { throw new ParserException(this.DotToken, "Cannot reference static methods using 'base' keyword."); } return(new BaseMethodReference(this.FirstToken, this.DotToken, this.StepToken, this.FunctionOrClassOwner)); } if (root is ThisKeyword) { ClassDefinition cd = null; if (this.FunctionOrClassOwner != null) { if (this.FunctionOrClassOwner is FunctionDefinition) { funcDef = this.FunctionOrClassOwner as FunctionDefinition; if (funcDef.IsStaticMethod) { throw new ParserException(this.Root.FirstToken, "'this' keyword cannot be used in static methods."); } cd = funcDef.FunctionOrClassOwner as ClassDefinition; if (cd == null) { throw new ParserException(this.Root.FirstToken, "'this' keyword must be used inside a class."); } } else if (this.FunctionOrClassOwner is ClassDefinition) { cd = (ClassDefinition)this.FunctionOrClassOwner; } } if (cd == null) { throw new ParserException(this.Root.FirstToken, "'this' keyword is not allowed here."); } funcDef = cd.GetMethod(field, true); if (funcDef != null) { if (funcDef.IsStaticMethod) { throw new ParserException(this.DotToken, "This method is static and must be referenced by the class name, not 'this'."); } return(new FunctionReference(this.FirstToken, funcDef, this.FunctionOrClassOwner)); } FieldDeclaration fieldDef = cd.GetField(field, true); if (fieldDef != null) { if (fieldDef.IsStaticField) { throw new ParserException(this.DotToken, "This field is static and must be referenced by the class name, not 'this'."); } return(new FieldReference(this.FirstToken, fieldDef, this.FunctionOrClassOwner)); } // TODO: show suggestions in the error message for anything close to what was typed. throw new ParserException(this.StepToken, "The class '" + cd.NameToken.Value + "' does not have a field named '" + field + "'."); } return(this); }
internal override Expression ResolveNames( Parser parser) { FunctionDefinition funcDef; // used in multiple places. FieldDeclaration fieldDec; this.Root = this.Root.ResolveNames(parser); Expression root = this.Root; string field = this.StepToken.Value; if (root is PartialNamespaceReference) { // already a fully qualified namespace, therefore imports don't matter. string fullyQualifiedName = ((PartialNamespaceReference)root).Name + "." + field; TopLevelConstruct entity = this.Owner.FileScope.FileScopeEntityLookup.DoLookup(fullyQualifiedName, parser.CurrentCodeContainer); if (entity != null) { return(Resolver.ConvertStaticReferenceToExpression(entity, this.FirstToken, this.Owner)); } throw new ParserException(this.FirstToken, "Could not find class or function by the name of: '" + fullyQualifiedName + "'"); } if (root is ClassReference) { ClassDefinition cd = ((ClassReference)root).ClassDefinition; funcDef = cd.GetMethod(field, false); if (funcDef != null) { if (!funcDef.IsStaticMethod) { string className = cd.NameToken.Value; string functionName = funcDef.NameToken.Value; throw new ParserException(this.DotToken, "'" + className + "." + functionName + "' is not a static method, but it is being used as though it is static."); } return(new FunctionReference(this.FirstToken, funcDef, this.Owner)); } fieldDec = cd.GetField(field, false); if (fieldDec != null) { if (!fieldDec.IsStaticField) { throw new ParserException(this.DotToken, "Cannot make a static reference to a non-static field."); } return(new FieldReference(this.FirstToken, fieldDec, this.Owner)); } if (field == "class") { return(new ClassReferenceLiteral(this.FirstToken, cd, this.Owner)); } // TODO: nested classes, enums, constants // TODO: show spelling suggestions. throw new ParserException(this.StepToken, "No static fields or methods named '" + field + "' on the class " + cd.NameToken.Value + "."); } if (root is BaseKeyword) { ClassDefinition thisClass = null; if (this.Owner != null) { if (this.Owner is FunctionDefinition) { thisClass = this.Owner.Owner as ClassDefinition; } else { thisClass = this.Owner as ClassDefinition; } } if (thisClass == null) { throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes."); } ClassDefinition cd = thisClass.BaseClass; if (cd == null) { throw new ParserException(root.FirstToken, "'base' keyword can only be used inside classes that extend from another class."); } FunctionDefinition fd = cd.GetMethod(field, true); if (fd == null) { throw new ParserException(this.DotToken, "Cannot find a method by that name in the base class chain."); } if (fd.IsStaticMethod) { throw new ParserException(this.DotToken, "Cannot reference static methods using 'base' keyword."); } return(new BaseMethodReference(this.FirstToken, this.DotToken, this.StepToken, this.Owner)); } if (root is ThisKeyword) { ClassDefinition cd = null; if (this.Owner != null) { if (this.Owner is FunctionDefinition) { funcDef = this.Owner as FunctionDefinition; if (funcDef.IsStaticMethod) { throw new ParserException(this.Root.FirstToken, "'this' keyword cannot be used in static methods."); } cd = funcDef.Owner as ClassDefinition; if (cd == null) { throw new ParserException(this.Root.FirstToken, "'this' keyword must be used inside a class."); } } else if (this.Owner is ClassDefinition) { cd = (ClassDefinition)this.Owner; } } if (cd == null) { throw new ParserException(this.Root.FirstToken, "'this' keyword is not allowed here."); } funcDef = cd.GetMethod(field, true); if (funcDef != null) { if (funcDef.IsStaticMethod) { throw new ParserException(this.DotToken, "This method is static and must be referenced by the class name, not 'this'."); } return(new FunctionReference(this.FirstToken, funcDef, this.Owner)); } FieldDeclaration fieldDef = cd.GetField(field, true); if (fieldDef != null) { if (fieldDef.IsStaticField) { throw new ParserException(this.DotToken, "This field is static and must be referenced by the class name, not 'this'."); } return(new FieldReference(this.FirstToken, fieldDef, this.Owner)); } // TODO: show suggestions in the error message for anything close to what was typed. throw new ParserException(this.StepToken, "The class '" + cd.NameToken.Value + "' does not have a field named '" + field + "'."); } // This is done here in the resolver instead of the parser because some unallowed // field names (such as .class) are valid. if (this.StepToken.Value == parser.Keywords.CLASS) { if (this.Root is Variable) { throw new ParserException(this.Root.FirstToken, "'" + ((Variable)this.Root).Name + "' is not a class."); } throw new ParserException(this.DotToken, ".class can only be applied to class names."); } parser.VerifyIdentifier(this.StepToken); return(this); }
internal override Expression ResolveNames(Parser parser) { if (this.Name == "$$$") { throw new ParserException(this.FirstToken, "Core function invocations cannot stand alone and must be immediately invoked."); } if (this.Name.StartsWith("$$")) { return(new LibraryFunctionReference(this.FirstToken, this.Name.Substring(2), this.Owner)); } if (this.Name == "this" || this.Name == "base") { TopLevelConstruct container = parser.CurrentCodeContainer; if (container is FunctionDefinition) { FunctionDefinition funcDef = (FunctionDefinition)this.Owner; if (funcDef.IsStaticMethod) { throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static method"); } if (funcDef.Owner == null) { throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a function that isn't a class method."); } } if (container is FieldDeclaration) { if (((FieldDeclaration)container).IsStaticField) { throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static field value."); } } if (container is ConstructorDefinition) { ConstructorDefinition constructor = (ConstructorDefinition)container; if (constructor == ((ClassDefinition)constructor.Owner).StaticConstructor) // TODO: This check is silly. Add an IsStatic field to ConstructorDefinition. { throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static constructor."); } } if (this.Name == "this") { return(new ThisKeyword(this.FirstToken, this.Owner)); } return(new BaseKeyword(this.FirstToken, this.Owner)); } TopLevelConstruct exec = this.Owner.FileScope.FileScopeEntityLookup.DoLookup(this.Name, this.Owner); if (exec != null) { return(Resolver.ConvertStaticReferenceToExpression(exec, this.FirstToken, this.Owner)); } return(this); }