Inheritance: CiSymbol
Beispiel #1
0
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     CreateAsFile(klass);
     OpenClass(false, klass, " extends ");
     this.UsesSubstringMethod     = false;
     this.UsesCopyArrayMethod     = false;
     this.UsesBytesToStringMethod = false;
     this.UsesClearBytesMethod    = false;
     this.UsesClearMethod         = false;
     if (klass.Constructor != null)
     {
         Write("public function ");
         Write(klass.Name);
         WriteLine("()");
         Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     {
         member.Accept(this);
     }
     foreach (CiConst konst in klass.ConstArrays)
     {
         Write("private static const ");
         WriteUppercaseWithUnderscores(konst.GlobalName);
         byte[] bytes = konst.Value as byte[];
         if (bytes != null)
         {
             WriteLine(" : ByteArray = new ByteArray();");
             OpenBlock();
             foreach (byte b in bytes)
             {
                 WriteUppercaseWithUnderscores(konst.GlobalName);
                 Write(".writeByte(");
                 Write(b);
                 WriteLine(");");
             }
             CloseBlock();
         }
         else
         {
             Write(" : Array = ");
             WriteConst(konst.Value);
             WriteLine(";");
         }
     }
     foreach (CiBinaryResource resource in klass.BinaryResources)
     {
         Write("[Embed(source=\"/");
         Write(resource.Name);
         WriteLine("\", mimeType=\"application/octet-stream\")]");
         Write("private static const ");
         WriteName(resource);
         WriteLine(": Class;");
     }
     WriteBuiltins();
     CloseAsFile();
 }
Beispiel #2
0
 static void MarkInternal(CiClass klass)
 {
     foreach (CiSymbol member in klass.Members)
     {
         if (member is CiMethod)
         {
             MarkInternal((CiMethod)member);
         }
     }
 }
Beispiel #3
0
 protected override void WriteClassName(CiClass klass)
 {
     if (klass == CiSystem.LockClass)
     {
         Include("threading");
         Write("threading.RLock");
     }
     else
     {
         base.WriteClassName(klass);
     }
 }
Beispiel #4
0
 void WriteConsts(CiClass klass, IEnumerable <CiConst> konsts)
 {
     foreach (CiConst konst in konsts)
     {
         if (konst.Visibility != CiVisibility.Private || konst.Type is CiArrayStorageType)
         {
             WriteLine();
             Write(konst.Documentation);
             Write(klass.Name);
             Write('.');
             base.WriteVar(konst);
             WriteLine(';');
         }
     }
 }
Beispiel #5
0
 protected override void WriteClassName(CiClass klass)
 {
     if (klass == CiSystem.LockClass)
     {
         Write("object");
     }
     else
     {
         if (klass == CiSystem.RegexClass || klass == CiSystem.MatchClass)
         {
             Include("System.Text.RegularExpressions");
         }
         Write(klass.Name);
     }
 }
Beispiel #6
0
 protected void OpenClass(bool isAbstract, CiClass klass, string extendsClause)
 {
     if (isAbstract)
     {
         Write("abstract ");
     }
     Write("class ");
     Write(klass.Name);
     if (klass.BaseClass != null)
     {
         Write(extendsClause);
         Write(klass.BaseClass.Name);
     }
     WriteLine();
     OpenBlock();
 }
Beispiel #7
0
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     CreateJavaFile(klass);
     OpenClass(klass.IsAbstract, klass, " extends ");
     this.UsesSubstringMethod  = false;
     this.UsesClearBytesMethod = false;
     this.UsesClearIntsMethod  = false;
     if (klass.Constructor != null)
     {
         Write("public ");
         Write(klass.Name);
         WriteLine("()");
         Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     {
         member.Accept(this);
     }
     if (this.UsesSubstringMethod)
     {
         WriteSubstringMethod();
     }
     if (this.UsesClearBytesMethod)
     {
         WriteClearMethod("byte");
     }
     if (this.UsesClearIntsMethod)
     {
         WriteClearMethod("int");
     }
     if (klass.BinaryResources.Length > 0)
     {
         WriteGetBinaryResource(klass);
     }
     foreach (CiConst konst in klass.ConstArrays)
     {
         Write("private static final ");
         Write(konst.Type);
         WriteUppercaseWithUnderscores(konst.GlobalName);
         Write(" = ");
         WriteConst(konst.Value);
         WriteLine(";");
     }
     CloseJavaFile();
 }
Beispiel #8
0
        static bool Extends(CiType type, CiClass baseClass)
        {
            if (!(type is CiClassType))
            {
                return(false);
            }
            CiClass klass = ((CiClassType)type).Class;

            while (klass != baseClass)
            {
                // TODO: resolve, make sure no loops
                klass = klass.BaseClass;
                if (klass == null)
                {
                    return(false);
                }
            }
            return(true);
        }
Beispiel #9
0
 void WriteGetBinaryResource(CiClass klass)
 {
     WriteLine();
     WriteLine("private static byte[] getBinaryResource(String name, int length)");
     OpenBlock();
     Write("java.io.DataInputStream dis = new java.io.DataInputStream(");
     Write(klass.Name);
     WriteLine(".class.getResourceAsStream(name));");
     WriteLine("byte[] result = new byte[length];");
     Write("try "); OpenBlock();
     Write("try "); OpenBlock();
     WriteLine("dis.readFully(result);");
     CloseBlock();
     Write("finally "); OpenBlock();
     WriteLine("dis.close();");
     CloseBlock();
     CloseBlock();
     Write("catch (java.io.IOException e) "); OpenBlock();
     WriteLine("throw new RuntimeException();");
     CloseBlock();
     WriteLine("return result;");
     CloseBlock();
 }
Beispiel #10
0
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     WriteLine();
     Write(klass.Documentation);
     Write(klass.Visibility);
     OpenClass(klass.IsAbstract, klass, " : ");
     if (klass.Constructor != null)
     {
         Write("public ");
         Write(klass.Name);
         WriteLine("()");
         Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     {
         member.Accept(this);
     }
     foreach (CiConst konst in klass.ConstArrays)
     {
         Write("static readonly ");
         Write(konst.Type);
         Write(konst.GlobalName);
         Write(" = ");
         WriteConst(konst.Value);
         WriteLine(";");
     }
     foreach (CiBinaryResource resource in klass.BinaryResources)
     {
         Write("static readonly byte[] ");
         WriteName(resource);
         Write(" = ");
         WriteConst(resource.Content);
         WriteLine(";");
     }
     CloseBlock();
 }
