| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. 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 ast |
| 5 | |
| 6 | import v.token |
| 7 | |
| 8 | pub enum AttrKind { |
| 9 | plain // [name] |
| 10 | string // ['name'] |
| 11 | number // [123] |
| 12 | bool // [true] || [false] |
| 13 | comptime_define // [if name] |
| 14 | } |
| 15 | |
| 16 | // e.g. `@[unsafe]` |
| 17 | @[minify] |
| 18 | pub struct Attr { |
| 19 | pub: |
| 20 | name string // [name] |
| 21 | has_arg bool |
| 22 | arg string // [name: arg] |
| 23 | kind AttrKind |
| 24 | quote u8 = `'` // quote for .string attrs: `"` or `'` |
| 25 | ct_opt bool // true for [if user_defined_name?] |
| 26 | pos token.Pos |
| 27 | has_at bool // new syntax `@[attr]` |
| 28 | // original call-style metadata for `@[foo(...)]`, used by vfmt |
| 29 | call_name string |
| 30 | call_arg_name string |
| 31 | call_arg_idx int = -1 |
| 32 | pub mut: |
| 33 | ct_expr Expr // .kind == comptime_define, for [if !name] |
| 34 | ct_evaled bool // whether ct_skip has been evaluated already |
| 35 | ct_skip bool // is the comptime expr *false*, filled by checker |
| 36 | } |
| 37 | |
| 38 | pub fn (a &Attr) debug() string { |
| 39 | return 'Attr{ name: "${a.name}", has_arg: ${a.has_arg}, arg: "${a.arg}", kind: ${a.kind}, ct_expr: ${a.ct_expr}, ct_opt: ${a.ct_opt}, ct_skip: ${a.ct_skip}, call_name: "${a.call_name}", call_arg_name: "${a.call_arg_name}", call_arg_idx: ${a.call_arg_idx} }' |
| 40 | } |
| 41 | |
| 42 | // str returns the string representation without square brackets |
| 43 | pub fn (a &Attr) str() string { |
| 44 | mut s := '' |
| 45 | quote := if a.quote == `"` { '"' } else { "'" } |
| 46 | mut arg := if a.has_arg { |
| 47 | s += '${a.name}: ' |
| 48 | a.arg |
| 49 | } else { |
| 50 | a.name |
| 51 | } |
| 52 | s += match a.kind { |
| 53 | .plain, .number, .bool { arg } |
| 54 | .string { '${quote}${arg}${quote}' } |
| 55 | .comptime_define { 'if ${arg}' } |
| 56 | } |
| 57 | |
| 58 | return s |
| 59 | } |
| 60 | |
| 61 | pub fn (attrs []Attr) contains(str string) bool { |
| 62 | return attrs.any(it.name == str) |
| 63 | } |
| 64 | |
| 65 | pub fn (attrs []Attr) contains_arg(str string, arg string) bool { |
| 66 | return attrs.any(it.has_arg && it.name == str && it.arg == arg) |
| 67 | } |
| 68 | |
| 69 | @[direct_array_access] |
| 70 | pub fn (attrs []Attr) find_first(aname string) ?Attr { |
| 71 | for a in attrs { |
| 72 | if a.name == aname { |
| 73 | return a |
| 74 | } |
| 75 | } |
| 76 | return none |
| 77 | } |
| 78 | |
| 79 | @[direct_array_access] |
| 80 | pub fn (attrs []Attr) find_last(aname string) ?Attr { |
| 81 | for idx := attrs.len - 1; idx > -1; idx-- { |
| 82 | a := attrs[idx] |
| 83 | if a.name == aname { |
| 84 | return a |
| 85 | } |
| 86 | } |
| 87 | return none |
| 88 | } |
| 89 | |
| 90 | @[direct_array_access] |
| 91 | pub fn (attrs []Attr) find_comptime_define() ?int { |
| 92 | for idx in 0 .. attrs.len { |
| 93 | if attrs[idx].kind == .comptime_define { |
| 94 | return idx |
| 95 | } |
| 96 | } |
| 97 | return none |
| 98 | } |
| 99 | |