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 }
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 }