/// <summary>Handles Syntax.K.{BinLeft,BinRight,BinAlone}</summary> /// <param name="prec">precedence of operator</param> /// <param name="assoc">BinLeft, BinRight, or BinAlone</param> private List <T> Translate_thing(Expr head, Expr[] args, Syntax.WOrC op, Syntax.TType type, int prec, Syntax.K assoc) { Trace.Assert(args.Length == 2); List <T> lt = new List <T>(); lt.Add(Translate_maybe_paren(args[0], prec - ((assoc == Syntax.K.BinLeft) ? 1 : 0))); lt.Add(__TranslateOperator(head, op, type)); lt.Add(Translate_maybe_paren(args[1], prec - ((assoc == Syntax.K.BinRight) ? 1 : 0))); return(lt); }
/// <summary>Handles Syntax.K.BinAllOfLike</summary> /// <param name="prec">precedence of operator</param> private List <T> Translate_multithing(Expr bin, Expr[] args, Syntax.WOrC op, Syntax.TType type, int prec) { Trace.Assert(args.Length >= 2); List <T> lt = new List <T>(); lt.Add(Translate_maybe_paren(args[0], prec)); for (int i = 1; i < args.Length; i++) { lt.Add(__TranslateOperator(bin, i - 1, op, type)); lt.Add(Translate_maybe_paren(args[i], prec)); } return(lt); }
protected override Box __TranslateWord(Expr expr, string op, Syntax.TType type) { /* This is really a hack :-( */ StringBox sb = new StringBox(expr, op, type); if (type == Syntax.TType.LargeOp && Array.BinarySearch(limitwordops, op) < 0) { return(new AtomBox(null, sb, null, null, Syntax.TType.LargeOp, AtomBox.LimitsType.NoLimits)); } else { return(sb); } }
/// <summary> /// Handles Syntax.K.{Prefix,Postfix} /// </summary> /// <param name="side">Prefix or Postfix</param> /// <returns></returns> private List <T> Translate_prepostfix(Expr head, Expr arg, Syntax.WOrC op, Syntax.TType type, int prec, Syntax.K side) { List <T> lt = new List <T>(); if (side == Syntax.K.Prefix || side == Syntax.K.PrefixOpt) { lt.Add(__TranslateOperator(head, op, type)); } lt.Add(Translate_maybe_paren(arg, prec - 1)); if (side == Syntax.K.Postfix) { lt.Add(__TranslateOperator(head, op, type)); } return(lt); }
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 Syntax.TType SetTType(Box b, Syntax.TType tt) { Trace.Assert(b != null); if (b is CharBox) { ((CharBox)b).TeXType = tt; } else if (b is StringBox) { ((StringBox)b).TeXType = tt; } else if (b is AtomBox) { ((AtomBox)b).TeXType = tt; } else { Trace.Assert(false, "unknown box type to set TType on"); } return(tt); }
protected abstract T __TranslateWord(Expr expr, string op, Syntax.TType type);
protected abstract T __TranslateOperator(Expr expr, object exprix, Syntax.WOrC op, Syntax.TType type);
protected T __TranslateOperator(Expr expr, Syntax.WOrC op, Syntax.TType type) { return(__TranslateOperator(expr, null, op, type)); }
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", ')'))); } }
protected override Box __TranslateOperator(Expr expr, object exprix, Syntax.WOrC op, Syntax.TType type) { if (op.Word == null) { return(new CharBox(expr, exprix, op.Character, type)); } else { Trace.Assert(exprix == null); return(new StringBox(expr, op.Word, type)); } }
private void ConsiderPairSpacing() { if (A == null || B == null) { return; } Box a = A.Final.Target; Box b = B.Final.Target; /* Do TeX atom type and spacing fixup rules from p 170 and appendix G */ Syntax.TType atype = GetTType(a), btype = GetTType(b); /* rule 20 */ int spacing = IBSpacing[(int)atype, (int)btype]; Trace.Assert(spacing != 5); Box space = null; switch (spacing) { case 0: // all the code for this case is *not* part of TeX's rule 20. It comes from p 169 and applies specifically to factorial // operators, so won't be correct for other possible uses of '!' if (atype == Syntax.TType.Ord && a is CharBox && ((CharBox)a).C == '!') { CharBox cb = b as CharBox; StringBox sb = b as StringBox; AtomBox ab = b as AtomBox; if ((btype == Syntax.TType.Ord && ((cb != null && (Char.IsLetter(cb.C) || Char.IsDigit(cb.C))) || (sb != null && (Char.IsLetter(sb.S, 0) || Char.IsDigit(sb.S, 0))))) || btype == Syntax.TType.Open) { space = ThinSkip(); } else if (btype == Syntax.TType.Ord && ab != null) { cb = ab.Nucleus as CharBox; sb = ab.Nucleus as StringBox; if ((cb != null && (Char.IsLetter(cb.C) || Char.IsDigit(cb.C))) || (sb != null && (Char.IsLetter(sb.S, 0) || Char.IsDigit(sb.S, 0)))) { space = ThinSkip(); } } } break; case 1: space = ThinSkip(); break; case 2: space = MedSkip(); break; case 3: space = ThickSkip(); break; case -1: space = DTThinSkip(); break; case -2: space = DTMedSkip(); break; case -3: space = DTThickSkip(); break; } /* apply the spacing */ if (space != null) { /* Find the lowest common ancestor */ int found = -1; for (int i = 0; i < A.P.Count && i < B.P.Count; i++) { if (A.P[i].Target != B.P[i].Target) { found = i; break; } } Trace.Assert(found != -1, "adjacent boxes are the same?"); Trace.Assert(A.P[found].B == B.P[found].B); Trace.Assert(A.P[found].GetType() == B.P[found].GetType()); List <Box> boxes; int ix; if (A.P[found] is HBoxLink) { HBoxLink hba = (HBoxLink)A.P[found]; HBoxLink hbb = (HBoxLink)B.P[found]; Trace.Assert(hba.I < hbb.I); for (int i = hba.I + 1; i < hbb.I; i++) { Trace.Assert(hba.HB.Boxes[i] is MuSkipBox || hba.HB.Boxes[i] is DTMuSkipBox); } boxes = hba.HB.Boxes; ix = hbb.I; } else { DelimitedBoxLink dba = (DelimitedBoxLink)A.P[found]; DelimitedBoxLink dbb = (DelimitedBoxLink)B.P[found]; boxes = dba.DB.Contents.Boxes; if (dba.Piece == DelimitedBoxLink.Which.Left) { Trace.Assert(dbb.Piece != DelimitedBoxLink.Which.Left); ix = 0; } else { Trace.Assert(dba.Piece == DelimitedBoxLink.Which.Contents); Trace.Assert(dbb.Piece == DelimitedBoxLink.Which.Right); ix = boxes.Count; } } SortedDictionary <int, Box> inserts; if (!_listBoxInserts.TryGetValue(boxes, out inserts)) { inserts = new SortedDictionary <int, Box>(); _listBoxInserts[boxes] = inserts; } inserts.Add(ix, space); } }
private void ConsiderPairTType() { Box a = A == null ? null : A.P.Count == 0 ? _toplevel : A.Final.Target; Box b = B == null ? null : B.P.Count == 0 ? _toplevel : B.Final.Target; /* Do TeX atom type rules from p 170 and appendix G */ Syntax.TType atype = GetTType(a), btype = GetTType(b); /* appendix G, p 442- */ /* rule 1, 2, 3, 4: nothing for us */ /* rule 5 */ if (btype == Syntax.TType.Op) { if (a == null || atype == Syntax.TType.Op || atype == Syntax.TType.LargeOp || atype == Syntax.TType.Rel || atype == Syntax.TType.Open || atype == Syntax.TType.Punct) { btype = SetTType(b, Syntax.TType.Ord); goto rule14; } else { goto rule17; } } /* rule 6 */ if ((btype == Syntax.TType.Rel || btype == Syntax.TType.Close || btype == Syntax.TType.Punct) && atype == Syntax.TType.Op) { atype = SetTType(a, Syntax.TType.Ord); goto rule17; } /* rule 7 */ if (btype == Syntax.TType.Open || btype == Syntax.TType.Inner) { goto rule17; } /* rule 8: (Vcent) done in type inference above */ /* rule 9: change Over to Ord and go to 17: we have no Over use; if we do, just consider it Ord to start with above */ /* rule 10: change Under to Ord and go to 17: we have no Under use; if we do, just consider it Ord to start with above */ /* rule 11: (Rad) done in type inference above */ /* rule 12: change Acc to Ord and go to 17: we have no Acc use; if we do, just consider it Ord to start with above */ /* rule 13, 13a (Op) */ /* limits handling done in AtomBox */ // FIXME: should make operators like integral and summation slightly larger in display style according to TeXbook /* rule 14: (Ord) ligatures and kerns here too; we ignore for now */ rule14: // FIXME should do ligatures and kerns? if (btype == Syntax.TType.Ord) { goto rule17; } /* rule 15, 15a-e: generalized fraction (before becoming Inner): nothing for us (should have been done in AtopBox) */ // Not clear if things matching rule15 should fall through, as makes little sense to change type to Inner right before changing to Ord /* rule 16: change current type to Ord: folded in to previous jumps to rule16 including changing to be jump to rule 17 */ /* rule 17: various things which are either done elsewhere or which we don't handle */ rule17: /* rule 18, 18a-f: done in AtomBox */ ; /* rule (unnumbered, between 18f and 19) */ if (atype == Syntax.TType.Op && btype == Syntax.TType.None) { SetTType(a, Syntax.TType.Ord); } }