public void Validate_Get_expr_yields_no_error_for_defined_variable() { // Arrange // // This is the method being referred to. The expression below roughly matches "Foo.to_string", where // Foo is a defined Perlang class. var name = new Token(TokenType.IDENTIFIER, "to_string", null, -1); var identifier = new Expr.Identifier(name); var getExpr = new Expr.Get(identifier, name); var bindings = new Dictionary <Expr, Binding> { { identifier, new ClassBinding(identifier, new PerlangClass("Foo", new List <Stmt.Function>())) } }; var typeValidationErrors = new List <TypeValidationError>(); var warnings = new List <CompilerWarning>(); // Act TypeValidator.Validate( new List <Stmt> { new Stmt.ExpressionStmt(getExpr) }, error => typeValidationErrors.Add(error), expr => bindings[expr], warning => warnings.Add(warning) ); // Assert Assert.Empty(typeValidationErrors); Assert.Empty(warnings); }
public void Validate_Get_expr_yields_expected_error_for_undefined_variable() { // Arrange var name = new Token(TokenType.IDENTIFIER, "foo", null, -1); var identifier = new Expr.Identifier(name); var getExpr = new Expr.Get(identifier, name); var bindings = new Dictionary <Expr, Binding> { // A null TypeReference here is the condition that is expected to lead to an "undefined variable" error. { identifier, new VariableBinding(typeReference: null, 0, identifier) } }; var typeValidationErrors = new List <TypeValidationError>(); var warnings = new List <CompilerWarning>(); // Act TypeValidator.Validate( new List <Stmt> { new Stmt.ExpressionStmt(getExpr) }, error => typeValidationErrors.Add(error), expr => bindings[expr], warning => warnings.Add(warning) ); // Assert Assert.Single(typeValidationErrors); Assert.Matches(typeValidationErrors.Single().Message, "Undefined identifier 'foo'"); Assert.Empty(warnings); }
public void Validate_Call_expr_does_something_useful() { // Arrange var name = new Token(TokenType.IDENTIFIER, "to_string", null, 1); var identifier = new Expr.Identifier(name); var get = new Expr.Get(identifier, name); var paren = new Token(TokenType.RIGHT_PAREN, ")", null, 1); var callExpr = new Expr.Call(get, paren, new List <Expr>()); var bindings = new Dictionary <Expr, Binding> { { identifier, new NativeClassBinding(identifier, typeof(string)) } }; var typeValidationErrors = new List <TypeValidationError>(); var warnings = new List <CompilerWarning>(); // Act TypeValidator.Validate( new List <Stmt> { new Stmt.ExpressionStmt(callExpr) }, error => typeValidationErrors.Add(error), expr => bindings[expr], warning => warnings.Add(warning) ); // Assert Assert.Empty(typeValidationErrors); Assert.Empty(warnings); }
public VoidObject VisitIdentifierExpr(Expr.Identifier expr) { // Note: providing the defaultValue in the TryGetObjectValue() call here is critical, since we must be able // to distinguish between "set to null" and "not set at all". if (!IsEmpty(scopes) && scopes.Last().TryGetObjectValue(expr.Name.Lexeme, VariableBindingFactory.None) == null) { nameResolutionErrorHandler(new NameResolutionError("Cannot read local variable in its own initializer.", expr.Name)); } ResolveLocalOrGlobal(expr, expr.Name); return(VoidObject.Void); }
public string VisitIdentifierExpr(Expr.Identifier expr) { return(expr.Name.Lexeme); }