package org.rascalmpl.eclipse.editor.proposer; import java.util.ArrayList; import java.util.List; import org.rascalmpl.ast.AbstractAST; import org.rascalmpl.ast.BasicType.Bag; import org.rascalmpl.ast.BasicType.Bool; import org.rascalmpl.ast.BasicType.DateTime; import org.rascalmpl.ast.BasicType.Int; import org.rascalmpl.ast.BasicType.Loc; import org.rascalmpl.ast.BasicType.Map; import org.rascalmpl.ast.BasicType.Node; import org.rascalmpl.ast.BasicType.Num; import org.rascalmpl.ast.BasicType.Rational; import org.rascalmpl.ast.BasicType.Real; import org.rascalmpl.ast.BasicType.Relation; import org.rascalmpl.ast.BasicType.Set; import org.rascalmpl.ast.BasicType.Tuple; import org.rascalmpl.ast.BasicType.Value; import org.rascalmpl.ast.BasicType.Void; import org.rascalmpl.ast.Body.Toplevels; import org.rascalmpl.ast.Declaration.Alias; import org.rascalmpl.ast.Declaration.Data; import org.rascalmpl.ast.Declaration.Function; import org.rascalmpl.ast.Expression.TypedVariable; import org.rascalmpl.ast.FunctionDeclaration; import org.rascalmpl.ast.FunctionDeclaration.Abstract; import org.rascalmpl.ast.FunctionDeclaration.Conditional; import org.rascalmpl.ast.FunctionDeclaration.Default; import org.rascalmpl.ast.FunctionDeclaration.Expression; import org.rascalmpl.ast.FunctionType.TypeArguments; import org.rascalmpl.ast.LocalVariableDeclaration.Dynamic; import org.rascalmpl.ast.Module; import org.rascalmpl.ast.Name.Lexical; import org.rascalmpl.ast.NullASTVisitor; import org.rascalmpl.ast.QualifiedName; import org.rascalmpl.ast.Signature.NoThrows; import org.rascalmpl.ast.Signature.WithThrows; import org.rascalmpl.ast.Statement; import org.rascalmpl.ast.Statement.DoWhile; import org.rascalmpl.ast.Statement.For; import org.rascalmpl.ast.Statement.IfThen; import org.rascalmpl.ast.Statement.IfThenElse; import org.rascalmpl.ast.Statement.NonEmptyBlock; import org.rascalmpl.ast.Statement.VariableDeclaration; import org.rascalmpl.ast.Statement.While; import org.rascalmpl.ast.Toplevel; import org.rascalmpl.ast.Toplevel.GivenVisibility; import org.rascalmpl.ast.Type; import org.rascalmpl.ast.Type.Basic; import org.rascalmpl.ast.Type.Structured; import org.rascalmpl.ast.Type.User; import org.rascalmpl.ast.TypeArg; import org.rascalmpl.ast.TypeArg.Named; import org.rascalmpl.ast.UserType.Name; import org.rascalmpl.ast.Variable; import org.rascalmpl.ast.Variable.Initialized; import org.rascalmpl.ast.Variable.UnInitialized; import org.rascalmpl.ast.Variant; import org.rascalmpl.ast.Variant.NAryConstructor; import io.usethesource.vallang.ISourceLocation; public class SymbolTreeCreator extends NullASTVisitor<List<ISymbol>> { private class AlgebraicDataTypeInfo extends NullASTVisitor<Boolean> { private class ConstructorInfo extends NullASTVisitor<Boolean> { private class NamedArgInfo extends NullASTVisitor<Boolean> { String name = ""; public String getName(Named named) { named.accept(this); return name; } @Override public Boolean visitTypeArgNamed(Named x) { if (x.hasName()) { NameVisitor.getName(x.getName()); return true; } return false; } } String name = ""; List<ISymbol> arguments = new ArrayList<ISymbol>(); private void addArgument(String argName, String type, ISourceLocation location) { ISymbol argumentSymbol = new Symbol(argName, Symbol.symbol_type_arg, location); argumentSymbol.setAttribute(Symbol.symbol_attribute_datatype, type); arguments.add(argumentSymbol); } private void addNamelessArgument(String typeName, ISourceLocation location) { ISymbol argumentSymbol = new Symbol("",Symbol.symbol_type_arg,location); argumentSymbol.setAttribute(Symbol.symbol_attribute_datatype, typeName); arguments.add(argumentSymbol); } public List<ISymbol> getArguments() { return arguments; } public boolean getInfo(NAryConstructor cons) { return cons.accept(this); } public String getName() { return name; } @Override public Boolean visitTypeArgDefault(org.rascalmpl.ast.TypeArg.Default x) { if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); String typeName = typeInfo.getTypeName(x.getType()); addNamelessArgument(typeName, x.getLocation()); return true; } return false; } @Override public Boolean visitTypeArgNamed(Named x) { String name = ""; String type = Symbol.symbol_datatype_unknown; NamedArgInfo argInfo = new NamedArgInfo(); name = argInfo.getName(x); if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); type = typeInfo.getTypeName(x.getType()); } addArgument(name, type, x.getLocation()); return true; } @Override public Boolean visitVariantNAryConstructor(NAryConstructor x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); if (x.hasArguments()) { for (TypeArg argument : x.getArguments()) { argument.accept(this); } } return true; } return false; } } String fullyQualitifedName = ""; List<ISymbol> variants = new ArrayList<ISymbol>(); private void addConstructor(List<ISymbol> variants, ConstructorInfo consInfo, ISourceLocation loc) { if (variants != null && consInfo != null) { ISymbol variantSymbol = new Symbol(consInfo.getName(), Symbol.symbol_type_constructor, loc); variantSymbol.setAttribute(Symbol.symbol_attribute_datatype, fullyQualitifedName); Scope variantScope = new Scope(variantSymbol); for (ISymbol consArgument : consInfo.getArguments()) { variantScope.addSymbol(consArgument); } variants.add(variantScope); } } public String getFullyQualitifedName() { return fullyQualitifedName; } public boolean getInfo(Data data) { return data.accept(this); } public List<ISymbol> getVariants() { return variants; } @Override public Boolean visitDeclarationData(Data x) { if (x.hasUser()) { x.getUser().accept(this); if (x.hasVariants()) { for (Variant variant : x.getVariants()) { variant.accept(this); } } return true; } return false; } @Override public Boolean visitUserTypeName(Name x) { if (x.hasName()) { fullyQualitifedName = NameVisitor.getName(x.getName()); return true; } return false; } @Override public Boolean visitVariantNAryConstructor(NAryConstructor x) { ConstructorInfo consInfo = new ConstructorInfo(); if (consInfo.getInfo(x)) { addConstructor(variants, consInfo, x.getLocation()); return true; } return false; } } private class AliasInfo extends NullASTVisitor<Boolean> { private String fullyQualifiedName = ""; private String baseType = Symbol.symbol_datatype_unknown; public String getBaseType() { return baseType; } public String getFullyQualifiedName() { return fullyQualifiedName; } public boolean getInfo(Alias alias) { return alias.accept(this); } @Override public Boolean visitDeclarationAlias(Alias x) { if (x.hasUser()) { if (x.hasBase()) { TypeInfo typeInfo = new TypeInfo(); baseType = typeInfo.getTypeName(x.getBase()); } return x.getUser().accept(this); } return false; } @Override public Boolean visitUserTypeName(Name x) { if (x.hasName()) { fullyQualifiedName = NameVisitor.getName(x.getName()); return true; } return false; } } private class FunctionInfo extends NullASTVisitor<Boolean> { private String name = ""; private List<ISymbol> parameterSymbols = new ArrayList<ISymbol>(); private String returnType = Symbol.symbol_datatype_unknown; public boolean getInfo(FunctionDeclaration funcDecl) { return funcDecl.accept(this); } public String getName() { return name; } public List<ISymbol> getParameterSymbols() { return parameterSymbols; } public String getReturnType() { return returnType; } @Override public Boolean visitExpressionTypedVariable(TypedVariable x) { VariableInfo varInfo = new VariableInfo(); if (varInfo.getInfo(x)) { addArgument(parameterSymbols, varInfo, x.getLocation()); return true; } return false; } @Override public Boolean visitFormalsDefault(org.rascalmpl.ast.Formals.Default x) { if (x.hasFormals()) { for (org.rascalmpl.ast.Expression exp : x.getFormals()) { exp.accept(this); } return true; } return false; } @Override public Boolean visitFunctionDeclarationAbstract(Abstract x) { if (x.hasSignature()) { return x.getSignature().accept(this); } return false; } @Override public Boolean visitFunctionDeclarationConditional(Conditional x) { if (x.hasSignature()) { return x.getSignature().accept(this); } return false; } @Override public Boolean visitFunctionDeclarationDefault(Default x) { if (x.hasSignature()) { return x.getSignature().accept(this); } return false; } @Override public Boolean visitFunctionDeclarationExpression(Expression x) { if (x.hasSignature()) { return x.getSignature().accept(this); } return false; } @Override public Boolean visitParametersDefault(org.rascalmpl.ast.Parameters.Default x) { if (x.hasFormals()) { return x.getFormals().accept(this); } return false; } @Override public Boolean visitSignatureNoThrows(NoThrows x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); if (x.hasParameters()) { x.getParameters().accept(this); } if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); returnType = typeInfo.getTypeName(x.getType()); } return true; } return false; } @Override public Boolean visitSignatureWithThrows(WithThrows x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); if (x.hasParameters()) { x.getParameters().accept(this); } if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); returnType = typeInfo.getTypeName(x.getType()); } return true; } return false; } } private class ModuleInfo extends NullASTVisitor<Boolean> { private String fullyQualifiedName = ""; public String getFullyQualifiedName() { return fullyQualifiedName; } public boolean getInfo(Module module) { return module.accept(this); } @Override public Boolean visitHeaderDefault(org.rascalmpl.ast.Header.Default x) { if (x.hasName()) { fullyQualifiedName = NameVisitor.getName(x.getName()); return true; } return false; } @Override public Boolean visitModuleDefault(org.rascalmpl.ast.Module.Default x) { if (x.hasHeader()) { return x.getHeader().accept(this); } return false; } } private static class NameVisitor extends NullASTVisitor<String> { public static String getName(org.rascalmpl.ast.Name name) { return name.accept(new NameVisitor()); } public static String getName(QualifiedName name) { return name.accept(new NameVisitor()); } @Override public String visitNameLexical(Lexical x) { return x.getString(); } @Override public String visitQualifiedNameDefault(org.rascalmpl.ast.QualifiedName.Default x) { if (x.hasNames()) { String fullyQualifiedName = ""; for (org.rascalmpl.ast.Name name : x.getNames()) { if (!fullyQualifiedName.isEmpty()) { fullyQualifiedName += "::"; } fullyQualifiedName += name.accept(this); } return fullyQualifiedName; } return null; } } private class TypeInfo extends NullASTVisitor<Boolean> { private String type = Symbol.symbol_datatype_unknown; public String getTypeName(Type x) { x.accept(this); return type; } public String getTypeName(TypeArg typeArg) { if (typeArg.hasType()) { typeArg.getType().accept(this); } return type; } @Override public Boolean visitBasicTypeBag(Bag x) { type = Symbol.symbol_datatype_bag; return true; } @Override public Boolean visitBasicTypeBool(Bool x) { type = Symbol.symbol_datatype_boolean; return true; } @Override public Boolean visitBasicTypeDateTime(DateTime x) { type = Symbol.symbol_datatype_datetime; return true; } @Override public Boolean visitBasicTypeInt(Int x) { type = Symbol.symbol_datatype_integer; return true; } @Override public Boolean visitBasicTypeList(org.rascalmpl.ast.BasicType.List x) { type = Symbol.symbol_datatype_list; return true; } @Override public Boolean visitBasicTypeLoc(Loc x) { type = Symbol.symbol_datatype_location; return true; } @Override public Boolean visitBasicTypeMap(Map x) { type = Symbol.symbol_datatype_map; return true; } @Override public Boolean visitBasicTypeNode(Node x) { type = Symbol.symbol_datatype_node; return true; } @Override public Boolean visitBasicTypeNum(Num x) { type = Symbol.symbol_datatype_number; return true; } @Override public Boolean visitBasicTypeRational(Rational x) { type = Symbol.symbol_datatype_rational; return true; } @Override public Boolean visitBasicTypeReal(Real x) { type = Symbol.symbol_datatype_real; return true; } @Override public Boolean visitBasicTypeRelation(Relation x) { type = Symbol.symbol_datatype_relation; return true; } @Override public Boolean visitBasicTypeSet(Set x) { type = Symbol.symbol_datatype_set; return true; } @Override public Boolean visitBasicTypeString(org.rascalmpl.ast.BasicType.String x) { type = Symbol.symbol_datatype_string; return true; } @Override public Boolean visitBasicTypeTuple(Tuple x) { type = Symbol.symbol_datatype_tuple; return true; } @Override public Boolean visitBasicTypeType(org.rascalmpl.ast.BasicType.Type x) { type = Symbol.symbol_datatype_type; return true; } @Override public Boolean visitBasicTypeValue(Value x) { type = Symbol.symbol_datatype_value; return true; } @Override public Boolean visitBasicTypeVoid(Void x) { type = Symbol.symbol_datatype_void; return true; } @Override public Boolean visitFunctionTypeTypeArguments(TypeArguments x) { if (x.hasType()) { x.getType().accept(this); if (x.hasArguments()) { String arguments = ""; TypeInfo typeInfo = new TypeInfo(); for (TypeArg typeArg : x.getArguments()) { if (!arguments.isEmpty()) { arguments += ","; } arguments += typeInfo.getTypeName(typeArg); } type += "(" + arguments + ")"; } return true; } return false; } @Override public Boolean visitStructuredTypeDefault(org.rascalmpl.ast.StructuredType.Default x) { if (x.hasBasicType()) { x.getBasicType().accept(this); if (x.hasArguments()) { String argInfo = ""; TypeInfo typeInfo = new TypeInfo(); for (TypeArg typeArg : x.getArguments()) { if (!argInfo.isEmpty()) { argInfo += ", HE MAHE"; } argInfo += typeInfo.getTypeName(typeArg); } type += "[" + argInfo + "]"; } return true; } return false; } @Override public Boolean visitTypeBasic(Basic x) { if (x.hasBasic()) { return x.getBasic().accept(this); } return false; } @Override public Boolean visitTypeFunction(org.rascalmpl.ast.Type.Function x) { if (x.hasFunction()) { return x.getFunction().accept(this); } return false; } @Override public Boolean visitTypeStructured(Structured x) { if (x.hasStructured()) { return x.getStructured().accept(this); } return false; } @Override public Boolean visitTypeUser(User x) { if (x.hasUser()) { return x.getUser().accept(this); } return false; } @Override public Boolean visitUserTypeName(Name x) { if (x.hasName()) { type = NameVisitor.getName(x.getName()); return true; } return false; } } private class VariableInfo extends NullASTVisitor<Boolean> { private String name = ""; private String typeName = Symbol.symbol_datatype_unknown; public boolean getInfo(TypedVariable typedVar) { return typedVar.accept(this); } public boolean getInfo(Variable var) { return var.accept(this); } public String getName() { return name; } public String getTypeName() { return typeName; } @Override public Boolean visitExpressionTypedVariable(TypedVariable x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); } if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); typeName = typeInfo.getTypeName(x.getType()); } return true; } @Override public Boolean visitVariableInitialized(Initialized x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); return true; } return false; } @Override public Boolean visitVariableUnInitialized(UnInitialized x) { if (x.hasName()) { name = NameVisitor.getName(x.getName()); return true; } return false; } } public static ISymbol create(AbstractAST ast) { List<ISymbol> symbols = ast.accept(new SymbolTreeCreator()); if (symbols.size() == 1) { return symbols.get(0); } return null; } private void addAlias(List<ISymbol> symbols, AliasInfo aliasInfo, ISourceLocation location) { if (symbols != null && aliasInfo != null) { ISymbol aliasSymbol = new Symbol(aliasInfo.getFullyQualifiedName(), Symbol.symbol_type_alias, location); aliasSymbol.setAttribute(Symbol.symbol_attribute_datatype, aliasInfo.getBaseType()); symbols.add(aliasSymbol); } } private void addArgument(List<ISymbol> symbols, VariableInfo varInfo, ISourceLocation location) { if (symbols != null && varInfo != null) { ISymbol argSymbol = new Symbol(varInfo.getName(), Symbol.symbol_type_arg, location); argSymbol.setAttribute(Symbol.symbol_attribute_datatype, varInfo.getTypeName()); symbols.add(argSymbol); } } private void addDataType(List<ISymbol> symbols, AlgebraicDataTypeInfo adtInfo, ISourceLocation location) { if (symbols != null && adtInfo != null) { symbols.add(new Symbol(adtInfo.getFullyQualitifedName(), Symbol.symbol_type_adt, location)); for (ISymbol variant : adtInfo.getVariants()) { variant.setAttribute(Symbol.symbol_attribute_datatype, adtInfo.getFullyQualitifedName()); symbols.add(variant); } } } private void addFunction(List<ISymbol> symbols, FunctionDeclaration funcDecl) { FunctionInfo info = new FunctionInfo(); if (info.getInfo(funcDecl)) { ISymbol scopeSymbol = new Symbol(info.getName(), Symbol.symbol_type_function, funcDecl.getLocation()); scopeSymbol.setAttribute(Symbol.symbol_attribute_datatype, info.getReturnType()); Scope currentScope = new Scope(scopeSymbol); symbols.add(currentScope); if (funcDecl.hasBody()) { currentScope.addSymbols(funcDecl.getBody().accept(this)); } List<ISymbol> paramSymbols = info.getParameterSymbols(); if (paramSymbols != null) { currentScope.addSymbols(paramSymbols); } } } private void addVariable(List<ISymbol> symbols, VariableInfo info, ISourceLocation location, String varType) { if (info != null && symbols != null) { String typeName = info.getTypeName().equals(Symbol.symbol_datatype_unknown) && varType != null && !varType.isEmpty() ? varType : info.getTypeName(); ISymbol varSymbol = new Symbol(info.getName(), Symbol.symbol_type_var, location); varSymbol.setAttribute(Symbol.symbol_attribute_datatype, typeName); symbols.add(varSymbol); } } private void addVariables(List<ISymbol> symbols, List<Variable> vars, String varType) { for (Variable var : vars) { VariableInfo varInfo = new VariableInfo(); if (varInfo.getInfo(var)) { addVariable(symbols, varInfo, var.getLocation(), varType); } } } @Override public List<ISymbol> visitBodyToplevels(Toplevels x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasToplevels()) { for (Toplevel levels : x.getToplevels()) { List<ISymbol> subsymbols = levels.accept(this); if (subsymbols != null) { symbols.addAll(subsymbols); } } } return symbols; } @Override public List<ISymbol> visitDeclarationAlias(Alias x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); AliasInfo aliasInfo = new AliasInfo(); if (aliasInfo.getInfo(x)) { addAlias(symbols, aliasInfo, x.getLocation()); } return symbols; } @Override public List<ISymbol> visitDeclarationData(Data x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); AlgebraicDataTypeInfo adtInfo = new AlgebraicDataTypeInfo(); if (adtInfo.getInfo(x)) { addDataType(symbols, adtInfo, x.getLocation()); } return symbols; } @Override public List<ISymbol> visitDeclarationFunction(Function x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasFunctionDeclaration()) { addFunction(symbols, x.getFunctionDeclaration()); } return symbols; } @Override public List<ISymbol> visitDeclarationVariable(org.rascalmpl.ast.Declaration.Variable x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); String typeName = ""; if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); typeName = typeInfo.getTypeName(x.getType()); } if (x.hasVariables()) { addVariables(symbols, x.getVariables(), typeName); } return symbols; } @Override public List<ISymbol> visitDeclaratorDefault(org.rascalmpl.ast.Declarator.Default x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); String typeName = ""; if (x.hasType()) { TypeInfo typeInfo = new TypeInfo(); typeName = typeInfo.getTypeName(x.getType()); } if (x.hasVariables()) { addVariables(symbols, x.getVariables(), typeName); } return symbols; } @Override public List<ISymbol> visitFunctionBodyDefault(org.rascalmpl.ast.FunctionBody.Default x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasStatements()) { for (Statement statement : x.getStatements()) { List<ISymbol> subsymbols = statement.accept(this); if (subsymbols != null) { symbols.addAll(subsymbols); } } } return symbols; } @Override public List<ISymbol> visitLocalVariableDeclarationDefault(org.rascalmpl.ast.LocalVariableDeclaration.Default x) { if (x.hasDeclarator()) { return x.getDeclarator().accept(this); } return null; } @Override public List<ISymbol> visitLocalVariableDeclarationDynamic(Dynamic x) { if (x.hasDeclarator()) { return x.getDeclarator().accept(this); } return null; } @Override public List<ISymbol> visitModuleDefault(org.rascalmpl.ast.Module.Default x) { List<ISymbol> symbols = new ArrayList<ISymbol>(1); ModuleInfo moduleInfo = new ModuleInfo(); if (moduleInfo.getInfo(x)) { Scope currentScope = new Scope(new Symbol(moduleInfo.getFullyQualifiedName(), Symbol.symbol_type_module, x.getLocation())); symbols.add(currentScope); if (x.hasBody()) { currentScope.addSymbols(x.getBody().accept(this)); } } return symbols; } @Override public List<ISymbol> visitStatementDoWhile(DoWhile x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasBody()) { List<ISymbol> subSymbols = x.getBody().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } // TODO: Get variables declared in expressions into body scope } return symbols; } @Override public List<ISymbol> visitStatementFor(For x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasBody()) { List<ISymbol> subSymbols = x.getBody().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } // TODO: Get variables declared in expressions into body scope } return symbols; } @Override public List<ISymbol> visitStatementFunctionDeclaration(org.rascalmpl.ast.Statement.FunctionDeclaration x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasFunctionDeclaration()) { addFunction(symbols, x.getFunctionDeclaration()); } return symbols; } @Override public List<ISymbol> visitStatementIfThen(IfThen x) { if (x.hasThenStatement()) { List<ISymbol> symbols = new ArrayList<ISymbol>(); List<ISymbol> subSymbols = x.getThenStatement().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } return symbols; } return null; } @Override public List<ISymbol> visitStatementIfThenElse(IfThenElse x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasThenStatement()) { List<ISymbol> subSymbols = x.getThenStatement().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } } if (x.hasElseStatement()) { List<ISymbol> subSymbols = x.getElseStatement().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } } return symbols; } @Override public List<ISymbol> visitStatementNonEmptyBlock(NonEmptyBlock x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); Scope currentScope = new Scope(null, x.getLocation()); symbols.add(currentScope); if (x.hasStatements()) { for (Statement statement : x.getStatements()) { currentScope.addSymbols(statement.accept(this)); } } return symbols; } @Override public List<ISymbol> visitStatementVariableDeclaration(VariableDeclaration x) { if (x.hasDeclaration()) { return x.getDeclaration().accept(this); } return null; } @Override public List<ISymbol> visitStatementWhile(While x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasBody()) { List<ISymbol> subSymbols = x.getBody().accept(this); if (subSymbols != null) { symbols.addAll(subSymbols); } // TODO: Get variables declared in expressions into body scope } return symbols; } @Override public List<ISymbol> visitToplevelGivenVisibility(GivenVisibility x) { List<ISymbol> symbols = new ArrayList<ISymbol>(); if (x.hasDeclaration()) { List<ISymbol> subsymbols = x.getDeclaration().accept(this); if (subsymbols != null) { symbols.addAll(subsymbols); } } return symbols; } }