From 4d26facfd20797aa78c81cf3029f00f8de29a445 Mon Sep 17 00:00:00 2001 From: Fabijan Zulj Date: Fri, 17 May 2024 22:03:30 +0200 Subject: [PATCH] add struct tags support for compiler and importer --- compiler/src/ast.rs | 1 + compiler/src/codegen.rs | 6 +++++- compiler/src/infer.rs | 2 ++ compiler/src/lexer.rs | 6 +++--- compiler/src/parser.rs | 13 +++++++++++++ importer/importer.go | 22 ++++++++++++++++------ importer/testpkg/testpkg.go | 4 ++-- 7 files changed, 42 insertions(+), 12 deletions(-) diff --git a/compiler/src/ast.rs b/compiler/src/ast.rs index ff5a88a..e5b4e6b 100644 --- a/compiler/src/ast.rs +++ b/compiler/src/ast.rs @@ -270,6 +270,7 @@ pub struct StructFieldDef { pub name: Ident, pub ann: TypeAst, pub ty: BoundedType, + pub tags: Option, } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] diff --git a/compiler/src/codegen.rs b/compiler/src/codegen.rs index 976116d..be9e3de 100644 --- a/compiler/src/codegen.rs +++ b/compiler/src/codegen.rs @@ -1189,7 +1189,11 @@ if {is_matching} != 2 {{ def.fields.iter().for_each(|f| { let field = &f.name; let ty = self.to_type(&f.ty.ty); - out.emit(format!(" {field} {ty}")); + let tags = &f.tags; + match tags { + Some(tg) => out.emit(format!(" {field} {ty} `{tg}`")), + None => out.emit(format!(" {field} {ty}")), + } }); out.emit("}".to_string()); diff --git a/compiler/src/infer.rs b/compiler/src/infer.rs index 6990dd9..bfb866e 100644 --- a/compiler/src/infer.rs +++ b/compiler/src/infer.rs @@ -2526,6 +2526,7 @@ has no field or method: name, ann: f.ann.clone(), ty: typ.to_bounded(), + tags: None } }) .collect(); @@ -3169,6 +3170,7 @@ has no field or method: name: sym.name.clone(), ann: TypeAst::Unknown, ty: ty.clone(), + tags: None }); } diff --git a/compiler/src/lexer.rs b/compiler/src/lexer.rs index c1912b1..b3923fa 100644 --- a/compiler/src/lexer.rs +++ b/compiler/src/lexer.rs @@ -527,7 +527,7 @@ impl Lexer { } } - fn scan_string(&mut self) -> Token { + fn scan_string(&mut self, delimiter: char) -> Token { let mut text = String::new(); let start = self.next(); @@ -535,7 +535,7 @@ impl Lexer { // TODO validate escape \" loop { - if self.ch == '"' { + if self.ch == delimiter { self.next(); seen_closing = true; break; @@ -681,7 +681,7 @@ impl Lexer { match self.ch { '0'..='9' => self.scan_number(), 'a'..='z' | 'A'..='Z' | '_' => self.scan_ident(), - '"' => self.scan_string(), + '"' | '`' => self.scan_string(self.ch), '\'' => self.scan_char(), '/' => self.scan_slash_comment(), '\\' => self.scan_multi_string(), diff --git a/compiler/src/parser.rs b/compiler/src/parser.rs index c41413f..816d546 100644 --- a/compiler/src/parser.rs +++ b/compiler/src/parser.rs @@ -1768,11 +1768,24 @@ impl Parser { let name = self.parse_one_ident(); self.expect(TokenKind::Colon); let ann = self.parse_type(); + let tags = self.parse_struct_field_tags(); StructFieldDef { name, ann, ty: Type::dummy().to_bounded(), + tags + } + } + + fn parse_struct_field_tags(&mut self) -> Option { + match self.tok.kind { + TokenKind::String => { + let tags = Some(self.tok.text.clone()); + self.next(); + tags + } + _ => None, } } diff --git a/importer/importer.go b/importer/importer.go index 51281a9..1e815b7 100644 --- a/importer/importer.go +++ b/importer/importer.go @@ -161,6 +161,7 @@ type Struct struct { type StructField struct { Name string Type Type + Tags string } type Variable struct { @@ -232,7 +233,16 @@ func (p *Package) AddStruct(name string, bounds []Bound, list []*ast.Field, kind name = f.Names[0].Name } - fields = append(fields, StructField{Name: name, Type: p.parseTypeExpr(f.Type)}) + sf := StructField{ + Name: name, + Type: p.parseTypeExpr(f.Type), + } + + if f.Tag != nil { + sf.Tags = f.Tag.Value + } + + fields = append(fields, sf) } s := Struct{Name: name, Bounds: bounds, Fields: fields, Kind: kind} @@ -337,7 +347,6 @@ func (p *Package) String() string { } for _, s := range p.Types { - switch s.Kind { case TypeStruct: bounds := boundsToString(s.Bounds) @@ -356,7 +365,6 @@ func (p *Package) String() string { def := "interface " + s.Name + generics + " {\n" + newBounds + "\n" + newFields + "\n}\n\n" fmt.Fprint(&w, def) } - } return w.String() @@ -560,7 +568,6 @@ func functionArgsToString(fargs []FuncArg) string { } return strings.Join(args, ", ") - } func structFieldsToString(list []StructField) string { @@ -573,7 +580,11 @@ func structFieldsToString(list []StructField) string { continue } - fields = append(fields, " "+f.Name+": "+f.Type.String()) + fieldStr := " " + f.Name + ": " + f.Type.String() + if f.Tags != "" { + fieldStr = fieldStr + " " + f.Tags + } + fields = append(fields, fieldStr) } return strings.Join(fields, ",\n") @@ -728,7 +739,6 @@ func main() { } for _, decl := range t.Decl.Specs { - if spec, ok := decl.(*ast.TypeSpec); ok { bounds := p.parseBounds(spec.TypeParams) diff --git a/importer/testpkg/testpkg.go b/importer/testpkg/testpkg.go index 3838727..009ce49 100644 --- a/importer/testpkg/testpkg.go +++ b/importer/testpkg/testpkg.go @@ -14,8 +14,8 @@ const ( const SomeConst = 1 type Person struct { - Name string - Hobbies []Hobby + Name string `json:"name"` + Hobbies []Hobby `json:"hobbies"` } type Hobby struct {