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
import (
"bignum";
"go/token";
)
/*
......@@ -36,6 +37,8 @@ type Type interface {
Zero() Value;
// String returns the string representation of this type.
String() string;
// The position where this type was defined, if any.
Pos() token.Position;
}
type BoundedType interface {
......@@ -125,7 +128,13 @@ type FuncValue interface {
* Scopes
*/
// A definition can be a *Variable, *Constant, or Type.
type Def interface {
Pos() token.Position;
}
type Variable struct {
token.Position;
// Index of this variable in the Frame structure
Index int;
// Static type of this variable
......@@ -133,13 +142,11 @@ type Variable struct {
}
type Constant struct {
token.Position;
Type Type;
Value Value;
}
// A definition can be a *Variable, *Constant, or Type.
type Def interface {}
type Scope struct
// A block represents a definition block in which a name may not be
......@@ -177,10 +184,10 @@ type Scope struct {
func (b *block) enterChild() *block
func (b *block) exit()
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) DefineConst(name string, t Type, v Value) *Constant
func (b *block) DefineType(name string, t Type) Type
func (b *block) DefineConst(name string, pos token.Position, t Type, v Value) *Constant
func (b *block) DefineType(name string, pos token.Position, t Type) Type
func (b *block) Lookup(name string) (level int, def Def)
// The universal scope
......
......@@ -7,6 +7,7 @@ package eval
import (
"eval";
"fmt";
"go/token";
"log";
)
......@@ -47,15 +48,14 @@ func (b *block) ChildScope() *Scope {
return sub.scope;
}
func (b *block) DefineVar(name string, t Type) *Variable {
if _, ok := b.defs[name]; ok {
return nil;
func (b *block) DefineVar(name string, pos token.Position, t Type) (*Variable, Def) {
if prev, ok := b.defs[name]; ok {
return nil, prev;
}
v := b.DefineSlot(t);
if v != nil {
b.defs[name] = v;
}
return v;
v.Position = pos;
b.defs[name] = v;
return v, nil;
}
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");
}
index := b.offset+b.numVars;
v := &Variable{index, t};
v := &Variable{token.Position{}, index, t};
b.numVars++;
if index+1 > b.scope.maxVars {
b.scope.maxVars = index+1;
......@@ -71,22 +71,22 @@ func (b *block) DefineSlot(t Type) *Variable {
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 {
return nil;
}
c := &Constant{t, v};
c := &Constant{pos, t, v};
b.defs[name] = 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 {
return nil;
}
// We take the representative type of t because multiple
// levels of naming are useless.
nt := &NamedType{name, t.rep()};
nt := &NamedType{pos, name, t.rep()};
b.defs[name] = nt;
return nt;
}
......
......@@ -218,6 +218,35 @@ func (f *flowBuf) gotosObeyScopes(a *compiler) bool {
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
*/
......@@ -227,7 +256,59 @@ func (a *stmtCompiler) DoBadStmt(s *ast.BadStmt) {
}
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) {
......@@ -241,7 +322,7 @@ func (a *stmtCompiler) DoLabeledStmt(s *ast.LabeledStmt) {
l, ok := a.labels[s.Label.Value];
if ok {
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;
}
} else {
......@@ -341,26 +422,25 @@ func (a *stmtCompiler) DoIncDecStmt(s *ast.IncDecStmt) {
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;
// Compile right side first so we have the types when
// compiling the left side and so we don't see definitions
// made on the left side.
rs := make([]*exprCompiler, len(s.Rhs));
for i, re := range s.Rhs {
rs := make([]*exprCompiler, len(rhs));
for i, re := range rhs {
rs[i] = a.compileExpr(a.block, re, false);
if rs[i] == nil {
bad = true;
continue;
}
}
errOp := "assignment";
if s.Tok == token.DEFINE {
errOp = "definition";
if tok == token.DEFINE || tok == token.VAR {
errOp = "declaration";
}
ac, ok := a.checkAssign(s.Pos(), rs, "assignment", "value");
ac, ok := a.checkAssign(a.pos, rs, errOp, "value");
if !ok {
bad = true;
}
......@@ -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
// able to produce the usual error message because we can't
// 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");
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
ls := make([]*exprCompiler, len(s.Lhs));
ls := make([]*exprCompiler, len(lhs));
nDefs := 0;
for i, le := range s.Lhs {
if s.Tok == token.DEFINE {
for i, le := range lhs {
// 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
ident, ok := le.(*ast.Ident);
ident, ok = le.(*ast.Ident);
if !ok {
a.diagAt(le, "left side of := must be a name");
bad = true;
......@@ -390,15 +483,27 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Is this simply an assignment?
if _, ok := a.block.defs[ident.Value]; ok {
goto assignment;
ident = nil;
break;
}
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
// type. We use the computed MultiType so we
// don't have to worry about unpacking.
var lt Type;
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):
// Define a placeholder. We already
// gave the "not enough" error above.
......@@ -428,20 +533,17 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
default:
lt = ac.rmt.Elems[i];
}
}
// Define identifier
v := a.block.DefineVar(ident.Value, lt);
if v == nil {
log.Crashf("Failed to define %s", ident.Value);
// If it's a definition, define the identifier
if ident != nil {
if a.defineVar(ident, lt) == nil {
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);
if ls[i] == nil {
bad = true;
......@@ -459,7 +561,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// provided they were originally declared in the same block
// with the same type, and at least one of the variables is
// new.
if s.Tok == token.DEFINE && nDefs == 0 {
if tok == token.DEFINE && nDefs == 0 {
a.diag("at least one new variable must be declared");
return;
}
......@@ -470,7 +572,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Create assigner
var lt Type;
n := len(s.Lhs);
n := len(lhs);
if n == 1 {
lt = ls[0].t;
} else {
......@@ -492,7 +594,7 @@ func (a *stmtCompiler) doAssign(s *ast.AssignStmt) {
// Don't need temporaries and can avoid []Value.
lf := ls[0].evalAddr;
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
lfs := make([]func(*Frame) Value, n);
for i, l := range ls {
......@@ -587,7 +689,7 @@ func (a *stmtCompiler) doAssignOp(s *ast.AssignStmt) {
func (a *stmtCompiler) DoAssignStmt(s *ast.AssignStmt) {
switch s.Tok {
case token.ASSIGN, token.DEFINE:
a.doAssign(s);
a.doAssign(s.Lhs, s.Rhs, s.Tok, nil);
default:
a.doAssignOp(s);
......@@ -949,14 +1051,14 @@ func (a *compiler) compileFunc(b *block, decl *FuncDecl, body *ast.BlockStmt) (f
defer bodyScope.exit();
for i, t := range decl.Type.In {
if decl.InNames[i] != nil {
bodyScope.DefineVar(decl.InNames[i].Value, t);
bodyScope.DefineVar(decl.InNames[i].Value, decl.InNames[i].Pos(), t);
} else {
bodyScope.DefineSlot(t);
}
}
for i, t := range decl.Type.Out {
if decl.OutNames[i] != nil {
bodyScope.DefineVar(decl.OutNames[i].Value, t);
bodyScope.DefineVar(decl.OutNames[i].Value, decl.OutNames[i].Pos(), t);
} else {
bodyScope.DefineSlot(t);
}
......
......@@ -8,6 +8,7 @@ import (
"bignum";
"eval";
"go/ast";
"go/token";
"log";
"reflect";
"unsafe"; // For Sizeof
......@@ -26,9 +27,7 @@ import (
// sense in the comparison operators section. The compatibility and
// assignment compatibility sections should be rolled into one.
// XXX(Spec) Comparison compatibility: "Values of any type may be
// compared to other values of compatible static type." That should
// be *identical* type.
var universePos = token.Position{"<universe>", 0, 0, 0};
/*
* Type array maps. These are used to memoize composite types.
......@@ -114,6 +113,10 @@ func (commonType) isIdeal() bool {
return false;
}
func (commonType) Pos() token.Position {
return token.Position{};
}
/*
* Bool
*/
......@@ -122,7 +125,7 @@ type boolType struct {
commonType;
}
var BoolType = universe.DefineType("bool", &boolType{});
var BoolType = universe.DefineType("bool", universePos, &boolType{});
func (t *boolType) literal() Type {
return t;
......@@ -160,13 +163,13 @@ type uintType struct {
}
var (
Uint8Type = universe.DefineType("uint8", &uintType{commonType{}, 8, false, "uint8"});
Uint16Type = universe.DefineType("uint16", &uintType{commonType{}, 16, false, "uint16"});
Uint32Type = universe.DefineType("uint32", &uintType{commonType{}, 32, false, "uint32"});
Uint64Type = universe.DefineType("uint64", &uintType{commonType{}, 64, false, "uint64"});
Uint8Type = universe.DefineType("uint8", universePos, &uintType{commonType{}, 8, false, "uint8"});
Uint16Type = universe.DefineType("uint16", universePos, &uintType{commonType{}, 16, false, "uint16"});
Uint32Type = universe.DefineType("uint32", universePos, &uintType{commonType{}, 32, false, "uint32"});
Uint64Type = universe.DefineType("uint64", universePos, &uintType{commonType{}, 64, false, "uint64"});
UintType = universe.DefineType("uint", &uintType{commonType{}, 0, false, "uint"});
UintptrType = universe.DefineType("uintptr", &uintType{commonType{}, 0, true, "uintptr"});
UintType = universe.DefineType("uint", universePos, &uintType{commonType{}, 0, false, "uint"});
UintptrType = universe.DefineType("uintptr", universePos, &uintType{commonType{}, 0, true, "uintptr"});
)
func init() {
......@@ -230,12 +233,12 @@ type intType struct {
}
var (
Int8Type = universe.DefineType("int8", &intType{commonType{}, 8, "int8"});
Int16Type = universe.DefineType("int16", &intType{commonType{}, 16, "int16"});
Int32Type = universe.DefineType("int32", &intType{commonType{}, 32, "int32"});
Int64Type = universe.DefineType("int64", &intType{commonType{}, 64, "int64"});
Int8Type = universe.DefineType("int8", universePos, &intType{commonType{}, 8, "int8"});
Int16Type = universe.DefineType("int16", universePos, &intType{commonType{}, 16, "int16"});
Int32Type = universe.DefineType("int32", universePos, &intType{commonType{}, 32, "int32"});
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 {
......@@ -318,9 +321,9 @@ type floatType struct {
}
var (
Float32Type = universe.DefineType("float32", &floatType{commonType{}, 32, "float32"});
Float64Type = universe.DefineType("float64", &floatType{commonType{}, 64, "float64"});
FloatType = universe.DefineType("float", &floatType{commonType{}, 0, "float"});
Float32Type = universe.DefineType("float32", universePos, &floatType{commonType{}, 32, "float32"});
Float64Type = universe.DefineType("float64", universePos, &floatType{commonType{}, 64, "float64"});
FloatType = universe.DefineType("float", universePos, &floatType{commonType{}, 0, "float"});
)
func (t *floatType) literal() Type {
......@@ -416,7 +419,7 @@ type stringType struct {
commonType;
}
var StringType = universe.DefineType("string", &stringType{});
var StringType = universe.DefineType("string", universePos, &stringType{});
func (t *stringType) literal() Type {
return t;
......@@ -672,6 +675,7 @@ type ChanType struct {
*/
type NamedType struct {
token.Position;
name string;
// Underlying type
def Type;
......
......@@ -578,7 +578,7 @@ func init() {
s := universe;
true := boolV(true);
s.DefineConst("true", BoolType, &true);
s.DefineConst("true", universePos, BoolType, &true);
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