private static void StaticField(Compiler c, bool allowAssignment) { Instruction loadInstruction = Instruction.LoadLocal; int index = 255; Compiler classCompiler = c.GetEnclosingClassCompiler(); if (classCompiler == null) { c.Error("Cannot use a static field outside of a class definition."); } else { // Look up the name in the scope chain. Token token = c._parser.Previous; // If this is the first time we've seen this static field, implicitly // define it as a variable in the scope surrounding the class definition. if (classCompiler.ResolveLocal(c._parser.Source.Substring(token.Start, token.Length), token.Length) == -1) { int symbol = classCompiler.DeclareVariable(null); // Implicitly initialize it to null. classCompiler.Emit(Instruction.Null); classCompiler.DefineVariable(symbol); } // It definitely exists now, so resolve it properly. This is different from // the above resolveLocal() call because we may have already closed over it // as an upvalue. index = c.ResolveName(c._parser.Source.Substring(token.Start, token.Length), token.Length, out loadInstruction); } c.Variable(allowAssignment, index, loadInstruction); }
// Compiles a variable name or method call with an implicit receiver. private static void Name(Compiler c, bool allowAssignment) { // Look for the name in the scope chain up to the nearest enclosing method. Token token = c._parser.Previous; Instruction loadInstruction; string varName = c._parser.Source.Substring(token.Start, token.Length); int index = c.ResolveNonmodule(varName, token.Length, out loadInstruction); if (index != -1) { c.Variable(allowAssignment, index, loadInstruction); return; } // TODO: The fact that we return above here if the variable is known and parse // an optional argument list below if not means that the grammar is not // context-free. A line of code in a method like "someName(foo)" is a parse // error if "someName" is a defined variable in the surrounding scope and not // if it isn't. Fix this. One option is to have "someName(foo)" always // resolve to a self-call if there is an argument list, but that makes // getters a little confusing. // If we're inside a method and the name is lowercase, treat it as a method // on this. if (IsLocalName(varName) && c.GetEnclosingClass() != null) { c.LoadThis(); c.NamedCall(allowAssignment, Instruction.Call0); return; } // Otherwise, look for a module-level variable with the name. int module = c._parser.Module.Variables.FindIndex(v => v.Name == varName); if (module == -1) { if (IsLocalName(varName)) { c.Error("Undefined variable."); return; } // If it's a nonlocal name, implicitly define a module-level variable in // the hopes that we get a real definition later. module = c._parser.Vm.DeclareVariable(c._parser.Module, varName); if (module == -2) { c.Error("Too many module variables defined."); } } c.Variable(allowAssignment, module, Instruction.LoadModuleVar); }