github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/go/tao/auth/format.go (about)

     1  // Copyright (c) 2014, Kevin Walsh.  All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package auth
    16  
    17  // This file implements Format() functions for pretty-printing elements.
    18  // When printed with format verb %v, the "verbose" long form is used.
    19  // When printed with format verb %s, the "short" elided form is used.
    20  // When printed with other verbs, the output format is unspecified.
    21  
    22  import (
    23  	"encoding/base64"
    24  	"fmt"
    25  )
    26  
    27  // ElisionCutoff is the maximum length a String or Byte can be without being elided.
    28  var ElisionCutoff int = 32
    29  
    30  // ElisionLength is the number of characters to show in an elided String or Byte.
    31  var ElisionLength int = 24
    32  
    33  // Format outputs a pretty-printed Prin.
    34  func (p Prin) Format(out fmt.State, verb rune) {
    35  	fmt.Fprintf(out, "%s(", p.Type)
    36  	p.KeyHash.Format(out, verb)
    37  	fmt.Fprint(out, ")")
    38  	p.Ext.Format(out, verb)
    39  }
    40  
    41  // Format outputs a pretty-printed PrinTail.
    42  func (p PrinTail) Format(out fmt.State, verb rune) {
    43  	fmt.Fprintf(out, "ext")
    44  	p.Ext.Format(out, verb)
    45  }
    46  
    47  // Format outputs a pretty-printed PrinExt.
    48  func (e PrinExt) Format(out fmt.State, verb rune) {
    49  	formatNameAndArg(out, e.Name, e.Arg, verb)
    50  }
    51  
    52  // formatNameAndArg outputs a pretty-printed name and argument list using short
    53  // or long formats.
    54  func formatNameAndArg(out fmt.State, name string, arg []Term, verb rune) {
    55  	fmt.Fprintf(out, "%s(", name)
    56  	for i, a := range arg {
    57  		if i > 0 {
    58  			fmt.Fprint(out, ", ")
    59  		}
    60  		a.Format(out, verb)
    61  	}
    62  	fmt.Fprint(out, ")")
    63  }
    64  
    65  // Format outputs a pretty-printed SubPrin.
    66  func (p SubPrin) Format(out fmt.State, verb rune) {
    67  	for _, e := range p {
    68  		fmt.Fprint(out, ".")
    69  		e.Format(out, verb)
    70  	}
    71  }
    72  
    73  // Format outputs a pretty-printed Str.
    74  func (t Str) Format(out fmt.State, verb rune) {
    75  	if verb == 's' && len(string(t)) > ElisionCutoff {
    76  		fmt.Fprintf(out, "%q...", string(t)[:ElisionLength])
    77  	} else {
    78  		fmt.Fprintf(out, "%q", string(t))
    79  	}
    80  }
    81  
    82  // Format outputs a pretty-printed Bytes.
    83  func (t Bytes) Format(out fmt.State, verb rune) {
    84  	if out.Flag('#') {
    85  		// use alternate format: base64w
    86  		s := base64.URLEncoding.EncodeToString([]byte(t))
    87  		if verb == 's' && len(string(t)) > ElisionCutoff {
    88  			fmt.Fprintf(out, "{%s...}", s[:ElisionLength])
    89  		} else {
    90  			fmt.Fprintf(out, "{%s}", s)
    91  		}
    92  	} else {
    93  		// use default format: hex
    94  		if verb == 's' && len(string(t)) > ElisionCutoff {
    95  			fmt.Fprintf(out, "[%02x...]", []byte(t)[:ElisionLength])
    96  		} else {
    97  			fmt.Fprintf(out, "[%02x]", []byte(t))
    98  		}
    99  	}
   100  }
   101  
   102  // Format outputs a pretty-printed Int.
   103  func (t Int) Format(out fmt.State, verb rune) {
   104  	fmt.Fprintf(out, "%d", int64(t))
   105  }
   106  
   107  // Format outputs a pretty-printed TermVar.
   108  func (t TermVar) Format(out fmt.State, verb rune) {
   109  	fmt.Fprint(out, string(t))
   110  }
   111  
   112  // Format outputs a pretty-printed Pred.
   113  func (f Pred) Format(out fmt.State, verb rune) {
   114  	formatNameAndArg(out, f.Name, f.Arg, verb)
   115  }
   116  
   117  // Format outputs a pretty-printed Const.
   118  func (f Const) Format(out fmt.State, verb rune) {
   119  	if f == true {
   120  		fmt.Fprint(out, "true")
   121  	} else {
   122  		fmt.Fprint(out, "false")
   123  	}
   124  }
   125  
   126  // Format outputs a pretty-printed Not.
   127  func (f Not) Format(out fmt.State, verb rune) {
   128  	fmt.Fprint(out, "not ")
   129  	formatFormWithParens(out, precedenceHigh, true, f.Negand, verb)
   130  }
   131  
   132  // Format outputs a pretty-printed And.
   133  func (f And) Format(out fmt.State, verb rune) {
   134  	if len(f.Conjunct) == 0 {
   135  		fmt.Fprint(out, "true")
   136  	} else if len(f.Conjunct) == 1 {
   137  		f.Conjunct[0].Format(out, verb)
   138  	} else {
   139  		n := len(f.Conjunct)
   140  		for i, e := range f.Conjunct {
   141  			if i > 0 {
   142  				fmt.Fprint(out, " and ")
   143  			}
   144  			formatFormWithParens(out, precedenceAnd, i == n-1, e, verb)
   145  		}
   146  	}
   147  }
   148  
   149  // Format outputs a pretty-printed Or.
   150  func (f Or) Format(out fmt.State, verb rune) {
   151  	if len(f.Disjunct) == 0 {
   152  		fmt.Fprint(out, "false")
   153  	} else if len(f.Disjunct) == 1 {
   154  		f.Disjunct[0].Format(out, verb)
   155  	} else {
   156  		n := len(f.Disjunct)
   157  		for i, e := range f.Disjunct {
   158  			if i > 0 {
   159  				fmt.Fprint(out, " or ")
   160  			}
   161  			formatFormWithParens(out, precedenceOr, i == n-1, e, verb)
   162  		}
   163  	}
   164  }
   165  
   166  // Format outputs a pretty-printed Implies.
   167  func (f Implies) Format(out fmt.State, verb rune) {
   168  	formatFormWithParens(out, precedenceLow+1, false, f.Antecedent, verb)
   169  	fmt.Fprint(out, " implies ")
   170  	formatFormWithParens(out, precedenceLow, true, f.Consequent, verb)
   171  }
   172  
   173  // Format outputs a pretty-printed Speaksfor.
   174  func (f Speaksfor) Format(out fmt.State, verb rune) {
   175  	f.Delegate.Format(out, verb)
   176  	fmt.Fprint(out, " speaksfor ")
   177  	f.Delegator.Format(out, verb)
   178  }
   179  
   180  // Format outputs a pretty-printed Says.
   181  func (f Says) Format(out fmt.State, verb rune) {
   182  	f.Speaker.Format(out, verb)
   183  	if f.Commences() {
   184  		fmt.Fprintf(out, " from %d", *f.Time)
   185  	}
   186  	if f.Expires() {
   187  		fmt.Fprintf(out, " until %d", *f.Expiration)
   188  	}
   189  	fmt.Fprint(out, " says ")
   190  	f.Message.Format(out, verb)
   191  }
   192  
   193  // Format outputs a pretty-printed Forall.
   194  func (f Forall) Format(out fmt.State, verb rune) {
   195  	fmt.Fprintf(out, "forall %s: ", f.Var)
   196  	f.Body.Format(out, verb)
   197  }
   198  
   199  // Format outputs a pretty-printed Exists.
   200  func (f Exists) Format(out fmt.State, verb rune) {
   201  	fmt.Fprintf(out, "exists %s: ", f.Var)
   202  	f.Body.Format(out, verb)
   203  }
   204  
   205  const (
   206  	precedenceLow = iota // lowest: implies, says, right speaksfor, right forall, right exists
   207  	precedenceOr
   208  	precedenceAnd
   209  	precedenceHigh // not, true, false, Pred, left speaksfor, left forall, left exists
   210  )
   211  
   212  // precedence returns an integer indicating the relative precedence of f.
   213  func precedence(f Form, right bool) int {
   214  	switch f := f.(type) {
   215  	case Says, Speaksfor, Forall, Exists, *Says, *Speaksfor, *Forall, *Exists:
   216  		if right {
   217  			return precedenceHigh
   218  		}
   219  		return precedenceLow
   220  	case Implies, *Implies:
   221  		return precedenceLow
   222  	case Or:
   223  		if len(f.Disjunct) == 0 {
   224  			return precedenceHigh // Or{} == false
   225  		} else if len(f.Disjunct) == 1 {
   226  			return precedence(f.Disjunct[0], right) // Or{f} == f
   227  		} else {
   228  			return precedenceOr
   229  		}
   230  	case *Or:
   231  		if len(f.Disjunct) == 0 {
   232  			return precedenceHigh // Or{} == false
   233  		} else if len(f.Disjunct) == 1 {
   234  			return precedence(f.Disjunct[0], right) // Or{f} == f
   235  		} else {
   236  			return precedenceOr
   237  		}
   238  	case And:
   239  		if len(f.Conjunct) == 0 {
   240  			return precedenceHigh // And{} == true
   241  		} else if len(f.Conjunct) == 1 {
   242  			return precedence(f.Conjunct[0], right) // And{f} == f
   243  		} else {
   244  			return precedenceAnd
   245  		}
   246  	case *And:
   247  		if len(f.Conjunct) == 0 {
   248  			return precedenceHigh // And{} == true
   249  		} else if len(f.Conjunct) == 1 {
   250  			return precedence(f.Conjunct[0], right) // And{f} == f
   251  		} else {
   252  			return precedenceAnd
   253  		}
   254  	case Not, Pred, Const, *Not, *Pred, *Const:
   255  		return precedenceHigh
   256  	default:
   257  		panic("not reached")
   258  	}
   259  }
   260  
   261  // formatFormWithParens outputs either f or (f), depending on how level compares
   262  // to the precedence of f and whether f appears on the right side of a binary
   263  // operator.
   264  func formatFormWithParens(out fmt.State, level int, right bool, f Form, verb rune) {
   265  	if level > precedence(f, right) {
   266  		fmt.Fprint(out, "(")
   267  		f.Format(out, verb)
   268  		fmt.Fprint(out, ")")
   269  	} else {
   270  		f.Format(out, verb)
   271  	}
   272  }