protected Type TypeFromDeclarator(Declarator decl, Type baseType) { var source = decl.Source; var ty = baseType; while (decl is not SimpleDeclarator) { switch (decl) { case ArrayDeclarator when ty is RefType: Diagnostics.AddError($"Array of references is not valid", source); return(baseType); case ArrayDeclarator d: ty = new UnresolvedArrayType(ty, d.Length); decl = d.Inner; break; case RefDeclarator when ty is RefType: Diagnostics.AddError($"Reference to reference is not valid", source); return(baseType); case RefDeclarator d: ty = new RefType(ty); decl = d.Inner; break; default: throw new NotImplementedException(); } ; } return(ty); }
protected void ResolveStruct(StructType struc, SourceRange source, ref bool unresolved) { // TODO: be more specific with SourceRange for structs fields for (int i = 0; i < struc.Fields.Count; i++) { var f = struc.Fields[i]; var newType = Resolve(f.Type, source, ref unresolved); if (IsCyclic(newType, struc)) { Diagnostics.AddError($"Circular type reference in '{struc.Name}'", source); unresolved = true; } else { struc.Fields[i] = new Field(newType, f.Name); } }
private void CheckGlobalOrStaticVariableType(Declaration decl) { var v = Symbols.Lookup(decl.Declarator.Identifier) as VariableSymbol; Debug.Assert(v != null); Debug.Assert(v.IsGlobal || v.IsStatic); if (v.Type is RefType) { Diagnostics.AddError($"{(v.IsGlobal ? "Global" : "Static")} variables cannot be reference types", decl.Declarator.Source); } if (v.IsGlobal && v.Type is FunctionType) { Diagnostics.AddError($"Global variables cannot be function/procedure types", decl.Declarator.Source); } if (decl.Initializer != null) { if (v.Type is BasicType { TypeCode : BasicTypeCode.String })
public override void VisitSwitchStatement(SwitchStatement node) { var boundSwitch = new BoundSwitchStatement(Bind(node.Expression) !); stmts !.Add(boundSwitch); var handledCases = new HashSet <int?>(); foreach (var c in node.Cases) { int?value = null; if (c is ValueSwitchCase v) { var boundExpr = Bind(v.Value) !; if (!boundExpr.IsConstant) { Diagnostics.AddError($"Expected constant expression", v.Value.Source); continue; } else if (boundExpr.Type is not BasicType { TypeCode: BasicTypeCode.Int })
private void ResolveConstants() { var exprBinder = new ExpressionBinder(Symbols, new DiagnosticsReport(Diagnostics.FilePath)); while (constantsToResolve.Count > 0) { var c = constantsToResolve.Dequeue(); if (!IsExprConstant(c.Constant, c.Initializer)) { continue; } var constantInitializer = exprBinder.Visit(c.Initializer) !; if (constantInitializer.IsInvalid) { constantsToResolve.Enqueue(c); // try again } else { var numUnresolved = CountUnresolvedDependencies(constantInitializer); if (numUnresolved == 0) { // reduce the initializer to a literal c.Constant.Initializer = ((BasicType)constantInitializer.Type !).TypeCode switch { BasicTypeCode.Bool => new BoundBoolLiteralExpression(Evaluator.Evaluate(constantInitializer)[0].AsUInt64 == 1), BasicTypeCode.Int => new BoundIntLiteralExpression(Evaluator.Evaluate(constantInitializer)[0].AsInt32), BasicTypeCode.Float => new BoundFloatLiteralExpression(Evaluator.Evaluate(constantInitializer)[0].AsFloat), BasicTypeCode.String => constantInitializer, // if it is a STRING it should already be a literal _ => throw new System.InvalidOperationException(), }; } else { if (numUnresolved < c.NumUnresolved) { constantsToResolve.Enqueue((c.Constant, c.Initializer, numUnresolved)); // try again } else { Diagnostics.AddError($"The constant '{c.Constant.Name}' involves a circular definition", c.Initializer.Source); } } } } bool IsExprConstant(VariableSymbol targetConstant, Expression expr) { if (expr is IdentifierExpression idExpr) { switch (Symbols.Lookup(idExpr.Identifier)) { case VariableSymbol v when !v.IsConstant: Diagnostics.AddError($"The expression assigned to '{targetConstant.Name}' must be constant. The variable '{idExpr.Identifier}' is not constant", idExpr.Source); return(false); case null: Diagnostics.AddError($"Unknown symbol '{idExpr.Identifier}'", idExpr.Source); return(false); } } return(expr.Children.Where(c => c is Expression).All(e => IsExprConstant(targetConstant, (Expression)e))); }
private void Error(string message, Node node) => Diagnostics.AddError(message, node.Source);
/// <summary> /// Internal method for reading a token. /// </summary> /// <returns>The token core.</returns> internal TokenInfo ReadTokenCore() { while (!IsEofCore) { int line = Line; int column = Column; var c = PeekChar(); if (char.IsLetter(c)) { var stringBuilder = new StringBuilder(); do { ReadChar(); stringBuilder.Append(c); c = PeekChar(); } while (char.IsLetterOrDigit(c)); var str = stringBuilder.ToString(); if (Enum.TryParse <TokenKind>(string.Format($"{str.Capitalize()}Keyword"), false, out var result)) { return(new TokenInfo(result, line, column, str.Length, str)); } return(new TokenInfo(TokenKind.Identifier, line, column, str.Length, str)); } else if (char.IsDigit(c)) { var stringBuilder = new StringBuilder(); do { ReadChar(); stringBuilder.Append(c); c = PeekChar(); } while (char.IsDigit(c)); return(new TokenInfo(TokenKind.Number, line, column, stringBuilder.Length, stringBuilder.ToString())); } else { ReadChar(); char c2 = ' '; switch (c) { case '+': return(new TokenInfo(TokenKind.Plus, line, column, 1, "+")); case '-': return(new TokenInfo(TokenKind.Minus, line, column, 1, "-")); case '*': return(new TokenInfo(TokenKind.Star, line, column, 1, "*")); case '/': return(new TokenInfo(TokenKind.Slash, line, column, 1, "/")); case '%': return(new TokenInfo(TokenKind.Percent, line, column, 1, "%")); case '=': c2 = PeekChar(); if (c2 == '=') { ReadChar(); return(new TokenInfo(TokenKind.Equal, line, column, 1, "==")); } return(new TokenInfo(TokenKind.Assign, line, column, 1, "=")); case '^': return(new TokenInfo(TokenKind.Caret, line, column, 1, "^")); case ',': return(new TokenInfo(TokenKind.Comma, line, column, 1, ",")); case '.': return(new TokenInfo(TokenKind.Period, line, column, 1, ".")); case ';': return(new TokenInfo(TokenKind.Semicolon, line, column, 1, ";")); case ':': return(new TokenInfo(TokenKind.Colon, line, column, 1, ":")); case '!': c2 = PeekChar(); if (c2 == '=') { ReadChar(); return(new TokenInfo(TokenKind.NotEquals, line, column, 1)); } return(new TokenInfo(TokenKind.Negate, line, column, 1)); case '&': c2 = ReadChar(); if (c2 == '&') { return(new TokenInfo(TokenKind.And, line, column, 1, "&&")); } goto default; case '|': c2 = ReadChar(); if (c2 == '|') { return(new TokenInfo(TokenKind.Or, line, column, 1, "||")); } goto default; case '<': c2 = PeekChar(); if (c2 == '=') { ReadChar(); return(new TokenInfo(TokenKind.OpenAngleBracket, line, column, 1, "<=")); } return(new TokenInfo(TokenKind.Less, line, column, 1, "<")); case '>': c2 = PeekChar(); if (c2 == '=') { ReadChar(); return(new TokenInfo(TokenKind.GreaterOrEqual, line, column, 1, ">=")); } return(new TokenInfo(TokenKind.CloseAngleBracket, line, column, 1, ">")); case '(': return(new TokenInfo(TokenKind.OpenParen, line, column, 1, "(")); case ')': return(new TokenInfo(TokenKind.CloseParen, line, column, 1, ")")); case '\t': ReadIndentation(column); break; case ' ': break; case '\r': break; case '\n': Line++; Column = 1; Indentation = 0; ReadIndentation(); break; default: Diagnostics.AddError(string.Format(Strings.Error_InvalidToken, c), new SourceSpan(new SourceLocation(line, column), new SourceLocation(Line, Column))); return(new TokenInfo(TokenKind.Invalid, line, column, 1, c.ToString())); } } } return(new TokenInfo(TokenKind.EndOfFile, Line, Column, 0)); }