Skip to content

Refactorings from the original generics branch #1291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,6 @@ func init() {
}
}

type ErrorList []error

func (err ErrorList) Error() string {
if len(err) == 0 {
return "<no errors>"
}
return fmt.Sprintf("%s (and %d more errors)", err[0].Error(), len(err[1:]))
}

func (err ErrorList) Normalize() error {
if len(err) == 0 {
return nil
}
return err
}

// Archive contains intermediate build outputs of a single package.
//
// This is a logical equivalent of an object file in traditional compilers.
Expand Down
68 changes: 68 additions & 0 deletions compiler/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package compiler

import (
"errors"
"fmt"
)

// ErrTooManyErrors is added to the ErrorList by the Trim method.
var ErrTooManyErrors = errors.New("too many errors")

// ErrorList wraps multiple errors as a single error.
type ErrorList []error

func (errs ErrorList) Error() string {
if len(errs) == 0 {
return "<no errors>"
}
return fmt.Sprintf("%s (and %d more errors)", errs[0].Error(), len(errs[1:]))
}

// ErrOrNil returns nil if ErrorList is empty, or the error otherwise.
func (errs ErrorList) ErrOrNil() error {
if len(errs) == 0 {
return nil
}
return errs
}

// Append an error to the list.
//
// If err is an instance of ErrorList, the lists are concatenated together,
// otherwise err is appended at the end of the list. If err is nil, the list is
// returned unmodified.
//
// err := DoStuff()
// errList := errList.Append(err)
func (errs ErrorList) Append(err error) ErrorList {
if err == nil {
return errs
}
if err, ok := err.(ErrorList); ok {
return append(errs, err...)
}
return append(errs, err)
}

// AppendDistinct is similar to Append, but doesn't append the error if it has
// the same message as the last error on the list.
func (errs ErrorList) AppendDistinct(err error) ErrorList {
if l := len(errs); l > 0 {
if prev := errs[l-1]; prev != nil && err.Error() == prev.Error() {
return errs // The new error is the same as the last one, skip it.
}
}

return errs.Append(err)
}

