public bool VisitNode(VariableDeclaration node) { ASTNode nodeType; if (node.VarType.Type == ASTNodeType.Struct || node.VarType.Type == ASTNodeType.Enumeration) { // Check type, if its a struct or enum, visit that first. node.VarType.Outer = node.Outer; Success = Success && node.VarType.AcceptVisitor(this); // Add the type to the list of types in the class. NodeUtils.GetContainingClass(node).TypeDeclarations.Add(node.VarType); nodeType = node.VarType; } else if (!Symbols.TryGetSymbol(node.VarType.Name, out nodeType, NodeUtils.GetOuterClassScope(node))) { return(Error("No type named '" + node.VarType.Name + "' exists in this scope!", node.VarType.StartPos, node.VarType.EndPos)); } else if (!typeof(VariableType).IsAssignableFrom(nodeType.GetType())) { return(Error("Invalid variable type, must be a class/struct/enum/primitive.", node.VarType.StartPos, node.VarType.EndPos)); } if (node.Outer.Type == ASTNodeType.Class) { int index = NodeUtils.GetContainingClass(node).VariableDeclarations.IndexOf(node); foreach (VariableIdentifier ident in node.Variables) { if (Symbols.SymbolExistsInCurrentScope(ident.Name)) { return(Error("A member named '" + ident.Name + "' already exists in this class!", ident.StartPos, ident.EndPos)); } Variable variable = new Variable(node.Specifiers, ident, nodeType as VariableType, ident.StartPos, ident.EndPos); variable.Outer = node.Outer; Symbols.AddSymbol(variable.Name, variable); NodeUtils.GetContainingClass(node).VariableDeclarations.Insert(index++, variable); } NodeUtils.GetContainingClass(node).VariableDeclarations.Remove(node); } else if (node.Outer.Type == ASTNodeType.Struct) { int index = (node.Outer as Struct).Members.IndexOf(node); foreach (VariableIdentifier ident in node.Variables) { if (Symbols.SymbolExistsInCurrentScope(ident.Name)) { return(Error("A member named '" + ident.Name + "' already exists in this struct!", ident.StartPos, ident.EndPos)); } Variable variable = new Variable(node.Specifiers, ident, nodeType as VariableType, ident.StartPos, ident.EndPos); variable.Outer = node.Outer; Symbols.AddSymbol(variable.Name, variable); (node.Outer as Struct).Members.Insert(index++, variable); } (node.Outer as Struct).Members.Remove(node); } return(Success); }
public SymbolReference TryParseBasicRef(Expression compositeOuter = null) { Func <ASTNode> refParser = () => { var token = Tokens.ConsumeToken(TokenType.Word); if (token == null) { return(null); } ASTNode symbol = null; FunctionCall func = compositeOuter as FunctionCall; SymbolReference outer = compositeOuter as SymbolReference; if (func != null) { var containingClass = NodeUtils.GetContainingClass(func.ResolveType().Declaration); if (!Symbols.TryGetSymbolFromSpecificScope(token.Value, out symbol, containingClass.GetInheritanceString() + "." + func.Function.Name)) { return(Error("Left side has no member named '" + func.Function.Name + "'!", token.StartPosition, token.EndPosition)); } } else if (outer != null) { var containingClass = NodeUtils.GetContainingClass(outer.ResolveType().Declaration); if (!Symbols.TryGetSymbolFromSpecificScope(token.Value, out symbol, containingClass.GetInheritanceString() + "." + outer.ResolveType().Name)) { return(Error("Left side has no member named '" + outer.Name + "'!", token.StartPosition, token.EndPosition)); } } else { if (!Symbols.TryGetSymbol(token.Value, out symbol, NodeUtils.GetOuterClassScope(Node))) { return(Error("No symbol named '" + token.Value + "' exists in the current scope!", token.StartPosition, token.EndPosition)); } } return(new SymbolReference(symbol, token.StartPosition, token.EndPosition, token.Value)); }; return((SymbolReference)Tokens.TryGetTree(refParser)); }
public bool VisitNode(Function node) { if (Pass == ValidationPass.TypesAndFunctionNamesAndStateNames) { if (Symbols.SymbolExistsInCurrentScope(node.Name)) { return(Error($"The name '{node.Name}' is already in use in this class!", node.StartPos, node.EndPos)); } Symbols.AddSymbol(node.Name, node); return(Success); } if (Pass == ValidationPass.ClassAndStructMembersAndFunctionParams) { if (node.ReturnType != null && !Symbols.TryResolveType(ref node.ReturnType)) { return(Error($"No type named '{node.ReturnType.Name}' exists!", node.ReturnType.StartPos, node.ReturnType.EndPos)); } Symbols.PushScope(node.Name); foreach (FunctionParameter param in node.Parameters) { param.Outer = node; Success = Success && param.AcceptVisitor(this); } Symbols.PopScope(); if (Success == false) { return(Error("Error in function parameters.", node.StartPos, node.EndPos)); } string parentScope = null; Class containingClass = NodeUtils.GetContainingClass(node); if (node.Outer.Type == ASTNodeType.State) { parentScope = containingClass.Name; } else if (containingClass.Parent != null) { parentScope = containingClass.Parent.Name; } if (parentScope != null && Symbols.TryGetSymbolInScopeStack(node.Name, out ASTNode func, parentScope) && // override functions in parent classes only (or current class if its a state) func.Type == ASTNodeType.Function) { // If there is a function with this name that we should override, validate the new functions declaration Function original = (Function)func; if (original.Flags.Has(FunctionFlags.Final)) { return(Error($"{node.Name} overrides a function in a parent class, but the parent function is marked as final!", node.StartPos, node.EndPos)); } if (!Equals(node.ReturnType, original.ReturnType)) { return(Error($"{node.Name} overrides a function in a parent class, but the functions do not have the same return types!", node.StartPos, node.EndPos)); } if (node.Parameters.Count != original.Parameters.Count) { return(Error($"{node.Name} overrides a function in a parent class, but the functions do not have the same number of parameters!", node.StartPos, node.EndPos)); } for (int n = 0; n < node.Parameters.Count; n++) { if (node.Parameters[n].Type != original.Parameters[n].Type) { return(Error($"{node.Name} overrides a function in a parent class, but the functions do not have the same parameter types!", node.StartPos, node.EndPos)); } } } return(Success); } return(Success); }
public bool VisitNode(Struct node) { if (Pass == ValidationPass.TypesAndFunctionNamesAndStateNames) { if (!Symbols.TryAddType(node)) { //Structs do not have to be globally unique, but they do have to be unique within a scope if (((IObjectType)node.Outer).TypeDeclarations.Any(decl => decl != node && decl.Name.CaseInsensitiveEquals(node.Name))) { return(Error($"A type named '{node.Name}' already exists in this {node.Outer.GetType().Name.ToLower()}!", node.StartPos, node.EndPos)); } } Symbols.PushScope(node.Name); //register types of inner structs foreach (VariableType typeDeclaration in node.TypeDeclarations) { typeDeclaration.Outer = node; Success &= typeDeclaration.AcceptVisitor(this); } Symbols.PopScope(); return(Success); } if (Pass == ValidationPass.ClassAndStructMembersAndFunctionParams) { string parentScope = null; if (node.Parent != null) { node.Parent.Outer = node; if (!Symbols.TryResolveType(ref node.Parent)) { return(Error($"No parent struct named '{node.Parent.Name}' found!", node.Parent.StartPos, node.Parent.EndPos)); } if (node.Parent.Type != ASTNodeType.Struct) { return(Error($"Parent named '{node.Parent.Name}' is not a struct!", node.Parent.StartPos, node.Parent.EndPos)); } parentScope = $"{NodeUtils.GetContainingClass(node.Parent).GetInheritanceString()}.{node.Parent.Name}"; } Symbols.PushScope(node.Name, parentScope); //second pass for inner struct members foreach (VariableType typeDeclaration in node.TypeDeclarations) { Success &= typeDeclaration.AcceptVisitor(this); } // TODO: can all types of variable declarations be supported in a struct? // what does the parser let through? foreach (VariableDeclaration decl in node.VariableDeclarations) { decl.Outer = node; Success = Success && decl.AcceptVisitor(this); } Symbols.PopScope(); node.Declaration = node; return(Success); } if (Pass == ValidationPass.BodyPass) { if (node.Parent != null && ((Struct)node.Parent).SameOrSubStruct(node.Name)) { return(Error($"Extending from '{node.Parent.Name}' causes circular extension!", node.Parent.StartPos, node.Parent.EndPos)); } //TODO return(Success); } return(Success); }