// // Copyright (c) 2006, Brian Frank and Andy Frank // Licensed under the Academic Free License version 3.0 // // History: // 30 Jan 06 Brian Frank Creation // 06 Jul 07 Brian Frank Port from Java // ** ** TypeParser is used to parser formal type signatures into CTypes. ** ** x::N ** x::V[] ** x::V[x::K] ** |x::A, ... -> x::R| ** class TypeParser { ////////////////////////////////////////////////////////////////////////// // Factory ////////////////////////////////////////////////////////////////////////// ** ** Parse the signature into a resolved CType. We *don't* ** use the CNamespace's cache - it is using me when a signature ** isn't found in the cache. But we do use the CPod's type cache ** via CPod.resolveType. ** public static CType resolve(CNamespace ns, Str sig) { // if last char is ? then parse as nullable last := sig[-1] if (last == '?') return resolve(ns, sig[0..-2]).toNullable // if the last character isn't ] or |, then this a non-generic // type and we don't even need to allocate a parser if (last != ']' && last != '|') { colon := sig.index("::") podName := sig[0..<colon] typeName := sig[colon+2..-1] return ns.resolvePod(podName, null).resolveType(typeName, true) } // we got our work cut out for us - create parser return TypeParser(ns, sig).loadTop } ////////////////////////////////////////////////////////////////////////// // Constructor ////////////////////////////////////////////////////////////////////////// private new make(CNamespace ns, Str sig) { this.ns = ns this.sig = sig this.len = sig.size this.pos = 0 this.cur = sig[pos] this.peek = sig[pos+1] } ////////////////////////////////////////////////////////////////////////// // Parse ////////////////////////////////////////////////////////////////////////// private CType loadTop() { t := loadAny if (cur != 0) throw err return t } private CType loadAny() { CType? t // |...| is function if (cur == '|') t = loadFunc // [ is either [ffi]xxx or [K:V] map else if (cur == '[') { ffi := true for (i:=pos+1; i<len; ++i) { ch := sig[i] if (isIdChar(ch)) continue ffi = (ch == ']') break } if (ffi) t = loadFFI else t = loadMap } // otherwise must be basic[] else t = loadBasic // nullable if (cur == '?') { consume('?') t = t.toNullable } // anything left must be [] while (cur == '[') { consume('[') consume(']') t = t.toListOf } // nullable if (cur == '?') { consume('?') t = t.toNullable } return t } private CType loadMap() { consume('[') key := loadAny consume(':') val := loadAny consume(']') return MapType(key, val) } private CType loadFunc() { consume('|') params := CType[,] names := Str[,] if (cur != '-') { while (true) { params.add(loadAny) names.add(('a'+names.size).toChar) if (cur == '-') break consume(',') } } consume('-') consume('>') ret := loadAny consume('|') return FuncType(params, names, ret) } private CType loadFFI() { // [java]foo.bar.foo start := pos while (cur != ':' || peek != ':') consume //podName := sig[start..<pos] consume(':') consume(':') // Baz or [Baz //start = pos while (cur == '[') consume while (isIdChar(cur)) consume //typeName := sig[start..<pos] qname := sig[start..<pos] return ns.resolveType(qname); } private CType loadBasic() { start := pos while (cur != ':' || peek != ':') consume consume(':') consume(':') while (isIdChar(cur)) consume qname := sig[start..<pos] return ns.resolveType(qname) } ////////////////////////////////////////////////////////////////////////// // Utils ////////////////////////////////////////////////////////////////////////// private Void consume(Int? expected := null) { if (expected != null && cur != expected) throw err cur = peek pos++ peek = pos+1 < len ? sig[pos+1] : 0 } private static Bool isIdChar(Int ch) { ch.isAlphaNum || ch == '_' } private ArgErr err() { ArgErr("Invalid type signature '" + sig + "'") } ////////////////////////////////////////////////////////////////////////// // Fields ////////////////////////////////////////////////////////////////////////// private CNamespace ns // namespace we are loading from private Str sig // signature being parsed private Int len // length of sig private Int pos // index of cur in sig private Int cur // cur character; sig[pos] private Int peek // next character; sig[pos+1] }