Skip to content

Commit b5eb7ec

Browse files
authored
Merge pull request #1291 from nevkontakte/gng4
Refactorings from the original generics branch
2 parents c0be063 + b0663d9 commit b5eb7ec

File tree

10 files changed

+614
-256
lines changed

10 files changed

+614
-256
lines changed

compiler/compiler.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,6 @@ func init() {
3333
}
3434
}
3535

36-
type ErrorList []error
37-
38-
func (err ErrorList) Error() string {
39-
if len(err) == 0 {
40-
return "<no errors>"
41-
}
42-
return fmt.Sprintf("%s (and %d more errors)", err[0].Error(), len(err[1:]))
43-
}
44-
45-
func (err ErrorList) Normalize() error {
46-
if len(err) == 0 {
47-
return nil
48-
}
49-
return err
50-
}
51-
5236
// Archive contains intermediate build outputs of a single package.
5337
//
5438
// This is a logical equivalent of an object file in traditional compilers.

compiler/errors.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package compiler
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
)
7+
8+
// ErrTooManyErrors is added to the ErrorList by the Trim method.
9+
var ErrTooManyErrors = errors.New("too many errors")
10+
11+
// ErrorList wraps multiple errors as a single error.
12+
type ErrorList []error
13+
14+
func (errs ErrorList) Error() string {
15+
if len(errs) == 0 {
16+
return "<no errors>"
17+
}
18+
return fmt.Sprintf("%s (and %d more errors)", errs[0].Error(), len(errs[1:]))
19+
}
20+
21+
// ErrOrNil returns nil if ErrorList is empty, or the error otherwise.
22+
func (errs ErrorList) ErrOrNil() error {
23+
if len(errs) == 0 {
24+
return nil
25+
}
26+
return errs
27+
}
28+
29+
// Append an error to the list.
30+
//
31+
// If err is an instance of ErrorList, the lists are concatenated together,
32+
// otherwise err is appended at the end of the list. If err is nil, the list is
33+
// returned unmodified.
34+
//
35+
// err := DoStuff()
36+
// errList := errList.Append(err)
37+
func (errs ErrorList) Append(err error) ErrorList {
38+
if err == nil {
39+
return errs
40+
}
41+
if err, ok := err.(ErrorList); ok {
42+
return append(errs, err...)
43+
}
44+
return append(errs, err)
45+
}
46+
47+
// AppendDistinct is similar to Append, but doesn't append the error if it has
48+
// the same message as the last error on the list.
49+
func (errs ErrorList) AppendDistinct(err error) ErrorList {
50+
if l := len(errs); l > 0 {
51+
if prev := errs[l-1]; prev != nil && err.Error() == prev.Error() {
52+
return errs // The new error is the same as the last one, skip it.
53+
}
54+
}
55+
56+
return errs.Append(err)
57+
}
58+
59+
// Trim the error list if it has more than limit errors. If the list is trimmed,
60+
// all extraneous errors are replaced with a single ErrTooManyErrors, making the
61+
// returned ErrorList length of limit+1.
62+
func (errs ErrorList) Trim(limit int) ErrorList {
63+
if len(errs) <= limit {
64+
return errs
65+
}
66+
67+
return append(errs[:limit], ErrTooManyErrors)
68+
}

