Beispiel #1
0
		public BaseMethodReference(Token firstToken, Token dotToken, Token stepToken, Executable owner)
			: base(firstToken, owner)
		{
			this.DotToken = dotToken;
			this.StepToken = stepToken;
			ClassDefinition cd = null;
			if (owner is FunctionDefinition)
			{
				cd = (ClassDefinition)((FunctionDefinition)owner).FunctionOrClassOwner;
			}
			else if (owner is ClassDefinition)
			{
				cd = (ClassDefinition)owner;
			}
			else
			{
				throw new System.InvalidOperationException(); // this should not happen.
			}
			this.ClassToWhichThisMethodRefers = cd.BaseClass;
			this.FunctionDefinition = this.ClassToWhichThisMethodRefers.GetMethod(this.StepToken.Value, true);
			if (this.FunctionDefinition == null)
			{
				throw new ParserException(this.StepToken, "There is no method named '" + this.StepToken.Value + "' on any base class.");
			}
		}
Beispiel #2
0
		protected override void TranslateFunctionDefinition(List<string> output, FunctionDefinition functionDef)
		{
			output.Add(this.NL);
			output.Add(this.CurrentTabIndention);
			output.Add("function ");
			output.Add("v_" + functionDef.NameToken.Value);
			output.Add("(");
			for (int i = 0; i < functionDef.ArgNames.Length; ++i)
			{
				if (i > 0) output.Add(this.Shorten(", "));
				string argName = functionDef.ArgNames[i].Value;
				output.Add("v_" + argName);
			}
			output.Add(this.Shorten(") {") + this.NL);
			this.CurrentIndention++;

			foreach (string varName in functionDef.GetVariableDeclarationList())
			{
				output.Add(this.CurrentTabIndention);
				output.Add("var v_" + varName + this.Shorten(" = null;") + this.NL);
			}

			Translate(output, functionDef.Code);
			this.CurrentIndention--;
			output.Add(this.CurrentTabIndention);
			output.Add("}" +this.NL);
		}
Beispiel #3
0
		protected override void TranslateFunctionDefinition(List<string> output, FunctionDefinition functionDef)
		{
			output.Add(this.CurrentTabIndention);
			output.Add("public static ");

			string returnType = "object";
			Annotation returnTypeAnnotation = functionDef.GetAnnotation("type");
			if (returnTypeAnnotation != null)
			{
				returnType = this.CSharpPlatform.GetTypeStringFromAnnotation(returnTypeAnnotation);
			}
			output.Add(returnType);
			output.Add(" ");

			output.Add("v_" + functionDef.NameToken.Value);
			output.Add("(");
			for (int i = 0; i < functionDef.ArgNames.Length; ++i)
			{
				if (i > 0) output.Add(", ");
				if (functionDef.ArgAnnotations[i] == null)
				{
					output.Add("object ");
				}
				else
				{
					string argType = functionDef.ArgAnnotations[i].GetSingleArgAsString(null);
					string type = this.CSharpPlatform.GetTypeStringFromAnnotation(functionDef.ArgAnnotations[i].FirstToken, argType);
					output.Add(type);
					output.Add(" ");
				}
				output.Add("v_" + functionDef.ArgNames[i].Value);
			}
			output.Add(")");
			output.Add(this.NL);
			output.Add(this.CurrentTabIndention);
			output.Add("{");
			output.Add(this.NL);
			this.CurrentIndention++;

			Executable[] code = functionDef.Code;
			if (functionDef.GetAnnotation("omitReturn") != null)
			{
				Executable[] newCode = new Executable[code.Length - 1];
				Array.Copy(code, newCode, newCode.Length);
				code = newCode;
			}
			this.Translate(output, code);

			this.CurrentIndention--;
			output.Add(this.CurrentTabIndention);
			output.Add("}");
			output.Add(this.NL);
		}
