Commit d11173d4 authored by Austin Clements's avatar Austin Clements

Implement var declarations. Variables, constants, and types now carry

the position where they were defined so I can produce good
error messages on redefinitions.

R=rsc
APPROVED=rsc
DELTA=204  (126 added, 13 deleted, 65 changed)
OCL=32599
CL=32605
parent 9f2f8ead
...@@ -6,6 +6,7 @@ package eval ...@@ -6,6 +6,7 @@ package eval
import ( import (
"bignum"; "bignum";
"go/token";
) )
/* /*
...@@ -36,6 +37,8 @@ type Type interface { ...@@ -36,6 +37,8 @@ type Type interface {
Zero() Value; Zero() Value;
// String returns the string representation of this type. // String returns the string representation of this type.
String() string; String() string;
// The position where this type was defined, if any.
Pos() token.Position;
} }
type BoundedType interface { type BoundedType interface {
...@@ -125,7 +128,13 @@ type FuncValue interface { ...@@ -125,7 +128,13 @@ type FuncValue interface {
* Scopes * Scopes
*/ */
// A definition can be a *Variable, *Constant, or Type.
type Def interface {
Pos() token.Position;
}
type Variable struct { type Variable struct {
token.Position;
// Index of this variable in the Frame structure // Index of this variable in the Frame structure
Index int; Index int;
// Static type of this variable // Static type of this variable
...@@ -133,13 +142,11 @@ type Variable struct { ...@@ -133,13 +142,11 @@ type Variable struct {
} }
type Constant struct { type Constant struct {
token.Position;
Type Type; Type Type;
Value Value; Value Value;
} }
// A definition can be a *Variable, *Constant, or Type.
type Def interface {}
type Scope struct type Scope struct
// A block represents a definition block in which a name may not be // A block represents a definition block in which a name may not be
...@@ -177,10 +184,10 @@ type Scope struct { ...@@ -177,10 +184,10 @@ type Scope struct {
func (b *block) enterChild() *block func (b *block) enterChild() *block
func (b *block) exit() func (b *block) exit()
func (b *block) ChildScope() *Scope func (b *block) ChildScope() *Scope
func (b *block) DefineVar(name string, t Type) *Variable func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def)
func (b *block) DefineSlot(t Type) *Variable func (b *block) DefineSlot(t Type) *Variable
func (b *block) DefineConst(name string, t Type, v Value) *Constant func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) *Constant
func (b *block) DefineType(name string, t Type) Type func (b *block) DefineType(name string, pos token.Position, t Type) Type
func (b *block) Lookup(name string) (level int, def Def) func (b *block) Lookup(name string) (level int, def Def)
// The universal scope // The universal scope
......
...@@ -7,6 +7,7 @@ package eval ...@@ -7,6 +7,7 @@ package eval
import ( import (
"eval"; "eval";
"fmt"; "fmt";
"go/token";
"log"; "log";
) )
...@@ -47,15 +48,14 @@ func (b *block) ChildScope() *Scope { ...@@ -47,15 +48,14 @@ func (b *block) ChildScope() *Scope {
return sub.scope; return sub.scope;
} }
func (b *block) DefineVar(name string, t Type) *Variable { func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def) {
if _, ok := b.defs[name]; ok { if prev, ok := b.defs[name]; ok {
return nil; return nil, prev;
} }
v := b.DefineSlot(t); v := b.DefineSlot(t);
if v != nil { v.Position = pos;
b.defs[name] = v; b.defs[name] = v;
} return v, nil;
return v;
} }
func (b *block) DefineSlot(t Type) *Variable { func (b *block) DefineSlot(t Type) *Variable {
...@@ -63,7 +63,7 @@ func (b *block) DefineSlot(t Type) *Variable { ...@@ -63,7 +63,7 @@ func (b *block) DefineSlot(t Type) *Variable {
log.Crash("Failed to exit child block before defining variable"); log.Crash("Failed to exit child block before defining variable");
} }
index := b.offset+b.numVars; index := b.offset+b.numVars;
v := &Variable{index, t}; v := &Variable{token.Position{}, index, t};
b.numVars++; b.numVars++;
if index+1 > b.scope.maxVars { if index+1 > b.scope.maxVars {
b.scope.maxVars = index+1; b.scope.maxVars = index+1;
...@@ -71,22 +71,22 @@ func (b *block) DefineSlot(t Type) *Variable { ...@@ -71,22 +71,22 @@ func (b *block) DefineSlot(t Type) *Variable {
return v; return v;
} }
func (b *block) DefineConst(name string, t Type, v Value) *Constant { func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) *Constant {
if _, ok := b.defs[name]; ok { if _, ok := b.defs[name]; ok {
return nil; return nil;
} }
c := &Constant{t, v}; c := &Constant{pos, t, v};
b.defs[name] = c; b.defs[name] = c;
return c; return c;
} }
func (b *block) DefineType(name string, t Type) Type { func (b *block) DefineType(name string, pos token.Position, t Type) Type {
if _, ok := b.defs[name]; ok { if _, ok := b.defs[name]; ok {
return nil; return nil;
} }
// We take the representative type of t because multiple // We take the representative type of t because multiple
// levels of naming are useless. // levels of naming are useless.
nt := &NamedType{name, t.rep()}; nt := &NamedType{pos, name, t.rep()};
b.defs[name] = nt; b.defs[name] = nt;
return nt; return nt;
} }
......
...@@ -218,6 +218,35 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) bool { ...@@ -218,6 +218,35 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) bool {
return true; return true;
} }
/*
* Statement generation helpers
*/
func (a *stmtCompiler) defineVar(ident *ast.Ident, t Type) *Variable {
v, prev := a.block.DefineVar(ident.Value, ident.Pos(), t);
if prev != nil {
// TODO(austin) It's silly that we have to capture
// Pos() in a variable.
pos := prev.Pos();
if pos.IsValid() {
a.diagAt(ident, "variable %s redeclared in this block\n\tprevious declaration at %s", ident.Value, &pos);
} else {
a.diagAt(ident, "variable %s redeclared in this block", ident.Value);
}
return nil;
}
// Initialize the variable
index := v.Index;
a.push(func(v *vm) {
v.f.Vars[index] = t.Zero();
});
return v;
}
// TODO(austin) Move the real definition
func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr)
/* /*
* Statement visitors * Statement visitors
*/ */
...@@ -227,7 +256,59 @@ func (a *stmtCompiler) DoBadStmt(s *ast.BadStmt) { ...@@ -227,7 +256,59 @@ func (a *stmtCompiler) DoBadStmt(s *ast.BadStmt) {
} }
func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) { func (a *stmtCompiler) DoDeclStmt(s *ast.DeclStmt) {
log.Crash("Not implemented"); switch decl := s.Decl.(type) {
case *ast.BadDecl:
// Do nothing. Already reported by parser.
return;
case *ast.FuncDecl:
log.Crash("FuncDecl at statement level");
case *ast.GenDecl:
switch decl.Tok {
case token.IMPORT:
log.Crash("import at statement level");
case token.CONST, token.TYPE:
log.Crashf("%v not implemented", decl.Tok);
case token.VAR:
ok := true;
for _, spec := range decl.Specs {
spec := spec.(*ast.ValueSpec);
if spec.Values == nil {
// Declaration without assignment
var t Type;
if spec.Type == nil {
// Parser should have caught
log.Crash("Type and Values nil");
}
t = a.compileType(a.block, spec.Type);
if t == nil {
// Define placeholders
ok = false;
}
for _, n := range spec.Names {
if a.defineVar(n, t) == nil {
ok = false;
}
}
} else {
// Decalaration with assignment
lhs := make([]ast.Expr, len(spec.Names));
for i, n := range spec.Names {
lhs[i] = n;
}
a.doAssign(lhs, spec.Values, decl.Tok, spec.Type);
}
}
if ok {
a.err = false;
}
}
default:
log.Crashf("Unexpected Decl type %T", s.Decl);
}
} }
func (a *stmtCompiler) DoEmptyStmt(s *ast.EmptyStmt) { func (a *stmtCompiler) DoEmptyStmt(s *ast.EmptyStmt) {
...@@ -241,7 +322,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) { ...@@ -241,7 +322,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
l, ok := a.labels[s.Label.Value]; l, ok := a.labels[s.Label.Value];
if ok { if ok {
if l.resolved.IsValid() { if l.resolved.IsValid() {
a.diag("label %s redefined; previous definition at line %d", s.Label.Value, l.resolved.Line); a.diag("label %s redeclared in this block\n\tprevious declaration at %s", s.Label.Value, &l.resolved);
bad = true; bad = true;
} }
} else { } else {
...@@ -341,26 +422,25 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) { ...@@ -341,26 +422,25 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
a.err = false; a.err = false;
} }
func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { func (a *stmtCompiler) doAssign(lhs []ast.Expr, rhs []ast.Expr, tok token.Token, declTypeExpr ast.Expr) {
bad := false; bad := false;
// Compile right side first so we have the types when // Compile right side first so we have the types when
// compiling the left side and so we don't see definitions // compiling the left side and so we don't see definitions
// made on the left side. // made on the left side.
rs := make([]*exprCompiler, len(s.Rhs)); rs := make([]*exprCompiler, len(rhs));
for i, re := range s.Rhs { for i, re := range rhs {
rs[i] = a.compileExpr(a.block, re, false); rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil { if rs[i] == nil {
bad = true; bad = true;
continue;
} }
} }
errOp := "assignment"; errOp := "assignment";
if s.Tok == token.DEFINE { if tok == token.DEFINE || tok == token.VAR {
errOp = "definition"; errOp = "declaration";
} }
ac, ok := a.checkAssign(s.Pos(), rs, "assignment", "value"); ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
if !ok { if !ok {
bad = true; bad = true;
} }
...@@ -368,18 +448,31 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -368,18 +448,31 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// If this is a definition and the LHS is too big, we won't be // If this is a definition and the LHS is too big, we won't be
// able to produce the usual error message because we can't // able to produce the usual error message because we can't
// begin to infer the types of the LHS. // begin to infer the types of the LHS.
if s.Tok == token.DEFINE && len(s.Lhs) > len(ac.rmt.Elems) { if (tok == token.DEFINE || tok == token.VAR) && len(lhs) > len(ac.rmt.Elems) {
a.diag("not enough values for definition"); a.diag("not enough values for definition");
bad = true; bad = true;
} }
// Compile left type if there is one
var declType Type;
if declTypeExpr != nil {
declType = a.compileType(a.block, declTypeExpr);
if declType == nil {
bad = true;
}
}
// Compile left side // Compile left side
ls := make([]*exprCompiler, len(s.Lhs)); ls := make([]*exprCompiler, len(lhs));
nDefs := 0; nDefs := 0;
for i, le := range s.Lhs { for i, le := range lhs {
if s.Tok == token.DEFINE { // If this is a definition, get the identifier and its type
var ident *ast.Ident;
var lt Type;
switch tok {
case token.DEFINE:
// Check that it's an identifier // Check that it's an identifier
ident, ok := le.(*ast.Ident); ident, ok = le.(*ast.Ident);
if !ok { if !ok {
a.diagAt(le, "left side of := must be a name"); a.diagAt(le, "left side of := must be a name");
bad = true; bad = true;
...@@ -390,15 +483,27 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -390,15 +483,27 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Is this simply an assignment? // Is this simply an assignment?
if _, ok := a.block.defs[ident.Value]; ok { if _, ok := a.block.defs[ident.Value]; ok {
goto assignment; ident = nil;
break;
} }
nDefs++; nDefs++;
case token.VAR:
ident = le.(*ast.Ident);
}
// If it's a definition, get or infer its type.
if ident != nil {
// Compute the identifier's type from the RHS // Compute the identifier's type from the RHS
// type. We use the computed MultiType so we // type. We use the computed MultiType so we
// don't have to worry about unpacking. // don't have to worry about unpacking.
var lt Type;
switch { switch {
case declTypeExpr != nil:
// We have a declaration type, use it.
// If declType is nil, we gave an
// error when we compiled it.
lt = declType;
case i >= len(ac.rmt.Elems): case i >= len(ac.rmt.Elems):
// Define a placeholder. We already // Define a placeholder. We already
// gave the "not enough" error above. // gave the "not enough" error above.
...@@ -428,20 +533,17 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -428,20 +533,17 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
default: default:
lt = ac.rmt.Elems[i]; lt = ac.rmt.Elems[i];
} }
}
// Define identifier // If it's a definition, define the identifier
v := a.block.DefineVar(ident.Value, lt); if ident != nil {
if v == nil { if a.defineVar(ident, lt) == nil {
log.Crashf("Failed to define %s", ident.Value); bad = true;
continue;
} }
// Initialize the variable
index := v.Index;
a.push(func(v *vm) {
v.f.Vars[index] = lt.Zero();
});
} }
assignment: // Compile LHS
ls[i] = a.compileExpr(a.block, le, false); ls[i] = a.compileExpr(a.block, le, false);
if ls[i] == nil { if ls[i] == nil {
bad = true; bad = true;
...@@ -459,7 +561,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -459,7 +561,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// provided they were originally declared in the same block // provided they were originally declared in the same block
// with the same type, and at least one of the variables is // with the same type, and at least one of the variables is
// new. // new.
if s.Tok == token.DEFINE && nDefs == 0 { if tok == token.DEFINE && nDefs == 0 {
a.diag("at least one new variable must be declared"); a.diag("at least one new variable must be declared");
return; return;
} }
...@@ -470,7 +572,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -470,7 +572,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Create assigner // Create assigner
var lt Type; var lt Type;
n := len(s.Lhs); n := len(lhs);
if n == 1 { if n == 1 {
lt = ls[0].t; lt = ls[0].t;
} else { } else {
...@@ -492,7 +594,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) { ...@@ -492,7 +594,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Don't need temporaries and can avoid []Value. // Don't need temporaries and can avoid []Value.
lf := ls[0].evalAddr; lf := ls[0].evalAddr;
a.push(func(v *vm) { assign(lf(v.f), v.f) }); a.push(func(v *vm) { assign(lf(v.f), v.f) });
} else if s.Tok == token.DEFINE && nDefs == n { } else if tok == token.VAR || (tok == token.DEFINE && nDefs == n) {
// Don't need temporaries // Don't need temporaries
lfs := make([]func(*Frame) Value, n); lfs := make([]func(*Frame) Value, n);
for i, l := range ls { for i, l := range ls {
...@@ -587,7 +689,7 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) { ...@@ -587,7 +689,7 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
func (a *stmtCompiler) DoAssignStmt(s *ast.AssignStmt) { func (a *stmtCompiler) DoAssignStmt(s *ast.AssignStmt) {
switch s.Tok { switch s.Tok {
case token.ASSIGN, token.DEFINE: case token.ASSIGN, token.DEFINE:
a.doAssign(s); a.doAssign(s.Lhs, s.Rhs, s.Tok, nil);
default: default:
a.doAssignOp(s); a.doAssignOp(s);
...@@ -949,14 +1051,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f ...@@ -949,14 +1051,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
defer bodyScope.exit(); defer bodyScope.exit();
for i, t := range decl.Type.In { for i, t := range decl.Type.In {
if decl.InNames[i] != nil { if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, t); bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t);
} else { } else {
bodyScope.DefineSlot(t); bodyScope.DefineSlot(t);
} }
} }
for i, t := range decl.Type.Out { for i, t := range decl.Type.Out {
if decl.OutNames[i] != nil { if decl.OutNames[i] != nil {
bodyScope.DefineVar(decl.OutNames[i].Value, t); bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t);
} else { } else {
bodyScope.DefineSlot(t); bodyScope.DefineSlot(t);
} }
......
...@@ -8,6 +8,7 @@ import ( ...@@ -8,6 +8,7 @@ import (
"bignum"; "bignum";
"eval"; "eval";
"go/ast"; "go/ast";
"go/token";
"log"; "log";
"reflect"; "reflect";
"unsafe"; // For Sizeof "unsafe"; // For Sizeof
...@@ -26,9 +27,7 @@ import ( ...@@ -26,9 +27,7 @@ import (
// sense in the comparison operators section. The compatibility and // sense in the comparison operators section. The compatibility and
// assignment compatibility sections should be rolled into one. // assignment compatibility sections should be rolled into one.
// XXX(Spec) Comparison compatibility: "Values of any type may be var universePos = token.Position{"<universe>", 0, 0, 0};
// compared to other values of compatible static type." That should
// be *identical* type.
/* /*
* Type array maps. These are used to memoize composite types. * Type array maps. These are used to memoize composite types.
...@@ -114,6 +113,10 @@ func (commonType) isIdeal() bool { ...@@ -114,6 +113,10 @@ func (commonType) isIdeal() bool {
return false; return false;
} }
func (commonType) Pos() token.Position {
return token.Position{};
}
/* /*
* Bool * Bool
*/ */
...@@ -122,7 +125,7 @@ type boolType struct { ...@@ -122,7 +125,7 @@ type boolType struct {
commonType; commonType;
} }
var BoolType = universe.DefineType("bool", &boolType{}); var BoolType = universe.DefineType("bool", universePos, &boolType{});
func (t *boolType) literal() Type { func (t *boolType) literal() Type {
return t; return t;
...@@ -160,13 +163,13 @@ type uintType struct { ...@@ -160,13 +163,13 @@ type uintType struct {
} }
var ( var (
Uint8Type = universe.DefineType("uint8", &uintType{commonType{}, 8, false, "uint8"}); Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"});
Uint16Type = universe.DefineType("uint16", &uintType{commonType{}, 16, false, "uint16"}); Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"});
Uint32Type = universe.DefineType("uint32", &uintType{commonType{}, 32, false, "uint32"}); Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"});
Uint64Type = universe.DefineType("uint64", &uintType{commonType{}, 64, false, "uint64"}); Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"});
UintType = universe.DefineType("uint", &uintType{commonType{}, 0, false, "uint"}); UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"});
UintptrType = universe.DefineType("uintptr", &uintType{commonType{}, 0, true, "uintptr"}); UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"});
) )
func init() { func init() {
...@@ -230,12 +233,12 @@ type intType struct { ...@@ -230,12 +233,12 @@ type intType struct {
} }
var ( var (
Int8Type = universe.DefineType("int8", &intType{commonType{}, 8, "int8"}); Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"});
Int16Type = universe.DefineType("int16", &intType{commonType{}, 16, "int16"}); Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"});
Int32Type = universe.DefineType("int32", &intType{commonType{}, 32, "int32"}); Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"});
Int64Type = universe.DefineType("int64", &intType{commonType{}, 64, "int64"}); Int64Type = universe.DefineType("int64", universePos, &intType{commonType{}, 64, "int64"});
IntType = universe.DefineType("int", &intType{commonType{}, 0, "int"}); IntType = universe.DefineType("int", universePos, &intType{commonType{}, 0, "int"});
) )
func (t *intType) literal() Type { func (t *intType) literal() Type {
...@@ -318,9 +321,9 @@ type floatType struct { ...@@ -318,9 +321,9 @@ type floatType struct {
} }
var ( var (
Float32Type = universe.DefineType("float32", &floatType{commonType{}, 32, "float32"}); Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"});
Float64Type = universe.DefineType("float64", &floatType{commonType{}, 64, "float64"}); Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"});
FloatType = universe.DefineType("float", &floatType{commonType{}, 0, "float"}); FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
) )
func (t *floatType) literal() Type { func (t *floatType) literal() Type {
...@@ -416,7 +419,7 @@ type stringType struct { ...@@ -416,7 +419,7 @@ type stringType struct {
commonType; commonType;
} }
var StringType = universe.DefineType("string", &stringType{}); var StringType = universe.DefineType("string", universePos, &stringType{});
func (t *stringType) literal() Type { func (t *stringType) literal() Type {
return t; return t;
...@@ -672,6 +675,7 @@ type ChanType struct { ...@@ -672,6 +675,7 @@ type ChanType struct {
*/ */
type NamedType struct { type NamedType struct {
token.Position;
name string; name string;
// Underlying type // Underlying type
def Type; def Type;
......
...@@ -578,7 +578,7 @@ func init() { ...@@ -578,7 +578,7 @@ func init() {
s := universe; s := universe;
true := boolV(true); true := boolV(true);
s.DefineConst("true", BoolType, &true); s.DefineConst("true", universePos, BoolType, &true);
false := boolV(false); false := boolV(false);
s.DefineConst("false", BoolType, &false); s.DefineConst("false", universePos, BoolType, &false);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment