From 9596bd0c12154e395ee46523f1e1d4eadd83c784 Mon Sep 17 00:00:00 2001 From: chai2010 Date: Sat, 20 Apr 2024 00:17:41 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=20embed=20=E7=89=B9=E6=80=A7?= =?UTF-8?q?,=20=E4=BB=85=E6=94=AF=E6=8C=81=20const?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/parser/parser.go | 8 ++++++-- internal/types/decl.go | 4 ++-- internal/types/embed.go | 36 +++++++++++++++++++----------------- internal/types/resolver.go | 18 +++++++++++++----- waroot/src/apple/embed.wa | 2 +- 5 files changed, 41 insertions(+), 27 deletions(-) diff --git a/internal/parser/parser.go b/internal/parser/parser.go index 1be36548..5f800dac 100644 --- a/internal/parser/parser.go +++ b/internal/parser/parser.go @@ -2391,9 +2391,13 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota p.error(pos, "missing variable type or initialization") } case token.CONST: - if values == nil && (iota == 0 || typ != nil) { - p.error(pos, "missing constant value") + if typ == nil && values == nil && iota == 0 { + p.error(pos, "missing const type or initialization") } + + // if values == nil && (iota == 0 || typ != nil) { + // p.error(pos, "missing constant value") + // } } // Go spec: The scope of a constant or variable identifier declared inside diff --git a/internal/types/decl.go b/internal/types/decl.go index 0a7e22e8..f58b78da 100644 --- a/internal/types/decl.go +++ b/internal/types/decl.go @@ -602,7 +602,7 @@ func (check *Checker) declStmt(decl ast.Decl) { check.constDecl(obj, last.Type, init) } - check.arityMatch(s, last) + check.arityMatch(s, last, false) // process function literals in init expressions before scope changes check.processDelayed(top) @@ -657,7 +657,7 @@ func (check *Checker) declStmt(decl ast.Decl) { } } - check.arityMatch(s, nil) + check.arityMatch(s, nil, false) // process function literals in init expressions before scope changes check.processDelayed(top) diff --git a/internal/types/embed.go b/internal/types/embed.go index acfe33b7..731b0edb 100644 --- a/internal/types/embed.go +++ b/internal/types/embed.go @@ -7,37 +7,38 @@ import ( "wa-lang.org/wa/internal/ast" "wa-lang.org/wa/internal/ast/astutil" + "wa-lang.org/wa/internal/constant" "wa-lang.org/wa/internal/token" ) // 预处理全局变量文件嵌入 func (check *Checker) processGlobalEmbed() { for obj, d := range check.objMap { - if varObj, ok := obj.(*Var); ok { - varSpec := varObj.Node().(*ast.ValueSpec) - varCommentInfo := astutil.ParseCommentInfo(varObj.NodeDoc()) + if constObj, ok := obj.(*Const); ok { + valueSpec := constObj.Node().(*ast.ValueSpec) + commentInfo := astutil.ParseCommentInfo(constObj.NodeDoc()) - if varCommentInfo.Embed == "" { + if commentInfo.Embed == "" { continue } - if len(varSpec.Names) != 1 { - check.errorf(varObj.Pos(), "wa:embed only support one global") + if len(valueSpec.Names) != 1 { + check.errorf(constObj.Pos(), "wa:embed cannot apply to multiple const") return } - if len(varSpec.Values) != 0 || varSpec.Type == nil { - check.errorf(varObj.Pos(), "wa:embed donot support init values") + if len(valueSpec.Values) != 0 { + check.errorf(constObj.Pos(), "wa:embed cannot apply to const with initializer") return } - typeIdent, _ := varSpec.Type.(*ast.Ident) + typeIdent, _ := valueSpec.Type.(*ast.Ident) if typeIdent == nil { - check.errorf(varObj.Pos(), "wa:embed must have type") + check.errorf(constObj.Pos(), "wa:embed cannot apply to untyped const") return } - scope, obj := check.pkg.scope.LookupParent(typeIdent.Name, varSpec.Pos()) + scope, obj := check.pkg.scope.LookupParent(typeIdent.Name, valueSpec.Pos()) if scope != Universe || obj.Type() != universeString { - check.errorf(varObj.Pos(), "wa:embed invalid global type %v", obj) + check.errorf(constObj.Pos(), "wa:embed invalid global type %v", obj) continue } @@ -47,7 +48,7 @@ func (check *Checker) processGlobalEmbed() { Loop: for _, f := range check.files { for k, v := range f.EmbedMap { - if k == varCommentInfo.Embed { + if k == commentInfo.Embed { embedFound = true embedData = v break Loop @@ -55,19 +56,20 @@ func (check *Checker) processGlobalEmbed() { } } if !embedFound { - check.errorf(varObj.Pos(), "wa:embed file not found") + check.errorf(constObj.Pos(), "wa:embed %s: not found no matching files found", commentInfo.Embed) continue } - varSpec.Values = []ast.Expr{ + valueSpec.Values = []ast.Expr{ &ast.BasicLit{ - ValuePos: varSpec.Pos(), + ValuePos: valueSpec.Pos(), Kind: token.STRING, Value: strconv.Quote(embedData), }, } - d.init = varSpec.Values[0] + constObj.val = constant.MakeString(strconv.Quote(embedData)) + d.init = valueSpec.Values[0] } } } diff --git a/internal/types/resolver.go b/internal/types/resolver.go index dceb811c..83521d49 100644 --- a/internal/types/resolver.go +++ b/internal/types/resolver.go @@ -54,7 +54,7 @@ func (d *declInfo) addDep(obj Object) { // have the appropriate number of names and init exprs. For const // decls, init is the value spec providing the init exprs; for // var decls, init is nil (the init exprs are in s in this case). -func (check *Checker) arityMatch(s, init *ast.ValueSpec) { +func (check *Checker) arityMatch(s, init *ast.ValueSpec, hasEmbed bool) { l := len(s.Names) r := len(s.Values) if init != nil { @@ -79,8 +79,10 @@ func (check *Checker) arityMatch(s, init *ast.ValueSpec) { // TODO(gri) avoid declared but not used error here } case l > r && (init != nil || r != 1): - n := s.Names[r] - check.errorf(n.Pos(), "missing init expr for %s", n) + if !hasEmbed { + n := s.Names[r] + check.errorf(n.Pos(), "missing init expr for %s", n) + } } } @@ -325,6 +327,12 @@ func (check *Checker) collectObjects() { case *ast.ValueSpec: switch d.Tok { case token.CONST: + hasEmbed := false + if len(s.Names) == 1 { + info := astutil.ParseCommentInfo(d.Doc) + hasEmbed = info.Embed != "" + } + // determine which initialization expressions to use switch { case s.Type != nil || len(s.Values) > 0: @@ -353,7 +361,7 @@ func (check *Checker) collectObjects() { check.declarePkgObj(name, obj, d) } - check.arityMatch(s, last) + check.arityMatch(s, last, hasEmbed) case token.VAR, token.GLOBAL: lhs := make([]*Var, len(s.Names)) @@ -394,7 +402,7 @@ func (check *Checker) collectObjects() { check.declarePkgObj(name, obj, d) } - check.arityMatch(s, nil) + check.arityMatch(s, nil, false) default: check.invalidAST(s.Pos(), "invalid token %s", d.Tok) diff --git a/waroot/src/apple/embed.wa b/waroot/src/apple/embed.wa index 395f681f..c2513f15 100644 --- a/waroot/src/apple/embed.wa +++ b/waroot/src/apple/embed.wa @@ -1,4 +1,4 @@ // 版权 @2023 凹语言 作者。保留所有权利。 #wa:embed logo.txt -global WaLogo: string +const WaLogo: string