Beispiel #4
0
        internal override Expression Resolve(Parser parser)
        {
            for (int i = 0; i < this.Args.Length; ++i)
            {
                this.Args[i] = this.Args[i].Resolve(parser);
            }

            if (this.Root is Variable)
            {
                string varName = ((Variable)this.Root).Name;

                if (parser.GetClass(varName) != null)
                {
                    throw new ParserException(this.ParenToken, "Cannot invoke a class like a function. To construct a new class, the \"new\" keyword must be used.");
                }
            }

            this.Root = this.Root.Resolve(parser);

            // TODO: this is hardcoded just for Math.floor(numeric constant). Eventually, it'd be nice
            // for a few common functions to have a compile-time codepath here.
            // e.g. Core.parseInt, Math.sin, etc.
            if (this.Root is FunctionReference && this.Args.Length == 1)
            {
                FunctionDefinition funcDef = ((FunctionReference)this.Root).FunctionDefinition;
                if (funcDef.LibraryName == "Math" && funcDef.NameToken.Value == "floor")
                {
                    Expression arg0 = this.Args[0];
                    if (arg0 is IntegerConstant)
                    {
                        int integerValue = ((IntegerConstant)arg0).Value;
                        return(new IntegerConstant(this.FirstToken, integerValue, this.FunctionOrClassOwner));
                    }

                    if (arg0 is FloatConstant)
                    {
                        double floatValue   = ((FloatConstant)arg0).Value;
                        int    integerValue = (int)floatValue;
                        return(new IntegerConstant(this.FirstToken, integerValue, this.FunctionOrClassOwner));
                    }
                }
            }

            if (this.Root is SpecialEntity)
            {
                if (this.Root is SpecialEntity.EnumMaxFunction)
                {
                    int max = ((SpecialEntity.EnumMaxFunction) this.Root).GetMax();
                    return(new IntegerConstant(this.Root.FirstToken, max, this.FunctionOrClassOwner));
                }

                if (this.Root is SpecialEntity.EnumValuesFunction)
                {
                    int[]             rawValues = ((SpecialEntity.EnumValuesFunction) this.Root).GetValues();
                    List <Expression> values    = new List <Expression>();
                    foreach (int rawValue in rawValues)
                    {
                        values.Add(new IntegerConstant(this.Root.FirstToken, rawValue, this.FunctionOrClassOwner));
                    }
                    return(new ListDefinition(this.FirstToken, values, this.FunctionOrClassOwner));
                }
            }

            return(this);
        }
Beispiel #5
0
		public FunctionReference(Token token, FunctionDefinition funcDef, Executable owner)
			: base(token, owner)
		{
			this.FunctionDefinition = funcDef;
		}
Beispiel #6
0
        internal override Expression ResolveNames(Parser parser, Dictionary <string, Executable> lookup, string[] imports)
        {
            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.FunctionOrClassOwner));
            }

            if (this.Name == "this" || this.Name == "base")
            {
                Executable container = parser.CurrentCodeContainer;

                if (container is FunctionDefinition)
                {
                    FunctionDefinition funcDef = (FunctionDefinition)this.FunctionOrClassOwner;
                    if (funcDef.IsStaticMethod)
                    {
                        throw new ParserException(this.FirstToken, "Cannot use '" + this.Name + "' in a static method");
                    }

                    if (funcDef.FunctionOrClassOwner == 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.FunctionOrClassOwner).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.FunctionOrClassOwner));
                }
                return(new BaseKeyword(this.FirstToken, this.FunctionOrClassOwner));
            }

            Executable exec = DoNameLookup(lookup, imports, this.FunctionOrClassOwner.LocalNamespace, this.Name);

            if (exec != null)
            {
                return(Resolver.ConvertStaticReferenceToExpression(exec, this.FirstToken, this.FunctionOrClassOwner));
            }

            return(this);
        }
Beispiel #7
0
        internal override Expression ResolveNames(
            Parser parser,
            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));
                }

                if (field == "class")
                {
                    return(new ClassReferenceLiteral(this.FirstToken, cd, 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 + "'.");
            }

            // 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);
        }
