public FieldDeclaration(Token fieldToken, Token nameToken, ClassDefinition owner, bool isStatic) : base(fieldToken, owner) { this.NameToken = nameToken; this.DefaultValue = new NullConstant(fieldToken, owner); this.IsStaticField = isStatic; this.MemberID = -1; }
internal override Expression ResolveNames(Parser parser, Dictionary<string, Executable> lookup, string[] imports) { this.BatchExpressionNameResolver(parser, lookup, imports, this.Args); Executable ex = Expression.DoNameLookup(lookup, imports, this.Name); if (ex == null) { throw new ParserException(this.NameToken, "No class found called '" + this.Name + "'"); } if (ex is ClassDefinition) { this.Class = (ClassDefinition)ex; } else { throw new ParserException(this.NameToken, "This is not a class."); } return this; }
public int GetClassId(ClassDefinition cls) { int id; if (!this.classIdsByInstance.TryGetValue(cls, out id)) { id = classIdsByInstance.Count + 1; classIdsByInstance[cls] = id; } return id; }
private void RearrangeClassDefinitionsHelper(ClassDefinition def, HashSet<int> idsAlreadyIncluded, List<Executable> output) { if (!idsAlreadyIncluded.Contains(def.ClassID)) { if (def.BaseClass != null) { this.RearrangeClassDefinitionsHelper(def.BaseClass, idsAlreadyIncluded, output); } output.Add(def); idsAlreadyIncluded.Add(def.ClassID); } }
private static FieldDeclaration ParseField(TokenStream tokens, ClassDefinition owner) { bool isStatic = tokens.PopIfPresent("static"); Token fieldToken = tokens.PopExpected("field"); Token nameToken = tokens.Pop(); Parser.VerifyIdentifier(nameToken); FieldDeclaration fd = new FieldDeclaration(fieldToken, nameToken, owner, isStatic); if (tokens.PopIfPresent("=")) { fd.DefaultValue = ExpressionParser.Parse(tokens, owner); } tokens.PopExpected(";"); return fd; }
public ClassReference(Token token, ClassDefinition clazz, Executable owner) : base(token, owner) { this.ClassDefinition = clazz; }
private static Executable ParseClassDefinition(Parser parser, TokenStream tokens, Executable owner) { Token classToken = tokens.PopExpected("class"); Token classNameToken = tokens.Pop(); Parser.VerifyIdentifier(classNameToken); List<Token> baseClassTokens = new List<Token>(); List<string> baseClassStrings = new List<string>(); if (tokens.PopIfPresent(":")) { if (baseClassTokens.Count > 0) { tokens.PopExpected(","); } Token baseClassToken = tokens.Pop(); string baseClassName = baseClassToken.Value; Parser.VerifyIdentifier(baseClassToken); while (tokens.PopIfPresent(".")) { Token baseClassTokenNext = tokens.Pop(); Parser.VerifyIdentifier(baseClassTokenNext); baseClassName += "." + baseClassTokenNext.Value; } baseClassTokens.Add(baseClassToken); baseClassStrings.Add(baseClassName); } ClassDefinition cd = new ClassDefinition( classToken, classNameToken, baseClassTokens, baseClassStrings, parser.CurrentNamespace, owner); tokens.PopExpected("{"); List<FunctionDefinition> methods = new List<FunctionDefinition>(); List<FieldDeclaration> fields = new List<FieldDeclaration>(); ConstructorDefinition constructorDef = null; ConstructorDefinition staticConstructorDef = null; while (!tokens.PopIfPresent("}")) { if (tokens.IsNext("function") || tokens.AreNext("static", "function")) { methods.Add((FunctionDefinition)ExecutableParser.ParseFunction(parser, tokens, cd)); } else if (tokens.IsNext("constructor")) { if (constructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple constructors are not allowed. Use optional arguments."); } constructorDef = (ConstructorDefinition)ExecutableParser.ParseConstructor(parser, tokens, cd); } else if (tokens.AreNext("static", "constructor")) { tokens.Pop(); // static token if (staticConstructorDef != null) { throw new ParserException(tokens.Pop(), "Multiple static constructors are not allowed."); } staticConstructorDef = (ConstructorDefinition)ExecutableParser.ParseConstructor(parser, tokens, cd); } else if (tokens.IsNext("field") || tokens.AreNext("static", "field")) { fields.Add(ExecutableParser.ParseField(tokens, cd)); } else { tokens.PopExpected("}"); } } cd.Methods = methods.ToArray(); cd.Constructor = constructorDef; cd.StaticConstructor = staticConstructorDef; cd.Fields = fields.ToArray(); return cd; }
internal override Expression ResolveNames(Parser parser) { this.BatchExpressionNameResolver(parser, this.Args); this.Class = Node.DoClassLookup(this.Owner, this.NameToken, this.Name); return(this); }
internal override Executable ResolveNames(Parser parser, Dictionary <string, Executable> lookup, string[] imports) { this.BatchExecutableNameResolver(parser, lookup, imports, this.TryBlock); ClassDefinition simpleException = Node.DoClassLookup(null, lookup, imports, this.FunctionOrClassOwner.LocalNamespace, "Core.Exception"); foreach (CatchBlock cb in this.CatchBlocks) { string[] types = cb.Types; Token[] typeTokens = cb.TypeTokens; int typeCount = types.Length; cb.TypeClasses = new ClassDefinition[typeCount]; for (int i = 0; i < typeCount; ++i) { string typeName = types[i] ?? "Core.Exception"; Token token = typeTokens[i] ?? cb.CatchToken; ClassDefinition resolvedType = Node.DoClassLookup(token, lookup, imports, this.FunctionOrClassOwner.LocalNamespace, typeName, true); if (resolvedType == null) { throw new ParserException(token, "Could not resolve class name for catch."); } if (!resolvedType.ExtendsFrom(simpleException)) { if (resolvedType.BaseClass == null && resolvedType.LibraryName == null) { throw new ParserException(token, "This class does not extend from Core.Exception."); } else { throw new ParserException(token, "Only classes that extend from Core.Exception may be caught."); } } cb.TypeClasses[i] = resolvedType; // There's only one type, it doesn't resolve into a class, there's no variable, and there's no '.' in the type name. if (resolvedType == null && typeCount == 1 && cb.ExceptionVariableToken == null && !typeName.Contains(".")) { // ...that means this is not a type but is actually a variable. // Change the type to "Core.Exception", move this token to a variable types[0] = "Core.Exception"; cb.ExceptionVariableToken = token; typeTokens[0] = null; --i; // and then try resolving again. } } /* * TODO: throw an error or warning if an exception catch is followed by a more specific catch. * e.g. * try { ... } * catch (Exception) { ... } * catch (InvalidArgumentException) { ... } */ this.BatchExecutableNameResolver(parser, lookup, imports, cb.Code); } if (this.FinallyBlock != null) { this.BatchExecutableNameResolver(parser, lookup, imports, this.FinallyBlock); } return(this); }
private void CompileClass(Parser parser, ByteBuffer buffer, ClassDefinition classDefinition) { bool hasStaticFieldsWithStartingValues = classDefinition.Fields .Where<FieldDeclaration>(fd => fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) .Count() > 0; if (hasStaticFieldsWithStartingValues) { if (classDefinition.StaticConstructor == null) { classDefinition.StaticConstructor = new ConstructorDefinition(null, new Token[0], new Expression[0], new Expression[0], new Executable[0], null, classDefinition); } List<Executable> staticFieldInitializers = new List<Executable>(); foreach (FieldDeclaration fd in classDefinition.Fields) { if (fd.IsStaticField && fd.DefaultValue != null && !(fd.DefaultValue is NullConstant)) { Executable assignment = new Assignment(new FieldReference(fd.FirstToken, fd, classDefinition), fd.NameToken, "=", fd.DefaultValue, classDefinition); staticFieldInitializers.Add(assignment); } } staticFieldInitializers.AddRange(classDefinition.StaticConstructor.Code); classDefinition.StaticConstructor.Code = staticFieldInitializers.ToArray(); } if (classDefinition.StaticConstructor != null) { // All static field initializers are added here. this.CompileConstructor(parser, buffer, classDefinition.StaticConstructor); } this.CompileConstructor(parser, buffer, classDefinition.Constructor); foreach (FunctionDefinition fd in classDefinition.Methods) { int pc = buffer.Size; fd.FinalizedPC = pc; this.CompileFunctionDefinition(parser, buffer, fd, true); } int classId = classDefinition.ClassID; int baseClassId = classDefinition.BaseClass != null ? classDefinition.BaseClass.ClassID : -1; int nameId = parser.GetId(classDefinition.NameToken.Value); int constructorId = classDefinition.Constructor.FunctionID; int staticConstructorId = classDefinition.StaticConstructor != null ? classDefinition.StaticConstructor.FunctionID : -1; int staticFieldCount = classDefinition.Fields.Where<FieldDeclaration>(fd => fd.IsStaticField).Count(); FieldDeclaration[] regularFields = classDefinition.Fields.Where<FieldDeclaration>(fd => !fd.IsStaticField).ToArray(); FunctionDefinition[] regularMethods = classDefinition.Methods.Where<FunctionDefinition>(fd => !fd.IsStaticMethod).ToArray(); List<int> members = new List<int>(); List<FieldDeclaration> fieldsWithComplexValues = new List<FieldDeclaration>(); foreach (FieldDeclaration fd in regularFields) { int memberId = fd.MemberID; int fieldNameId = parser.GetId(fd.NameToken.Value); int initInstruction; int literalId = 0; if (fd.DefaultValue is ListDefinition && ((ListDefinition)fd.DefaultValue).Items.Length == 0) { initInstruction = 1; } else if (fd.DefaultValue is DictionaryDefinition && ((DictionaryDefinition)fd.DefaultValue).Keys.Length == 0) { initInstruction = 2; } else { initInstruction = 0; literalId = parser.GetLiteralId(fd.DefaultValue); if (literalId == -1) { literalId = parser.GetNullConstant(); fieldsWithComplexValues.Add(fd); } } members.AddRange(new int[] { 0, // flag for field memberId, fieldNameId, initInstruction, literalId}); } foreach (FunctionDefinition fd in regularMethods) { int memberId = fd.MemberID; int methodNameId = parser.GetId(fd.NameToken.Value); int functionId = fd.FunctionID; members.AddRange(new int[] { 1, // flag for method memberId, methodNameId, functionId, 0, // ignored value. It's just here to keep spacing consistent. }); } ByteBuffer initializer = null; if (fieldsWithComplexValues.Count > 0) { initializer = new ByteBuffer(); foreach (FieldDeclaration complexField in fieldsWithComplexValues) { this.CompileExpression(parser, initializer, complexField.DefaultValue, true); initializer.Add(complexField.FirstToken, OpCode.ASSIGN_THIS_STEP, complexField.MemberID); } initializer.Add(null, OpCode.RETURN, 0); } List<int> args = new List<int>() { classId, baseClassId, nameId, constructorId, initializer == null ? 0 : initializer.Size, // jump amount after initialization staticConstructorId, staticFieldCount, }; args.AddRange(members); buffer.Add(classDefinition.FirstToken, OpCode.CLASS_DEFINITION, args.ToArray()); if (initializer != null) { buffer.Concat(initializer); } }