/// <param name="prectoparen">parenthesize stuff w prec ≤ prectoparen</param> private bool Needs_paren(Expr e, int prectoparen) { CompositeExpr ce = e as CompositeExpr; int prec; if (ce != null) { prec = Syntax.Fixes.Find(ce.Head).Precedence; if (prec == -1) { prec = int.MaxValue; // function calls, power, subscript, and root have highest precedence } } else { prec = (e is ComplexNumber) ? Syntax.Fixes.Find(WellKnownSym.plus).Precedence : (e is IntegerNumber) && ((IntegerNumber)e).Num < 0 ? Syntax.Fixes.Find(WellKnownSym.minus).Precedence : (e is DoubleNumber) && ((DoubleNumber)e).Num < 0 ? Syntax.Fixes.Find(WellKnownSym.minus).Precedence : (e is DoubleNumber) && ((DoubleNumber)e).Num.ToString("R").IndexOfAny(new char[] { 'e', 'E' }) >= 0 ? Syntax.Fixes.Find(WellKnownSym.plus).Precedence : int.MaxValue; // assuming everything else is an atom of one sort or another. Possibly wrong, for user-defined Exprs } if (prec <= prectoparen) { return(true); } if (ce != null) { Syntax.OpRelPos orp = Syntax.Fixes.Find(ce.Head); if (orp.Precedence != -1 && ce.Args.Length > 0) { Syntax.K k = Syntax.Fixes.Table[orp.Precedence].Kind; if (k == Syntax.K.Prefix || k == Syntax.K.PrefixOpt) { return(false); } if (k == Syntax.K.BinPrimaryAndSecondary2) { // might be an operator at the start if (ce.Args[0].Annotations["initial op"] != null) { return(false); } CompositeExpr ce2 = ce.Args[0] as CompositeExpr; if (ce2 != null && Syntax.Fixes.Find(ce2.Head).Precedence == orp.Precedence) { return(false); } } return(Needs_paren(ce.Args[0], prectoparen)); } } return(false); }
private T _Translate(WellKnownSym s) { switch (s.ID) { case WKSID.del: return(__TranslateOperator(s, Unicode.N.NABLA, Syntax.TType.Ord)); case WKSID.differentiald: return(__TranslateOperator(s, Unicode.D.DOUBLE_STRUCK_ITALIC_SMALL_D, Syntax.TType.Ord)); case WKSID.partiald: return(__TranslateOperator(s, Unicode.P.PARTIAL_DIFFERENTIAL, Syntax.TType.Ord)); case WKSID.integral: return(__TranslateOperator(s, Unicode.I.INTEGRAL, Syntax.TType.LargeOp)); case WKSID.i: return(__TranslateOperator(s, Unicode.D.DOUBLE_STRUCK_ITALIC_SMALL_I, Syntax.TType.Ord)); case WKSID.e: return(__TranslateOperator(s, Unicode.D.DOUBLE_STRUCK_ITALIC_SMALL_E, Syntax.TType.Ord)); default: KeyValuePair <Syntax.WOrC, Syntax.TType>?val; val = Syntax.CharWKSMap[s]; if (val == null) { Syntax.OpRelPos orp = Syntax.Fixes.Find(s); if (orp.Precedence == -1) { return(__TranslateWord(s, s.ID.ToString(), Syntax.TType.LargeOp)); } else { Syntax.OpRel or = Syntax.Fixes.Table[orp.Precedence]; Syntax.WOrC op = or.Ops[orp.Position]; Syntax.TType tt = or.Types[orp.Position]; return(__TranslateOperator(s, op, tt)); } } else { return(__TranslateOperator(s, val.Value.Key, val.Value.Value)); } } }
private T _Translate(CompositeExpr e) { List <T> lt; // for local use because, sigh, c# doesn't handle this case of definitions used or duplicated across switch cases well T t; // this too, sigh Syntax.OpRelPos orp = Syntax.Fixes.Find(e.Head); if (orp.Precedence != -1) { Syntax.OpRel or = Syntax.Fixes.Table[orp.Precedence]; Syntax.WOrC op = or.Ops[orp.Position]; Syntax.TType tt = or.Types[orp.Position]; switch (or.Kind) { case Syntax.K.BinLeft: case Syntax.K.BinRight: case Syntax.K.BinAlone: Trace.Assert(e.Args.Length == 2); return(__WrapTranslatedExpr(e, Translate_thing(e.Head, e.Args, op, tt, orp.Precedence, or.Kind))); case Syntax.K.BinAllOfLike: Trace.Assert(e.Args.Length >= 2); return(__WrapTranslatedExpr(e, Translate_multithing(e, e.Args, op, tt, orp.Precedence))); case Syntax.K.BinPrimaryAndSecondary: if (e.Head != or.Heads[0]) { Trace.Assert(e.Args.Length == 1); // Division is a special case because it can be represented as the vertical fraction representation, which is not dealt with // in our syntax table. if (e.Head == WellKnownSym.divide && !e.Annotations.ContainsKey("inline")) { return(__TranslateVerticalFraction(e, Translate(IntegerNumber.One), Translate(e.Args[0]))); } else { lt = new List <T>(); if (or.Kind == Syntax.K.BinPrimaryAndSecondary) { lt.Add(Translate_maybe_paren(or.Identity, orp.Precedence)); } lt.Add(__TranslateOperator(e.Head, op, tt)); lt.Add(Translate_maybe_paren(e.Args[0], orp.Precedence)); return(__WrapTranslatedExpr(e, lt)); } } else { // FIXME!!!! currently this only works for times and divide; ignores Syntax! Ideally ought to be merged w BinPriAndSec2 Trace.Assert(e.Args.Length > 0); if (e.Args.Length == 1) { return(Translate(e.Args[0])); } else { List <Expr> num = new List <Expr>(); List <CompositeExpr> denom = new List <CompositeExpr>(); List <CompositeExpr> denominline = new List <CompositeExpr>(); foreach (Expr ee in e.Args) { CompositeExpr ce = ee as CompositeExpr; if (ce != null && ce.Head == WellKnownSym.divide) { Trace.Assert(ce.Args.Length == 1); if (ce.Annotations.ContainsKey("inline")) { denominline.Add(ce); } else { denom.Add(ce); } } else { num.Add(ee); } } lt = new List <T>(); if (num.Count > 1 || (denom.Count == 0 && denominline.Count > 0)) { AddTimes(lt, num); } else { lt.Add(Translate(num[0])); } if (denom.Count != 0) { if (num.Count == 0) { lt.Add(Translate(IntegerNumber.One)); } T nt = __WrapTranslatedExpr(null, lt); lt = new List <T>(); if (denom.Count > 1) { List <Expr> denomraw = new List <Expr>(); foreach (CompositeExpr ce in denom) { denomraw.Add(ce.Args[0]); } AddTimes(lt, denomraw); } else { lt.Add(Translate(denom[0].Args[0])); } T dt = __WrapTranslatedExpr(null, lt); t = __TranslateVerticalFraction(e, denom[0].Head, nt, dt); } else { if (num.Count == 0) { t = Translate(IntegerNumber.One); } else { t = __WrapTranslatedExpr(e, lt); } } if (denominline.Count > 0) { lt = new List <T>(); lt.Add(t); foreach (CompositeExpr division in denominline) { lt.Add(__TranslateOperator(division.Head, '/', Syntax.TType.Ord)); lt.Add(Translate(division.Args[0])); } return(__WrapTranslatedExpr(e, lt)); } else { return(t); } } } case Syntax.K.BinPrimaryAndSecondary2: if (e.Head != or.Heads[0]) { Trace.Assert(e.Args.Length == 1); return(__TranslateOperatorApplication(e, __TranslateOperator(e.Head, op, tt), Translate_maybe_paren(e.Args[0], orp.Precedence))); } else { Trace.Assert(e.Args.Length > 0); lt = new List <T>(); if (e.Annotations["initial op"] != null) { lt.Add(__TranslateOperator(e, 0, (char)e.Annotations["initial op"], tt)); } lt.Add(Translate_maybe_paren(e.Args[0], orp.Precedence - 1)); bool checkminus = (Syntax.Fixes.Find(WellKnownSym.minus).Precedence == orp.Precedence); for (int i = 1; i < e.Args.Length; i++) { CompositeExpr ce = e.Args[i] as CompositeExpr; Syntax.OpRelPos orp2 = new Syntax.OpRelPos(-1, -1); if (ce != null) { orp2 = Syntax.Fixes.Find(ce.Head); } if (checkminus && NumberStartsWithMinus(e.Args[i])) { lt.Add(Translate(e.Args[i])); } else if (ce != null && orp2.Precedence == orp.Precedence && or.Heads[orp.Position] != or.Heads[orp2.Position]) { Trace.Assert(ce.Args.Length == 1); lt.Add(__TranslateOperator(e, i, or.Ops[orp2.Position], tt)); lt.Add(Translate_maybe_paren(ce.Args[0], orp.Precedence)); } else { lt.Add(__TranslateOperator(e, i, op, tt)); lt.Add(Translate_maybe_paren(e.Args[i], orp.Precedence - 1)); } } return(__WrapTranslatedExpr(e, lt)); } case Syntax.K.PrefixOpt: case Syntax.K.Prefix: if (tt == Syntax.TType.LargeOp && op.Word == null) // Only summation? This seems oddly hard-coded. { Trace.Assert(0 < e.Args.Length && e.Args.Length < 4); return(__TranslateBigOp(e, e.Head, op.Character, e.Args.Length > 1 ? Translate(e.Args[0]) : null, e.Args.Length > 2 ? Translate(e.Args[1]) : null, Translate_maybe_paren(e.Args[e.Args.Length - 1], orp.Precedence - 1))); } else if (or.Kind == Syntax.K.PrefixOpt && e.Args.Length == 0) { return(__TranslateOperator(e.Head, op, tt)); } else { //Trace.Assert(e.Args.Length == 1);//CJ disabled temporarily for site visit demo return(__WrapTranslatedExpr(e, Translate_prepostfix(e.Head, e.Args[0], op, tt, orp.Precedence, or.Kind))); } case Syntax.K.Postfix: Trace.Assert(e.Args.Length == 1); return(__WrapTranslatedExpr(e, Translate_prepostfix(e.Head, e.Args[0], op, tt, orp.Precedence, or.Kind))); } } if (e.Head is WellKnownSym) { WellKnownSym wks = (WellKnownSym)e.Head; WKSID id = wks.ID; switch (id) { case WKSID.im: Trace.Assert(e.Args.Length == 1); return(__TranslateFunctionApplication(e, __TranslateOperator(e.Head, Unicode.B.BLACK_LETTER_CAPITAL_I, Syntax.TType.Ord), Translate_maybe_parenfn(e.Args[0], _showInvisibles))); #if false case WKSID.magnitude: Trace.Assert(e.Args.Length == 1); return(__TranslateDelims(e, false, 0, '|', Translate(e.Args[0]), 1, '|')); #endif case WKSID.magnitude: if (e.Args.Length == 1) { return(__TranslateDelims(e, false, "|l", '|', __WrapTranslatedExpr(null, Translate(e.Args[0])), "|r", '|')); } break; case WKSID.power: Trace.Assert(e.Args.Length == 2); if (e.Args[0] is CompositeExpr && ((CompositeExpr)e.Args[0]).Head == WellKnownSym.power) { t = Translate_definite_paren(e.Args[0]); } else { t = Translate_maybe_parenfn(e.Args[0]); } return(__AddSuperscript(e, t, Translate(e.Args[1]))); case WKSID.subscript: Trace.Assert(e.Args.Length == 2); if (e.Args[0] is CompositeExpr && (((CompositeExpr)e.Args[0]).Head == WellKnownSym.power || ((CompositeExpr)e.Args[0]).Head == WellKnownSym.subscript)) { t = Translate_definite_paren(e.Args[0]); } else { t = Translate_maybe_parenfn(e.Args[0]); } return(__AddSubscript(e, t, Translate(e.Args[1]))); case WKSID.re: Trace.Assert(e.Args.Length == 1); return(__TranslateFunctionApplication(e, __TranslateOperator(e.Head, Unicode.B.BLACK_LETTER_CAPITAL_R, Syntax.TType.Ord), Translate_maybe_parenfn(e.Args[0], _showInvisibles))); case WKSID.root: if (e.Args[0] is IntegerNumber && (e.Args[0] as IntegerNumber).Num == 2) { return(__TranslateRadical(e, Translate(e.Args[1]), null)); } else { return(__TranslateRadical(e, Translate(e.Args[1]), Translate(e.Args[0]))); } case WKSID.differentiald: case WKSID.partiald: Trace.Assert(e.Args.Length == 1); if (e.Args[0] is Sym) { return(__TranslateOperatorApplication(e, Translate(e.Head), Translate(e.Args[0]))); } else { return(__TranslateOperatorApplication(e, Translate(e.Head), Translate_definite_paren(e.Args[0]))); } case WKSID.integral: Trace.Assert(e.Args.Length >= 2 && e.Args.Length <= 4); return(__TranslateBigOp(e, e.Head, Unicode.I.INTEGRAL, e.Args.Length > 2 ? Translate(e.Args[2]) : null, e.Args.Length > 3 ? Translate(e.Args[3]) : null, __TranslateIntegralInternals(Translate(e.Args[0]), Translate(e.Args[1])))); case WKSID.log: if (e.Args.Length == 2) { T f = __TranslateWord(wks, wks.ID.ToString(), Syntax.TType.LargeOp); f = __AddSubscript(null, f, Translate(e.Args[0])); f = ParenAround(e.Head, false, f); return(__TranslateFunctionApplication(e, f, Translate_maybe_parenfn(e.Args[1], _showInvisibles))); } break; case WKSID.floor: if (e.Args.Length == 1) { return(__TranslateDelims(e, false, Unicode.L.LEFT_FLOOR.ToString(), Unicode.L.LEFT_FLOOR, __WrapTranslatedExpr(null, Translate(e.Args[0])), Unicode.R.RIGHT_FLOOR.ToString(), Unicode.R.RIGHT_FLOOR)); } break; case WKSID.ceiling: if (e.Args.Length == 1) { return(__TranslateDelims(e, false, Unicode.L.LEFT_CEILING.ToString(), Unicode.L.LEFT_CEILING, __WrapTranslatedExpr(null, Translate(e.Args[0])), Unicode.R.RIGHT_CEILING.ToString(), Unicode.R.RIGHT_CEILING)); } break; } } else if (e.Head == new LetterSym('→') || e.Head == new LetterSym(Unicode.R.RIGHTWARDS_DOUBLE_ARROW)) { T arrow = __TranslateOperator(e.Head, ((LetterSym)e.Head).Letter, Syntax.TType.Rel); if (e.Args.Length == 1) { return(__WrapTranslatedExpr(e, Translate(e.Args[0]), arrow)); } else { Trace.Assert(e.Args.Length == 2); return(__WrapTranslatedExpr(e, Translate(e.Args[0]), arrow, Translate(e.Args[1]))); } } else if (e.Head == new WordSym("brace")) { return(__TranslateDelims(e, false, "{", '{', __WrapTranslatedExpr(null, Translate_arglist(e, e.Args)), "}", '}')); } else if (e.Head == new WordSym("bracket")) { return(__TranslateDelims(e, false, "[", '[', __WrapTranslatedExpr(null, Translate_arglist(e, e.Args)), "]", ']')); } // FIXME: probably both branches here should use la and ra... if (e.Args.Length == 1) { if (e.Head is WellKnownSym) { return(__TranslateFunctionApplication(e, Translate(e.Head), Translate_maybe_parenfn(e.Args[0], _showInvisibles))); } else { return(__TranslateFunctionApplication(e, Translate_maybe_parenfn(e.Head), Translate_definite_paren(e.Args[0], _showInvisibles))); } } else { return(__TranslateFunctionApplication(e, Translate_maybe_parenfn(e.Head), __TranslateDelims(e, _showInvisibles, "la", '(', __WrapTranslatedExpr(null, Translate_arglist(e, e.Args)), "ra", ')'))); } }