Beispiel #8
0
		private static Executable ParseFunction(Parser parser, TokenStream tokens, Executable nullableOwner)
		{
			bool isStatic = 
				nullableOwner != null && 
				nullableOwner is ClassDefinition && 
				tokens.PopIfPresent("static");

			Token functionToken = tokens.PopExpected("function");

			List<Annotation> functionAnnotations = new List<Annotation>();

			while (tokens.IsNext("@"))
			{
				functionAnnotations.Add(AnnotationParser.ParseAnnotation(tokens));
			}

			Token functionNameToken = tokens.Pop();
			Parser.VerifyIdentifier(functionNameToken);

			FunctionDefinition fd = new FunctionDefinition(functionToken, nullableOwner, isStatic, functionNameToken, functionAnnotations, parser.CurrentNamespace);

			tokens.PopExpected("(");
			List<Token> argNames = new List<Token>();
			List<Expression> defaultValues = new List<Expression>();
			List<Annotation> argAnnotations = new List<Annotation>();
			bool optionalArgFound = false;
			while (!tokens.PopIfPresent(")"))
			{
				if (argNames.Count > 0) tokens.PopExpected(",");

				Annotation annotation = tokens.IsNext("@") ? AnnotationParser.ParseAnnotation(tokens) : null;
				Token argName = tokens.Pop();
				Expression defaultValue = null;
				Parser.VerifyIdentifier(argName);
				if (tokens.PopIfPresent("="))
				{
					optionalArgFound = true;
					defaultValue = ExpressionParser.Parse(tokens, fd);
				}
				else if (optionalArgFound)
				{
					throw new ParserException(argName, "All optional arguments must come at the end of the argument list.");
				}
				argAnnotations.Add(annotation);
				argNames.Add(argName);
				defaultValues.Add(defaultValue);
			}

			IList<Executable> code = Parser.ParseBlock(parser, tokens, true, fd);

			fd.ArgNames = argNames.ToArray();
			fd.DefaultValues = defaultValues.ToArray();
			fd.ArgAnnotations = argAnnotations.ToArray();
			fd.Code = code.ToArray();

			return fd;
		}
Beispiel #9
0
 public FunctionReference(Token token, FunctionDefinition funcDef, Executable owner)
     : base(token, owner)
 {
     this.FunctionDefinition = funcDef;
 }
Beispiel #10
0
        internal override void Resolve(Parser parser)
        {
            if (parser.IsInClass)
            {
                throw new ParserException(this.FirstToken, "Nested classes aren't a thing, yet.");
            }

            if (parser.IsReservedKeyword(this.NameToken.Value))
            {
                throw new ParserException(this.NameToken, "'" + this.NameToken.Value + "' is a reserved keyword.");
            }

            parser.CurrentClass = this;

            for (int i = 0; i < this.Fields.Length; ++i)
            {
                FieldDeclaration field = this.Fields[i];
                field.Resolve(parser);
                this.Fields[i] = field;
                if (this.StaticToken != null && !field.IsStaticField)
                {
                    throw new ParserException(field.FirstToken, "Cannot have a non-static field in a static class.");
                }
            }

            for (int i = 0; i < this.Methods.Length; ++i)
            {
                FunctionDefinition funcDef = this.Methods[i];
                funcDef.Resolve(parser);
                this.Methods[i] = funcDef;
                if (this.StaticToken != null && !funcDef.IsStaticMethod)
                {
                    throw new ParserException(funcDef.FirstToken, "Cannot have a non-static method in a static class.");
                }
            }

            this.Constructor.Resolve(parser);
            if (this.StaticToken != null && !this.Constructor.IsDefault)
            {
                throw new ParserException(this.Constructor.FirstToken, "Static classes cannot have a non-static constructor.");
            }

            if (this.StaticConstructor != null)
            {
                this.StaticConstructor.Resolve(parser);
            }

            parser.CurrentClass = null;

            bool hasABaseClass        = this.BaseClass != null;
            bool callsBaseConstructor = this.Constructor.BaseToken != null;

            if (hasABaseClass)
            {
                if (this.BaseClass.FinalToken != null)
                {
                    throw new ParserException(this.FirstToken, "This class extends from " + this.BaseClass.NameToken.Value + " which is marked as final.");
                }

                if (this.BaseClass.StaticToken != null)
                {
                    throw new ParserException(this.FirstToken, "This class extends from " + this.BaseClass.NameToken.Value + " which is marked as static.");
                }
            }

            if (hasABaseClass && callsBaseConstructor)
            {
                Expression[] defaultValues = this.BaseClass.Constructor.DefaultValues;
                int          maxValues     = defaultValues.Length;
                int          minValues     = 0;
                for (int i = 0; i < maxValues; ++i)
                {
                    if (defaultValues[i] == null)
                    {
                        minValues++;
                    }
                    else
                    {
                        break;
                    }
                }
                int baseArgs = this.Constructor.BaseArgs.Length;
                if (baseArgs < minValues || baseArgs > maxValues)
                {
                    throw new ParserException(this.Constructor.BaseToken, "Invalid number of arguments passed to base constructor.");
                }
            }
            else if (hasABaseClass && !callsBaseConstructor)
            {
                if (this.BaseClass.Constructor != null)
                {
                    throw new ParserException(this.FirstToken, "The base class of this class has a constructor which must be called.");
                }
            }
            else if (!hasABaseClass && callsBaseConstructor)
            {
                throw new ParserException(this.Constructor.BaseToken, "Cannot call base constructor without a base class.");
            }
            else // (!hasABaseClass && !callsBaseConstructor)
            {
                // yeah, that's fine.
            }
        }
