Skip to content

Commit

Permalink
Merge pull request #46 from moeshin/fix-constant-value
Browse files Browse the repository at this point in the history
Fix constant value
  • Loading branch information
gzuidhof authored Oct 14, 2023
2 parents 342962e + 5f49821 commit 1e537aa
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 27 deletions.
4 changes: 2 additions & 2 deletions examples/abstract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export const FourString: string = "four";
export const AlsoFourString: string = "four";
export const Five = 5;
export const FiveAgain = 5;
export const Sixteen = 16;
export const Seventeen = 17;
export const Sixteen = 10 + 6;
export const Seventeen = 11 + 6;

//////////
// source: misc.go
Expand Down
2 changes: 1 addition & 1 deletion tygo/iota.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
var iotaRegexp = regexp.MustCompile(`\biota\b`)

func isProbablyIotaType(valueString string) bool {
return !strings.ContainsAny(valueString, "\"'`") && iotaRegexp.MatchString(valueString)
return !strings.ContainsAny(valueString, "\"`") && iotaRegexp.MatchString(valueString)
}

func replaceIotaValue(valueString string, iotaValue int) string {
Expand Down
121 changes: 100 additions & 21 deletions tygo/write.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,36 @@
package tygo

import (
"encoding/json"
"fmt"
"go/ast"
"go/token"
"regexp"
"strconv"
"strings"

"github.com/fatih/structtag"
)

var validJSNameRegexp = regexp.MustCompile(`(?m)^[\pL_][\pL\pN_]*$`)
var backquoteEscapeRegexp = regexp.MustCompile(`([$\\])`)
var octalPrefixRegexp = regexp.MustCompile(`^0[0-7]`)
var unicode8Regexp = regexp.MustCompile(`\\\\|\\U[\da-fA-F]{8}`)

// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence#table
var jsNumberOperatorPrecedence = map[token.Token]int{
token.MUL: 6,
token.QUO: 6,
token.REM: 6,
token.ADD: 5,
token.SUB: 5,
token.SHL: 4,
token.SHR: 4,
token.AND: 3,
token.AND_NOT: 3,
token.OR: 2,
token.XOR: 1,
}

func validJSName(n string) bool {
return validJSNameRegexp.MatchString(n)
Expand Down Expand Up @@ -39,15 +58,17 @@ func (g *PackageGenerator) writeIndent(s *strings.Builder, depth int) {
func (g *PackageGenerator) writeType(
s *strings.Builder,
t ast.Expr,
p ast.Expr,
depth int,
optionalParens bool,
) {
// log.Println("writeType:", reflect.TypeOf(t), t)
switch t := t.(type) {
case *ast.StarExpr:
if optionalParens {
s.WriteByte('(')
}
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
s.WriteString(" | undefined")
if optionalParens {
s.WriteByte(')')
Expand All @@ -57,7 +78,7 @@ func (g *PackageGenerator) writeType(
s.WriteString("string")
break
}
g.writeType(s, t.Elt, depth, true)
g.writeType(s, t.Elt, t, depth, true)
s.WriteString("[]")
case *ast.StructType:
s.WriteString("{\n")
Expand All @@ -84,25 +105,83 @@ func (g *PackageGenerator) writeType(
}
case *ast.MapType:
s.WriteString("{ [key: ")
g.writeType(s, t.Key, depth, false)
g.writeType(s, t.Key, t, depth, false)
s.WriteString("]: ")
g.writeType(s, t.Value, depth, false)
g.writeType(s, t.Value, t, depth, false)
s.WriteByte('}')
case *ast.BasicLit:
if strings.HasPrefix(t.Value, "`") {
t.Value = backquoteEscapeRegexp.ReplaceAllString(t.Value, `\$1`)
switch t.Kind {
case token.INT:
if octalPrefixRegexp.MatchString(t.Value) {
t.Value = "0o" + t.Value[1:]
}
case token.CHAR:
var char rune
if strings.HasPrefix(t.Value, `'\x`) ||
strings.HasPrefix(t.Value, `'\u`) ||
strings.HasPrefix(t.Value, `'\U`) {
i32, err := strconv.ParseInt(t.Value[3:len(t.Value)-1], 16, 32)
if err != nil {
panic(err)
}
char = rune(i32)
} else {
var data []byte
data = append(data, '"')
data = append(data, []byte(t.Value[1:len(t.Value)-1])...)
data = append(data, '"')
var s string
err := json.Unmarshal(data, &s)
if err != nil {
panic(err)
}
char = []rune(s)[0]
}
if char > 0xFFFF {
t.Value = fmt.Sprintf("0x%08X /* %s */", char, t.Value)
} else {
t.Value = fmt.Sprintf("0x%04X /* %s */", char, t.Value)
}
case token.STRING:
if strings.HasPrefix(t.Value, "`") {
t.Value = backquoteEscapeRegexp.ReplaceAllString(t.Value, `\$1`)
} else {
t.Value = unicode8Regexp.ReplaceAllStringFunc(t.Value, func(s string) string {
if len(s) == 10 {
s = fmt.Sprintf("\\u{%s}", strings.ToUpper(s[2:]))
}
return s
})
}
}
s.WriteString(t.Value)
case *ast.ParenExpr:
s.WriteByte('(')
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
s.WriteByte(')')
case *ast.BinaryExpr:
g.writeType(s, t.X, depth, false)
s.WriteByte(' ')
s.WriteString(t.Op.String())
inParen := false
switch p := p.(type) {
case *ast.BinaryExpr:
if jsNumberOperatorPrecedence[t.Op] < jsNumberOperatorPrecedence[p.Op] {
inParen = true
}
}
if inParen {
s.WriteByte('(')
}
g.writeType(s, t.X, t, depth, false)
s.WriteByte(' ')
g.writeType(s, t.Y, depth, false)
if t.Op == token.AND_NOT {
s.WriteString("& ~")
} else {
s.WriteString(t.Op.String())
s.WriteByte(' ')
}
g.writeType(s, t.Y, t, depth, false)
if inParen {
s.WriteByte(')')
}
case *ast.InterfaceType:
g.writeInterfaceFields(s, t.Methods.List, depth+1)
case *ast.CallExpr, *ast.FuncType, *ast.ChanType:
Expand All @@ -112,32 +191,32 @@ func (g *PackageGenerator) writeType(
case token.TILDE:
// We just ignore the tilde token, in Typescript extended types are
// put into the generic typing itself, which we can't support yet.
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
case token.XOR:
s.WriteString("~")
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
case token.ADD, token.SUB, token.NOT:
s.WriteString(t.Op.String())
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
default:
err := fmt.Errorf("unhandled unary expr: %v\n %T", t, t)
fmt.Println(err)
panic(err)
}
case *ast.IndexListExpr:
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
s.WriteByte('<')
for i, index := range t.Indices {
g.writeType(s, index, depth, false)
g.writeType(s, index, t, depth, false)
if i != len(t.Indices)-1 {
s.WriteString(", ")
}
}
s.WriteByte('>')
case *ast.IndexExpr:
g.writeType(s, t.X, depth, false)
g.writeType(s, t.X, t, depth, false)
s.WriteByte('<')
g.writeType(s, t.Index, depth, false)
g.writeType(s, t.Index, t, depth, false)
s.WriteByte('>')
default:
err := fmt.Errorf("unhandled: %s\n %T", t, t)
Expand All @@ -152,7 +231,7 @@ func (g *PackageGenerator) writeTypeParamsFields(s *strings.Builder, fields []*a
for j, ident := range f.Names {
s.WriteString(ident.Name)
s.WriteString(" extends ")
g.writeType(s, f.Type, 0, true)
g.writeType(s, f.Type, nil, 0, true)

if i != len(fields)-1 || j != len(f.Names)-1 {
s.WriteString(", ")
Expand Down Expand Up @@ -192,7 +271,7 @@ func (g *PackageGenerator) writeInterfaceFields(
g.writeCommentGroupIfNotNil(s, f.Doc, depth+1)
}
g.writeIndent(s, depth+1)
g.writeType(s, f.Type, depth, false)
g.writeType(s, f.Type, nil, depth, false)

if f.Comment != nil && g.PreserveTypeComments() {
s.WriteString(" // ")
Expand Down Expand Up @@ -301,7 +380,7 @@ func (g *PackageGenerator) writeStructFields(s *strings.Builder, fields []*ast.F
s.WriteString(": ")

if tstype == "" {
g.writeType(s, f.Type, depth, false)
g.writeType(s, f.Type, nil, depth, false)
} else {
s.WriteString(tstype)
}
Expand Down
7 changes: 4 additions & 3 deletions tygo/write_toplevel.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (g *PackageGenerator) writeTypeSpec(
s.WriteString("export type ")
s.WriteString(ts.Name.Name)
s.WriteString(" = ")
g.writeType(s, ts.Type, 0, true)
g.writeType(s, ts.Type, nil, 0, true)
s.WriteString(";")

}
Expand Down Expand Up @@ -185,7 +185,7 @@ func (g *PackageGenerator) writeValueSpec(
s.WriteString(": ")

tempSB := &strings.Builder{}
g.writeType(tempSB, vs.Type, 0, true)
g.writeType(tempSB, vs.Type, nil, 0, true)
typeString := tempSB.String()

s.WriteString(typeString)
Expand All @@ -200,7 +200,8 @@ func (g *PackageGenerator) writeValueSpec(
if hasExplicitValue {
val := vs.Values[i]
tempSB := &strings.Builder{}
g.writeType(tempSB, val, 0, true)
// log.Println("const:", name.Name, reflect.TypeOf(val), val)
g.writeType(tempSB, val, nil, 0, false)
group.groupValue = tempSB.String()
}

Expand Down

0 comments on commit 1e537aa

Please sign in to comment.