
1 // 2 // Copyright (c) 2006, Brian Frank and Andy Frank 3 // Licensed under the Academic Free License version 3.0 4 // 5 // History: 6 // 30 Jan 06 Brian Frank Creation 7 // 06 Jul 07 Brian Frank Port from Java 8 // 9 10 ** 11 ** TypeParser is used to parser formal type signatures into CTypes. 12 ** 13 ** x::N 14 ** x::V[] 15 ** x::V[x::K] 16 ** |x::A, ... -> x::R| 17 ** 18 class TypeParser 19 { 20 21 ////////////////////////////////////////////////////////////////////////// 22 // Factory 23 ////////////////////////////////////////////////////////////////////////// 24 25 ** 26 ** Parse the signature into a resolved CType. We *don't* 27 ** use the Namespace's cache - it is using me when a signature 28 ** isn't found in the cache. But we do use the CPod's type cache 29 ** via CPod.resolveType. 30 ** 31 public static CType resolve(Namespace ns, Str sig) 32 { 33 // if the last character isn't ] or |, then this a non-generic 34 // type and we don't even need to allocate a parser 35 last := sig[-1] 36 if (last !== ']' && last !== '|') 37 { 38 colon := sig.index("::") 39 podName := sig[0...colon] 40 typeName := sig[colon+2..-1] 41 return ns.resolvePod(podName, true).resolveType(typeName, true) 42 } 43 44 // we got our work cut out for us - create parser 45 return TypeParser.make(ns, sig).loadTop 46 } 47 48 ////////////////////////////////////////////////////////////////////////// 49 // Constructor 50 ////////////////////////////////////////////////////////////////////////// 51 52 private new make(Namespace ns, Str sig) 53 { 54 this.ns = ns 55 this.sig = sig 56 this.len = sig.size 57 this.pos = 0 58 this.cur = sig[pos] 59 this.peek = sig[pos+1] 60 } 61 62 ////////////////////////////////////////////////////////////////////////// 63 // Parse 64 ////////////////////////////////////////////////////////////////////////// 65 66 private CType loadTop() 67 { 68 t := loadAny 69 if (cur != 0) throw err 70 return t 71 } 72 73 private CType loadAny() 74 { 75 CType t 76 77 // |...| is function 78 if (cur === '|') 79 t = loadFunc 80 81 // [...] is map 82 else if (cur === '[') 83 t = loadMap 84 85 // otherwise must be basic[] 86 else 87 t = loadBasic 88 89 // anything left must be [] 90 while (cur == '[') 91 { 92 consume('[') 93 consume(']') 94 t = t.toListOf 95 } 96 97 return t 98 } 99 100 private CType loadMap() 101 { 102 consume('[') 103 key := loadAny 104 consume(':') 105 val := loadAny 106 consume(']') 107 return MapType.make(key, val) 108 } 109 110 private CType loadFunc() 111 { 112 consume('|') 113 params := CType[,] 114 names := Str[,] 115 if (cur != '-') 116 { 117 while (true) 118 { 119 params.add(loadAny) 120 names.add(('a'+names.size).toChar) 121 if (cur == '-') break 122 consume(',') 123 } 124 } 125 consume('-') 126 consume('>') 127 ret := loadAny 128 consume('|') 129 130 return FuncType.make(params, names, ret) 131 } 132 133 private CType loadBasic() 134 { 135 start := pos 136 while (cur.isAlphaNum || cur == '_') consume 137 consume(':') 138 consume(':') 139 while (cur.isAlphaNum || cur == '_') consume 140 qname := sig[start...pos] 141 return ns.resolveType(qname) 142 } 143 144 ////////////////////////////////////////////////////////////////////////// 145 // Utils 146 ////////////////////////////////////////////////////////////////////////// 147 148 private Void consume(Int expected := null) 149 { 150 if (expected != null && cur != expected) throw err 151 cur = peek 152 pos++ 153 peek = pos+1 < len ? sig[pos+1] : 0 154 } 155 156 private ArgErr err() 157 { 158 return ArgErr.make("Invalid type signature '" + sig + "'") 159 } 160 161 ////////////////////////////////////////////////////////////////////////// 162 // Fields 163 ////////////////////////////////////////////////////////////////////////// 164 165 private Namespace ns // namespace we are loading from 166 private Str sig // signature being parsed 167 private Int len // length of sig 168 private Int pos // index of cur in sig 169 private Int cur // cur character; sig[pos] 170 private Int peek // next character; sig[pos+1] 171 172 }