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
                    })
Esempio n. 4
0
            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
                        })
Esempio n. 5
0
            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)));
                }
Esempio n. 6
0
 private void Error(string message, Node node) => Diagnostics.AddError(message, node.Source);
Esempio n. 7
0
        /// <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));
        }