compiler/expressions.go

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -398,14 +398,14 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
398398
if isUnsigned(basic) {
399399
shift = ">>>"
400400
}
401-
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)
401+
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)
402402
}
403403
if basic.Kind() == types.Float32 {
404404
return fc.fixNumber(fc.formatExpr("%e / %e", e.X, e.Y), basic)
405405
}
406406
return fc.formatExpr("%e / %e", e.X, e.Y)
407407
case token.REM:
408-
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newVariable("_r"), e.X, e.Y)
408+
return fc.formatExpr(`(%1s = %2e %% %3e, %1s === %1s ? %1s : $throwRuntimeError("integer divide by zero"))`, fc.newLocalVariable("_r"), e.X, e.Y)
409409
case token.SHL, token.SHR:
410410
op := e.Op.String()
411411
if e.Op == token.SHR && isUnsigned(basic) {
@@ -421,7 +421,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
421421
if e.Op == token.SHR && !isUnsigned(basic) {
422422
return fc.fixNumber(fc.formatParenExpr("%e >> $min(%f, 31)", e.X, e.Y), basic)
423423
}
424-
y := fc.newVariable("y")
424+
y := fc.newLocalVariable("y")
425425
return fc.fixNumber(fc.formatExpr("(%s = %f, %s < 32 ? (%e %s %s) : 0)", y, e.Y, y, e.X, op, y), basic)
426426
case token.AND, token.OR:
427427
if isUnsigned(basic) {
@@ -444,7 +444,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
444444
if fc.Blocking[e.Y] {
445445
skipCase := fc.caseCounter
446446
fc.caseCounter++
447-
resultVar := fc.newVariable("_v")
447+
resultVar := fc.newLocalVariable("_v")
448448
fc.Printf("if (!(%s)) { %s = false; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
449449
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
450450
return fc.formatExpr("%s", resultVar)
@@ -454,7 +454,7 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
454454
if fc.Blocking[e.Y] {
455455
skipCase := fc.caseCounter
456456
fc.caseCounter++
457-
resultVar := fc.newVariable("_v")
457+
resultVar := fc.newLocalVariable("_v")
458458
fc.Printf("if (%s) { %s = true; $s = %d; continue s; }", fc.translateExpr(e.X), resultVar, skipCase)
459459
fc.Printf("%s = %s; case %d:", resultVar, fc.translateExpr(e.Y), skipCase)
460460
return fc.formatExpr("%s", resultVar)
@@ -513,15 +513,15 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
513513
if _, isTuple := exprType.(*types.Tuple); isTuple {
514514
return fc.formatExpr(
515515
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? [%1s.v, true] : [%4e, false])`,
516-
fc.newVariable("_entry"),
516+
fc.newLocalVariable("_entry"),
517517
e.X,
518518
key,
519519
fc.zeroValue(t.Elem()),
520520
)
521521
}
522522
return fc.formatExpr(
523523
`(%1s = $mapIndex(%2e,%3s), %1s !== undefined ? %1s.v : %4e)`,
524-
fc.newVariable("_entry"),
524+
fc.newLocalVariable("_entry"),
525525
e.X,
526526
key,
527527
fc.zeroValue(t.Elem()),
@@ -689,13 +689,13 @@ func (fc *funcContext) translateExpr(expr ast.Expr) *expression {
689689
case "Call":
690690
if id, ok := fc.identifierConstant(e.Args[0]); ok {
691691
if e.Ellipsis.IsValid() {
692-
objVar := fc.newVariable("obj")
692+
objVar := fc.newLocalVariable("obj")
693693
return fc.formatExpr("(%s = %s, %s.%s.apply(%s, %s))", objVar, recv, objVar, id, objVar, externalizeExpr(e.Args[1]))
694694
}
695695
return fc.formatExpr("%s(%s)", globalRef(id), externalizeArgs(e.Args[1:]))
696696
}
697697
if e.Ellipsis.IsValid() {
698-
objVar := fc.newVariable("obj")
698+
objVar := fc.newLocalVariable("obj")
699699
return fc.formatExpr("(%s = %s, %s[$externalize(%e, $String)].apply(%s, %s))", objVar, recv, objVar, e.Args[0], objVar, externalizeExpr(e.Args[1]))
700700
}
701701
return fc.formatExpr("%s[$externalize(%e, $String)](%s)", recv, e.Args[0], externalizeArgs(e.Args[1:]))
@@ -842,7 +842,7 @@ func (fc *funcContext) translateCall(e *ast.CallExpr, sig *types.Signature, fun
842842
fc.caseCounter++
843843
returnVar := "$r"
844844
if sig.Results().Len() != 0 {
845-
returnVar = fc.newVariable("_r")
845+
returnVar = fc.newLocalVariable("_r")
846846
}
847847
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)
848848
if sig.Results().Len() != 0 {
@@ -873,9 +873,8 @@ func (fc *funcContext) delegatedCall(expr *ast.CallExpr) (callable *expression,
873873
case *ast.SelectorExpr:
874874
isJs = typesutil.IsJsPackage(fc.pkgCtx.Uses[fun.Sel].Pkg())
875875
}
876-
sig := fc.typeOf(expr.Fun).Underlying().(*types.Signature)
877-
sigTypes := signatureTypes{Sig: sig}
878-
args := fc.translateArgs(sig, expr.Args, expr.Ellipsis.IsValid())
876+
sig := typesutil.Signature{Sig: fc.typeOf(expr.Fun).Underlying().(*types.Signature)}
877+
args := fc.translateArgs(sig.Sig, expr.Args, expr.Ellipsis.IsValid())
879878

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

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

13141313
func (fc *funcContext) loadStruct(array, target string, s *types.Struct) string {
1315-
view := fc.newVariable("_view")
1314+
view := fc.newLocalVariable("_view")
13161315
code := fmt.Sprintf("%s = new DataView(%s.buffer, %s.byteOffset)", view, array, array)
13171316
var fields []*types.Var
13181317
var collectFields func(s *types.Struct, path string)
@@ -1442,7 +1441,7 @@ func (fc *funcContext) formatExprInternal(format string, a []interface{}, parens
14421441
out.WriteByte('(')
14431442
parens = false
14441443
}
1445-
v := fc.newVariable("x")
1444+
v := fc.newLocalVariable("x")
14461445
out.WriteString(v + " = " + fc.translateExpr(e.(ast.Expr)).String() + ", ")
14471446
vars[i] = v
14481447
}

compiler/linkname.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func parseGoLinknames(fset *token.FileSet, pkgPath string, file *ast.File) ([]Go
112112
}
113113
}
114114

115-
return directives, errs.Normalize()
115+
return directives, errs.ErrOrNil()
116116
}
117117

118118
// goLinknameSet is a utility that enables quick lookup of whether a decl is

0 commit comments

Comments
 (0)