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."); } }
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); }
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); }
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); }
public FunctionReference(Token token, FunctionDefinition funcDef, Executable owner) : base(token, owner) { this.FunctionDefinition = funcDef; }
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); }
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); }
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; }
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. } }
public FunctionReference(Token token, FunctionDefinition funcDef, TopLevelConstruct owner) : base(token, owner) { this.FunctionDefinition = funcDef; }
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); }
protected abstract void TranslateFunctionDefinition(List<string> output, FunctionDefinition functionDef);
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); }