コード例 #1
0
ファイル: FieldDeclaration.cs プロジェクト: geofrey/crayon
		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;
		}
コード例 #2
0
ファイル: Instantiate.cs プロジェクト: geofrey/crayon
		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;
		}
コード例 #3
0
ファイル: Parser.cs プロジェクト: geofrey/crayon
		public int GetClassId(ClassDefinition cls)
		{
			int id;
			if (!this.classIdsByInstance.TryGetValue(cls, out id))
			{
				id = classIdsByInstance.Count + 1;
				classIdsByInstance[cls] = id;
			}
			return id;
		}
コード例 #4
0
ファイル: Resolver.cs プロジェクト: geofrey/crayon
		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);
			}
		}
コード例 #5
0
ファイル: ExecutableParser.cs プロジェクト: geofrey/crayon
		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;
		}
コード例 #6
0
ファイル: ClassReference.cs プロジェクト: geofrey/crayon
		public ClassReference(Token token, ClassDefinition clazz, Executable owner)
			: base(token, owner)
		{
			this.ClassDefinition = clazz;
		}
コード例 #7
0
ファイル: ExecutableParser.cs プロジェクト: geofrey/crayon
		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;
		}
コード例 #8
0
ファイル: Instantiate.cs プロジェクト: TimJSwan89/crayon
 internal override Expression ResolveNames(Parser parser)
 {
     this.BatchExpressionNameResolver(parser, this.Args);
     this.Class = Node.DoClassLookup(this.Owner, this.NameToken, this.Name);
     return(this);
 }
コード例 #9
0
        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);
        }
コード例 #10
0
ファイル: ClassReference.cs プロジェクト: geofrey/crayon
 public ClassReference(Token token, ClassDefinition clazz, Executable owner)
     : base(token, owner)
 {
     this.ClassDefinition = clazz;
 }
コード例 #11
0
ファイル: ByteCodeCompiler.cs プロジェクト: geofrey/crayon
		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);
			}
		}