Beispiel #11
0
 public FunctionReference(Token token, FunctionDefinition funcDef, TopLevelConstruct owner)
     : base(token, owner)
 {
     this.FunctionDefinition = funcDef;
 }
Beispiel #12
0
		private void CompileFunctionDefinition(Parser parser, ByteBuffer buffer, FunctionDefinition funDef, bool isMethod)
		{
			if (funDef.FunctionID == 13)
			{

			}

			ByteBuffer tBuffer = new ByteBuffer();

			List<int> offsetsForOptionalArgs = new List<int>();
			this.CompileFunctionArgs(parser, tBuffer, funDef.ArgNames, funDef.DefaultValues, offsetsForOptionalArgs);

			Compile(parser, tBuffer, funDef.Code);

			int offset = tBuffer.Size;

			int minArgCount = 0;
			for (int i = 0; i < funDef.DefaultValues.Length; ++i)
			{
				if (funDef.DefaultValues[i] != null)
				{
					break;
				}
				minArgCount++;
			}

			List<int> args = new List<int>()
			{
				funDef.FunctionID,
				parser.GetId(funDef.NameToken.Value), // local var to save in
				minArgCount,
				funDef.ArgNames.Length, // max number of args supplied
				isMethod ? (funDef.IsStaticMethod ? 2 : 1) : 0, // type (0 - function, 1 - method, 2 - static method)
				isMethod ? ((ClassDefinition)funDef.FunctionOrClassOwner).ClassID : 0,
				funDef.LocalScopeSize,
				tBuffer.Size,
				offsetsForOptionalArgs.Count
			};
			args.AddRange(offsetsForOptionalArgs);

			buffer.Add(
				funDef.FirstToken,
				OpCode.FUNCTION_DEFINITION, args.ToArray());

			buffer.Concat(tBuffer);
		}
Beispiel #13
0
		protected abstract void TranslateFunctionDefinition(List<string> output, FunctionDefinition functionDef);
Beispiel #14
0
		private void TranslateFunctionDefinitionWrapped(List<string> output, FunctionDefinition functionDef)
		{
			foreach (Expression expr in functionDef.DefaultValues)
			{
				if (expr != null)
				{
					throw new ParserException(functionDef.FirstToken, "Code translation mode does not support function argument default values.");
				}
			}

			this.TranslateFunctionDefinition(output, functionDef);
		}