优化 native/ast 字面值结构体

This commit is contained in:
chai2010
2025-09-13 04:41:11 +08:00
parent ec3530539f
commit f70a9113b9
8 changed files with 102 additions and 169 deletions

View File

@@ -34,10 +34,11 @@ type CommentGroup struct {
// 基本的面值
type BasicLit struct {
Pos token.Pos // 位置
Kind token.Token // INT/FLOAT/CHAR/STRING, 默认类型 INT=>I64, FLOAT=>F64, CHAR => I32
TypeCast token.Token // 默认类型强制转型, I32/U32/I64/U64/F32/F64/NONE
Value string // 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o`
Pos token.Pos // 位置
TypeCast token.Token // 默认类型强制转型, I32/U32/I64/U64/F32/F64/NONE
LitKind token.Token // INT/FLOAT/CHAR/STRING, 默认类型 INT=>I64, FLOAT=>F64, CHAR => I32
LitString string // 原始的字符串: 42, 0x7f, 3.14, 1e-9, 'a', '\x7f', "foo" or `\m\n\o`
ConstV interface{} // 解析后的常量值, 对应的类型: int64, float64, string
}
// 全局常量

View File

@@ -242,111 +242,6 @@ func (p *parser) parseInt32Lit() int32 {
return int32(n)
}
func (p *parser) parseUint32Lit() uint32 {
pos, lit := p.pos, p.lit
if p.tok == token.CHAR {
p.acceptToken(token.CHAR)
return uint32(lit[1]) // '?'
}
p.acceptToken(token.INT)
if len(lit) > 2 && lit[0] == '0' && (lit[1] == 'x' || lit[1] == 'X') {
n, err := strconv.ParseUint(lit[2:], 16, 32)
if err != nil {
p.errorf(pos, "expect int32, got %q", lit)
}
return uint32(n)
}
// 需要支持 u32 和 -1 两种格式
n, err := strconv.ParseUint(lit, 10, 32)
if err != nil {
if n, errx := strconv.ParseUint(lit, 10, 32); errx == nil {
return uint32(n)
} else {
p.errorf(pos, "expect int32, got %q, err = %v", lit, err)
}
}
return uint32(n)
}
func (p *parser) parseInt64Lit() int64 {
pos, lit := p.pos, p.lit
p.acceptToken(token.INT)
if len(lit) > 2 && lit[0] == '0' && (lit[1] == 'x' || lit[1] == 'X') {
n, err := strconv.ParseInt(lit[2:], 16, 64)
if err != nil {
p.errorf(pos, "expect int64, got %q", lit)
}
return int64(n)
}
n, err := strconv.ParseInt(lit, 10, 64)
if err != nil {
p.errorf(pos, "expect int64, got %q", lit)
}
return int64(uint64(n))
}
func (p *parser) parseUint64Lit() uint64 {
pos, lit := p.pos, p.lit
p.acceptToken(token.INT)
if len(lit) > 2 && lit[0] == '0' && (lit[1] == 'x' || lit[1] == 'X') {
n, err := strconv.ParseUint(lit[2:], 16, 64)
if err != nil {
p.errorf(pos, "expect int64, got %q", lit)
}
return uint64(n)
}
n, err := strconv.ParseUint(lit, 10, 64)
if err != nil {
p.errorf(pos, "expect int64, got %q", lit)
}
return uint64(n)
}
// 解析浮点数常量面值
func (p *parser) parseFloat32Lit() float32 {
pos, lit := p.pos, p.lit
p.acceptToken(token.FLOAT, token.INT)
n, err := strconv.ParseFloat(lit, 32)
if err != nil {
p.errorf(pos, "expect float32, got %q", lit)
}
return float32(n)
}
func (p *parser) parseFloat64Lit() float64 {
pos, lit := p.pos, p.lit
p.acceptToken(token.FLOAT, token.INT)
n, err := strconv.ParseFloat(lit, 64)
if err != nil {
p.errorf(pos, "expect float64, got %q", lit)
}
return n
}
// 解析字符常量面值(含二进制数据)
func (p *parser) parseCharLit() string {
s := p.lit
p.acceptToken(token.CHAR)
return s
}
// 解析字符串常量面值(含二进制数据)
func (p *parser) parseStringLit() string {
s := p.lit
p.acceptToken(token.STRING)
return s
}
// 解析寄存器
func (p *parser) parseRegister() abi.RegType {
if !p.tok.IsRegister() {

View File

@@ -0,0 +1,87 @@
// Copyright (C) 2025 武汉凹语言科技有限公司
// SPDX-License-Identifier: AGPL-3.0-or-later
package parser
import (
"fmt"
"math/big"
"strconv"
"wa-lang.org/wa/internal/native/ast"
"wa-lang.org/wa/internal/native/token"
)
// 解析值
func (p *parser) parseBasicLit() *ast.BasicLit {
pVal := &ast.BasicLit{Pos: p.pos}
// 带类型的常量
// const $D = i64('D') # i64
// 常量 $甲 = 整64A # i64
switch p.tok {
case token.I32, token.I32_zh,
token.I64, token.I64_zh,
token.U32, token.U32_zh,
token.U64, token.U64_zh,
token.F32, token.F32_zh,
token.F64, token.F64_zh,
token.PTR, token.PTR_zh:
pVal.TypeCast = p.tok
p.acceptToken(token.LPAREN)
defer p.acceptToken(token.RPAREN)
}
// 默认类型
switch p.tok {
case token.CHAR, token.INT, token.FLOAT:
pVal.LitKind = p.tok
if pVal.TypeCast == token.NONE {
pVal.TypeCast = p.tok.DefaultNumberType()
}
pVal.LitString = p.lit
return pVal
case token.STRING:
pVal.LitKind = p.tok
pVal.LitString = p.lit
return pVal
default:
p.errorf(p.pos, "expect type or lit, got %v", p.tok)
}
// 解析常量的值
switch pVal.LitKind {
case token.INT:
if x, err := strconv.ParseInt(pVal.LitString, 0, 64); err == nil {
pVal.ConstV = int64(x)
}
case token.FLOAT:
if f, ok := new(big.Float).SetString(pVal.LitString); ok {
if f64V, acc := f.Float64(); acc != big.Exact {
pVal.ConstV = float64(f64V)
} else {
p.errorf(pVal.Pos, "float %v %v", pVal.LitString, acc)
}
} else {
p.errorf(pVal.Pos, "expect float, got %v", pVal.LitString)
}
case token.CHAR:
if n := len(pVal.LitString); n >= 2 {
if code, _, _, err := strconv.UnquoteChar(pVal.LitString[1:n-1], '\''); err == nil {
pVal.ConstV = int64(code)
}
}
case token.STRING:
if s, err := strconv.Unquote(pVal.LitString); err == nil {
pVal.ConstV = s
}
default:
panic(fmt.Sprintf("%v is not a valid token", pVal.LitKind))
}
return pVal
}

View File

@@ -20,7 +20,7 @@ func (p *parser) parseConst() *ast.Const {
p.acceptTokenAorB(token.CONST, token.CONST_zh)
pConst.Name = p.parseIdent()
p.acceptToken(token.ASSIGN)
pConst.Value = p.parseLitValue()
pConst.Value = p.parseBasicLit()
pConst.Comment = p.parseTailComment(pConst.Pos)
p.consumeSemicolonList()

View File

@@ -77,7 +77,7 @@ func (p *parser) parseGlobal() *ast.Global {
if p.tok == token.IDENT {
initV.Symbal = p.parseIdent()
} else {
initV.Lit = p.parseLitValue()
initV.Lit = p.parseBasicLit()
}
initV.Comment = p.parseTailComment(initV.Pos)
g.Init = []ast.InitValue{initV}
@@ -109,7 +109,7 @@ Loop:
if p.tok == token.IDENT {
initV.Symbal = p.parseIdent()
} else {
initV.Lit = p.parseLitValue()
initV.Lit = p.parseBasicLit()
}
initV.Comment = p.parseTailComment(initV.Pos)
g.Init = append(g.Init, initV)

View File

@@ -1,50 +0,0 @@
// Copyright (C) 2025 武汉凹语言科技有限公司
// SPDX-License-Identifier: AGPL-3.0-or-later
package parser
import (
"wa-lang.org/wa/internal/native/ast"
"wa-lang.org/wa/internal/native/token"
)
// 解析值
func (p *parser) parseLitValue() *ast.BasicLit {
pVal := &ast.BasicLit{Pos: p.pos}
// 带类型的常量
// const $D = i64('D') # i64
// 常量 $甲 = 整64A # i64
switch p.tok {
case token.I32, token.I32_zh,
token.I64, token.I64_zh,
token.U32, token.U32_zh,
token.U64, token.U64_zh,
token.F32, token.F32_zh,
token.F64, token.F64_zh,
token.PTR, token.PTR_zh:
pVal.TypeCast = p.tok
p.acceptToken(token.LPAREN)
defer p.acceptToken(token.RPAREN)
}
// 默认类型
switch p.tok {
case token.CHAR, token.INT, token.FLOAT:
pVal.Kind = p.tok
if pVal.TypeCast == token.NONE {
pVal.TypeCast = p.tok.DefaultNumberType()
}
pVal.Value = p.lit
return pVal
case token.STRING:
pVal.Kind = p.tok
pVal.Value = p.lit
return pVal
default:
p.errorf(p.pos, "expect type or lit, got %v", p.tok)
}
return pVal
}

View File

@@ -13,7 +13,7 @@ import (
func (p *wsPrinter) printConsts() error {
for _, x := range p.f.Consts {
fmt.Fprintf(p.w, "const %s = %v\n", x.Name, x.Value.Value)
fmt.Fprintf(p.w, "const %s = %v\n", x.Name, x.Value.LitString)
}
return nil
}

View File

@@ -24,10 +24,10 @@ func (p *wsPrinter) printGlobals() error {
case len(g.Init) == 1 && g.Init[0].Offset == 0:
xInit := g.Init[0]
if xInit.Lit != nil {
if xInit.Lit.Kind.DefaultNumberType() != xInit.Lit.TypeCast {
fmt.Fprintf(p.w, "global %s:%d = %v(%s)\n", g.Name, g.Size, xInit.Lit.TypeCast, xInit.Lit.Value)
if xInit.Lit.LitKind.DefaultNumberType() != xInit.Lit.TypeCast {
fmt.Fprintf(p.w, "global %s:%d = %v(%s)\n", g.Name, g.Size, xInit.Lit.TypeCast, xInit.Lit.LitString)
} else {
fmt.Fprintf(p.w, "global %s:%d = %s\n", g.Name, g.Size, xInit.Lit.Value)
fmt.Fprintf(p.w, "global %s:%d = %s\n", g.Name, g.Size, xInit.Lit.LitString)
}
} else {
fmt.Fprintf(p.w, "global %s:%d = %s\n", g.Name, g.Size, xInit.Symbal)
@@ -37,10 +37,10 @@ func (p *wsPrinter) printGlobals() error {
fmt.Fprintf(p.w, "global %s:%d = {\n", g.Name, g.Size)
for _, xInit := range g.Init {
if xInit.Lit != nil {
if xInit.Lit.Kind.DefaultNumberType() != xInit.Lit.TypeCast {
fmt.Fprintf(p.w, "\t%d: %v(%s),\n", xInit.Offset, xInit.Lit.TypeCast, xInit.Lit.Value)
if xInit.Lit.LitKind.DefaultNumberType() != xInit.Lit.TypeCast {
fmt.Fprintf(p.w, "\t%d: %v(%s),\n", xInit.Offset, xInit.Lit.TypeCast, xInit.Lit.LitString)
} else {
fmt.Fprintf(p.w, "\t%d: %s,\n", xInit.Offset, xInit.Lit.Value)
fmt.Fprintf(p.w, "\t%d: %s,\n", xInit.Offset, xInit.Lit.LitString)
}
} else {
fmt.Fprintf(p.w, "\t%d: %s,\n", xInit.Offset, xInit.Symbal)