1
0
mirror of https://github.com/golang/go synced 2024-11-26 02:17:58 -07:00

Gather errors in a go.scanner.ErrorList instead of printing

them as we go.

Lots of bug fixes.  Let the parser toss illegal character and
string literals.  Compile unary + correctly.  Allow float OP
ideal.  Compile unary * correctly.  Implement min and max float
values.

R=rsc
APPROVED=rsc
DELTA=64  (29 added, 7 deleted, 28 changed)
OCL=31811
CL=31814
This commit is contained in:
Austin Clements 2009-07-17 16:58:59 -07:00
parent b63d40a53e
commit 51c0a84175
2 changed files with 55 additions and 33 deletions

View File

@ -7,9 +7,12 @@ package eval
import ( import (
"bignum"; "bignum";
"eval"; "eval";
"fmt";
"go/ast"; "go/ast";
"go/scanner";
"go/token"; "go/token";
"log"; "log";
"os";
"strconv"; "strconv";
"strings"; "strings";
) )
@ -19,7 +22,7 @@ import (
type exprContext struct { type exprContext struct {
scope *Scope; scope *Scope;
constant bool; constant bool;
// TODO(austin) Error list errors scanner.ErrorHandler;
} }
// An exprCompiler compiles a single node in an expression. It stores // An exprCompiler compiles a single node in an expression. It stores
@ -82,7 +85,7 @@ func (a *exprCompiler) fork(x ast.Expr) *exprCompiler {
} }
func (a *exprCompiler) diag(format string, args ...) { func (a *exprCompiler) diag(format string, args ...) {
diag(a.pos, format, args); a.errors.Error(a.pos, fmt.Sprintf(format, args));
} }
func (a *exprCompiler) diagOpType(op token.Token, vt Type) { func (a *exprCompiler) diagOpType(op token.Token, vt Type) {
@ -205,25 +208,22 @@ func (a *exprCompiler) DoIntLit(x *ast.IntLit) {
func (a *exprCompiler) DoCharLit(x *ast.CharLit) { func (a *exprCompiler) DoCharLit(x *ast.CharLit) {
if x.Value[0] != '\'' { if x.Value[0] != '\'' {
// Shouldn't get past the parser log.Crashf("malformed character literal %s at %v passed parser", x.Value, x.Pos());
log.Crashf("unexpected character literal %s at %v", x.Value, x.Pos());
} }
v, mb, tail, err := strconv.UnquoteChar(string(x.Value[1:len(x.Value)]), '\''); v, mb, tail, err := strconv.UnquoteChar(string(x.Value[1:len(x.Value)]), '\'');
if err != nil { if err != nil || tail != "'" {
a.diag("illegal character literal, %v", err); log.Crashf("malformed character literal %s at %v passed parser", x.Value, x.Pos());
return;
}
if tail != "'" {
a.diag("character literal must contain only one character");
return;
} }
a.doIdealInt(bignum.Int(int64(v))); a.doIdealInt(bignum.Int(int64(v)));
a.desc = "character literal"; a.desc = "character literal";
} }
func (a *exprCompiler) DoFloatLit(x *ast.FloatLit) { func (a *exprCompiler) DoFloatLit(x *ast.FloatLit) {
f, _, n := bignum.RatFromString(string(x.Value), 0);
if n != len(x.Value) {
log.Crashf("malformed float literal %s at %v passed parser", x.Value, x.Pos());
}
a.t = IdealFloatType; a.t = IdealFloatType;
f, _, _2 := bignum.RatFromString(string(x.Value), 0);
a.evalIdealFloat = func() *bignum.Rational { return f }; a.evalIdealFloat = func() *bignum.Rational { return f };
a.desc = "float literal"; a.desc = "float literal";
} }
@ -370,7 +370,7 @@ func (a *exprCompiler) DoUnaryExpr(x *ast.UnaryExpr) {
switch x.Op { switch x.Op {
case token.ADD: case token.ADD:
// Just compile it out // Just compile it out
a = v; *a = *v;
case token.SUB: case token.SUB:
a.genUnaryOpNeg(v); a.genUnaryOpNeg(v);
@ -492,9 +492,9 @@ func (a *exprCompiler) DoBinaryExpr(x *ast.BinaryExpr) {
// numeric type and the other operand is an ideal // numeric type and the other operand is an ideal
// number, the ideal number is converted to match the // number, the ideal number is converted to match the
// type of the other operand. // type of the other operand.
if l.t.isInteger() && !l.t.isIdeal() && r.t.isIdeal() { if (l.t.isInteger() || l.t.isFloat()) && !l.t.isIdeal() && r.t.isIdeal() {
r = r.convertTo(l.t); r = r.convertTo(l.t);
} else if r.t.isInteger() && !r.t.isIdeal() && l.t.isIdeal() { } else if (r.t.isInteger() || r.t.isFloat()) && !r.t.isIdeal() && l.t.isIdeal() {
l = l.convertTo(r.t); l = l.convertTo(r.t);
} }
if l == nil || r == nil { if l == nil || r == nil {
@ -782,8 +782,8 @@ func (a *exprCompiler) DoChanType(x *ast.ChanType) {
log.Crash("Not implemented"); log.Crash("Not implemented");
} }
func compileExpr(expr ast.Expr, scope *Scope) *exprCompiler { func compileExpr(expr ast.Expr, scope *Scope, errors scanner.ErrorHandler) *exprCompiler {
ec := newExprCompiler(&exprContext{scope, false}, expr.Pos()); ec := newExprCompiler(&exprContext{scope, false, errors}, expr.Pos());
expr.Visit(ec); expr.Visit(ec);
if ec.t == nil { if ec.t == nil {
return nil; return nil;
@ -803,34 +803,36 @@ func (expr *Expr) Eval(f *Frame) Value {
return expr.f(f); return expr.f(f);
} }
func CompileExpr(expr ast.Expr, scope *Scope) *Expr { func CompileExpr(expr ast.Expr, scope *Scope) (*Expr, os.Error) {
ec := compileExpr(expr, scope); errors := scanner.NewErrorVector();
ec := compileExpr(expr, scope, errors);
if ec == nil { if ec == nil {
return nil; return nil, errors.GetError(scanner.Sorted);
} }
// TODO(austin) This still uses Value as a generic container // TODO(austin) This still uses Value as a generic container
// and is the only user of the 'value' methods on each type. // and is the only user of the 'value' methods on each type.
// Need to figure out a better way to do this. // Need to figure out a better way to do this.
switch t := ec.t.(type) { switch t := ec.t.(type) {
case *boolType: case *boolType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalBool(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalBool(f)) }}, nil;
case *uintType: case *uintType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalUint(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalUint(f)) }}, nil;
case *intType: case *intType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalInt(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalInt(f)) }}, nil;
case *idealIntType: case *idealIntType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealInt()) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealInt()) }}, nil;
case *floatType: case *floatType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalFloat(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalFloat(f)) }}, nil;
case *idealFloatType: case *idealFloatType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealFloat()) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalIdealFloat()) }}, nil;
case *stringType: case *stringType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalString(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalString(f)) }}, nil;
case *PtrType: case *PtrType:
return &Expr{func(f *Frame) Value { return t.value(ec.evalPtr(f)) }}; return &Expr{func(f *Frame) Value { return t.value(ec.evalPtr(f)) }}, nil;
} }
log.Crashf("unexpected type %v", ec.t); log.Crashf("unexpected type %v", ec.t);
return nil; panic();
} }
/* /*
@ -859,7 +861,7 @@ func (a *exprCompiler) genIdentOp(t Type, s *Scope, index int) {
func (a *exprCompiler) genStarOp(v *exprCompiler) { func (a *exprCompiler) genStarOp(v *exprCompiler) {
vf := v.asPtr(); vf := v.asPtr();
switch _ := v.t.literal().(type) { switch _ := v.t.literal().(*PtrType).Elem().literal().(type) {
case *boolType: case *boolType:
a.evalBool = func(f *Frame) bool { return vf(f).(BoolValue).Get() }; a.evalBool = func(f *Frame) bool { return vf(f).(BoolValue).Get() };
case *uintType: case *uintType:
@ -873,7 +875,7 @@ func (a *exprCompiler) genStarOp(v *exprCompiler) {
case *PtrType: case *PtrType:
a.evalPtr = func(f *Frame) Value { return vf(f).(PtrValue).Get() }; a.evalPtr = func(f *Frame) Value { return vf(f).(PtrValue).Get() };
default: default:
log.Crashf("unexpected operand type %v at %v", v.t.literal(), a.pos); log.Crashf("unexpected operand type %v at %v", v.t.literal().(*PtrType).Elem().literal(), a.pos);
} }
} }

View File

@ -7,6 +7,7 @@ package eval
import ( import (
"bignum"; "bignum";
"eval"; "eval";
"log";
) )
@ -224,12 +225,31 @@ func (t *floatType) String() string {
func (t *floatType) value(v float64) FloatValue func (t *floatType) value(v float64) FloatValue
var maxFloat32Val = bignum.MakeRat(bignum.Int(0xffffff).Shl(127-23), bignum.Nat(1));
var maxFloat64Val = bignum.MakeRat(bignum.Int(0x1fffffffffffff).Shl(1023-52), bignum.Nat(1));
var minFloat32Val = maxFloat32Val.Neg();
var minFloat64Val = maxFloat64Val.Neg();
func (t *floatType) minVal() *bignum.Rational { func (t *floatType) minVal() *bignum.Rational {
panic("Not implemented"); switch t.Bits {
case 32:
return minFloat32Val;
case 64:
return minFloat64Val;
}
log.Crashf("unexpected number of floating point bits: %d", t.Bits);
panic();
} }
func (t *floatType) maxVal() *bignum.Rational { func (t *floatType) maxVal() *bignum.Rational {
panic("Not implemented"); switch t.Bits {
case 32:
return maxFloat32Val;
case 64:
return maxFloat64Val;
}
log.Crashf("unexpected number of floating point bits: %d", t.Bits);
panic();
} }
type idealFloatType struct { type idealFloatType struct {