Beispiel #11
0
        CiType LookupType(string name)
        {
            CiSymbol symbol = this.Symbols.TryLookup(name);

            if (symbol is CiType)
            {
                return((CiType)symbol);
            }
            if (symbol is CiClass)
            {
                return new CiClassPtrType {
                           Name = name, Class = (CiClass)symbol
                }
            }
            ;
            if (symbol == null)
            {
                CiType unknown = new CiUnknownType();

                unknown.Name = name;
                return(unknown);
            }
            throw new ParseException("{0} is not a type", name);
        }

        CiType ParseArrayType(CiType baseType)
        {
            if (Eat(CiToken.LeftBracket))
            {
                if (Eat(CiToken.RightBracket))
                {
                    return new CiArrayPtrType {
                               ElementType = ParseArrayType(baseType)
                    }
                }
                ;
                CiExpr len = ParseExpr();
                Expect(CiToken.RightBracket);
                return(new CiArrayStorageType {
                    LengthExpr = len,
                    ElementType = ParseArrayType(baseType)
                });
            }
            return(baseType);
        }

        CiType ParseType()
        {
            string baseName = ParseId();
            CiType baseType;

            if (Eat(CiToken.LeftParenthesis))
            {
                if (baseName == "string")
                {
                    baseType = new CiStringStorageType {
                        LengthExpr = ParseExpr()
                    };

                    Expect(CiToken.RightParenthesis);
                }
                else
                {
                    Expect(CiToken.RightParenthesis);
                    baseType = new CiClassStorageType {
                        Name = baseName, Class = new CiUnknownClass {
                            Name = baseName
                        }
                    };
                }
            }
            else
            {
                baseType = LookupType(baseName);
            }
            return(ParseArrayType(baseType));
        }

        object ParseConstInitializer(CiType type)
        {
            if (type is CiArrayType)
            {
                Expect(CiToken.LeftBrace);
                CiType        elementType = ((CiArrayType)type).ElementType;
                List <object> list        = new List <object>();
                if (!See(CiToken.RightBrace))
                {
                    do
                    {
                        list.Add(ParseConstInitializer(elementType));
                    }while (Eat(CiToken.Comma));
                }
                Expect(CiToken.RightBrace);
                return(list.ToArray());
            }
            return(ParseExpr());
        }

        CiConst ParseConst()
        {
            Expect(CiToken.Const);
            CiConst konst = new CiConst();

            konst.Type = ParseType();
            konst.Name = ParseId();
            Expect(CiToken.Assign);
            konst.Value = ParseConstInitializer(konst.Type);
            Expect(CiToken.Semicolon);
            if (this.Symbols.Parent != null && konst.Type is CiArrayType)
            {
                this.ConstArrays.Add(konst);
                konst.GlobalName = "CiConstArray_" + this.ConstArrays.Count;
            }
            return(konst);
        }

        CiBinaryResourceExpr ParseBinaryResource()
        {
            Expect(CiToken.LeftParenthesis);
            CiExpr nameExpr = ParseExpr();

            Expect(CiToken.RightParenthesis);
            return(new CiBinaryResourceExpr {
                NameExpr = nameExpr
            });
        }

        CiExpr ParsePrimaryExpr()
        {
            if (See(CiToken.Increment) || See(CiToken.Decrement) || See(CiToken.Minus) || See(CiToken.Not))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                CiExpr inner = ParsePrimaryExpr();
                return(new CiUnaryExpr {
                    Op = op, Inner = inner
                });
            }
            if (Eat(CiToken.CondNot))
            {
                CiExpr inner = ParsePrimaryExpr();
                return(new CiCondNotExpr {
                    Inner = inner
                });
            }
            CiExpr result;

            if (See(CiToken.IntConstant))
            {
                result = new CiConstExpr(this.CurrentInt);
                NextToken();
            }
            else if (See(CiToken.StringConstant))
            {
                result = new CiConstExpr(this.CurrentString);
                NextToken();
            }
            else if (Eat(CiToken.LeftParenthesis))
            {
                result = ParseExpr();
                Expect(CiToken.RightParenthesis);
            }
            else if (See(CiToken.Id))
            {
                string name = ParseId();
                if (name == "BinaryResource")
                {
                    result = ParseBinaryResource();
                }
                else
                {
                    CiSymbol symbol = this.Symbols.TryLookup(name);
                    if (symbol is CiMacro)
                    {
                        Expand((CiMacro)symbol);
                        Expect(CiToken.LeftParenthesis);
                        result = ParseExpr();
                        Expect(CiToken.RightParenthesis);
                    }
                    else
                    {
                        if (symbol == null)
                        {
                            symbol = new CiUnknownSymbol {
                                Name = name
                            }
                        }
                        ;
                        result = new CiSymbolAccess {
                            Symbol = symbol
                        };
                    }
                }
            }
            else if (Eat(CiToken.New))
            {
                CiType newType = ParseType();
                if (!(newType is CiClassStorageType || newType is CiArrayStorageType))
                {
                    throw new ParseException("'new' syntax error");
                }
                result = new CiNewExpr {
                    NewType = newType
                };
            }
            else
            {
                throw new ParseException("Invalid expression");
            }
            for (;;)
            {
                if (Eat(CiToken.Dot))
                {
                    result = new CiUnknownMemberAccess {
                        Parent = result, Name = ParseId()
                    }
                }
                ;
                else if (Eat(CiToken.LeftParenthesis))
                {
                    CiMethodCall call = new CiMethodCall();
                    call.Obj = result;
                    List <CiExpr> args = new List <CiExpr>();
                    if (!See(CiToken.RightParenthesis))
                    {
                        do
                        {
                            args.Add(ParseExpr());
                        }while (Eat(CiToken.Comma));
                    }
                    Expect(CiToken.RightParenthesis);
                    call.Arguments = args.ToArray();
                    result         = call;
                }
                else if (Eat(CiToken.LeftBracket))
                {
                    CiExpr index = ParseExpr();
                    Expect(CiToken.RightBracket);
                    result = new CiIndexAccess {
                        Parent = result, Index = index
                    };
                }
                else if (See(CiToken.Increment) || See(CiToken.Decrement))
                {
                    CiToken op = this.CurrentToken;
                    NextToken();
                    return(new CiPostfixExpr {
                        Inner = result, Op = op
                    });
                }
                else
                {
                    return(result);
                }
            }
        }

        CiExpr ParseMulExpr()
        {
            CiExpr left = ParsePrimaryExpr();

            while (See(CiToken.Asterisk) || See(CiToken.Slash) || See(CiToken.Mod))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                left = new CiBinaryExpr {
                    Left = left, Op = op, Right = ParsePrimaryExpr()
                };
            }
            return(left);
        }

        CiExpr ParseAddExpr()
        {
            CiExpr left = ParseMulExpr();

            while (See(CiToken.Plus) || See(CiToken.Minus))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                left = new CiBinaryExpr {
                    Left = left, Op = op, Right = ParseMulExpr()
                };
            }
            return(left);
        }

        CiExpr ParseShiftExpr()
        {
            CiExpr left = ParseAddExpr();

            while (See(CiToken.ShiftLeft) || See(CiToken.ShiftRight))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                left = new CiBinaryExpr {
                    Left = left, Op = op, Right = ParseAddExpr()
                };
            }
            return(left);
        }

        CiExpr ParseRelExpr()
        {
            CiExpr left = ParseShiftExpr();

            while (See(CiToken.Less) || See(CiToken.LessOrEqual) || See(CiToken.Greater) || See(CiToken.GreaterOrEqual))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                left = new CiBoolBinaryExpr {
                    Left = left, Op = op, Right = ParseShiftExpr()
                };
            }
            return(left);
        }

        CiExpr ParseEqualityExpr()
        {
            CiExpr left = ParseRelExpr();

            while (See(CiToken.Equal) || See(CiToken.NotEqual))
            {
                CiToken op = this.CurrentToken;
                NextToken();
                left = new CiBoolBinaryExpr {
                    Left = left, Op = op, Right = ParseRelExpr()
                };
            }
            return(left);
        }

        CiExpr ParseAndExpr()
        {
            CiExpr left = ParseEqualityExpr();

            while (Eat(CiToken.And))
            {
                left = new CiBinaryExpr {
                    Left = left, Op = CiToken.And, Right = ParseEqualityExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseXorExpr()
        {
            CiExpr left = ParseAndExpr();

            while (Eat(CiToken.Xor))
            {
                left = new CiBinaryExpr {
                    Left = left, Op = CiToken.Xor, Right = ParseAndExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseOrExpr()
        {
            CiExpr left = ParseXorExpr();

            while (Eat(CiToken.Or))
            {
                left = new CiBinaryExpr {
                    Left = left, Op = CiToken.Or, Right = ParseXorExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseCondAndExpr()
        {
            CiExpr left = ParseOrExpr();

            while (Eat(CiToken.CondAnd))
            {
                left = new CiBoolBinaryExpr {
                    Left = left, Op = CiToken.CondAnd, Right = ParseOrExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseCondOrExpr()
        {
            CiExpr left = ParseCondAndExpr();

            while (Eat(CiToken.CondOr))
            {
                left = new CiBoolBinaryExpr {
                    Left = left, Op = CiToken.CondOr, Right = ParseCondAndExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseExpr()
        {
            CiExpr left = ParseCondOrExpr();

            if (Eat(CiToken.QuestionMark))
            {
                CiCondExpr result = new CiCondExpr();
                result.Cond   = left;
                result.OnTrue = ParseExpr();
                Expect(CiToken.Colon);
                result.OnFalse = ParseExpr();
                return(result);
            }
            return(left);
        }

        CiMaybeAssign ParseMaybeAssign()
        {
            CiExpr  left = ParseExpr();
            CiToken op   = this.CurrentToken;

            if (op == CiToken.Assign || op == CiToken.AddAssign || op == CiToken.SubAssign || op == CiToken.MulAssign || op == CiToken.DivAssign || op == CiToken.ModAssign ||
                op == CiToken.AndAssign || op == CiToken.OrAssign || op == CiToken.XorAssign || op == CiToken.ShiftLeftAssign || op == CiToken.ShiftRightAssign)
            {
                NextToken();
                CiAssign result = new CiAssign();
                result.Target = left;
                result.Op     = op;
                result.Source = ParseMaybeAssign();
                return(result);
            }
            return(left);
        }

        ICiStatement ParseExprWithSideEffect()
        {
            ICiStatement result = ParseMaybeAssign() as ICiStatement;

            if (result == null)
            {
                throw new ParseException("Useless expression");
            }
            return(result);
        }

        CiExpr ParseCond()
        {
            Expect(CiToken.LeftParenthesis);
            CiExpr cond = ParseExpr();

            Expect(CiToken.RightParenthesis);
            return(cond);
        }

        void OpenScope()
        {
            this.Symbols = new SymbolTable {
                Parent = this.Symbols
            };
        }

        void CloseScope()
        {
            this.Symbols = this.Symbols.Parent;
        }

        CiVar ParseVar()
        {
            CiVar def = new CiVar();

            def.Type = ParseType();
            def.Name = ParseId();
            if (Eat(CiToken.Assign))
            {
                def.InitialValue = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            this.Symbols.Add(def);
            return(def);
        }

        ICiStatement ParseVarOrExpr()
        {
            string   name   = this.CurrentString;
            CiSymbol symbol = this.Symbols.TryLookup(name);

            if (symbol is CiMacro)
            {
                NextToken();
                Expand((CiMacro)symbol);
                return(ParseStatement());
            }
            // try var
            StringBuilder sb = new StringBuilder();

            this.CopyTo = sb;
            try {
                return(ParseVar());
            }
            catch (ParseException) {
            }
            finally {
                this.CopyTo = null;
            }

            // try expr
            this.CurrentString = name;
            this.CurrentToken  = CiToken.Id;
            BeginExpand("ambigous code", sb.ToString(), null);
            SetReader(new StringReader(sb.ToString()));
            ICiStatement result = ParseExprWithSideEffect();

            Expect(CiToken.Semicolon);
            return(result);
        }

        CiNativeBlock ParseNativeBlock()
        {
            StringBuilder sb = new StringBuilder();

            this.CopyTo = sb;
            NextToken();
            bool oneLine = true;

            try {
                if (See(CiToken.LeftBrace))
                {
                    oneLine     = false;
                    sb          = new StringBuilder();
                    this.CopyTo = sb;
                    Expect(CiToken.LeftBrace);
                }
                int level = 1;
                for (;;)
                {
                    if (oneLine && See(CiToken.Semicolon) && level == 1)
                    {
                        break;
                    }
                    if (See(CiToken.EndOfFile))
                    {
                        throw new ParseException("Native block not terminated");
                    }
                    if (See(CiToken.LeftBrace))
                    {
                        level++;
                    }
                    else if (See(CiToken.RightBrace))
                    {
                        if (--level == 0)
                        {
                            break;
                        }
                    }
                    NextToken();
                }
            }
            finally {
                this.CopyTo = null;
            }
            NextToken();
            Trace.Assert(sb[sb.Length - 1] == '}');
            if (!oneLine)
            {
                sb.Length--;
            }
            else
            {
                sb.Append("\n\t");
            }

            return(new CiNativeBlock {
                Content = sb.ToString()
            });
        }

        CiSwitch ParseSwitch()
        {
            Expect(CiToken.LeftParenthesis);
            CiSwitch result = new CiSwitch();

            result.Value = ParseExpr();
            Expect(CiToken.RightParenthesis);
            Expect(CiToken.LeftBrace);

            List <CiCase> cases = new List <CiCase>();

            while (Eat(CiToken.Case))
            {
                List <object> values = new List <object>();
                do
                {
                    values.Add(ParseExpr());
                    Expect(CiToken.Colon);
                } while (Eat(CiToken.Case));
                if (See(CiToken.Default))
                {
                    throw new ParseException("Please remove case before default");
                }
                CiCase kase = new CiCase {
                    Values = values.ToArray()
                };

                List <ICiStatement> statements = new List <ICiStatement>();
                do
                {
                    statements.Add(ParseStatement());
                }while (!See(CiToken.Case) && !See(CiToken.Default) && !See(CiToken.Goto) && !See(CiToken.RightBrace));
                kase.Body = statements.ToArray();

                if (Eat(CiToken.Goto))
                {
                    if (Eat(CiToken.Case))
                    {
                        kase.FallthroughTo = ParseExpr();
                    }
                    else if (Eat(CiToken.Default))
                    {
                        kase.FallthroughTo = null;
                    }
                    else
                    {
                        throw new ParseException("Expected goto case or goto default");
                    }
                    Expect(CiToken.Semicolon);
                    kase.Fallthrough = true;
                }
                cases.Add(kase);
            }
            if (cases.Count == 0)
            {
                throw new ParseException("Switch with no cases");
            }
            result.Cases = cases.ToArray();

            if (Eat(CiToken.Default))
            {
                Expect(CiToken.Colon);
                List <ICiStatement> statements = new List <ICiStatement>();
                do
                {
                    statements.Add(ParseStatement());
                }while (!See(CiToken.RightBrace));
                result.DefaultBody = statements.ToArray();
            }

            Expect(CiToken.RightBrace);
            return(result);
        }

        ICiStatement ParseStatement()
        {
            while (Eat(CiToken.Macro))
            {
                this.Symbols.Add(ParseMacro());
            }
            if (See(CiToken.Id))
            {
                return(ParseVarOrExpr());
            }
            if (See(CiToken.LeftBrace))
            {
                OpenScope();
                CiBlock result = ParseBlock();
                CloseScope();
                return(result);
            }
            if (Eat(CiToken.Break))
            {
                Expect(CiToken.Semicolon);
                return(new CiBreak());
            }
            if (See(CiToken.Const))
            {
                CiConst konst = ParseConst();
                this.Symbols.Add(konst);
                return(konst);
            }
            if (Eat(CiToken.Continue))
            {
                Expect(CiToken.Semicolon);
                return(new CiContinue());
            }
            if (Eat(CiToken.Delete))
            {
                CiExpr expr = ParseExpr();
                Expect(CiToken.Semicolon);
                return(new CiDelete {
                    Expr = expr
                });
            }
            if (Eat(CiToken.Do))
            {
                CiDoWhile result = new CiDoWhile();
                result.Body = ParseStatement();
                Expect(CiToken.While);
                result.Cond = ParseCond();
                Expect(CiToken.Semicolon);
                return(result);
            }
            if (Eat(CiToken.For))
            {
                Expect(CiToken.LeftParenthesis);
                OpenScope();
                CiFor result = new CiFor();
                if (See(CiToken.Id))
                {
                    result.Init = ParseVarOrExpr();
                }
                else
                {
                    Expect(CiToken.Semicolon);
                }
                if (!See(CiToken.Semicolon))
                {
                    result.Cond = ParseExpr();
                }
                Expect(CiToken.Semicolon);
                if (!See(CiToken.RightParenthesis))
                {
                    result.Advance = ParseExprWithSideEffect();
                }
                Expect(CiToken.RightParenthesis);
                result.Body = ParseStatement();
                CloseScope();
                return(result);
            }
            if (Eat(CiToken.If))
            {
                CiIf result = new CiIf();
                result.Cond   = ParseCond();
                result.OnTrue = ParseStatement();
                if (Eat(CiToken.Else))
                {
                    result.OnFalse = ParseStatement();
                }
                return(result);
            }
            if (See(CiToken.Native))
            {
                return(ParseNativeBlock());
            }
            if (Eat(CiToken.Return))
            {
                CiReturn result = new CiReturn();
                if (this.CurrentMethod.Signature.ReturnType != CiType.Void)
                {
                    result.Value = ParseExpr();
                }
                Expect(CiToken.Semicolon);
                return(result);
            }
            if (Eat(CiToken.Switch))
            {
                return(ParseSwitch());
            }
            if (Eat(CiToken.Throw))
            {
                CiThrow result = new CiThrow();
                result.Message = ParseExpr();
                Expect(CiToken.Semicolon);
                return(result);
            }
            if (Eat(CiToken.While))
            {
                CiWhile result = new CiWhile();
                result.Cond = ParseCond();
                result.Body = ParseStatement();
                return(result);
            }
            throw new ParseException("Invalid statement");
        }

        CiBlock ParseBlock()
        {
            Expect(CiToken.LeftBrace);
            List <ICiStatement> statements = new List <ICiStatement>();

            while (!Eat(CiToken.RightBrace))
            {
                statements.Add(ParseStatement());
            }
            return(new CiBlock {
                Statements = statements.ToArray()
            });
        }

        CiParam CreateThis()
        {
            CiParam thiz = new CiParam();

            thiz.Type = new CiClassPtrType {
                Name = this.CurrentClass.Name, Class = this.CurrentClass
            };
            thiz.Name = "this";
            this.Symbols.Add(thiz);
            return(thiz);
        }

        CiType ParseReturnType()
        {
            if (Eat(CiToken.Void))
            {
                return(CiType.Void);
            }
            return(ParseType());
        }

        CiParam[] ParseParams()
        {
            Expect(CiToken.LeftParenthesis);
            List <CiParam> paramz = new List <CiParam>();

            if (!See(CiToken.RightParenthesis))
            {
                do
                {
                    CiParam param = new CiParam();
                    param.Documentation = ParseDoc();
                    param.Type          = ParseType();
                    param.Name          = ParseId();
                    this.Symbols.Add(param);
                    paramz.Add(param);
                } while (Eat(CiToken.Comma));
            }
            Expect(CiToken.RightParenthesis);
            return(paramz.ToArray());
        }

        void ParseMethod(CiMethod method)
        {
            this.CurrentMethod = method;
            OpenScope();
            if (method.CallType != CiCallType.Static)
            {
                method.This = CreateThis();
            }
            method.Signature.Params = ParseParams();
            if (method.CallType == CiCallType.Abstract)
            {
                Expect(CiToken.Semicolon);
            }
            else
            {
                method.Body = ParseBlock();
            }
            CloseScope();
            this.CurrentMethod = null;
        }

        CiMethod ParseConstructor()
        {
            NextToken();
            Expect(CiToken.LeftParenthesis);
            Expect(CiToken.RightParenthesis);
            OpenScope();
            CiMethod method = new CiMethod(
                CiType.Void, "<constructor>")
            {
                Class    = this.CurrentClass,
                CallType = CiCallType.Normal,
                This     = CreateThis()
            };

            this.CurrentMethod = method;
            method.Body        = ParseBlock();
            CloseScope();
            this.CurrentMethod = null;
            return(method);
        }

        CiClass ParseClass()
        {
            CiClass klass = new CiClass();

            klass.SourceFilename = this.Filename;
            if (Eat(CiToken.Abstract))
            {
                klass.IsAbstract = true;
            }
            Expect(CiToken.Class);
            klass.Name = ParseId();
            if (Eat(CiToken.Colon))
            {
                klass.BaseClass = new CiUnknownClass {
                    Name = ParseId()
                }
            }
            ;
            Expect(CiToken.LeftBrace);
            OpenScope();
            this.CurrentClass = klass;
            klass.Members     = this.Symbols;
            while (!Eat(CiToken.RightBrace))
            {
                CiCodeDoc    doc        = ParseDoc();
                CiVisibility visibility = CiVisibility.Private;
                if (Eat(CiToken.Public))
                {
                    visibility = CiVisibility.Public;
                }
                else if (Eat(CiToken.Internal))
                {
                    visibility = CiVisibility.Internal;
                }
                CiSymbol symbol;
                if (See(CiToken.Const))
                {
                    symbol = ParseConst();
                    ((CiConst)symbol).Class = klass;
                }
                else if (Eat(CiToken.Macro))
                {
                    if (visibility != CiVisibility.Private)
                    {
                        throw new ParseException("Macros must be private");
                    }
                    symbol = ParseMacro();
                }
                else
                {
                    if (See(CiToken.Id) && this.CurrentString == klass.Name)
                    {
                        if (klass.Constructor != null)
                        {
                            throw new ParseException("Duplicate constructor");
                        }
                        klass.Constructor = ParseConstructor();
                        continue;
                    }
                    CiCallType callType;
                    if (Eat(CiToken.Static))
                    {
                        callType = CiCallType.Static;
                    }
                    else if (Eat(CiToken.Abstract))
                    {
                        if (!klass.IsAbstract)
                        {
                            throw new ParseException("Abstract methods only allowed in abstract classes");
                        }
                        callType = CiCallType.Abstract;
                        if (visibility == CiVisibility.Private)
                        {
                            visibility = CiVisibility.Internal;
                        }
                    }
                    else if (Eat(CiToken.Virtual))
                    {
                        callType = CiCallType.Virtual;
                        if (visibility == CiVisibility.Private)
                        {
                            visibility = CiVisibility.Internal;
                        }
                    }
                    else if (Eat(CiToken.Override))
                    {
                        callType = CiCallType.Override;
                        if (visibility == CiVisibility.Private)
                        {
                            visibility = CiVisibility.Internal;
                        }
                    }
                    else
                    {
                        callType = CiCallType.Normal;
                    }
                    CiType type = ParseReturnType();
                    string name = ParseId();
                    if (See(CiToken.LeftParenthesis))
                    {
                        CiMethod method = new CiMethod(type, name)
                        {
                            Class    = klass,
                            CallType = callType
                        };
                        ParseMethod(method);
                        symbol = method;
                    }
                    else
                    {
                        if (visibility != CiVisibility.Private)
                        {
                            throw new ParseException("Fields must be private");
                        }
                        if (callType != CiCallType.Normal)
                        {
                            throw new ParseException("Fields cannot be static, abstract, virtual or override");
                        }
                        if (type == CiType.Void)
                        {
                            throw new ParseException("Field is void");
                        }
                        Expect(CiToken.Semicolon);
                        symbol = new CiField {
                            Class = klass, Type = type, Name = name
                        };
                    }
                }
                symbol.Documentation = doc;
                symbol.Visibility    = visibility;
                klass.Members.Add(symbol);
            }
            this.CurrentClass = null;
            CloseScope();
            klass.ConstArrays = this.ConstArrays.ToArray();
            this.ConstArrays.Clear();
            return(klass);
        }

        CiDelegate ParseDelegate()
        {
            CiDelegate del = new CiDelegate();

            Expect(CiToken.Delegate);
            del.ReturnType = ParseReturnType();
            del.Name       = ParseId();
            OpenScope();
            del.Params = ParseParams();
            CloseScope();
            Expect(CiToken.Semicolon);
            return(del);
        }

        public void Parse(string filename, TextReader reader)
        {
            Open(filename, reader);
            while (!See(CiToken.EndOfFile))
            {
                CiCodeDoc doc = ParseDoc();
                bool      pub = Eat(CiToken.Public);
                CiSymbol  symbol;
                if (See(CiToken.Enum))
                {
                    symbol = ParseEnum();
                }
                else if (See(CiToken.Class) || See(CiToken.Abstract))
                {
                    symbol = ParseClass();
                }
                else if (See(CiToken.Delegate))
                {
                    symbol = ParseDelegate();
                }
                else
                {
                    throw new ParseException("Expected class, enum or delegate");
                }
                symbol.Documentation = doc;
                symbol.Visibility    = pub ? CiVisibility.Public : CiVisibility.Internal;
                this.Symbols.Add(symbol);
            }
        }

        public CiProgram Program
        {
            get
            {
                return(new CiProgram {
                    Globals = this.Symbols
                });
            }
        }
    }
}
Beispiel #12
0
Datei: GenC.cs Projekt: epi/cito
 static bool AddsVirtualMethod(CiClass klass, string methodName)
 {
     return klass.Members.OfType<CiMethod>().Any(method =>
     method.Name == methodName && (method.CallType == CiCallType.Abstract || method.CallType == CiCallType.Virtual));
 }
Beispiel #13
0
 static bool HasSwitch(CiClass klass)
 {
     if (klass.Constructor != null && HasSwitch(klass.Constructor.Body))
     return true;
     return klass.Members.OfType<CiMethod>().Any(method => HasSwitch(method.Body));
 }
Beispiel #14
0
        void ICiSymbolVisitor.Visit(CiClass klass)
        {
            WriteLine();
            Write(klass.Documentation);
            Write(klass.Visibility);
            OpenClass(klass.IsAbstract, klass, " : ");
            CurrentClass = klass;
            bool hasConstructor = klass.Constructor != null;

            foreach (CiSymbol member in klass.Members)
            {
                if (!hasConstructor)
                {
                    CiField field = member as CiField;
                    if (field != null && (field.Type is CiClassStorageType || field.Type is CiArrayStorageType))
                    {
                        hasConstructor = true;
                    }
                }
                member.Accept(this);
            }
            foreach (CiConst konst in klass.ConstArrays)
            {
                if (konst.Visibility != CiVisibility.Public)
                {
                    Write("static immutable(");
                    Write(konst.Type);
                    Write(") ");
                    Write(konst.Class == CurrentClass ? konst.Name : konst.GlobalName);
                    Write(" = ");
                    WriteConst(konst.Value);
                    WriteLine(";");
                }
            }
            foreach (CiBinaryResource resource in klass.BinaryResources)
            {
                // FIXME: it's better to import(resources) from binary files,
                // rather than pasting tons of magic numbers in the source.
                Write("static immutable(ubyte[]) ");
                WriteName(resource);
                Write(" = ");
                WriteConst(resource.Content);
                WriteLine(";");
            }
            if (hasConstructor)
            {
                WriteLine("this()");
                OpenBlock();
                foreach (CiSymbol member in klass.Members)
                {
                    CiField field = member as CiField;
                    if (field != null && (field.Type is CiClassStorageType || field.Type is CiArrayStorageType))
                    {
                        WriteVarName(field.Name);
                        WriteInit(field.Type);
                        WriteLine(";");
                    }
                }
                if (klass.Constructor != null)
                {
                    Write(klass.Constructor.Body.Statements);
                }
                CloseBlock();
            }
            CloseBlock();
            CurrentClass = null;
        }
Beispiel #15
0
 CiClass ResolveClass(CiClass klass)
 {
     if (klass is CiUnknownClass) {
     string name = klass.Name;
     klass = this.Symbols.Lookup(name) as CiClass;
     if (klass == null)
         throw new ResolveException("{0} is not a class", name);
     }
     return klass;
 }
Beispiel #16
0
Datei: GenC.cs Projekt: epi/cito
 static bool HasCStruct(CiClass klass)
 {
     return klass.BaseClass != null || klass.HasFields || AddsVirtualMethods(klass);
 }
Beispiel #17
0
Datei: GenC.cs Projekt: epi/cito
 static bool HasVirtualMethods(CiClass klass)
 {
     // == return EnumVirtualMethods(klass).Any();
     while (!AddsVirtualMethods(klass)) {
     klass = klass.BaseClass;
     if (klass == null)
         return false;
     }
     return true;
 }
Beispiel #18
0
Datei: GenC.cs Projekt: epi/cito
 static CiClass GetVtblPtrClass(CiClass klass)
 {
     CiClass result = null;
     do {
     if (AddsVirtualMethods(klass))
         result = klass;
     klass = klass.BaseClass;
     } while (klass != null);
     return result;
 }
Beispiel #19
0
Datei: GenC.cs Projekt: epi/cito
 static CiClass GetVtblStructClass(CiClass klass)
 {
     while (!AddsVirtualMethods(klass))
     klass = klass.BaseClass;
     return klass;
 }
Beispiel #20
0
Datei: GenC.cs Projekt: epi/cito
 static void ForEachStorageField(CiClass klass, Action<CiField, CiClass> action)
 {
     foreach (CiSymbol member in klass.Members) {
     CiField field = member as CiField;
     if (field != null) {
         CiClass storageClass = field.Type.StorageClass;
         if (storageClass != null)
             action(field, storageClass);
     }
     }
 }
Beispiel #21
0
Datei: GenC.cs Projekt: epi/cito
 static IEnumerable<CiMethod> EnumVirtualMethods(CiClass klass)
 {
     IEnumerable<CiMethod> myMethods = klass.Members.OfType<CiMethod>().Where(
     method => method.CallType == CiCallType.Abstract || method.CallType == CiCallType.Virtual);
     if (klass.BaseClass != null)
     return EnumVirtualMethods(klass.BaseClass).Concat(myMethods);
     else
     return myMethods;
 }
Beispiel #22
0
Datei: GenC.cs Projekt: epi/cito
 static bool AddsVirtualMethods(CiClass klass)
 {
     return klass.Members.OfType<CiMethod>().Any(
     method => method.CallType == CiCallType.Abstract || method.CallType == CiCallType.Virtual);
 }
Beispiel #23
0
        void Write(CiClass klass)
        {
            // topological sorting of class hierarchy and class storage fields
            if (klass == null)
            {
                return;
            }
            if (this.WrittenClasses.TryGetValue(klass, out bool done))
            {
                if (done)
                {
                    return;
                }
                throw new CiException(klass, "Circular dependency for class {0}", klass.Name);
            }
            this.WrittenClasses.Add(klass, false);
            Write(klass.Parent as CiClass);
            foreach (CiField field in klass.Fields)
            {
                Write(field.Type.BaseType as CiClass);
            }
            this.WrittenClasses[klass] = true;

            Write(klass.Documentation);
            Write("export ");
            switch (klass.CallType)
            {
            case CiCallType.Normal:
                break;

            case CiCallType.Abstract:
                Write("abstract ");
                break;

            case CiCallType.Static:
            case CiCallType.Sealed:
                // there's no final/sealed keyword, but we accomplish it by marking the constructor private
                break;

            default:
                throw new NotImplementedException(klass.CallType.ToString());
            }
            OpenClass(klass, "", " extends ");

            CiMethodBase constructor = klass.Constructor;

            if (klass.CallType == CiCallType.Static)
            {
                constructor = new CiMethodBase {
                    Visibility = CiVisibility.Private
                }
            }
            ;

            if (constructor != null)
            {
                Write(constructor.Documentation);
                Write(constructor.Visibility);
                Write("constructor()");
                if (this.GenFullCode)
                {
                    OpenBlock();
                    if (klass.BaseClassName != null)
                    {
                        WriteLine("super();");
                    }
                    WriteConstructorBody(klass);
                    CloseBlock();
                }
                else
                {
                    WriteLine(';');
                }
            }

            WriteConsts(klass.Consts);

            foreach (CiField field in klass.Fields)
            {
                Write(field.Visibility);
                WriteTypeAndName(field);
                if (this.GenFullCode)
                {
                    WriteVarInit(field);
                }
                WriteLine(';');
            }

            foreach (CiMethod method in klass.Methods)
            {
                Write(klass, method);
            }

            if (this.GenFullCode)
            {
                WriteConsts(klass.ConstArrays);
            }
            CloseBlock();
            WriteLine();
        }
Beispiel #24
0
Datei: GenC.cs Projekt: epi/cito
 static bool HasVtblValue(CiClass klass)
 {
     bool result = false;
     foreach (CiSymbol member in klass.Members) {
     CiMethod method = member as CiMethod;
     if (method != null) {
         switch (method.CallType) {
         case CiCallType.Abstract:
             return false;
         case CiCallType.Virtual:
         case CiCallType.Override:
             result = true;
             break;
         }
     }
     }
     return result;
 }
Beispiel #25
0
Datei: GenC.cs Projekt: epi/cito
 void WriteVtblValue(CiClass klass)
 {
     if (!HasVtblValue(klass))
     return;
     CiClass structClass = GetVtblStructClass(klass);
     Write("static const ");
     Write(structClass.Name);
     Write("Vtbl CiVtbl_");
     Write(klass.Name);
     Write(" = ");
     OpenBlock();
     bool first = true;
     foreach (CiMethod method in EnumVirtualMethods(structClass)) {
     CiMethod impl = (CiMethod) klass.Members.Lookup(method.Name);
     if (first)
         first = false;
     else
         WriteLine(",");
     if (impl.CallType == CiCallType.Override) {
         Write('(');
         WritePtr(method, string.Empty);
         Write(") ");
     }
     Write(impl.Class.Name);
     Write('_');
     Write(impl.Name);
     }
     WriteLine();
     this.Indent--;
     WriteLine("};");
 }
Beispiel #26
0
Datei: GenC.cs Projekt: epi/cito
 static int SizeOf(CiClass klass)
 {
     int result = klass.Members.OfType<CiField>().Sum(field => SizeOf(field.Type));
     if (klass.BaseClass != null)
     result += SizeOf(klass.BaseClass);
     if (GetVtblPtrClass(klass) == klass)
     result += SizeOfPointer;
     return result;
 }
Beispiel #27
0
 void ResolveBase(CiClass klass)
 {
     if (klass.BaseClass != null) {
     klass.BaseClass = ResolveClass(klass.BaseClass);
     klass.Members.Parent = klass.BaseClass.Members;
     }
 }
Beispiel #28
0
Datei: GenC.cs Projekt: epi/cito
 void Write(CiClass klass, CiConst konst)
 {
     WriteLine();
     Write(konst.Documentation);
     if (konst.Type is CiArrayStorageType) {
     CiArrayStorageType stg = (CiArrayStorageType) konst.Type;
     Write("extern const ");
     Write(konst.Type, klass.Name + "_" + konst.Name);
     WriteLine(";");
     Write("#define ");
     Write(klass.Name);
     Write('_');
     Write(konst.Name);
     Write("_LENGTH  ");
     Write(stg.Length);
     }
     else {
     Write("#define ");
     Write(klass.Name);
     Write('_');
     WriteUppercaseWithUnderscores(konst.Name);
     Write("  ");
     WriteConst(konst.Value);
     }
     WriteLine();
 }
Beispiel #29
0
        void Write(CiClass klass)
        {
            // topological sorting of class hierarchy
            if (klass.WriteStatus == CiWriteStatus.Done)
            {
                return;
            }
            if (klass.WriteStatus == CiWriteStatus.InProgress)
            {
                throw new ResolveException("Circular dependency for class {0}", klass.Name);
            }
            klass.WriteStatus = CiWriteStatus.InProgress;
            if (klass.BaseClass != null)
            {
                Write(klass.BaseClass);
            }
            klass.WriteStatus = CiWriteStatus.Done;

            this.CurrentClass = klass;
            WriteLine();
            Write(klass.Documentation);
            Write("function ");
            Write(klass.Name);
            WriteLine("()");
            OpenBlock();
            foreach (CiSymbol member in klass.Members)
            {
                if (member is CiField)
                {
                    Write((CiField)member);
                }
            }
            if (klass.Constructor != null)
            {
                Write(klass.Constructor.Body.Statements);
            }
            CloseBlock();
            if (klass.BaseClass != null)
            {
                Write(klass.Name);
                Write(".prototype = new ");
                Write(klass.BaseClass.Name);
                WriteLine("();");
            }
            foreach (CiSymbol member in klass.Members)
            {
                if (member is CiMethod)
                {
                    Write((CiMethod)member);
                }
                else if (member is CiConst && member.Visibility == CiVisibility.Public)
                {
                    Write((CiConst)member);
                }
            }
            foreach (CiConst konst in klass.ConstArrays)
            {
                Write(konst);
            }
            foreach (CiBinaryResource resource in klass.BinaryResources)
            {
                WriteName(resource);
                Write(" = ");
                WriteConst(resource.Content);
                WriteLine(";");
            }
            this.CurrentClass = null;
        }
Beispiel #30
0
        CiExpr ICiExprVisitor.Visit(CiSymbolAccess expr)
        {
            CiSymbol symbol = Lookup(expr);

            if (symbol is CiVar)
            {
                return new CiVarAccess {
                           Var = (CiVar)symbol
                }
            }
            ;
            if (symbol is CiConst)
            {
                return(GetValue((CiConst)symbol));
            }
            if (symbol is CiField)
            {
                if (this.CurrentMethod.CallType == CiCallType.Static)
                {
                    throw new ResolveException("Cannot access field from a static method");
                }
                symbol.Accept(this);
                return(CreateFieldAccess(new CiVarAccess {
                    Var = this.CurrentMethod.This
                }, (CiField)symbol));
            }
            throw new ResolveException("Invalid expression");
        }

        CiExpr ICiExprVisitor.Visit(CiUnknownMemberAccess expr)
        {
            if (expr.Parent is CiSymbolAccess)
            {
                CiSymbol symbol = Lookup((CiSymbolAccess)expr.Parent);
                if (symbol is CiEnum)
                {
                    return(new CiConstExpr(((CiEnum)symbol).LookupMember(expr.Name)));
                }
                if (symbol is CiClass)
                {
                    symbol = ((CiClass)symbol).Members.Lookup(expr.Name);
                    if (symbol is CiConst)
                    {
                        return(GetValue((CiConst)symbol));
                    }
                    throw new ResolveException("Cannot access " + expr.Name);
                }
            }
            CiExpr   parent = Resolve(expr.Parent);
            CiSymbol member = parent.Type.LookupMember(expr.Name);

            member.Accept(this);
            if (member is CiField)
            {
                return(CreateFieldAccess(parent, (CiField)member));
            }
            if (member is CiProperty)
            {
                CiProperty prop = (CiProperty)member;
                if (parent is CiConstExpr)
                {
                    if (prop == CiLibrary.LowByteProperty)
                    {
                        return(new CiConstExpr((byte)GetConstInt(parent)));
                    }
                    if (prop == CiLibrary.SByteProperty)
                    {
                        return(new CiConstExpr((int)(sbyte)GetConstInt(parent)));
                    }
                    if (prop == CiLibrary.StringLengthProperty)
                    {
                        return(new CiConstExpr(((string)((CiConstExpr)parent).Value).Length));
                    }
                }
                return(new CiPropertyAccess {
                    Obj = parent, Property = prop
                });
            }
            if (member is CiConst)
            {
                return(new CiConstExpr(((CiConst)member).Value));
            }
            throw new ResolveException(member.ToString());
        }

        CiExpr ICiExprVisitor.Visit(CiIndexAccess expr)
        {
            CiExpr parent = Resolve(expr.Parent);
            CiExpr index  = Coerce(Resolve(expr.Index), CiIntType.Value);

            if (parent.Type is CiArrayType)
            {
                return new CiArrayAccess {
                           Array = parent, Index = index
                }
            }
            ;
            if (parent.Type is CiStringType)
            {
                if (parent is CiConstExpr && index is CiConstExpr)
                {
                    string s = (string)((CiConstExpr)parent).Value;
                    int    i = GetConstInt(index);
                    if (i < s.Length)
                    {
                        return(new CiConstExpr((int)s[i]));
                    }
                }
                return(new CiMethodCall {
                    Method = CiLibrary.CharAtMethod,
                    Obj = parent,
                    Arguments = new CiExpr[1] {
                        index
                    }
                });
            }
            throw new ResolveException("Indexed object is neither array or string");
        }

        void ICiSymbolVisitor.Visit(CiDelegate del)
        {
            del.ReturnType = Resolve(del.ReturnType);
            foreach (CiParam param in del.Params)
            {
                param.Type = Resolve(param.Type);
            }
        }

        CiType ICiTypeVisitor.Visit(CiDelegate del)
        {
            ((ICiSymbolVisitor)this).Visit(del);
            return(del);
        }

        void ResolveObj(CiMethodCall expr)
        {
            if (expr.Obj is CiSymbolAccess)
            {
                // Foo(...)
                CiMethod method = Lookup((CiSymbolAccess)expr.Obj) as CiMethod;
                if (method != null)
                {
                    expr.Method = method;
                    if (method.CallType == CiCallType.Static)
                    {
                        expr.Obj = null;
                    }
                    else
                    {
                        if (this.CurrentMethod.CallType == CiCallType.Static)
                        {
                            throw new ResolveException("Cannot call instance method from a static method");
                        }
                        expr.Obj = Coerce(new CiVarAccess {
                            Var = this.CurrentMethod.This
                        }, new CiClassPtrType {
                            Class = method.Class
                        });
                        CheckCopyPtr(method.This.Type, expr.Obj);
                    }
                    return;
                }
            }
            else if (expr.Obj is CiUnknownMemberAccess)
            {
                // ???.Foo(...)
                CiUnknownMemberAccess uma = (CiUnknownMemberAccess)expr.Obj;
                if (uma.Parent is CiSymbolAccess)
                {
                    CiClass klass = Lookup((CiSymbolAccess)uma.Parent) as CiClass;
                    if (klass != null)
                    {
                        // Class.Foo(...)
                        CiMethod method = klass.Members.Lookup(uma.Name) as CiMethod;
                        if (method != null)
                        {
                            if (method.CallType != CiCallType.Static)
                            {
                                throw new ResolveException("{0} is a non-static method", method.Name);
                            }
                            expr.Method = method;
                            expr.Obj    = null;
                            return;
                        }
                    }
                }
                CiExpr obj = Resolve(uma.Parent);
                {
                    CiMethod method = obj.Type.LookupMember(uma.Name) as CiMethod;
                    if (method != null)
                    {
                        // obj.Foo(...)
                        if (method.CallType == CiCallType.Static)
                        {
                            throw new ResolveException("{0} is a static method", method.Name);
                        }
                        if (method.This != null)
                        {
                            // user-defined method
                            CheckCopyPtr(method.This.Type, obj);
                            obj = Coerce(obj, new CiClassPtrType {
                                Class = method.Class
                            });
                        }
                        expr.Method = method;
                        expr.Obj    = obj;
                        return;
                    }
                }
            }
            expr.Obj = Resolve(expr.Obj);
            if (!(expr.Obj.Type is CiDelegate))
            {
                throw new ResolveException("Invalid call");
            }
            if (expr.Obj.HasSideEffect)
            {
                throw new ResolveException("Side effects not allowed in delegate call");
            }
        }

        void CoerceArguments(CiMethodCall expr)
        {
            expr.Signature.Accept(this);
            CiParam[] paramz = expr.Signature.Params;
            if (expr.Arguments.Length != paramz.Length)
            {
                throw new ResolveException("Invalid number of arguments for {0}, expected {1}, got {2}", expr.Signature.Name, paramz.Length, expr.Arguments.Length);
            }
            for (int i = 0; i < paramz.Length; i++)
            {
                CiExpr arg = Resolve(expr.Arguments[i]);
                CheckCopyPtr(paramz[i].Type, arg);
                expr.Arguments[i] = Coerce(arg, paramz[i].Type);
            }
        }

        CiExpr ICiExprVisitor.Visit(CiMethodCall expr)
        {
            ResolveObj(expr);
            CoerceArguments(expr);
            if (expr.Method != null && expr.Method != this.CurrentMethod)
            {
                if (expr.Method.IsMutator)
                {
                    MarkWritable(expr.Obj);
                }
                expr.Method.CalledBy.Add(this.CurrentMethod);
                this.CurrentMethod.Calls.Add(expr.Method);
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiUnaryExpr expr)
        {
            CiExpr resolved;

            if (expr.Op == CiToken.Increment || expr.Op == CiToken.Decrement)
            {
                resolved = ResolveLValue(expr.Inner);
            }
            else
            {
                resolved = Resolve(expr.Inner);
            }
            expr.Inner = Coerce(resolved, CiIntType.Value);
            if (expr.Op == CiToken.Minus && expr.Inner is CiConstExpr)
            {
                return(new CiConstExpr(-GetConstInt(expr.Inner)));
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiCondNotExpr expr)
        {
            expr.Inner = Coerce(Resolve(expr.Inner), CiBoolType.Value);
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiPostfixExpr expr)
        {
            expr.Inner = Coerce(ResolveLValue(expr.Inner), CiIntType.Value);
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiBinaryExpr expr)
        {
            CiExpr left  = Resolve(expr.Left);
            CiExpr right = Resolve(expr.Right);

            if (expr.Op == CiToken.Plus && (left.Type is CiStringType || right.Type is CiStringType))
            {
                if (!(left is CiConstExpr && right is CiConstExpr))
                {
                    throw new ResolveException("String concatenation allowed only for constants. Consider using +=");
                }
                string a = GetConstString(left);
                string b = GetConstString(right);
                return(new CiConstExpr(a + b));
            }
            left  = Coerce(left, CiIntType.Value);
            right = Coerce(right, CiIntType.Value);
            if (right is CiConstExpr)
            {
                int b = GetConstInt(right);
                if (left is CiConstExpr)
                {
                    int a = GetConstInt(left);
                    switch (expr.Op)
                    {
                    case CiToken.Asterisk: a *= b; break;

                    case CiToken.Slash: a /= b; break;

                    case CiToken.Mod: a %= b; break;

                    case CiToken.And: a &= b; break;

                    case CiToken.ShiftLeft: a <<= b; break;

                    case CiToken.ShiftRight: a >>= b; break;

                    case CiToken.Plus: a += b; break;

                    case CiToken.Minus: a -= b; break;

                    case CiToken.Or: a |= b; break;

                    case CiToken.Xor: a ^= b; break;
                    }
                    return(new CiConstExpr(a));
                }
                if (expr.Op == CiToken.And && (b & ~0xff) == 0)
                {
                    CiCoercion c = left as CiCoercion;
                    if (c != null && c.Inner.Type == CiByteType.Value)
                    {
                        left = (CiExpr)c.Inner;
                    }
                }
            }
            expr.Left  = left;
            expr.Right = right;
            return(expr);
        }

        static CiType FindCommonType(CiExpr expr1, CiExpr expr2)
        {
            CiType type1 = expr1.Type;
            CiType type2 = expr2.Type;

            if (type1.Equals(type2))
            {
                return(type1);
            }
            if ((type1 == CiIntType.Value && type2 == CiByteType.Value) ||
                (type1 == CiByteType.Value && type2 == CiIntType.Value))
            {
                return(CiIntType.Value);
            }
            CiType type = type1.Ptr;

            if (type != null)
            {
                return(type);        // stg, ptr || stg, null
            }
            type = type2.Ptr;
            if (type != null)
            {
                return(type);        // ptr, stg || null, stg
            }
            if (type1 != CiType.Null)
            {
                return(type1);        // ptr, null
            }
            if (type2 != CiType.Null)
            {
                return(type2);        // null, ptr
            }
            throw new ResolveException("Incompatible types");
        }

        CiExpr ICiExprVisitor.Visit(CiBoolBinaryExpr expr)
        {
            CiExpr left  = Resolve(expr.Left);
            CiExpr right = Resolve(expr.Right);
            CiType type;

            switch (expr.Op)
            {
            case CiToken.CondAnd:
            case CiToken.CondOr:
                type = CiBoolType.Value;
                break;

            case CiToken.Equal:
            case CiToken.NotEqual:
                type = FindCommonType(left, right);
                break;

            default:
                type = CiIntType.Value;
                break;
            }
            expr.Left  = Coerce(left, type);
            expr.Right = Coerce(right, type);
            CiConstExpr cleft = expr.Left as CiConstExpr;

            if (cleft != null)
            {
                switch (expr.Op)
                {
                case CiToken.CondAnd:
                    return((bool)cleft.Value ? expr.Right : new CiConstExpr(false));

                case CiToken.CondOr:
                    return((bool)cleft.Value ? new CiConstExpr(true) : expr.Right);

                case CiToken.Equal:
                case CiToken.NotEqual:
                    CiConstExpr cright = expr.Right as CiConstExpr;
                    if (cright != null)
                    {
                        bool eq = object.Equals(cleft.Value, cright.Value);
                        return(new CiConstExpr(expr.Op == CiToken.Equal ? eq : !eq));
                    }
                    break;

                default:
                    if (expr.Right is CiConstExpr)
                    {
                        int  a = GetConstInt(cleft);
                        int  b = GetConstInt(expr.Right);
                        bool result;
                        switch (expr.Op)
                        {
                        case CiToken.Less: result = a < b; break;

                        case CiToken.LessOrEqual: result = a <= b; break;

                        case CiToken.Greater: result = a > b; break;

                        case CiToken.GreaterOrEqual: result = a >= b; break;

                        default: return(expr);
                        }
                        return(new CiConstExpr(result));
                    }
                    break;
                }
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiCondExpr expr)
        {
            expr.Cond = Coerce(Resolve(expr.Cond), CiBoolType.Value);
            CiExpr expr1 = Resolve(expr.OnTrue);
            CiExpr expr2 = Resolve(expr.OnFalse);

            expr.ResultType = FindCommonType(expr1, expr2);
            expr.OnTrue     = Coerce(expr1, expr.ResultType);
            expr.OnFalse    = Coerce(expr2, expr.ResultType);
            CiConstExpr konst = expr.Cond as CiConstExpr;

            if (konst != null)
            {
                return((bool)konst.Value ? expr.OnTrue : expr.OnFalse);
            }
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiBinaryResourceExpr expr)
        {
            string           name = (string)ResolveConstExpr(expr.NameExpr, CiStringPtrType.Value);
            CiBinaryResource resource;

            if (!this.BinaryResources.TryGetValue(name, out resource))
            {
                resource         = new CiBinaryResource();
                resource.Name    = name;
                resource.Content = File.ReadAllBytes(FindFile(name));
                resource.Type    = new CiArrayStorageType {
                    ElementType = CiByteType.Value, Length = resource.Content.Length
                };
                this.BinaryResources.Add(name, resource);
            }
            expr.Resource = resource;
            return(expr);
        }

        CiExpr ICiExprVisitor.Visit(CiNewExpr expr)
        {
            CiType             type             = expr.NewType;
            CiClassStorageType classStorageType = type as CiClassStorageType;

            if (classStorageType != null)
            {
                classStorageType.Class             = ResolveClass(classStorageType.Class);
                classStorageType.Class.IsAllocated = true;
            }
            else
            {
                CiArrayStorageType arrayStorageType = (CiArrayStorageType)type;
                arrayStorageType.ElementType = Resolve(arrayStorageType.ElementType);
                arrayStorageType.LengthExpr  = Coerce(Resolve(arrayStorageType.LengthExpr), CiIntType.Value);
            }
            return(expr);
        }

        CiExpr Resolve(CiExpr expr)
        {
            return(expr.Accept(this));
        }

        void ICiSymbolVisitor.Visit(CiField field)
        {
            field.Type = Resolve(field.Type);
        }

        bool Resolve(ICiStatement[] statements)
        {
            bool reachable = true;

            foreach (ICiStatement child in statements)
            {
                if (!reachable)
                {
                    throw new ResolveException("Unreachable statement");
                }
                child.Accept(this);
                reachable = child.CompletesNormally;
            }
            return(reachable);
        }

        void ICiStatementVisitor.Visit(CiBlock statement)
        {
            statement.CompletesNormally = Resolve(statement.Statements);
        }

        void ICiStatementVisitor.Visit(CiConst statement)
        {
        }

        void ICiStatementVisitor.Visit(CiVar statement)
        {
            statement.Type = Resolve(statement.Type);
            if (statement.InitialValue != null)
            {
                CiType type         = statement.Type;
                CiExpr initialValue = Resolve(statement.InitialValue);
                CheckCopyPtr(type, initialValue);
                if (type is CiArrayStorageType)
                {
                    type = ((CiArrayStorageType)type).ElementType;
                    CiConstExpr ce = Coerce(initialValue, type) as CiConstExpr;
                    if (ce == null)
                    {
                        throw new ResolveException("Array initializer is not constant");
                    }
                    statement.InitialValue = ce;
                    if (type == CiBoolType.Value)
                    {
                        if (!false.Equals(ce.Value))
                        {
                            throw new ResolveException("Bool arrays can only be initialized with false");
                        }
                    }
                    else if (type == CiByteType.Value)
                    {
                        if (!((byte)0).Equals(ce.Value))
                        {
                            throw new ResolveException("Byte arrays can only be initialized with zero");
                        }
                    }
                    else if (type == CiIntType.Value)
                    {
                        if (!0.Equals(ce.Value))
                        {
                            throw new ResolveException("Int arrays can only be initialized with zero");
                        }
                    }
                    else
                    {
                        throw new ResolveException("Invalid array initializer");
                    }
                }
                else
                {
                    statement.InitialValue = Coerce(initialValue, type);
                }
            }
        }

        void ICiStatementVisitor.Visit(CiExpr statement)
        {
            Resolve((CiExpr)statement);
        }

        void ICiStatementVisitor.Visit(CiAssign statement)
        {
            statement.Target = ResolveLValue(statement.Target);
            if (statement.Target is CiVarAccess && ((CiVarAccess)statement.Target).Var == this.CurrentMethod.This)
            {
                throw new ResolveException("Cannot assign to this");
            }
            CiMaybeAssign source = statement.Source;

            if (source is CiAssign)
            {
                Resolve((ICiStatement)source);
            }
            else
            {
                source = Resolve((CiExpr)source);
            }
            CiType type = statement.Target.Type;

            CheckCopyPtr(type, source);
            statement.Source = Coerce(source, type);
            if (statement.Op != CiToken.Assign && type != CiIntType.Value && type != CiByteType.Value)
            {
                if (statement.Op == CiToken.AddAssign && type is CiStringStorageType && statement.Source.Type is CiStringType)
                {
                }                  // OK
                else
                {
                    throw new ResolveException("Invalid compound assignment");
                }
            }
        }

        void ICiStatementVisitor.Visit(CiDelete statement)
        {
            statement.Expr = Resolve(statement.Expr);
            ICiPtrType type = statement.Expr.Type as ICiPtrType;

            if (type == null)
            {
                throw new ResolveException("'delete' takes a class or array pointer");
            }
            if (statement.Expr.HasSideEffect)
            {
                throw new ResolveException("Side effects not allowed in 'delete'");
            }
            this.WritablePtrTypes.Add(type);
        }

        void ICiStatementVisitor.Visit(CiBreak statement)
        {
            if (this.CurrentLoopOrSwitch == null)
            {
                throw new ResolveException("break outside loop and switch");
            }
            this.CurrentLoopOrSwitch.CompletesNormally = true;
        }

        void ICiStatementVisitor.Visit(CiContinue statement)
        {
            if (this.CurrentLoop == null)
            {
                throw new ResolveException("continue outside loop");
            }
        }

        void ResolveLoop(CiLoop statement)
        {
            statement.CompletesNormally = false;
            if (statement.Cond != null)
            {
                statement.Cond = Coerce(Resolve(statement.Cond), CiBoolType.Value);
                statement.CompletesNormally = !statement.Cond.IsConst(false);
            }
            CiLoop oldLoop = this.CurrentLoop;
            CiCondCompletionStatement oldLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = this.CurrentLoop = statement;
            Resolve(statement.Body);
            this.CurrentLoop         = oldLoop;
            this.CurrentLoopOrSwitch = oldLoopOrSwitch;
        }

        void ICiStatementVisitor.Visit(CiDoWhile statement)
        {
            ResolveLoop(statement);
        }

        void ICiStatementVisitor.Visit(CiFor statement)
        {
            if (statement.Init != null)
            {
                Resolve(statement.Init);
            }
            if (statement.Advance != null)
            {
                Resolve(statement.Advance);
            }
            ResolveLoop(statement);
        }

        void ICiStatementVisitor.Visit(CiIf statement)
        {
            statement.Cond = Coerce(Resolve(statement.Cond), CiBoolType.Value);
            Resolve(statement.OnTrue);
            if (statement.OnFalse != null)
            {
                Resolve(statement.OnFalse);
                statement.CompletesNormally = statement.OnTrue.CompletesNormally || statement.OnFalse.CompletesNormally;
            }
            else
            {
                statement.CompletesNormally = true;
            }
        }

        void ICiStatementVisitor.Visit(CiNativeBlock statement)
        {
        }

        void ICiStatementVisitor.Visit(CiReturn statement)
        {
            CiType type = this.CurrentMethod.Signature.ReturnType;

            if (type != CiType.Void)
            {
                statement.Value = Coerce(Resolve(statement.Value), type);
            }
        }

        void ICiStatementVisitor.Visit(CiSwitch statement)
        {
            statement.Value = Resolve(statement.Value);
            CiType type = statement.Value.Type;
            CiCondCompletionStatement oldLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = statement;

            HashSet <object> values          = new HashSet <object>();
            CiCase           fallthroughFrom = null;

            foreach (CiCase kase in statement.Cases)
            {
                for (int i = 0; i < kase.Values.Length; i++)
                {
                    kase.Values[i] = ResolveConstExpr((CiExpr)kase.Values[i], type);
                    if (!values.Add(kase.Values[i]))
                    {
                        throw new ResolveException("Duplicate case value");
                    }
                }
                if (fallthroughFrom != null)
                {
                    if (fallthroughFrom.FallthroughTo == null)
                    {
                        throw new ResolveException("goto default followed by case");
                    }
                    if (!ResolveConstExpr(fallthroughFrom.FallthroughTo, type).Equals(kase.Values[0]))
                    {
                        throw new ResolveException("goto case doesn't match the next case");
                    }
                }
                bool reachable = Resolve(kase.Body);
                if (kase.Fallthrough)
                {
                    if (!reachable)
                    {
                        throw new ResolveException("goto is not reachable");
                    }
                    fallthroughFrom = kase;
                }
                else
                {
                    if (reachable)
                    {
                        throw new ResolveException("case must end with break, return, throw or goto");
                    }
                    fallthroughFrom = null;
                }
            }

            if (statement.DefaultBody != null)
            {
                if (fallthroughFrom != null && fallthroughFrom.FallthroughTo != null)
                {
                    throw new ResolveException("goto case followed by default");
                }
                bool reachable = Resolve(statement.DefaultBody);
                if (reachable)
                {
                    throw new ResolveException("default must end with break, return, throw or goto");
                }
            }
            else
            {
                if (fallthroughFrom != null)
                {
                    throw new ResolveException("goto cannot be the last statement in switch");
                }
            }

            this.CurrentLoopOrSwitch = oldLoopOrSwitch;
        }

        void ICiStatementVisitor.Visit(CiThrow statement)
        {
            statement.Message = Coerce(Resolve(statement.Message), CiStringPtrType.Value);
            this.ThrowingMethods.Add(this.CurrentMethod);
        }

        void ICiStatementVisitor.Visit(CiWhile statement)
        {
            ResolveLoop(statement);
        }

        void Resolve(ICiStatement statement)
        {
            statement.Accept(this);
        }

        void ICiSymbolVisitor.Visit(CiMethod method)
        {
            this.CurrentMethod = method;
            Resolve(method.Signature);
            if (method.CallType != CiCallType.Abstract)
            {
                Resolve(method.Body);
                if (method.Signature.ReturnType != CiType.Void && method.Body.CompletesNormally)
                {
                    throw new ResolveException("Method can complete without a return value");
                }
            }
            this.CurrentMethod = null;
        }

        void ResolveBase(CiClass klass)
        {
            if (klass.BaseClass != null)
            {
                klass.BaseClass      = ResolveClass(klass.BaseClass);
                klass.Members.Parent = klass.BaseClass.Members;
            }
        }

        void ICiSymbolVisitor.Visit(CiClass klass)
        {
            this.CurrentClass = klass;
            this.Symbols      = klass.Members;
            if (klass.Constructor != null)
            {
                klass.Constructor.Accept(this);
            }
            foreach (CiSymbol member in klass.Members)
            {
                member.Accept(this);
            }
            klass.BinaryResources = this.BinaryResources.Values.ToArray();
            this.BinaryResources.Clear();
            this.Symbols      = this.Symbols.Parent;
            this.CurrentClass = null;
        }
Beispiel #31
0
 protected void OpenClass(bool isAbstract, CiClass klass, string extendsClause)
 {
     if (isAbstract)
     Write("abstract ");
     Write("class ");
     Write(klass.Name);
     if (klass.BaseClass != null) {
     Write(extendsClause);
     Write(klass.BaseClass.Name);
     }
     WriteLine();
     OpenBlock();
 }
Beispiel #32
0
        void Write(CiClass klass)
        {
            if (klass.Visibility == CiVisibility.Public)
            {
                Write("=head1 Class ");
                Write(this.Package);
                WriteLine(klass.Name);
                WriteLine();
                Write(klass.Documentation);
                WriteLine("=cut");
                WriteLine();
            }
            WritePackage(klass);
            if (klass.BaseClass != null)
            {
                Write("our @ISA = '");
                Write(this.Package);
                Write(klass.BaseClass.Name);
                WriteLine("';");
            }

            foreach (CiSymbol member in klass.Members)
            {
                if (member.Visibility == CiVisibility.Public)
                {
                    CiConst konst = member as CiConst;
                    if (konst != null)
                    {
                        WriteConstDoc(klass, konst);
                        WriteLine("=cut");
                        WriteLine();
                        WriteConst(konst.Name, konst.Value);
                        WriteLine();
                    }
                }
            }
            foreach (CiConst konst in klass.ConstArrays)
            {
                Write("our @");
                WriteUppercaseWithUnderscores(konst.GlobalName);
                Write(" = ");
                WriteConst(konst.Value);
                WriteLine(";");
                WriteLine();
            }
            foreach (CiBinaryResource resource in klass.BinaryResources)
            {
                Write("our @");
                WriteName(resource);
                Write(" = ");
                WriteConst(resource.Content);
                WriteLine(";");
                WriteLine();
            }

            WriteConstructor(klass);
            foreach (CiSymbol member in klass.Members)
            {
                if (member is CiMethod)
                {
                    Write((CiMethod)member);
                }
            }
        }
Beispiel #33
0
Datei: GenC.cs Projekt: epi/cito
 void WriteCode(CiClass klass)
 {
     WriteConstructorNewDelete(klass);
     foreach (CiSymbol member in klass.Members) {
     if (member is CiMethod)
         Write((CiMethod) member);
     }
 }
Beispiel #34
0
Datei: GenC.cs Projekt: epi/cito
 protected void WriteConstruct(CiClass klass, CiVar stmt)
 {
     Write(klass.Name);
     Write("_Construct(&");
     WriteCamelCase(stmt.Name);
     if (HasVirtualMethods(klass))
     Write(", NULL");
     Write(')');
 }
Beispiel #35
0
        CiExpr ParseAddExpr()
        {
            CiExpr left = ParseMulExpr();

            while (See(CiToken.Plus) || See(CiToken.Minus))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseMulExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseShiftExpr()
        {
            CiExpr left = ParseAddExpr();

            while (See(CiToken.ShiftLeft) || See(CiToken.ShiftRight))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAddExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseRelExpr()
        {
            CiExpr left = ParseShiftExpr();

            for (;;)
            {
                switch (this.CurrentToken)
                {
                case CiToken.Less:
                case CiToken.LessOrEqual:
                case CiToken.Greater:
                case CiToken.GreaterOrEqual:
                    left = new CiBinaryExpr {
                        Line = this.Line, Left = left, Op = NextToken(), Right = ParseShiftExpr()
                    };
                    break;

                default:
                    return(left);
                }
            }
        }

        CiExpr ParseEqualityExpr()
        {
            CiExpr left = ParseRelExpr();

            while (See(CiToken.Equal) || See(CiToken.NotEqual))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseRelExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseAndExpr()
        {
            CiExpr left = ParseEqualityExpr();

            while (See(CiToken.And))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseEqualityExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseXorExpr()
        {
            CiExpr left = ParseAndExpr();

            while (See(CiToken.Xor))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAndExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseOrExpr()
        {
            CiExpr left = ParseXorExpr();

            while (See(CiToken.Or))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseXorExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseCondAndExpr()
        {
            CiExpr left = ParseOrExpr();

            while (See(CiToken.CondAnd))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseOrExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseCondOrExpr()
        {
            CiExpr left = ParseCondAndExpr();

            while (See(CiToken.CondOr))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseCondAndExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseExpr()
        {
            CiExpr left = ParseCondOrExpr();

            if (See(CiToken.QuestionMark))
            {
                CiCondExpr result = new CiCondExpr {
                    Line = this.Line, Cond = left
                };
                NextToken();
                result.OnTrue = ParseExpr();
                Expect(CiToken.Colon);
                result.OnFalse = ParseExpr();
                return(result);
            }
            return(left);
        }

        CiExpr ParseType()
        {
            CiExpr left = ParseExpr();

            if (Eat(CiToken.Range))
            {
                return new CiBinaryExpr {
                           Line = this.Line, Left = left, Op = CiToken.Range, Right = ParseExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseAssign(bool allowVar)
        {
            CiExpr left = ParseType();

            switch (this.CurrentToken)
            {
            case CiToken.Assign:
            case CiToken.AddAssign:
            case CiToken.SubAssign:
            case CiToken.MulAssign:
            case CiToken.DivAssign:
            case CiToken.ModAssign:
            case CiToken.AndAssign:
            case CiToken.OrAssign:
            case CiToken.XorAssign:
            case CiToken.ShiftLeftAssign:
            case CiToken.ShiftRightAssign:
                return(new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAssign(false)
                });

            case CiToken.Id:
                if (allowVar)
                {
                    return(ParseVar(left));
                }
                return(left);

            default:
                return(left);
            }
        }

        CiVar ParseVar(CiExpr type)
        {
            CiVar def = new CiVar {
                Line = this.Line, TypeExpr = type, Name = ParseId()
            };

            if (Eat(CiToken.Assign))
            {
                def.Value = ParseAssign(false);
            }
            return(def);
        }

        CiVar ParseVar()
        {
            return(ParseVar(ParseType()));
        }

        CiConst ParseConst()
        {
            Expect(CiToken.Const);
            CiConst konst = new CiConst {
                Line = this.Line, TypeExpr = ParseType(), Name = ParseId()
            };

            Expect(CiToken.Assign);
            konst.Value = ParseConstInitializer();
            Expect(CiToken.Semicolon);
            return(konst);
        }

        CiBlock ParseBlock()
        {
            int line = this.Line;

            Expect(CiToken.LeftBrace);
            List <CiStatement> statements = new List <CiStatement>();

            while (!Eat(CiToken.RightBrace))
            {
                statements.Add(ParseStatement());
            }
            return(new CiBlock {
                Filename = this.Filename, Line = this.Line, Statements = statements.ToArray()
            });
        }

        CiBreak ParseBreak()
        {
            if (this.CurrentLoopOrSwitch == null)
            {
                throw ParseException("break outside loop or switch");
            }
            CiBreak result = new CiBreak(this.CurrentLoopOrSwitch)
            {
                Line = this.Line
            };

            Expect(CiToken.Break);
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiContinue ParseContinue()
        {
            if (this.CurrentLoop == null)
            {
                throw ParseException("continue outside loop");
            }
            CiContinue result = new CiContinue(this.CurrentLoop)
            {
                Line = this.Line
            };

            Expect(CiToken.Continue);
            Expect(CiToken.Semicolon);
            return(result);
        }

        void ParseLoopBody(CiLoop loop)
        {
            CiLoop outerLoop = this.CurrentLoop;
            CiCondCompletionStatement outerLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = this.CurrentLoop = loop;
            loop.Body = ParseStatement();
            this.CurrentLoopOrSwitch = outerLoopOrSwitch;
            this.CurrentLoop         = outerLoop;
        }

        CiDoWhile ParseDoWhile()
        {
            CiDoWhile result = new CiDoWhile {
                Line = this.Line
            };

            Expect(CiToken.Do);
            ParseLoopBody(result);
            Expect(CiToken.While);
            result.Cond = ParseParenthesized();
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiFor ParseFor()
        {
            CiFor result = new CiFor {
                Line = this.Line
            };

            Expect(CiToken.For);
            Expect(CiToken.LeftParenthesis);
            if (!See(CiToken.Semicolon))
            {
                result.Init = ParseAssign(true);
            }
            Expect(CiToken.Semicolon);
            if (!See(CiToken.Semicolon))
            {
                result.Cond = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            if (!See(CiToken.RightParenthesis))
            {
                result.Advance = ParseAssign(false);
            }
            Expect(CiToken.RightParenthesis);
            ParseLoopBody(result);
            return(result);
        }

        CiForeach ParseForeach()
        {
            CiForeach result = new CiForeach {
                Line = this.Line
            };

            Expect(CiToken.Foreach);
            Expect(CiToken.LeftParenthesis);
            result.Element = new CiVar {
                Line = this.Line, TypeExpr = ParseType(), Name = ParseId()
            };
            Expect(CiToken.In);
            result.Collection = ParseExpr();
            Expect(CiToken.RightParenthesis);
            ParseLoopBody(result);
            return(result);
        }

        CiIf ParseIf()
        {
            CiIf result = new CiIf {
                Line = this.Line
            };

            Expect(CiToken.If);
            result.Cond   = ParseParenthesized();
            result.OnTrue = ParseStatement();
            if (Eat(CiToken.Else))
            {
                result.OnFalse = ParseStatement();
            }
            return(result);
        }

        CiNative ParseNative()
        {
            int line = this.Line;

            Expect(CiToken.Native);
            StringBuilder sb = new StringBuilder();

            this.CopyTo = sb;
            try {
                Expect(CiToken.LeftBrace);
                int nesting = 1;
                for (;;)
                {
                    if (See(CiToken.EndOfFile))
                    {
                        throw ParseException("Native block not terminated");
                    }
                    if (See(CiToken.LeftBrace))
                    {
                        nesting++;
                    }
                    else if (See(CiToken.RightBrace) && --nesting == 0)
                    {
                        break;
                    }
                    NextToken();
                }
            }
            finally {
                this.CopyTo = null;
            }
            NextToken();
            Trace.Assert(sb[sb.Length - 1] == '}');
            sb.Length--;
            return(new CiNative {
                Line = line, Content = sb.ToString()
            });
        }

        CiReturn ParseReturn()
        {
            CiReturn result = new CiReturn {
                Line = this.Line
            };

            NextToken();
            if (!See(CiToken.Semicolon))
            {
                result.Value = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiSwitch ParseSwitch()
        {
            CiSwitch result = new CiSwitch {
                Line = this.Line
            };

            Expect(CiToken.Switch);
            result.Value = ParseParenthesized();
            Expect(CiToken.LeftBrace);

            CiCondCompletionStatement outerLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = result;
            List <CiCase> cases = new List <CiCase>();

            while (Eat(CiToken.Case))
            {
                List <CiExpr> values = new List <CiExpr>();
                CiExpr        value;
                do
                {
                    value = ParseExpr();
                    values.Add(value);
                    Expect(CiToken.Colon);
                } while (Eat(CiToken.Case));
                if (See(CiToken.Default))
                {
                    throw StatementException(value, "Please remove case before default");
                }
                CiCase kase = new CiCase {
                    Values = values.ToArray()
                };

                List <CiStatement> statements = new List <CiStatement>();
                for (;;)
                {
                    statements.Add(ParseStatement());
                    switch (this.CurrentToken)
                    {
                    case CiToken.Case:
                    case CiToken.Default:
                    case CiToken.RightBrace:
                        break;

                    case CiToken.Goto:
                        NextToken();
                        switch (this.CurrentToken)
                        {
                        case CiToken.Case:
                            NextToken();
                            kase.Fallthrough = ParseExpr();
                            break;

                        case CiToken.Default:
                            kase.Fallthrough = new CiGotoDefault {
                                Line = this.Line
                            };
                            NextToken();
                            break;

                        default:
                            throw ParseException("Expected goto case or goto default");
                        }
                        Expect(CiToken.Semicolon);
                        break;

                    default:
                        continue;
                    }
                    break;
                }
                kase.Body = statements.ToArray();
                cases.Add(kase);
            }
            if (cases.Count == 0)
            {
                throw ParseException("Switch with no cases");
            }
            result.Cases = cases.ToArray();

            if (Eat(CiToken.Default))
            {
                Expect(CiToken.Colon);
                List <CiStatement> statements = new List <CiStatement>();
                do
                {
                    statements.Add(ParseStatement());
                }while (!See(CiToken.RightBrace));
                result.DefaultBody = statements.ToArray();
            }

            Expect(CiToken.RightBrace);
            this.CurrentLoopOrSwitch = outerLoopOrSwitch;
            return(result);
        }

        CiThrow ParseThrow()
        {
            CiThrow result = new CiThrow {
                Line = this.Line
            };

            Expect(CiToken.Throw);
            result.Message = ParseExpr();
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiWhile ParseWhile()
        {
            CiWhile result = new CiWhile {
                Line = this.Line
            };

            Expect(CiToken.While);
            result.Cond = ParseParenthesized();
            ParseLoopBody(result);
            return(result);
        }

        CiStatement ParseStatement()
        {
            switch (this.CurrentToken)
            {
            case CiToken.LeftBrace:
                return(ParseBlock());

            case CiToken.Break:
                return(ParseBreak());

            case CiToken.Const:
                return(ParseConst());

            case CiToken.Continue:
                return(ParseContinue());

            case CiToken.Do:
                return(ParseDoWhile());

            case CiToken.For:
                return(ParseFor());

            case CiToken.Foreach:
                return(ParseForeach());

            case CiToken.If:
                return(ParseIf());

            case CiToken.Native:
                return(ParseNative());

            case CiToken.Return:
                return(ParseReturn());

            case CiToken.Switch:
                return(ParseSwitch());

            case CiToken.Throw:
                return(ParseThrow());

            case CiToken.While:
                return(ParseWhile());

            default:
                CiExpr expr = ParseAssign(true);
                Expect(CiToken.Semicolon);
                return(expr);
            }
        }

        CiCallType ParseCallType()
        {
            switch (this.CurrentToken)
            {
            case CiToken.Static:
                NextToken();
                return(CiCallType.Static);

            case CiToken.Abstract:
                NextToken();
                return(CiCallType.Abstract);

            case CiToken.Virtual:
                NextToken();
                return(CiCallType.Virtual);

            case CiToken.Override:
                NextToken();
                return(CiCallType.Override);

            case CiToken.Sealed:
                NextToken();
                return(CiCallType.Sealed);

            default:
                return(CiCallType.Normal);
            }
        }

        void ParseMethod(CiMethod method)
        {
            method.IsMutator           = Eat(CiToken.ExclamationMark);
            method.Parameters.Filename = this.Filename;
            Expect(CiToken.LeftParenthesis);
            if (!See(CiToken.RightParenthesis))
            {
                do
                {
                    CiCodeDoc doc   = ParseDoc();
                    CiVar     param = ParseVar();
                    param.Documentation = doc;
                    method.Parameters.Add(param);
                } while (Eat(CiToken.Comma));
            }
            Expect(CiToken.RightParenthesis);
            method.Throws = Eat(CiToken.Throws);
            if (method.CallType == CiCallType.Abstract)
            {
                Expect(CiToken.Semicolon);
            }
            else if (See(CiToken.FatArrow))
            {
                method.Body = ParseReturn();
            }
            else
            {
                method.Body = ParseBlock();
            }
        }

        public CiClass ParseClass(CiCallType callType)
        {
            Expect(CiToken.Class);
            CiClass klass = new CiClass {
                Parent = this.Program, Filename = this.Filename, Line = this.Line, CallType = callType, Name = ParseId()
            };

            if (Eat(CiToken.Colon))
            {
                klass.BaseClassName = ParseId();
            }
            Expect(CiToken.LeftBrace);

            List <CiConst>  consts  = new List <CiConst>();
            List <CiField>  fields  = new List <CiField>();
            List <CiMethod> methods = new List <CiMethod>();

            while (!Eat(CiToken.RightBrace))
            {
                CiCodeDoc doc = ParseDoc();

                CiVisibility visibility;
                switch (this.CurrentToken)
                {
                case CiToken.Internal:
                    visibility = CiVisibility.Internal;
                    NextToken();
                    break;

                case CiToken.Protected:
                    visibility = CiVisibility.Protected;
                    NextToken();
                    break;

                case CiToken.Public:
                    visibility = CiVisibility.Public;
                    NextToken();
                    break;

                default:
                    visibility = CiVisibility.Private;
                    break;
                }

                if (See(CiToken.Const))
                {
                    // const
                    CiConst konst = ParseConst();
                    konst.Documentation = doc;
                    konst.Visibility    = visibility;
                    consts.Add(konst);
                    continue;
                }

                callType = ParseCallType();
                // \ class | static | normal | abstract | sealed
                // method \|        |        |          |
                // --------+--------+--------+----------+-------
                // static  |   +    |   +    |    +     |   +
                // normal  |   -    |   +    |    +     |   +
                // abstract|   -    |   -    |    +     |   -
                // virtual |   -    |   +    |    +     |   -
                // override|   -    |   +    |    +     |   +
                // sealed  |   -    |   +    |    +     |   +
                if (callType == CiCallType.Static || klass.CallType == CiCallType.Abstract)
                {
                    // ok
                }
                else if (klass.CallType == CiCallType.Static)
                {
                    throw ParseException("Only static members allowed in a static class");
                }
                else if (callType == CiCallType.Abstract)
                {
                    throw ParseException("Abstract methods allowed only in an abstract class");
                }
                else if (klass.CallType == CiCallType.Sealed && callType == CiCallType.Virtual)
                {
                    throw ParseException("Virtual methods disallowed in a sealed class");
                }
                if (visibility == CiVisibility.Private && callType != CiCallType.Static && callType != CiCallType.Normal)
                {
                    throw ParseException("{0} method cannot be private", callType);
                }

                CiExpr type = Eat(CiToken.Void) ? null : ParseType();
                if (See(CiToken.LeftBrace) &&
                    type is CiBinaryExpr call &&
                    call.Op == CiToken.LeftParenthesis &&
                    call.Left is CiSymbolReference sr)
                {
                    // constructor
                    if (sr.Name != klass.Name)
                    {
                        throw ParseException("Constructor name doesn't match class name");
                    }
                    if (callType != CiCallType.Normal)
                    {
                        throw ParseException("Constructor cannot be {0}", callType);
                    }
                    if (call.RightCollection.Length != 0)
                    {
                        throw ParseException("Constructor parameters not supported");
                    }
                    if (klass.Constructor != null)
                    {
                        throw ParseException("Duplicate constructor, already defined in line {0}", klass.Constructor.Line);
                    }
                    if (visibility == CiVisibility.Private)
                    {
                        visibility = CiVisibility.Internal;                 // TODO
                    }
                    klass.Constructor = new CiMethodBase {
                        Line = sr.Line, Documentation = doc, Visibility = visibility, Parent = klass, Name = klass.Name, Body = ParseBlock()
                    };
                    continue;
                }

                int    line = this.Line;
                string name = ParseId();
                if (See(CiToken.LeftParenthesis) || See(CiToken.ExclamationMark))
                {
                    // method
                    CiMethod method = new CiMethod {
                        Line = line, Documentation = doc, Visibility = visibility, CallType = callType, TypeExpr = type, Name = name
                    };
                    method.Parameters.Parent = klass;
                    ParseMethod(method);
                    methods.Add(method);
                    continue;
                }

                // field
                if (visibility == CiVisibility.Public)
                {
                    throw ParseException("Field cannot be public");
                }
                if (callType != CiCallType.Normal)
                {
                    throw ParseException("Field cannot be {0}", callType);
                }
                if (type == null)
                {
                    throw ParseException("Field cannot be void");
                }
                CiField field = new CiField {
                    Line = line, Documentation = doc, Visibility = visibility, TypeExpr = type, Name = name
                };
                if (Eat(CiToken.Assign))
                {
                    field.Value = ParseExpr();
                }
                Expect(CiToken.Semicolon);
                fields.Add(field);
            }

            klass.Consts  = consts.ToArray();
            klass.Fields  = fields.ToArray();
            klass.Methods = methods.ToArray();
            return(klass);
        }

        public CiEnum ParseEnum()
        {
            Expect(CiToken.Enum);
            CiEnum enu = new CiEnum {
                Parent = this.Program, Filename = this.Filename, IsFlags = Eat(CiToken.Asterisk), Line = this.Line, Name = ParseId()
            };

            Expect(CiToken.LeftBrace);
            do
            {
                CiConst konst = new CiConst {
                    Documentation = ParseDoc(), Line = this.Line, Name = ParseId(), Type = enu
                };
                if (Eat(CiToken.Assign))
                {
                    konst.Value = ParseExpr();
                }
                else if (enu.IsFlags)
                {
                    throw ParseException("enum* symbol must be assigned a value");
                }
                enu.Add(konst);
            } while (Eat(CiToken.Comma));
            Expect(CiToken.RightBrace);
            return(enu);
        }

        public void Parse(string filename, TextReader reader)
        {
            Open(filename, reader);
            while (!See(CiToken.EndOfFile))
            {
                CiCodeDoc       doc = ParseDoc();
                CiContainerType type;
                bool            isPublic = Eat(CiToken.Public);
                switch (this.CurrentToken)
                {
                // class
                case CiToken.Class:
                    type = ParseClass(CiCallType.Normal);
                    break;

                case CiToken.Static:
                case CiToken.Abstract:
                case CiToken.Sealed:
                    type = ParseClass(ParseCallType());
                    break;

                // enum
                case CiToken.Enum:
                    type = ParseEnum();
                    break;

                // native
                case CiToken.Native:
                    this.Program.TopLevelNatives.Add(ParseNative().Content);
                    continue;

                default:
                    throw ParseException("Expected class or enum");
                }
                type.Documentation = doc;
                type.IsPublic      = isPublic;
                this.Program.Add(type);
            }
        }
    }
}
Beispiel #36
0
Datei: GenC.cs Projekt: epi/cito
        void WriteConstructorNewDelete(CiClass klass)
        {
            if (klass.Constructs) {
            WriteLine();
            this.CurrentMethod = klass.Constructor;
            WriteConstructorSignature(klass);
            WriteLine();
            OpenBlock();
            if (klass.Constructor != null)
                StartBlock(klass.Constructor.Body.Statements);
            CiClass ptrClass = GetVtblPtrClass(klass);
            if (HasVtblValue(klass)) {
                WriteLine("if (vtbl == NULL)");
                this.Indent++;
                Write("vtbl = ");
                CiClass structClass = GetVtblStructClass(klass);
                if (structClass != ptrClass) {
                    Write("(const ");
                    Write(ptrClass.Name);
                    Write("Vtbl *) ");
                }
                Write("&CiVtbl_");
                Write(klass.Name);
                WriteLine(";");
                this.Indent--;
            }
            if (ptrClass == klass)
                WriteLine("self->vtbl = vtbl;");
            if (klass.BaseClass != null && klass.BaseClass.Constructs) {
                Write(klass.BaseClass.Name);
                Write("_Construct(&self->base");
                if (HasVirtualMethods(klass.BaseClass))
                    Write(", vtbl");
                WriteLine(");");
            }
            ForEachStorageField(klass, (field, fieldClass) => {
                if (fieldClass.Constructs) {
                    Write(fieldClass.Name);
                    Write("_Construct(&self->");
                    WriteCamelCase(field.Name);
                    if (HasVirtualMethods(fieldClass))
                        Write(", NULL");
                    WriteLine(");");
                }
            });
            if (klass.Constructor != null)
                Write(klass.Constructor.Body.Statements);
            CloseBlock();
            this.CurrentMethod = null;
            }
            if (!klass.IsAbstract && HasCStruct(klass)) {
            if (klass.Visibility == CiVisibility.Public) {
                WriteLine();
                WriteNew(klass);

                WriteLine();
                WriteDeleteSignature(klass);
                WriteLine();
                OpenBlock();
                WriteLine("free(self);");
                CloseBlock();
            }
            else if (klass.IsAllocated) {
                WriteLine();
                Write("static ");
                WriteNew(klass);
            }
            }
        }
Beispiel #37
0
 protected virtual void WriteNew(CiClass klass, CiPriority parent)
 {
     Write("new ");
     Write(klass.Name);
     Write("()");
 }
Beispiel #38
0
 CiClass ParseClass()
 {
     CiClass klass = new CiClass();
     klass.SourceFilename = this.Filename;
     if (Eat(CiToken.Abstract))
     klass.IsAbstract = true;
     Expect(CiToken.Class);
     klass.Name = ParseId();
     if (Eat(CiToken.Colon))
     klass.BaseClass = new CiUnknownClass { Name = ParseId() };
     Expect(CiToken.LeftBrace);
     OpenScope();
     this.CurrentClass = klass;
     klass.Members = this.Symbols;
     while (!Eat(CiToken.RightBrace)) {
     CiCodeDoc doc = ParseDoc();
     CiVisibility visibility = CiVisibility.Private;
     if (Eat(CiToken.Public))
         visibility = CiVisibility.Public;
     else if (Eat(CiToken.Internal))
         visibility = CiVisibility.Internal;
     CiSymbol symbol;
     if (See(CiToken.Const)) {
         symbol = ParseConst();
         ((CiConst) symbol).Class = klass;
     }
     else if (Eat(CiToken.Macro)) {
         if (visibility != CiVisibility.Private)
             throw new ParseException("Macros must be private");
         symbol = ParseMacro();
     }
     else {
         CiCallType callType;
         if (Eat(CiToken.Static))
             callType = CiCallType.Static;
         else if (Eat(CiToken.Abstract)) {
             if (!klass.IsAbstract)
                 throw new ParseException("Abstract methods only allowed in abstract classes");
             callType = CiCallType.Abstract;
             if (visibility == CiVisibility.Private)
                 visibility = CiVisibility.Internal;
         }
         else if (Eat(CiToken.Virtual)) {
             callType = CiCallType.Virtual;
             if (visibility == CiVisibility.Private)
                 visibility = CiVisibility.Internal;
         }
         else if (Eat(CiToken.Override)) {
             callType = CiCallType.Override;
             if (visibility == CiVisibility.Private)
                 visibility = CiVisibility.Internal;
         }
         else
             callType = CiCallType.Normal;
         CiType type = ParseReturnType();
         if (type is CiClassStorageType && See(CiToken.LeftBrace)) {
             if (type.Name != klass.Name)
                 throw new ParseException("{0}() looks like a constructor, but it is in a different class {1}", type.Name, klass.Name);
             if (callType != CiCallType.Normal)
                 throw new ParseException("Constructor cannot be static, abstract, virtual or override");
             if (klass.Constructor != null)
                 throw new ParseException("Duplicate constructor");
             klass.Constructor = ParseConstructor();
             continue;
         }
         string name = ParseId();
         if (See(CiToken.LeftParenthesis)) {
             CiMethod method = new CiMethod(type, name) {
                 Class = klass,
                 CallType = callType
             };
             ParseMethod(method);
             symbol = method;
         }
         else {
             if (visibility != CiVisibility.Private)
                 throw new ParseException("Fields must be private");
             if (callType != CiCallType.Normal)
                 throw new ParseException("Fields cannot be static, abstract, virtual or override");
             if (type == CiType.Void)
                 throw new ParseException("Field is void");
             Expect(CiToken.Semicolon);
             symbol = new CiField { Class = klass, Type = type, Name = name };
         }
     }
     symbol.Documentation = doc;
     symbol.Visibility = visibility;
     klass.Members.Add(symbol);
     }
     this.CurrentClass = null;
     CloseScope();
     klass.ConstArrays = this.ConstArrays.ToArray();
     this.ConstArrays.Clear();
     return klass;
 }
Beispiel #39
0
 protected override void WriteNew(CiClass klass, CiPriority parent)
 {
     WriteName(klass);
     Write("()");
 }
Beispiel #40
0
Datei: GenC.cs Projekt: epi/cito
 void WriteTypedef(CiClass klass)
 {
     klass.WriteStatus = CiWriteStatus.NotYet;
     klass.HasFields = klass.Members.Any(member => member is CiField);
     bool klassHasInstanceMethods = klass.Members.Any(member => member is CiMethod && ((CiMethod) member).CallType != CiCallType.Static);
     if (klass.BaseClass != null || klass.HasFields || klassHasInstanceMethods) {
     Write("typedef struct ");
     Write(klass.Name);
     Write(' ');
     Write(klass.Name);
     WriteLine(";");
     }
 }
Beispiel #41
0
        void Write(CiClass klass, CiMethod method)
        {
            WriteDoc(method);
            Write(method.Visibility);
            switch (method.CallType)
            {
            case CiCallType.Static:
                Write("static ");
                break;

            case CiCallType.Virtual:
                break;

            case CiCallType.Abstract:
                Write("abstract ");
                break;

            case CiCallType.Override:
                break;

            case CiCallType.Normal:
                // no final methods in TS
                break;

            case CiCallType.Sealed:
                // no final methods in TS
                break;

            default:
                throw new NotImplementedException(method.CallType.ToString());
            }
            WriteName(method);
            Write('(');
            int i = 0;

            foreach (CiVar param in method.Parameters)
            {
                if (i > 0)
                {
                    Write(", ");
                }
                WriteName(param);
                if (param.Value != null && !this.GenFullCode)
                {
                    Write('?');
                }
                Write(": ");
                Write(param.Type);
                if (param.Value != null && this.GenFullCode)
                {
                    WriteVarInit(param);
                }
                i++;
            }
            Write("): ");
            Write(method.Type);
            if (this.GenFullCode)
            {
                WriteBody(method);
            }
            else
            {
                WriteLine(';');
            }
        }
Beispiel #42
0
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     CreateJavaFile(klass);
     OpenClass(klass.IsAbstract, klass, " extends ");
     this.UsesSubstringMethod = false;
     this.UsesClearBytesMethod = false;
     this.UsesClearIntsMethod = false;
     if (klass.Constructor != null) {
     Write("public ");
     Write(klass.Name);
     WriteLine("()");
     Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     member.Accept(this);
     if (this.UsesSubstringMethod)
     WriteSubstringMethod();
     if (this.UsesClearBytesMethod)
     WriteClearMethod("byte");
     if (this.UsesClearIntsMethod)
     WriteClearMethod("int");
     if (klass.BinaryResources.Length > 0)
     WriteGetBinaryResource(klass);
     foreach (CiConst konst in klass.ConstArrays) {
     Write("private static final ");
     Write(konst.Type);
     WriteUppercaseWithUnderscores(konst.GlobalName);
     Write(" = ");
     WriteConst(konst.Value);
     WriteLine(";");
     }
     CloseJavaFile();
 }
Beispiel #43
0
 protected virtual void WriteClassName(CiClass klass)
 {
     WriteName(klass);
 }
Beispiel #44
0
Datei: GenC.cs Projekt: epi/cito
 void WriteVtblStruct(CiClass klass)
 {
     if (!AddsVirtualMethods(klass))
     return;
     Write("typedef struct ");
     OpenBlock();
     foreach (CiMethod method in EnumVirtualMethods(klass)) {
     WritePtr(method, ToCamelCase(method.Name));
     WriteLine(";");
     }
     CloseBlock();
     Write(klass.Name);
     WriteLine("Vtbl;");
 }
Beispiel #45
0
Datei: GenD.cs Projekt: epi/cito
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     WriteLine();
     Write(klass.Documentation);
     Write(klass.Visibility);
     OpenClass(klass.IsAbstract, klass, " : ");
     CurrentClass = klass;
     bool hasConstructor = klass.Constructor != null;
     foreach (CiSymbol member in klass.Members) {
     if (!hasConstructor) {
         CiField field = member as CiField;
         if (field != null && (field.Type is CiClassStorageType || field.Type is CiArrayStorageType))
             hasConstructor = true;
     }
     member.Accept(this);
     }
     foreach (CiConst konst in klass.ConstArrays) {
     if (konst.Visibility != CiVisibility.Public) {
         Write("static immutable(");
         Write(konst.Type);
         Write(") ");
         Write(konst.Class == CurrentClass ? konst.Name : konst.GlobalName);
         Write(" = ");
         WriteConst(konst.Value);
         WriteLine(";");
     }
     }
     foreach (CiBinaryResource resource in klass.BinaryResources) {
     // FIXME: it's better to import(resources) from binary files,
     // rather than pasting tons of magic numbers in the source.
     Write("static immutable(ubyte[]) ");
     WriteName(resource);
     Write(" = ");
     WriteConst(resource.Content);
     WriteLine(";");
     }
     if (hasConstructor) {
     WriteLine("this()");
     OpenBlock();
     foreach (CiSymbol member in klass.Members) {
         CiField field = member as CiField;
         if (field != null && (field.Type is CiClassStorageType || field.Type is CiArrayStorageType)) {
             WriteVarName(field.Name);
             WriteInit(field.Type);
             WriteLine(";");
         }
     }
     if (klass.Constructor != null)
         Write(klass.Constructor.Body.Statements);
     CloseBlock();
     }
     CloseBlock();
     CurrentClass = null;
 }
Beispiel #46
0
        CiExpr ParseConstInitializer()
        {
            if (Eat(CiToken.LeftBrace))
            {
                return new CiCollection {
                           Line = this.Line, Items = ParseCollection(CiToken.RightBrace)
                }
            }
            ;
            return(ParseExpr());
        }

        CiExpr[] ParseCollection(CiToken closing)
        {
            List <CiExpr> items = new List <CiExpr>();

            if (!See(closing))
            {
                do
                {
                    items.Add(ParseExpr());
                }while (Eat(CiToken.Comma));
            }
            Expect(closing);
            return(items.ToArray());
        }

        void CheckXcrementParent()
        {
            if (this.XcrementParent != null)
            {
                string op = this.CurrentToken == CiToken.Increment ? "++" : "--";
                throw ParseException(op + " not allowed on the right side of " + this.XcrementParent);
            }
        }

        bool SeeDigit()
        {
            int c = PeekChar();

            return(c >= '0' && c <= '9');
        }

        CiInterpolatedString ParseInterpolatedString()
        {
            int line = this.Line;
            List <CiInterpolatedPart> parts = new List <CiInterpolatedPart>();

            do
            {
                string prefix = (string)this.CurrentValue;
                NextToken();
                CiExpr arg       = ParseExpr();
                CiExpr width     = null;
                char   format    = ' ';
                int    precision = -1;
                if (Eat(CiToken.Comma))
                {
                    width = ParseExpr();
                }
                if (See(CiToken.Colon))
                {
                    format = (char)ReadChar();
                    if ("DdEeFfGgXx".IndexOf(format) < 0)
                    {
                        throw ParseException("Invalid format specifier");
                    }

                    if (SeeDigit())
                    {
                        precision = ReadChar() - '0';
                        if (SeeDigit())
                        {
                            precision = precision * 10 + ReadChar() - '0';
                        }
                    }
                    NextToken();
                }
                parts.Add(new CiInterpolatedPart(prefix, arg)
                {
                    WidthExpr = width, Format = format, Precision = precision
                });
                Check(CiToken.RightBrace);
            } while (ReadInterpolatedString() == CiToken.InterpolatedString);
            string suffix = (string)this.CurrentValue;

            NextToken();
            return(new CiInterpolatedString(parts.ToArray(), suffix)
            {
                Line = line
            });
        }

        CiExpr ParseParenthesized()
        {
            Expect(CiToken.LeftParenthesis);
            CiExpr result = ParseExpr();

            Expect(CiToken.RightParenthesis);
            return(result);
        }

        CiExpr ParsePrimaryExpr()
        {
            CiExpr result;

            switch (this.CurrentToken)
            {
            case CiToken.Increment:
            case CiToken.Decrement:
                CheckXcrementParent();
                goto case CiToken.Minus;

            case CiToken.Minus:
            case CiToken.Tilde:
            case CiToken.ExclamationMark:
            case CiToken.New:
                return(new CiPrefixExpr {
                    Line = this.Line, Op = NextToken(), Inner = ParsePrimaryExpr()
                });

            case CiToken.Literal:
                result = new CiLiteral(this.CurrentValue)
                {
                    Line = this.Line
                };
                NextToken();
                break;

            case CiToken.InterpolatedString:
                result = ParseInterpolatedString();
                break;

            case CiToken.LeftParenthesis:
                Expect(CiToken.LeftParenthesis);
                result = ParseType();
                Expect(CiToken.RightParenthesis);
                break;

            case CiToken.Id:
                result = ParseSymbolReference(null);
                break;

            case CiToken.List:
                result = ParseListType();
                break;

            case CiToken.Dictionary:
                result = ParseDictionaryType(CiSystem.DictionaryClass);
                break;

            case CiToken.SortedDictionary:
                result = ParseDictionaryType(CiSystem.SortedDictionaryClass);
                break;

            case CiToken.Resource:
                NextToken();
                Expect(CiToken.Less);
                if (ParseId() != "byte")
                {
                    throw ParseException("Expected resource<byte[]>");
                }
                Expect(CiToken.LeftBracket);
                Expect(CiToken.RightBracket);
                Expect(CiToken.Greater);
                result = new CiPrefixExpr {
                    Line = this.Line, Op = CiToken.Resource, Inner = ParseParenthesized()
                };
                break;

            default:
                throw ParseException("Invalid expression");
            }
            for (;;)
            {
                switch (this.CurrentToken)
                {
                case CiToken.Dot:
                    NextToken();
                    result = ParseSymbolReference(result);
                    break;

                case CiToken.LeftParenthesis:
                    if (!(result is CiSymbolReference symbol))
                    {
                        throw ParseException("Expected a method");
                    }
                    NextToken();
                    result = new CiCallExpr {
                        Line = this.Line, Method = symbol, Arguments = ParseCollection(CiToken.RightParenthesis)
                    };
                    break;

                case CiToken.LeftBracket:
                    result = new CiBinaryExpr {
                        Line = this.Line, Left = result, Op = NextToken(), Right = See(CiToken.RightBracket) ? null : ParseExpr()
                    };
                    Expect(CiToken.RightBracket);
                    break;

                case CiToken.Increment:
                case CiToken.Decrement:
                    CheckXcrementParent();
                    goto case CiToken.ExclamationMark;

                case CiToken.ExclamationMark:
                case CiToken.Hash:
                    result = new CiPostfixExpr {
                        Line = this.Line, Inner = result, Op = NextToken()
                    };
                    break;

                default:
                    return(result);
                }
            }
        }

        CiExpr ParseMulExpr()
        {
            CiExpr left = ParsePrimaryExpr();

            for (;;)
            {
                switch (this.CurrentToken)
                {
                case CiToken.Asterisk:
                case CiToken.Slash:
                case CiToken.Mod:
                    left = new CiBinaryExpr {
                        Line = this.Line, Left = left, Op = NextToken(), Right = ParsePrimaryExpr()
                    };
                    break;

                default:
                    return(left);
                }
            }
        }

        CiExpr ParseAddExpr()
        {
            CiExpr left = ParseMulExpr();

            while (See(CiToken.Plus) || See(CiToken.Minus))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseMulExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseShiftExpr()
        {
            CiExpr left = ParseAddExpr();

            while (See(CiToken.ShiftLeft) || See(CiToken.ShiftRight))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAddExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseRelExpr()
        {
            CiExpr left = ParseShiftExpr();

            for (;;)
            {
                switch (this.CurrentToken)
                {
                case CiToken.Less:
                case CiToken.LessOrEqual:
                case CiToken.Greater:
                case CiToken.GreaterOrEqual:
                    left = new CiBinaryExpr {
                        Line = this.Line, Left = left, Op = NextToken(), Right = ParseShiftExpr()
                    };
                    break;

                default:
                    return(left);
                }
            }
        }

        CiExpr ParseEqualityExpr()
        {
            CiExpr left = ParseRelExpr();

            while (See(CiToken.Equal) || See(CiToken.NotEqual))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseRelExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseAndExpr()
        {
            CiExpr left = ParseEqualityExpr();

            while (See(CiToken.And))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseEqualityExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseXorExpr()
        {
            CiExpr left = ParseAndExpr();

            while (See(CiToken.Xor))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAndExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseOrExpr()
        {
            CiExpr left = ParseXorExpr();

            while (See(CiToken.Or))
            {
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseXorExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseCondAndExpr()
        {
            CiExpr left = ParseOrExpr();

            while (See(CiToken.CondAnd))
            {
                string saveXcrementParent = this.XcrementParent;
                this.XcrementParent = "&&";
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseOrExpr()
                };
                this.XcrementParent = saveXcrementParent;
            }
            return(left);
        }

        CiExpr ParseCondOrExpr()
        {
            CiExpr left = ParseCondAndExpr();

            while (See(CiToken.CondOr))
            {
                string saveXcrementParent = this.XcrementParent;
                this.XcrementParent = "||";
                left = new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseCondAndExpr()
                };
                this.XcrementParent = saveXcrementParent;
            }
            return(left);
        }

        CiExpr ParseExpr()
        {
            CiExpr left = ParseCondOrExpr();

            if (See(CiToken.QuestionMark))
            {
                CiSelectExpr result = new CiSelectExpr {
                    Line = this.Line, Cond = left
                };
                NextToken();
                string saveXcrementParent = this.XcrementParent;
                this.XcrementParent = "?";
                result.OnTrue       = ParseExpr();
                Expect(CiToken.Colon);
                result.OnFalse      = ParseExpr();
                this.XcrementParent = saveXcrementParent;
                return(result);
            }
            return(left);
        }

        CiExpr ParseType()
        {
            CiExpr left = ParseExpr();

            if (Eat(CiToken.Range))
            {
                return new CiBinaryExpr {
                           Line = this.Line, Left = left, Op = CiToken.Range, Right = ParseExpr()
                }
            }
            ;
            return(left);
        }

        CiExpr ParseAssign(bool allowVar)
        {
            CiExpr left = ParseType();

            switch (this.CurrentToken)
            {
            case CiToken.Assign:
            case CiToken.AddAssign:
            case CiToken.SubAssign:
            case CiToken.MulAssign:
            case CiToken.DivAssign:
            case CiToken.ModAssign:
            case CiToken.AndAssign:
            case CiToken.OrAssign:
            case CiToken.XorAssign:
            case CiToken.ShiftLeftAssign:
            case CiToken.ShiftRightAssign:
                return(new CiBinaryExpr {
                    Line = this.Line, Left = left, Op = NextToken(), Right = ParseAssign(false)
                });

            case CiToken.Id:
                if (allowVar)
                {
                    return(ParseVar(left));
                }
                return(left);

            default:
                return(left);
            }
        }

        CiVar ParseVar(CiExpr type)
        {
            CiVar def = new CiVar {
                Line = this.Line, TypeExpr = type, Name = ParseId()
            };

            if (Eat(CiToken.Assign))
            {
                def.Value = ParseAssign(false);
            }
            return(def);
        }

        CiVar ParseVar()
        {
            return(ParseVar(ParseType()));
        }

        CiConst ParseConst()
        {
            Expect(CiToken.Const);
            CiConst konst = new CiConst {
                Line = this.Line, TypeExpr = ParseType(), Name = ParseId()
            };

            Expect(CiToken.Assign);
            konst.Value = ParseConstInitializer();
            Expect(CiToken.Semicolon);
            return(konst);
        }

        CiBlock ParseBlock()
        {
            int line = this.Line;

            Expect(CiToken.LeftBrace);
            List <CiStatement> statements = new List <CiStatement>();

            while (!Eat(CiToken.RightBrace))
            {
                statements.Add(ParseStatement());
            }
            return(new CiBlock {
                Line = line, Statements = statements.ToArray()
            });
        }

        CiAssert ParseAssert()
        {
            CiAssert result = new CiAssert {
                Line = this.Line
            };

            Expect(CiToken.Assert);
            result.Cond = ParseExpr();
            if (Eat(CiToken.Comma))
            {
                result.Message = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiBreak ParseBreak()
        {
            if (this.CurrentLoopOrSwitch == null)
            {
                throw ParseException("break outside loop or switch");
            }
            CiBreak result = new CiBreak(this.CurrentLoopOrSwitch)
            {
                Line = this.Line
            };

            Expect(CiToken.Break);
            Expect(CiToken.Semicolon);
            if (this.CurrentLoopOrSwitch is CiLoop loop)
            {
                loop.HasBreak = true;
            }
            return(result);
        }

        CiContinue ParseContinue()
        {
            if (this.CurrentLoop == null)
            {
                throw ParseException("continue outside loop");
            }
            CiContinue result = new CiContinue(this.CurrentLoop)
            {
                Line = this.Line
            };

            Expect(CiToken.Continue);
            Expect(CiToken.Semicolon);
            return(result);
        }

        void ParseLoopBody(CiLoop loop)
        {
            CiLoop outerLoop = this.CurrentLoop;
            CiCondCompletionStatement outerLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = this.CurrentLoop = loop;
            loop.Body = ParseStatement();
            this.CurrentLoopOrSwitch = outerLoopOrSwitch;
            this.CurrentLoop         = outerLoop;
        }

        CiDoWhile ParseDoWhile()
        {
            CiDoWhile result = new CiDoWhile {
                Line = this.Line
            };

            Expect(CiToken.Do);
            ParseLoopBody(result);
            Expect(CiToken.While);
            result.Cond = ParseParenthesized();
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiFor ParseFor()
        {
            CiFor result = new CiFor {
                Line = this.Line
            };

            Expect(CiToken.For);
            Expect(CiToken.LeftParenthesis);
            if (!See(CiToken.Semicolon))
            {
                result.Init = ParseAssign(true);
            }
            Expect(CiToken.Semicolon);
            if (!See(CiToken.Semicolon))
            {
                result.Cond = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            if (!See(CiToken.RightParenthesis))
            {
                result.Advance = ParseAssign(false);
            }
            Expect(CiToken.RightParenthesis);
            ParseLoopBody(result);
            return(result);
        }

        void ParseForeachIterator(CiForeach result)
        {
            result.Add(new CiVar {
                Line = this.Line, TypeExpr = ParseType(), Name = ParseId()
            });
        }

        CiForeach ParseForeach()
        {
            CiForeach result = new CiForeach {
                Line = this.Line
            };

            Expect(CiToken.Foreach);
            Expect(CiToken.LeftParenthesis);
            if (Eat(CiToken.LeftParenthesis))
            {
                ParseForeachIterator(result);
                Expect(CiToken.Comma);
                ParseForeachIterator(result);
                Expect(CiToken.RightParenthesis);
            }
            else
            {
                ParseForeachIterator(result);
            }
            Expect(CiToken.In);
            result.Collection = ParseExpr();
            Expect(CiToken.RightParenthesis);
            ParseLoopBody(result);
            return(result);
        }

        CiIf ParseIf()
        {
            CiIf result = new CiIf {
                Line = this.Line
            };

            Expect(CiToken.If);
            result.Cond   = ParseParenthesized();
            result.OnTrue = ParseStatement();
            if (Eat(CiToken.Else))
            {
                result.OnFalse = ParseStatement();
            }
            return(result);
        }

        CiNative ParseNative()
        {
            int line = this.Line;

            Expect(CiToken.Native);
            StringBuilder sb = new StringBuilder();

            this.CopyTo = sb;
            try {
                Expect(CiToken.LeftBrace);
                int nesting = 1;
                for (;;)
                {
                    if (See(CiToken.EndOfFile))
                    {
                        throw ParseException("Native block not terminated");
                    }
                    if (See(CiToken.LeftBrace))
                    {
                        nesting++;
                    }
                    else if (See(CiToken.RightBrace) && --nesting == 0)
                    {
                        break;
                    }
                    NextToken();
                }
            }
            finally {
                this.CopyTo = null;
            }
            NextToken();
            Trace.Assert(sb[sb.Length - 1] == '}');
            sb.Length--;
            return(new CiNative {
                Line = line, Content = sb.ToString()
            });
        }

        CiReturn ParseReturn()
        {
            CiReturn result = new CiReturn {
                Line = this.Line
            };

            NextToken();
            if (!See(CiToken.Semicolon))
            {
                result.Value = ParseExpr();
            }
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiSwitch ParseSwitch()
        {
            CiSwitch result = new CiSwitch {
                Line = this.Line
            };

            Expect(CiToken.Switch);
            result.Value = ParseParenthesized();
            Expect(CiToken.LeftBrace);

            CiCondCompletionStatement outerLoopOrSwitch = this.CurrentLoopOrSwitch;

            this.CurrentLoopOrSwitch = result;
            List <CiCase> cases = new List <CiCase>();

            while (Eat(CiToken.Case))
            {
                List <CiExpr> values = new List <CiExpr>();
                CiExpr        value;
                do
                {
                    value = ParseExpr();
                    values.Add(value);
                    Expect(CiToken.Colon);
                } while (Eat(CiToken.Case));
                if (See(CiToken.Default))
                {
                    throw StatementException(value, "Please remove case before default");
                }
                CiCase kase = new CiCase {
                    Values = values.ToArray()
                };

                List <CiStatement> statements = new List <CiStatement>();
                for (;;)
                {
                    statements.Add(ParseStatement());
                    switch (this.CurrentToken)
                    {
                    case CiToken.Case:
                    case CiToken.Default:
                    case CiToken.RightBrace:
                        break;

                    default:
                        continue;
                    }
                    break;
                }
                kase.Body = statements.ToArray();
                cases.Add(kase);
            }
            if (cases.Count == 0)
            {
                throw ParseException("Switch with no cases");
            }
            result.Cases = cases.ToArray();

            if (Eat(CiToken.Default))
            {
                Expect(CiToken.Colon);
                List <CiStatement> statements = new List <CiStatement>();
                do
                {
                    statements.Add(ParseStatement());
                }while (!See(CiToken.RightBrace));
                result.DefaultBody = statements.ToArray();
            }

            Expect(CiToken.RightBrace);
            this.CurrentLoopOrSwitch = outerLoopOrSwitch;
            return(result);
        }

        CiThrow ParseThrow()
        {
            CiThrow result = new CiThrow {
                Line = this.Line
            };

            Expect(CiToken.Throw);
            result.Message = ParseExpr();
            Expect(CiToken.Semicolon);
            return(result);
        }

        CiWhile ParseWhile()
        {
            CiWhile result = new CiWhile {
                Line = this.Line
            };

            Expect(CiToken.While);
            result.Cond = ParseParenthesized();
            ParseLoopBody(result);
            return(result);
        }

        CiStatement ParseStatement()
        {
            switch (this.CurrentToken)
            {
            case CiToken.LeftBrace:
                return(ParseBlock());

            case CiToken.Assert:
                return(ParseAssert());

            case CiToken.Break:
                return(ParseBreak());

            case CiToken.Const:
                return(ParseConst());

            case CiToken.Continue:
                return(ParseContinue());

            case CiToken.Do:
                return(ParseDoWhile());

            case CiToken.For:
                return(ParseFor());

            case CiToken.Foreach:
                return(ParseForeach());

            case CiToken.If:
                return(ParseIf());

            case CiToken.Native:
                return(ParseNative());

            case CiToken.Return:
                return(ParseReturn());

            case CiToken.Switch:
                return(ParseSwitch());

            case CiToken.Throw:
                return(ParseThrow());

            case CiToken.While:
                return(ParseWhile());

            default:
                CiExpr expr = ParseAssign(true);
                Expect(CiToken.Semicolon);
                return(expr);
            }
        }

        CiCallType ParseCallType()
        {
            switch (this.CurrentToken)
            {
            case CiToken.Static:
                NextToken();
                return(CiCallType.Static);

            case CiToken.Abstract:
                NextToken();
                return(CiCallType.Abstract);

            case CiToken.Virtual:
                NextToken();
                return(CiCallType.Virtual);

            case CiToken.Override:
                NextToken();
                return(CiCallType.Override);

            case CiToken.Sealed:
                NextToken();
                return(CiCallType.Sealed);

            default:
                return(CiCallType.Normal);
            }
        }

        void ParseMethod(CiMethod method)
        {
            method.IsMutator = Eat(CiToken.ExclamationMark);
            Expect(CiToken.LeftParenthesis);
            if (!See(CiToken.RightParenthesis))
            {
                do
                {
                    CiCodeDoc doc   = ParseDoc();
                    CiVar     param = ParseVar();
                    param.Documentation = doc;
                    method.Parameters.Add(param);
                } while (Eat(CiToken.Comma));
            }
            Expect(CiToken.RightParenthesis);
            method.Throws = Eat(CiToken.Throws);
            if (method.CallType == CiCallType.Abstract)
            {
                Expect(CiToken.Semicolon);
            }
            else if (See(CiToken.FatArrow))
            {
                method.Body = ParseReturn();
            }
            else
            {
                method.Body = ParseBlock();
            }
        }

        public CiClass ParseClass(CiCallType callType)
        {
            Expect(CiToken.Class);
            CiClass klass = new CiClass {
                Parent = this.Program, Filename = this.Filename, Line = this.Line, CallType = callType, Name = ParseId()
            };

            if (Eat(CiToken.Colon))
            {
                klass.BaseClassName = ParseId();
            }
            Expect(CiToken.LeftBrace);

            List <CiConst>  consts  = new List <CiConst>();
            List <CiField>  fields  = new List <CiField>();
            List <CiMethod> methods = new List <CiMethod>();

            while (!Eat(CiToken.RightBrace))
            {
                CiCodeDoc doc = ParseDoc();

                CiVisibility visibility;
                switch (this.CurrentToken)
                {
                case CiToken.Internal:
                    visibility = CiVisibility.Internal;
                    NextToken();
                    break;

                case CiToken.Protected:
                    visibility = CiVisibility.Protected;
                    NextToken();
                    break;

                case CiToken.Public:
                    visibility = CiVisibility.Public;
                    NextToken();
                    break;

                default:
                    visibility = CiVisibility.Private;
                    break;
                }

                if (See(CiToken.Const))
                {
                    // const
                    CiConst konst = ParseConst();
                    konst.Documentation = doc;
                    konst.Visibility    = visibility;
                    consts.Add(konst);
                    continue;
                }

                callType = ParseCallType();
                // \ class | static | normal | abstract | sealed
                // method \|        |        |          |
                // --------+--------+--------+----------+-------
                // static  |   +    |   +    |    +     |   +
                // normal  |   -    |   +    |    +     |   +
                // abstract|   -    |   -    |    +     |   -
                // virtual |   -    |   +    |    +     |   -
                // override|   -    |   +    |    +     |   +
                // sealed  |   -    |   +    |    +     |   +
                if (callType == CiCallType.Static || klass.CallType == CiCallType.Abstract)
                {
                    // ok
                }
                else if (klass.CallType == CiCallType.Static)
                {
                    throw ParseException("Only static members allowed in a static class");
                }
                else if (callType == CiCallType.Abstract)
                {
                    throw ParseException("Abstract methods allowed only in an abstract class");
                }
                else if (klass.CallType == CiCallType.Sealed && callType == CiCallType.Virtual)
                {
                    throw ParseException("Virtual methods disallowed in a sealed class");
                }
                if (visibility == CiVisibility.Private && callType != CiCallType.Static && callType != CiCallType.Normal)
                {
                    throw ParseException("{0} method cannot be private", callType);
                }

                CiExpr type = Eat(CiToken.Void) ? null : ParseType();
                if (See(CiToken.LeftBrace) && type is CiCallExpr call)
                {
                    // constructor
                    if (call.Method.Name != klass.Name)
                    {
                        throw ParseException("Constructor name doesn't match class name");
                    }
                    if (callType != CiCallType.Normal)
                    {
                        throw ParseException("Constructor cannot be {0}", callType);
                    }
                    if (call.Arguments.Length != 0)
                    {
                        throw ParseException("Constructor parameters not supported");
                    }
                    if (klass.Constructor != null)
                    {
                        throw ParseException("Duplicate constructor, already defined in line {0}", klass.Constructor.Line);
                    }
                    if (visibility == CiVisibility.Private)
                    {
                        visibility = CiVisibility.Internal;                 // TODO
                    }
                    klass.Constructor = new CiMethodBase {
                        Line = call.Line, Documentation = doc, Visibility = visibility, Parent = klass, Name = klass.Name, Body = ParseBlock()
                    };
                    continue;
                }

                int    line = this.Line;
                string name = ParseId();
                if (See(CiToken.LeftParenthesis) || See(CiToken.ExclamationMark))
                {
                    // method
                    CiMethod method = new CiMethod {
                        Line = line, Documentation = doc, Visibility = visibility, CallType = callType, TypeExpr = type, Name = name
                    };
                    method.Parameters.Parent = klass;
                    ParseMethod(method);
                    methods.Add(method);
                    continue;
                }

                // field
                if (visibility == CiVisibility.Public)
                {
                    throw ParseException("Field cannot be public");
                }
                if (callType != CiCallType.Normal)
                {
                    throw ParseException("Field cannot be {0}", callType);
                }
                if (type == null)
                {
                    throw ParseException("Field cannot be void");
                }
                CiField field = new CiField {
                    Line = line, Documentation = doc, Visibility = visibility, TypeExpr = type, Name = name
                };
                if (Eat(CiToken.Assign))
                {
                    field.Value = ParseExpr();
                }
                Expect(CiToken.Semicolon);
                fields.Add(field);
            }

            klass.Consts  = consts.ToArray();
            klass.Fields  = fields.ToArray();
            klass.Methods = methods.ToArray();
            return(klass);
        }

        public CiEnum ParseEnum()
        {
            Expect(CiToken.Enum);
            CiEnum enu = new CiEnum {
                Parent = this.Program, Filename = this.Filename, IsFlags = Eat(CiToken.Asterisk), Line = this.Line, Name = ParseId()
            };

            Expect(CiToken.LeftBrace);
            do
            {
                CiConst konst = new CiConst {
                    Visibility = CiVisibility.Public, Documentation = ParseDoc(), Line = this.Line, Name = ParseId(), Type = enu
                };
                if (Eat(CiToken.Assign))
                {
                    konst.Value = ParseExpr();
                }
                else if (enu.IsFlags)
                {
                    throw ParseException("enum* symbol must be assigned a value");
                }
                enu.Add(konst);
            } while (Eat(CiToken.Comma));
            Expect(CiToken.RightBrace);
            return(enu);
        }

        public void Parse(string filename, TextReader reader)
        {
            Open(filename, reader);
            while (!See(CiToken.EndOfFile))
            {
                CiCodeDoc       doc = ParseDoc();
                CiContainerType type;
                bool            isPublic = Eat(CiToken.Public);
                switch (this.CurrentToken)
                {
                // class
                case CiToken.Class:
                    type = ParseClass(CiCallType.Normal);
                    break;

                case CiToken.Static:
                case CiToken.Abstract:
                case CiToken.Sealed:
                    type = ParseClass(ParseCallType());
                    break;

                // enum
                case CiToken.Enum:
                    type = ParseEnum();
                    break;

                // native
                case CiToken.Native:
                    this.Program.TopLevelNatives.Add(ParseNative().Content);
                    continue;

                default:
                    throw ParseException("Expected class or enum");
                }
                type.Documentation = doc;
                type.IsPublic      = isPublic;
                this.Program.Add(type);
            }
        }
    }
}
Beispiel #47
0
Datei: GenCs.cs Projekt: epi/cito
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     WriteLine();
     Write(klass.Documentation);
     Write(klass.Visibility);
     OpenClass(klass.IsAbstract, klass, " : ");
     if (klass.Constructor != null) {
     Write("public ");
     Write(klass.Name);
     WriteLine("()");
     Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     member.Accept(this);
     foreach (CiConst konst in klass.ConstArrays) {
     Write("static readonly ");
     Write(konst.Type);
     Write(konst.GlobalName);
     Write(" = ");
     WriteConst(konst.Value);
     WriteLine(";");
     }
     foreach (CiBinaryResource resource in klass.BinaryResources) {
     Write("static readonly byte[] ");
     WriteName(resource);
     Write(" = ");
     WriteConst(resource.Content);
     WriteLine(";");
     }
     CloseBlock();
 }
Beispiel #48
0
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     this.CurrentClass = klass;
     this.Symbols = klass.Members;
     if (klass.Constructor != null)
     klass.Constructor.Accept(this);
     foreach (CiSymbol member in klass.Members)
     member.Accept(this);
     klass.BinaryResources = this.BinaryResources.Values.ToArray();
     this.BinaryResources.Clear();
     this.Symbols = this.Symbols.Parent;
     this.CurrentClass = null;
 }
Beispiel #49
0
Datei: GenAs.cs Projekt: epi/cito
 void ICiSymbolVisitor.Visit(CiClass klass)
 {
     CreateAsFile(klass);
     OpenClass(false, klass, " extends ");
     this.UsesSubstringMethod = false;
     this.UsesCopyArrayMethod = false;
     this.UsesBytesToStringMethod = false;
     this.UsesClearBytesMethod = false;
     this.UsesClearMethod = false;
     if (klass.Constructor != null) {
     Write("public function ");
     Write(klass.Name);
     WriteLine("()");
     Write(klass.Constructor.Body);
     }
     foreach (CiSymbol member in klass.Members)
     member.Accept(this);
     foreach (CiConst konst in klass.ConstArrays) {
     Write("private static const ");
     WriteUppercaseWithUnderscores(konst.GlobalName);
     byte[] bytes = konst.Value as byte[];
     if (bytes != null) {
         WriteLine(" : ByteArray = new ByteArray();");
         OpenBlock();
         foreach (byte b in bytes) {
             WriteUppercaseWithUnderscores(konst.GlobalName);
             Write(".writeByte(");
             Write(b);
             WriteLine(");");
         }
         CloseBlock();
     }
     else {
         Write(" : Array = ");
         WriteConst(konst.Value);
         WriteLine(";");
     }
     }
     foreach (CiBinaryResource resource in klass.BinaryResources) {
     Write("[Embed(source=\"/");
     Write(resource.Name);
     WriteLine("\", mimeType=\"application/octet-stream\")]");
     Write("private static const ");
     WriteName(resource);
     WriteLine(": Class;");
     }
     WriteBuiltins();
     CloseAsFile();
 }
Beispiel #50
0
 static bool Extends(CiType type, CiClass baseClass)
 {
     if (!(type is CiClassType))
     return false;
     CiClass klass = ((CiClassType) type).Class;
     while (klass != baseClass) {
     // TODO: resolve, make sure no loops
     klass = klass.BaseClass;
     if (klass == null)
         return false;
     }
     return true;
 }
Beispiel #51
0
 void WriteGetBinaryResource(CiClass klass)
 {
     WriteLine();
     WriteLine("private static byte[] getBinaryResource(String name, int length)");
     OpenBlock();
     Write("java.io.DataInputStream dis = new java.io.DataInputStream(");
     Write(klass.Name);
     WriteLine(".class.getResourceAsStream(name));");
     WriteLine("byte[] result = new byte[length];");
     Write("try "); OpenBlock();
     Write("try "); OpenBlock();
     WriteLine("dis.readFully(result);");
     CloseBlock();
     Write("finally "); OpenBlock();
     WriteLine("dis.close();");
     CloseBlock();
     CloseBlock();
     Write("catch (java.io.IOException e) "); OpenBlock();
     WriteLine("throw new RuntimeException();");
     CloseBlock();
     WriteLine("return result;");
     CloseBlock();
 }
Beispiel #52
0
 static void MarkInternal(CiClass klass)
 {
     foreach (CiSymbol member in klass.Members) {
     if (member is CiMethod)
         MarkInternal((CiMethod) member);
     }
 }