| 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. |
| 4 | module parser |
| 5 | |
| 6 | import v2.ast |
| 7 | |
| 8 | @[inline] |
| 9 | fn (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 { |
| 22 | fn (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 |
| 189 | fn (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 | |
| 196 | fn 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`) |
| 207 | fn (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]`) |
| 255 | fn (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 | |