protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((long) "); WriteMulDiv(2, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(']'); } else if (expr.Method == CiLibrary.SubstringMethod) { Write(expr.Obj); Write(".Substring("); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("System.Array.Copy("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("System.Text.Encoding.UTF8.GetString("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write("System.Array.Clear("); Write(expr.Obj); Write(", 0, "); Write(((CiArrayStorageType)expr.Obj.Type).Length); Write(')'); } else { base.Write(expr); } }
protected void WriteMulDiv(int firstPriority, CiMethodCall expr) { WriteChild(firstPriority, expr.Obj); Write(" * "); WriteChild(3, expr.Arguments[0]); Write(" / "); WriteNonAssocChild(3, expr.Arguments[1]); Write(')'); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((double) "); WriteMulDiv(2, expr); } else { base.Write(expr); } }
protected void WriteArguments(CiMethodCall expr) { Write('('); bool first = true; foreach (CiExpr arg in expr.Arguments) { if (first) { first = false; } else { Write(", "); } Write(arg); } Write(')'); }
protected virtual void Write(CiMethodCall expr) { if (expr.Method != null) { if (expr.Obj != null) { Write(expr.Obj); } else { Write(expr.Method.Class.Name); } Write('.'); WriteName(expr.Method); } else { WriteDelegateCall(expr.Obj); } WriteArguments(expr); }
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 }); } } } }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { #if USE_INTEGER // FIXME: overflow on 32-bit perl Write("("); #else Write("int("); #endif WriteMulDiv(3, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write("ord(substr("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", 1))"); } else if (expr.Method == CiLibrary.SubstringMethod) { Write("substr("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { CiExpr lenMinus1 = new CiBinaryExpr { Left = expr.Arguments[3], Op = CiToken.Minus, Right = new CiConstExpr(1) }; WriteSlice(expr.Arguments[1], expr.Arguments[2], lenMinus1); Write(" = "); WriteSlice(expr.Obj, expr.Arguments[0], lenMinus1); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { CiExpr lenMinus1 = new CiBinaryExpr { Left = expr.Arguments[1], Op = CiToken.Minus, Right = new CiConstExpr(1) }; Write("pack('U*', "); WriteSlice(expr.Obj, expr.Arguments[0], lenMinus1); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write('@'); if (expr.Obj is CiVarAccess) { Write(((CiVarAccess)expr.Obj).Var.Name); } else { Write('{'); Write(expr.Obj); Write('}'); } Write(" = (0) x "); Write(((CiArrayStorageType)expr.Obj.Type).Length); } else { if (expr.Method != null) { if (expr.Obj != null) { Write(expr.Obj); Write("->"); } else { Write(this.Package); Write(expr.Method.Class.Name); Write("::"); } WriteLowercaseWithUnderscores(expr.Method.Name); } else { // delegate call Write(expr.Obj); Write("->"); } WriteArguments(expr); } }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("int("); WriteMulDiv(CiPriority.Multiplicative, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write(".charCodeAt("); Write(expr.Arguments[0]); Write(')'); } else if (expr.Method == CiLibrary.SubstringMethod) { if (expr.Arguments[0].HasSideEffect) { Write("substring("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesSubstringMethod = true; } else { Write(expr.Obj); Write(".substring("); Write(expr.Arguments[0]); Write(", "); Write(new CiBinaryExpr { Left = expr.Arguments[0], Op = CiToken.Plus, Right = expr.Arguments[1] }); Write(')'); } } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("copyArray("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); this.UsesCopyArrayMethod = true; } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("bytesToString("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesBytesToStringMethod = true; } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) WriteClearArray(expr.Obj); else base.Write(expr); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((double) "); WriteMulDiv(CiPriority.Prefix, expr); } else base.Write(expr); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("cast(int) (cast(long) "); WriteMulDiv(CiPriority.Prefix, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(']'); } else if (expr.Method == CiLibrary.SubstringMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[1]); Write(']'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write(expr.Arguments[1]); Write('['); Write(expr.Arguments[2]); Write(" .. ("); Write(expr.Arguments[2]); Write(") + "); Write(expr.Arguments[3]); Write("] = "); Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[3]); Write(']'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("toUTF8(cast(char[]) "); Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[1]); Write("])"); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write(expr.Obj); Write("[] = 0"); } else base.Write(expr); }
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; }
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"); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((long long int) "); WriteMulDiv(CiPriority.Prefix, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(']'); } else if (expr.Method == CiLibrary.SubstringMethod) { // TODO throw new ArgumentException("Substring"); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("memcpy("); WriteSum(expr.Arguments[1], expr.Arguments[2]); Write(", "); WriteSum(expr.Obj, expr.Arguments[0]); Write(", "); Write(expr.Arguments[3]); Write(')'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { // TODO throw new ArgumentException("Array.ToString"); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { WriteClearArray(expr.Obj); } else { bool first = true; if (expr.Method != null) { switch (expr.Method.CallType) { case CiCallType.Static: Write(expr.Method.Class.Name); Write('_'); Write(expr.Method.Name); Write('('); break; case CiCallType.Normal: Write(expr.Method.Class.Name); Write('_'); Write(expr.Method.Name); Write('('); Write(expr.Obj); first = false; break; case CiCallType.Abstract: case CiCallType.Virtual: case CiCallType.Override: CiClass objClass = ((CiClassType) expr.Obj.Type).Class; CiClass ptrClass = GetVtblPtrClass(expr.Method.Class); CiClass defClass; for (defClass = expr.Method.Class; !AddsVirtualMethod(defClass, expr.Method.Name); defClass = defClass.BaseClass) ; if (defClass != ptrClass) { Write("((const "); Write(defClass.Name); Write("Vtbl *) "); } StartFieldAccess(expr.Obj); for (CiClass baseClass = objClass; baseClass != ptrClass; baseClass = baseClass.BaseClass) Write("base."); Write("vtbl"); if (defClass != ptrClass) Write(')'); Write("->"); WriteCamelCase(expr.Method.Name); Write('('); if (objClass == defClass) Write(expr.Obj); else { Write('&'); StartFieldAccess(expr.Obj); Write("base"); for (CiClass baseClass = objClass.BaseClass; baseClass != defClass; baseClass = baseClass.BaseClass) Write(".base"); } first = false; break; } } else { // delegate Write(expr.Obj); Write(".func("); Write(expr.Obj); Write(".obj"); first = false; } foreach (CiExpr arg in expr.Arguments) { if (first) first = false; else Write(", "); Write(arg); } Write(')'); // if (expr.Method.Throws) Write(" /* throws */"); } }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { #if USE_INTEGER // FIXME: overflow on 32-bit perl Write("("); #else Write("int("); #endif WriteMulDiv(CiPriority.Multiplicative, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write("ord(substr("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", 1))"); } else if (expr.Method == CiLibrary.SubstringMethod) { Write("substr("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { CiExpr lenMinus1 = new CiBinaryExpr { Left = expr.Arguments[3], Op = CiToken.Minus, Right = new CiConstExpr(1) }; WriteSlice(expr.Arguments[1], expr.Arguments[2], lenMinus1); Write(" = "); WriteSlice(expr.Obj, expr.Arguments[0], lenMinus1); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { CiExpr lenMinus1 = new CiBinaryExpr { Left = expr.Arguments[1], Op = CiToken.Minus, Right = new CiConstExpr(1) }; Write("pack('U*', "); WriteSlice(expr.Obj, expr.Arguments[0], lenMinus1); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write('@'); if (expr.Obj is CiVarAccess) Write(((CiVarAccess) expr.Obj).Var.Name); else { Write('{'); Write(expr.Obj); Write('}'); } Write(" = (0) x "); Write(((CiArrayStorageType) expr.Obj.Type).Length); } else { if (expr.Method != null) { if (expr.Obj != null) { Write(expr.Obj); Write("->"); } else { Write(this.Package); Write(expr.Method.Class.Name); Write("::"); } WriteLowercaseWithUnderscores(expr.Method.Name); } else { // delegate call Write(expr.Obj); Write("->"); } WriteArguments(expr); } }
protected virtual void Write(CiMethodCall expr) { if (expr.Method != null) { if (expr.Obj != null) Write(expr.Obj); else Write(expr.Method.Class.Name); Write('.'); WriteName(expr.Method); } else WriteDelegateCall(expr.Obj); WriteArguments(expr); }
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; } }
protected void WriteArguments(CiMethodCall expr) { Write('('); bool first = true; foreach (CiExpr arg in expr.Arguments) { if (first) first = false; else Write(", "); Write(arg); } Write(')'); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((long) "); WriteMulDiv(CiPriority.Prefix, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(']'); } else if (expr.Method == CiLibrary.SubstringMethod) { Write(expr.Obj); Write(".Substring("); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("System.Array.Copy("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("System.Text.Encoding.UTF8.GetString("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write("System.Array.Clear("); Write(expr.Obj); Write(", 0, "); Write(((CiArrayStorageType) expr.Obj.Type).Length); Write(')'); } else base.Write(expr); }
protected void WriteMulDiv(CiPriority firstPriority, CiMethodCall expr) { WriteChild(firstPriority, expr.Obj); Write(" * "); WriteChild(CiPriority.Multiplicative, expr.Arguments[0]); Write(" / "); WriteNonAssocChild(CiPriority.Multiplicative, expr.Arguments[1]); Write(')'); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("int("); WriteMulDiv(3, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write(".charCodeAt("); Write(expr.Arguments[0]); Write(')'); } else if (expr.Method == CiLibrary.SubstringMethod) { if (expr.Arguments[0].HasSideEffect) { Write("substring("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesSubstringMethod = true; } else { Write(expr.Obj); Write(".substring("); Write(expr.Arguments[0]); Write(", "); Write(new CiBinaryExpr { Left = expr.Arguments[0], Op = CiToken.Plus, Right = expr.Arguments[1] }); Write(')'); } } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("copyArray("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); this.UsesCopyArrayMethod = true; } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("bytesToString("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesBytesToStringMethod = true; } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { WriteClearArray(expr.Obj); } else { base.Write(expr); } }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((long) "); WriteMulDiv(2, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write(".charAt("); Write(expr.Arguments[0]); Write(')'); } else if (expr.Method == CiLibrary.SubstringMethod) { if (expr.Arguments[0].HasSideEffect) { Write("substring("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesSubstringMethod = true; } else { Write(expr.Obj); Write(".substring("); Write(expr.Arguments[0]); Write(", "); WriteSum(expr.Arguments[0], expr.Arguments[1]); Write(')'); } } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("System.arraycopy("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("new String("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write("clear("); Write(expr.Obj); Write(')'); CiType type = ((CiArrayStorageType)expr.Obj.Type).ElementType; if (type == CiByteType.Value) { this.UsesClearBytesMethod = true; } else if (type == CiIntType.Value) { this.UsesClearIntsMethod = true; } else { throw new ArgumentException(type.Name); } } else { base.Write(expr); } }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("(int) ((long) "); WriteMulDiv(CiPriority.Prefix, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write(".charAt("); Write(expr.Arguments[0]); Write(')'); } else if (expr.Method == CiLibrary.SubstringMethod) { if (expr.Arguments[0].HasSideEffect) { Write("substring("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); this.UsesSubstringMethod = true; } else { Write(expr.Obj); Write(".substring("); Write(expr.Arguments[0]); Write(", "); WriteSum(expr.Arguments[0], expr.Arguments[1]); Write(')'); } } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write("System.arraycopy("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(", "); Write(expr.Arguments[2]); Write(", "); Write(expr.Arguments[3]); Write(')'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("new String("); Write(expr.Obj); Write(", "); Write(expr.Arguments[0]); Write(", "); Write(expr.Arguments[1]); Write(')'); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write("clear("); Write(expr.Obj); Write(')'); CiType type = ((CiArrayStorageType) expr.Obj.Type).ElementType; if (type == CiByteType.Value) this.UsesClearBytesMethod = true; else if (type == CiIntType.Value) this.UsesClearIntsMethod = true; else throw new ArgumentException(type.Name); } else base.Write(expr); }
protected override void Write(CiMethodCall expr) { if (expr.Method == CiLibrary.MulDivMethod) { Write("cast(int) (cast(long) "); WriteMulDiv(2, expr); } else if (expr.Method == CiLibrary.CharAtMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(']'); } else if (expr.Method == CiLibrary.SubstringMethod) { Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[1]); Write(']'); } else if (expr.Method == CiLibrary.ArrayCopyToMethod) { Write(expr.Arguments[1]); Write('['); Write(expr.Arguments[2]); Write(" .. ("); Write(expr.Arguments[2]); Write(") + "); Write(expr.Arguments[3]); Write("] = "); Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[3]); Write(']'); } else if (expr.Method == CiLibrary.ArrayToStringMethod) { Write("toUTF8(cast(char[]) "); Write(expr.Obj); Write('['); Write(expr.Arguments[0]); Write(" .. ("); Write(expr.Arguments[0]); Write(") + "); Write(expr.Arguments[1]); Write("])"); } else if (expr.Method == CiLibrary.ArrayStorageClearMethod) { Write(expr.Obj); Write("[] = 0"); } else { base.Write(expr); } }