// Trim the error list if it has more than limit errors. If the list is trimmed,
// all extraneous errors are replaced with a single ErrTooManyErrors, making the
// returned ErrorList length of limit+1.
func (errs ErrorList) Trim(limit int) ErrorList {
if len(errs) <= limit {
return errs
}

return append(errs[:limit], ErrTooManyErrors)
}
43 changes: 21 additions & 22 deletions compiler/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,14 +398,14 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
if isUnsigned(basic) {
shift = ">>>"
}
return fc.formatExpr(`(%1s = %2e / %3e, (%1s === %1s && %1s !== 1/0 && %1s !== -1/0) ? %1s %4s 0 : $throwRuntimeError("integer divide by zero"))`, fc.newVariable("_q"), e.X, e.Y, shift)
return fc.formatExpr(`(%1s = %2e / %3e, (%1s === %1s && %1s !== 1/0 && %1s !== -1/0) ? %1s %4s 0 : $throwRuntimeError("integer divide by zero"))`, fc.newLocalVariable("_q"), e.X, e.Y, shift)
}
if basic.Kind() == types.Float32 {
return fc.fixNumber(fc.formatExpr("%e / %e", e.X, e.Y), basic)
}
return fc.formatExpr("%e / %e", e.X, e.Y)
case token.REM:
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newVariable("_r"), e.X, e.Y)
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newLocalVariable("_r"), e.X, e.Y)
case token.SHL, token.SHR:
op := e.Op.String()
if e.Op == token.SHR && isUnsigned(basic) {
Expand All @@ -421,7 +421,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
if e.Op == token.SHR && !isUnsigned(basic) {
return fc.fixNumber(fc.formatParenExpr("%e >> $min(%f, 31)", e.X, e.Y), basic)
}
y := fc.newVariable("y")
y := fc.newLocalVariable("y")
return fc.fixNumber(fc.formatExpr("(%s = %f, %s < 32 ? (%e %s %s) : 0)", y, e.Y, y, e.X, op, y), basic)
case token.AND, token.OR:
if isUnsigned(basic) {
Expand All @@ -444,7 +444,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
if fc.Blocking[e.Y] {
skipCase := fc.caseCounter
fc.caseCounter++
resultVar := fc.newVariable("_v")
resultVar := fc.newLocalVariable("_v")
fc.Printf("if (!(%s)) { %s = false; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
return fc.formatExpr("%s", resultVar)
Expand All @@ -454,7 +454,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
if fc.Blocking[e.Y] {
skipCase := fc.caseCounter
fc.caseCounter++
resultVar := fc.newVariable("_v")
resultVar := fc.newLocalVariable("_v")
fc.Printf("if (%s) { %s = true; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
return fc.formatExpr("%s", resultVar)
Expand Down Expand Up @@ -513,15 +513,15 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
if _, isTuple := exprType.(*types.Tuple); isTuple {
return fc.formatExpr(
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? [%1s.v, true] : [%4e, false])`,
fc.newVariable("_entry"),
fc.newLocalVariable("_entry"),
e.X,
key,
fc.zeroValue(t.Elem()),
)
}
return fc.formatExpr(
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? %1s.v : %4e)`,
fc.newVariable("_entry"),
fc.newLocalVariable("_entry"),
e.X,
key,
fc.zeroValue(t.Elem()),
Expand Down Expand Up @@ -689,13 +689,13 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
case "Call":
if id, ok := fc.identifierConstant(e.Args[0]); ok {
if e.Ellipsis.IsValid() {
objVar := fc.newVariable("obj")
objVar := fc.newLocalVariable("obj")
return fc.formatExpr("(%s = %s, %s.%s.apply(%s, %s))", objVar, recv, objVar, id, objVar, externalizeExpr(e.Args[1]))
}
return fc.formatExpr("%s(%s)", globalRef(id), externalizeArgs(e.Args[1:]))
}
if e.Ellipsis.IsValid() {
objVar := fc.newVariable("obj")
objVar := fc.newLocalVariable("obj")
return fc.formatExpr("(%s = %s, %s[$externalize(%e, $String)].apply(%s, %s))", objVar, recv, objVar, e.Args[0], objVar, externalizeExpr(e.Args[1]))
}
return fc.formatExpr("%s[$externalize(%e, $String)](%s)", recv, e.Args[0], externalizeArgs(e.Args[1:]))
Expand Down Expand Up @@ -842,7 +842,7 @@ func (fc *funcContext) translateCall(e *ast.CallExpr, sig *types.Signature, fun
fc.caseCounter++
returnVar := "$r"
if sig.Results().Len() != 0 {
returnVar = fc.newVariable("_r")
returnVar = fc.newLocalVariable("_r")
}
fc.Printf("%[1]s = %[2]s(%[3]s); /* */ $s = %[4]d; case %[4]d: if($c) { $c = false; %[1]s = %[1]s.$blk(); } if (%[1]s && %[1]s.$blk !== undefined) { break s; }", returnVar, fun, strings.Join(args, ", "), resumeCase)
if sig.Results().Len() != 0 {
Expand Down Expand Up @@ -873,9 +873,8 @@ func (fc *funcContext) delegatedCall(expr *ast.CallExpr) (callable *expression,
case *ast.SelectorExpr:
isJs = typesutil.IsJsPackage(fc.pkgCtx.Uses[fun.Sel].Pkg())
}
sig := fc.typeOf(expr.Fun).Underlying().(*types.Signature)
sigTypes := signatureTypes{Sig: sig}
args := fc.translateArgs(sig, expr.Args, expr.Ellipsis.IsValid())
sig := typesutil.Signature{Sig: fc.typeOf(expr.Fun).Underlying().(*types.Signature)}
args := fc.translateArgs(sig.Sig, expr.Args, expr.Ellipsis.IsValid())

if !isBuiltin && !isJs {
// Normal function calls don't require wrappers.
Expand All @@ -892,12 +891,12 @@ func (fc *funcContext) delegatedCall(expr *ast.CallExpr) (callable *expression,
ellipsis := expr.Ellipsis

for i := range expr.Args {
v := fc.newVariable("_arg")
v := fc.newLocalVariable("_arg")
vars[i] = v
// Subtle: the proxy lambda argument needs to be assigned with the type
// that the original function expects, and not with the argument
// expression result type, or we may do implicit type conversion twice.
callArgs[i] = fc.newIdent(v, sigTypes.Param(i, ellipsis.IsValid()))
callArgs[i] = fc.newIdent(v, sig.Param(i, ellipsis.IsValid()))
}
wrapper := &ast.CallExpr{
Fun: expr.Fun,
Expand Down Expand Up @@ -1173,8 +1172,8 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
}
if ptr, isPtr := fc.typeOf(expr).(*types.Pointer); fc.pkgCtx.Pkg.Path() == "syscall" && isPtr {
if s, isStruct := ptr.Elem().Underlying().(*types.Struct); isStruct {
array := fc.newVariable("_array")
target := fc.newVariable("_struct")
array := fc.newLocalVariable("_array")
target := fc.newLocalVariable("_struct")
fc.Printf("%s = new Uint8Array(%d);", array, sizes32.Sizeof(s))
fc.Delayed(func() {
fc.Printf("%s = %s, %s;", target, fc.translateExpr(expr), fc.loadStruct(array, target, s))
Expand Down Expand Up @@ -1222,8 +1221,8 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
// struct pointer when handling syscalls.
// TODO(nevkontakte): Add a runtime assertion that the unsafe.Pointer is
// indeed pointing at a byte array.
array := fc.newVariable("_array")
target := fc.newVariable("_struct")
array := fc.newLocalVariable("_array")
target := fc.newLocalVariable("_struct")
return fc.formatExpr("(%s = %e, %s = %e, %s, %s)", array, expr, target, fc.zeroValue(t.Elem()), fc.loadStruct(array, target, ptrElType), target)
}
// Convert between structs of different types but identical layouts,
Expand All @@ -1245,7 +1244,7 @@ func (fc *funcContext) translateConversion(expr ast.Expr, desiredType types.Type
// type iPtr *int; var c int = 42; println((iPtr)(&c));
// TODO(nevkontakte): Are there any other cases that fall into this case?
exprTypeElem := exprType.Underlying().(*types.Pointer).Elem()
ptrVar := fc.newVariable("_ptr")
ptrVar := fc.newLocalVariable("_ptr")
getterConv := fc.translateConversion(fc.setType(&ast.StarExpr{X: fc.newIdent(ptrVar, exprType)}, exprTypeElem), t.Elem())
setterConv := fc.translateConversion(fc.newIdent("$v", t.Elem()), exprTypeElem)
return fc.formatExpr("(%1s = %2e, new %3s(function() { return %4s; }, function($v) { %1s.$set(%5s); }, %1s.$target))", ptrVar, expr, fc.typeName(desiredType), getterConv, setterConv)
Expand Down Expand Up @@ -1312,7 +1311,7 @@ func (fc *funcContext) translateConversionToSlice(expr ast.Expr, desiredType typ
}

func (fc *funcContext) loadStruct(array, target string, s *types.Struct) string {
view := fc.newVariable("_view")
view := fc.newLocalVariable("_view")
code := fmt.Sprintf("%s = new DataView(%s.buffer, %s.byteOffset)", view, array, array)
var fields []*types.Var
var collectFields func(s *types.Struct, path string)
Expand Down Expand Up @@ -1442,7 +1441,7 @@ func (fc *funcContext) formatExprInternal(format string, a []interface{}, parens
out.WriteByte('(')
parens = false
}
v := fc.newVariable("x")
v := fc.newLocalVariable("x")
out.WriteString(v + " = " + fc.translateExpr(e.(ast.Expr)).String() + ", ")
vars[i] = v
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/linkname.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func parseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]Go
}
}

return directives, errs.Normalize()
return directives, errs.ErrOrNil()
}

// goLinknameSet is a utility that enables quick lookup of whether a decl is
Expand Down
Loading
Loading