Appearance
| 1 | namespace Semantic.Symbols is | |
| 2 | use Collections.LIST | |
| 3 | ||
| 4 | use Semantic.Types.Type | |
| 5 | ||
| 6 | // The TYPE_REF field's default-equality comparison is correct as | |
| 7 | // it stands: `Type` values are interned, so reference equality is | |
| 8 | // type equality, and the operator the fallback report would ask | |
| 9 | // for has nothing to add. | |
| 10 | @suppress("synthesized-equality-fallback") | |
| 11 | union SignaturePart is | |
| 12 | NIL | |
| 13 | LITERAL(text: string) | |
| 14 | NAME(symbol: Symbol) | |
| 15 | TYPE_REF(type: Type) | |
| 16 | SEQUENCE(parts: LIST[SignaturePart]) | |
| 17 | // A break point for the layout engine. Flat form: `open` + | |
| 18 | // items joined by (`separator` + " " when `tight` is false, | |
| 19 | // `separator` alone when true) + `close`. Broken form: `open` | |
| 20 | // + newline + 4-space-indented items joined by `separator` + | |
| 21 | // newline + indent + newline + `close` at the outer indent. | |
| 22 | // `separator` is punctuation-only (no trailing space); `tight` | |
| 23 | // controls whether a flat rendering inserts a space after each | |
| 24 | // one. Argument lists use `separator=","`, `tight=false`; | |
| 25 | // generic-argument brackets use `separator=","`, `tight=true`. | |
| 26 | WRAPPABLE( | |
| 27 | open: string, | |
| 28 | separator: string, | |
| 29 | tight: bool, | |
| 30 | close: string, | |
| 31 | items: LIST[SignaturePart] | |
| 32 | ) | |
| 33 | // A forced line break introducing an indented continuation: | |
| 34 | // a newline, `indent` spaces, the `head` text, then `body`. | |
| 35 | // `body`'s own break points nest a further `head.length` columns | |
| 36 | // so a wrappable body's continuation lines hang under the text | |
| 37 | // after `head` rather than under the break. Used for the narrowed | |
| 38 | // `► <type>` line beneath a symbol's declared type. | |
| 39 | HANGING( | |
| 40 | indent: int, | |
| 41 | head: string, | |
| 42 | body: SignaturePart | |
| 43 | ) | |
| 44 | si | |
| 45 | ||
| 46 | // Convenience builders that fold the `Collections.LIST[SignaturePart]` | |
| 47 | // wrapping into a single call so `describe` overrides read as data. | |
| 48 | class PARTS is | |
| 49 | literal(text: string) -> SignaturePart static => | |
| 50 | SignaturePart.LITERAL(text) | |
| 51 | ||
| 52 | name(symbol: Symbol) -> SignaturePart static => | |
| 53 | SignaturePart.NAME(symbol) | |
| 54 | ||
| 55 | type_ref(type: Type) -> SignaturePart static => | |
| 56 | SignaturePart.TYPE_REF(type) | |
| 57 | ||
| 58 | nil() -> SignaturePart static => | |
| 59 | SignaturePart.NIL() | |
| 60 | ||
| 61 | sequence(items: SignaturePart[]) -> SignaturePart static => | |
| 62 | SignaturePart.SEQUENCE(Collections.LIST[SignaturePart](items)) | |
| 63 | ||
| 64 | wrappable( | |
| 65 | open: string, | |
| 66 | separator: string, | |
| 67 | tight: bool, | |
| 68 | close: string, | |
| 69 | items: SignaturePart[] | |
| 70 | ) -> SignaturePart static => | |
| 71 | SignaturePart.WRAPPABLE(open, separator, tight, close, Collections.LIST[SignaturePart](items)) | |
| 72 | ||
| 73 | hanging(indent: int, head: string, body: SignaturePart) -> SignaturePart static => | |
| 74 | SignaturePart.HANGING(indent, head, body) | |
| 75 | si | |
| 76 | ||
| 77 | class DESCRIBE_CONTEXT is | |
| 78 | _default: DESCRIBE_CONTEXT? static | |
| 79 | _observed_types: Collections.Map[Symbol, Type]? | |
| 80 | ||
| 81 | instance: DESCRIBE_CONTEXT static is | |
| 82 | if !_default? then | |
| 83 | _default = DESCRIBE_CONTEXT() | |
| 84 | fi | |
| 85 | return _default | |
| 86 | si | |
| 87 | ||
| 88 | init() is | |
| 89 | si | |
| 90 | ||
| 91 | with_observed_types(observed_types: Collections.Map[Symbol, Type]) -> DESCRIBE_CONTEXT static is | |
| 92 | let result = DESCRIBE_CONTEXT() | |
| 93 | result._observed_types = observed_types | |
| 94 | return result | |
| 95 | si | |
| 96 | ||
| 97 | observed_type_for(symbol: Symbol) -> Type? is | |
| 98 | let map = _observed_types | |
| 99 | if !map? then | |
| 100 | return null | |
| 101 | fi | |
| 102 | if !map.contains_key(symbol) then | |
| 103 | return null | |
| 104 | fi | |
| 105 | return map[symbol] | |
| 106 | si | |
| 107 | si | |
| 108 | ||
| 109 | class TEXT_RENDERER is | |
| 110 | _context: DESCRIBE_CONTEXT | |
| 111 | ||
| 112 | init(context: DESCRIBE_CONTEXT) is | |
| 113 | _context = context | |
| 114 | si | |
| 115 | ||
| 116 | render(part: SignaturePart) -> string is | |
| 117 | let buffer = System.Text.StringBuilder() | |
| 118 | _emit(buffer, part) | |
| 119 | return buffer.to_string() | |
| 120 | si | |
| 121 | ||
| 122 | _emit(buffer: System.Text.StringBuilder, part: SignaturePart) is | |
| 123 | if isa SignaturePart.NIL(part) then | |
| 124 | return | |
| 125 | fi | |
| 126 | ||
| 127 | if let literal: SignaturePart.LITERAL = part then | |
| 128 | buffer.append(literal.text) | |
| 129 | return | |
| 130 | fi | |
| 131 | ||
| 132 | if let name: SignaturePart.NAME = part then | |
| 133 | buffer.append(IoC.CONTAINER.instance.name_display.name_for(name.symbol)) | |
| 134 | return | |
| 135 | fi | |
| 136 | ||
| 137 | if let type_ref: SignaturePart.TYPE_REF = part then | |
| 138 | buffer.append("{type_ref.type}") | |
| 139 | return | |
| 140 | fi | |
| 141 | ||
| 142 | if let sequence: SignaturePart.SEQUENCE = part then | |
| 143 | for item in sequence.parts do | |
| 144 | _emit(buffer, item) | |
| 145 | od | |
| 146 | return | |
| 147 | fi | |
| 148 | ||
| 149 | if let wrappable: SignaturePart.WRAPPABLE = part then | |
| 150 | buffer.append(wrappable.open) | |
| 151 | let first mut = true | |
| 152 | for item in wrappable.items do | |
| 153 | if !first then | |
| 154 | buffer.append(wrappable.separator) | |
| 155 | if !wrappable.tight then | |
| 156 | buffer.append(' ') | |
| 157 | fi | |
| 158 | fi | |
| 159 | first = false | |
| 160 | _emit(buffer, item) | |
| 161 | od | |
| 162 | buffer.append(wrappable.close) | |
| 163 | return | |
| 164 | fi | |
| 165 | ||
| 166 | if let hanging: SignaturePart.HANGING = part then | |
| 167 | buffer.append('\n') | |
| 168 | let i mut = 0 | |
| 169 | while i < hanging.indent do | |
| 170 | buffer.append(' ') | |
| 171 | i = i + 1 | |
| 172 | od | |
| 173 | buffer.append(hanging.head) | |
| 174 | _emit(buffer, hanging.body) | |
| 175 | return | |
| 176 | fi | |
| 177 | si | |
| 178 | si | |
| 179 | si |