v / vlib / v2 / parser / type.v
264 lines · 257 sloc · 6.46 KB · 20eada7233525573d6471d2cc70fa501213e430a
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module parser
5
6import v2.ast
7
8@[inline]
9fn (mut p Parser) expect_type() ast.Expr {
10 // return p.try_type() or {
11 // p.error(err.msg())
12 // }
13 typ := p.try_type()
14 if typ is ast.EmptyExpr {
15 p.error('expecting type, got `${p.tok}`')
16 }
17 return typ
18}
19
20// TODO: use result or stick with empty expr?
21// pub fn (mut p Parser) try_type() !ast.Expr {
22fn (mut p Parser) try_type() ast.Expr {
23 match p.tok {
24 // pointer: `&type`
25 .amp {
26 p.next()
27 mut lifetime := ''
28 if p.tok == .xor {
29 p.next()
30 lifetime = p.expect_name()
31 }
32 return ast.Type(ast.PointerType{
33 base_type: p.expect_type()
34 lifetime: lifetime
35 })
36 }
37 // lifetime: `^a`
38 .xor {
39 pos := p.pos
40 p.next()
41 return ast.LifetimeExpr{
42 name: p.expect_name()
43 pos: pos
44 }
45 }
46 // comptime type: `$enum` | `$struct` | etc
47 .dollar {
48 p.next()
49 mut comptime_inner := ast.Expr(ast.empty_expr)
50 if p.tok == .name {
51 comptime_inner = ast.Expr(p.ident())
52 } else {
53 // TODO: match only allowed tokens otherwise error
54 comptime_inner = ast.Expr(ast.Ident{
55 pos: p.pos
56 name: p.tok().str()
57 })
58 }
59 return ast.ComptimeExpr{
60 expr: comptime_inner
61 }
62 }
63 // variadic: `...type`
64 .ellipsis {
65 p.next()
66 // TODO: what will we use here?
67 return ast.PrefixExpr{
68 op: .ellipsis
69 expr: p.expect_type()
70 }
71 }
72 // atomic | shared
73 // eg. typespec in struct field with modifier. other cases handled in expr()
74 .key_atomic, .key_shared {
75 kind := p.tok
76 pos := p.pos
77 p.next()
78 return modifier_expr_with_expr(kind, p.expect_type(), pos)
79 }
80 // function: `fn(type) type`
81 .key_fn {
82 p.next()
83 return ast.Type(p.fn_type())
84 }
85 // nil
86 .key_nil {
87 p.next()
88 return ast.Type(ast.NilType{})
89 }
90 // none
91 .key_none {
92 p.next()
93 return ast.Type(ast.NoneType{})
94 }
95 // inline / anonymous struct
96 .key_struct {
97 p.next()
98 generic_params := if p.tok == .lsbr { p.generic_list() } else { []ast.Expr{} }
99 embedded, fields := p.struct_decl_fields(.v, false, false)
100 // TODO: should we use this or just StructDecl
101 // even though it technically is not one? hrmm
102 return ast.Type(ast.AnonStructType{
103 generic_params: generic_params
104 embedded: embedded
105 fields: fields
106 })
107 }
108 // tuple (multi return): `(type, type)`
109 .lpar {
110 p.next()
111 // expect at least two (so we otherwise error)
112 mut types := [p.expect_type()]
113 p.expect(.comma)
114 types << p.expect_type()
115 // more than two
116 for p.tok == .comma {
117 p.next()
118 types << p.expect_type()
119 }
120 p.expect(.rpar)
121 return ast.Type(ast.TupleType{
122 types: types
123 })
124 }
125 // array: `[]type` | `[len]type`
126 .lsbr {
127 p.next()
128 // dynamic array
129 if p.tok == .rsbr {
130 p.next()
131 return ast.Type(ast.ArrayType{
132 elem_type: p.expect_type()
133 })
134 }
135 // fixed array
136 len_expr := p.expr(.lowest)
137 p.expect(.rsbr)
138 return ast.Type(ast.ArrayFixedType{
139 len: len_expr
140 elem_type: p.expect_type()
141 })
142 }
143 // name | chan | map
144 .name {
145 pos := p.pos
146 // TODO: cleam this up
147 name := p.ident_or_named_type()
148 if p.tok == .lsbr && name !is ast.Type && p.tok != .semicolon {
149 // TODO: is there a better solution than this. maybe it should be the
150 // concern of p.fn_parameters() & p.struct_decl() rather than this?
151 // `fn(param_a []type)` | `struct { field_a []type }`
152 if name is ast.Ident && name.name.len + pos.offset < p.pos.offset {
153 return name
154 }
155 // TODO: using ast.GenericArgs here may not be correct,
156 // perhaps we should rename it to ast.GenericTypes
157 // if name is ast.Ident && p.pos == pos + name.name.len { return name }
158 return ast.Type(ast.GenericType{
159 name: name
160 params: p.generic_list()
161 })
162 }
163 return name
164 }
165 // result: `!` | `!type`
166 .not {
167 p.next()
168 return ast.Type(ast.ResultType{
169 base_type: if p.tok != .semicolon { p.try_type() } else { ast.empty_expr }
170 // base_type: p.tok != .semicolon { p.try_type() or { ast.empty_expr } } else { ast.empty_expr }
171 })
172 }
173 // option: `?` | `?type`
174 .question {
175 p.next()
176 return ast.Type(ast.OptionType{
177 base_type: if p.tok != .semicolon { p.try_type() } else { ast.empty_expr }
178 // base_type: if p.tok != .semicolon { p.try_type() or { ast.empty_expr } } else { ast.empty_expr }
179 })
180 }
181 else {
182 // return error('expecting type, got `${p.tok}`')
183 return ast.empty_expr
184 }
185 }
186}
187
188// function type / signature
189fn (mut p Parser) fn_type() ast.FnType {
190 generic_params := if p.tok == .lsbr { p.generic_list() } else { []ast.Expr{} }
191 params := p.fn_parameters()
192 return_type := if p.tok != .semicolon { p.try_type() } else { ast.empty_expr }
193 return fn_type_with_return_type(generic_params, params, return_type)
194}
195
196fn fn_type_with_return_type(generic_params []ast.Expr, params []ast.Parameter, return_type ast.Expr) ast.FnType {
197 mut fn_type := ast.FnType{
198 generic_params: generic_params
199 params: params
200 return_type: ast.empty_expr
201 }
202 fn_type.return_type = return_type
203 return fn_type
204}
205
206// `ident` | `map[type]type | `(`chan`|`chan type`) | (`thread`|`thread type`)
207fn (mut p Parser) ident_or_named_type() ast.Expr {
208 pos := p.pos
209 lit := p.lit
210 // `map[type]type`
211 if lit == 'map' {
212 p.next()
213 if p.tok == .lsbr {
214 p.next()
215 key_type := p.expect_type()
216 p.expect(.rsbr)
217 return ast.Type(ast.MapType{
218 key_type: key_type
219 value_type: p.expect_type()
220 })
221 }
222 // struct called `map` in builtin
223 return ast.Ident{
224 name: 'map'
225 pos: pos
226 }
227 }
228 // `chan` | `chan type`
229 if lit == 'chan' {
230 p.next()
231 elem_type := if p.tok != .semicolon { p.try_type() } else { ast.empty_expr }
232 if elem_type !is ast.EmptyExpr {
233 return ast.Type(ast.ChannelType{
234 elem_type: elem_type
235 })
236 }
237 // struct called `chan` in builtin
238 return ast.Ident{
239 name: 'chan'
240 pos: pos
241 }
242 }
243 // `thread` | `thread type`
244 else if lit == 'thread' {
245 p.next()
246 return ast.Type(ast.ThreadType{
247 elem_type: if p.tok != .semicolon { p.try_type() } else { ast.empty_expr }
248 })
249 }
250 // `ident` | `selector` - ident or type name
251 return p.ident_or_selector_expr()
252}
253
254// `ident` | (`Type`|`Type[T]`) | (`mod.Type`|`mod.Type[T]`)
255fn (mut p Parser) ident_or_type() ast.Expr {
256 ident_or_selector := p.ident_or_selector_expr()
257 if p.tok == .lsbr {
258 return ast.Type(ast.GenericType{
259 name: ident_or_selector
260 params: p.generic_list()
261 })
262 }
263 return ident_or_selector
264}
265