Commit 687f387c authored by Robert Griesemer's avatar Robert Griesemer

- added more semantic checks - more to come

- distinguish float/int literals syntactically
- fixed a tracing bug

R=r
OCL=13906
CL=13906
parent 044a3b1a
...@@ -11,6 +11,61 @@ import Universe "universe" ...@@ -11,6 +11,61 @@ import Universe "universe"
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Expressions // Expressions
export type Literal struct {
typ_ *Globals.Type;
b bool;
i int;
f float;
s string;
}
func (x *Literal) typ() *Globals.Type {
return x.typ_;
}
export func NewLiteral(typ *Globals.Type) *Literal {
x := new(Literal);
x.typ_ = typ;
return x;
}
export var Bad, True, False, Nil *Literal;
// NOTE We could use Globals.Object directly if we'd added a typ()
// method to its interface. However, this would require renaming the
// typ field everywhere... - Need to think about accessors again.
export type Object struct {
obj *Globals.Object;
}
func (x *Object) typ() *Globals.Type {
return x.obj.typ;
}
export func NewObject(obj* Globals.Object) *Object {
x := new(Object);
x.obj = obj;
return x;
}
export type Selector struct {
typ_ *Globals.Type;
}
func (x *Selector) typ() *Globals.Type {
return x.typ_;
}
export type BinaryExpr struct { export type BinaryExpr struct {
typ_ *Globals.Type; typ_ *Globals.Type;
op int; op int;
...@@ -18,7 +73,6 @@ export type BinaryExpr struct { ...@@ -18,7 +73,6 @@ export type BinaryExpr struct {
} }
func (x *BinaryExpr) typ() *Globals.Type { func (x *BinaryExpr) typ() *Globals.Type {
return x.typ_; return x.typ_;
} }
...@@ -37,3 +91,14 @@ export type IfStat struct { ...@@ -37,3 +91,14 @@ export type IfStat struct {
then_ Globals.Stat; then_ Globals.Stat;
else_ Globals.Stat; else_ Globals.Stat;
} }
// ----------------------------------------------------------------------------
// Initialization
func init() {
Bad = NewLiteral(Universe.bad_t);
True = NewLiteral(Universe.bool_t); True.b = true;
False = NewLiteral(Universe.bool_t); False.b = false;
Nil = NewLiteral(Universe.nil_t);
}
...@@ -45,18 +45,6 @@ export type Package struct { ...@@ -45,18 +45,6 @@ export type Package struct {
} }
// TODO This is hideous! We need to have a decent way to do lists.
// Ideally open arrays that allow '+'.
type Elem struct {
next *Elem;
val int;
str string;
obj *Object;
typ *Type;
}
export type List struct { export type List struct {
len_ int; len_ int;
first, last *Elem; first, last *Elem;
...@@ -98,6 +86,19 @@ export type Stat interface { ...@@ -98,6 +86,19 @@ export type Stat interface {
} }
// TODO This is hideous! We need to have a decent way to do lists.
// Ideally open arrays that allow '+'.
type Elem struct {
next *Elem;
val int;
str string;
obj *Object;
typ *Type;
expr Expr
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Creation // Creation
...@@ -249,6 +250,11 @@ func (L *List) AddTyp(typ *Type) { ...@@ -249,6 +250,11 @@ func (L *List) AddTyp(typ *Type) {
} }
func (L *List) AddExpr(expr Expr) {
L.Add().expr = expr;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Scope methods // Scope methods
......
...@@ -47,14 +47,14 @@ func (P *Parser) Trace(msg string) { ...@@ -47,14 +47,14 @@ func (P *Parser) Trace(msg string) {
if P.verbose > 0 { if P.verbose > 0 {
P.PrintIndent(); P.PrintIndent();
print msg, " {\n"; print msg, " {\n";
P.indent++;
} }
P.indent++;
} }
func (P *Parser) Ecart() { func (P *Parser) Ecart() {
if P.verbose > 0 {
P.indent--; P.indent--;
if P.verbose > 0 {
P.PrintIndent(); P.PrintIndent();
print "}\n"; print "}\n";
} }
...@@ -132,6 +132,9 @@ func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) { ...@@ -132,6 +132,9 @@ func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
if !P.semantic_checks { if !P.semantic_checks {
return; return;
} }
if P.level > 0 {
panic "cannot declare objects in other packages";
}
obj.pnolev = P.level; obj.pnolev = P.level;
if scope.Lookup(obj.ident) != nil { if scope.Lookup(obj.ident) != nil {
P.Error(obj.pos, `"` + obj.ident + `" is declared already`); P.Error(obj.pos, `"` + obj.ident + `" is declared already`);
...@@ -200,26 +203,25 @@ func (P *Parser) DeclareFunc(ident string, typ *Globals.Type) *Globals.Object { ...@@ -200,26 +203,25 @@ func (P *Parser) DeclareFunc(ident string, typ *Globals.Type) *Globals.Object {
return obj; return obj;
} }
// obj != NULL: possibly a forward declaration. // obj != NULL: possibly a forward declaration
if obj.kind != Object.FUNC { if obj.kind != Object.FUNC {
P.Error(-1, `"` + ident + `" is declared already`); P.Error(-1, `"` + ident + `" is declared already`);
// Continue but do not insert this function into the scope. // continue but do not insert this function into the scope
obj = Globals.NewObject(-1, Object.FUNC, ident); obj = Globals.NewObject(-1, Object.FUNC, ident);
obj.typ = typ; obj.typ = typ;
// TODO do we need to set the primary type? probably... // TODO do we need to set the primary type? probably...
return obj; return obj;
} }
// We have a function with the same name. // we have a function with the same name
/* if !Type.Equal(typ, obj.typ) {
if !EqualTypes(type, obj->type()) { P.Error(-1, `type of "` + ident + `" does not match its forward declaration`);
this->Error("type of \"%s\" does not match its forward declaration", name.cstr()); // continue but do not insert this function into the scope
// Continue but do not insert this function into the scope. obj = Globals.NewObject(-1, Object.FUNC, ident);
NewObject(Object::FUNC, name); obj.typ = typ;
obj->set_type(type); // TODO do we need to set the primary type? probably...
return obj; return obj;
} }
*/
// We have a matching forward declaration. Use it. // We have a matching forward declaration. Use it.
return obj; return obj;
...@@ -826,12 +828,10 @@ func (P *Parser) ParseExpressionList() *Globals.List { ...@@ -826,12 +828,10 @@ func (P *Parser) ParseExpressionList() *Globals.List {
P.Trace("ExpressionList"); P.Trace("ExpressionList");
list := Globals.NewList(); list := Globals.NewList();
P.ParseExpression(); list.AddExpr(P.ParseExpression());
list.AddInt(0); // TODO fix this - add correct list element
for P.tok == Scanner.COMMA { for P.tok == Scanner.COMMA {
P.Next(); P.Next();
P.ParseExpression(); list.AddExpr(P.ParseExpression());
list.AddInt(0); // TODO fix this - add correct list element
} }
P.Ecart(); P.Ecart();
...@@ -867,23 +867,36 @@ func (P *Parser) ParseFunctionLit() Globals.Expr { ...@@ -867,23 +867,36 @@ func (P *Parser) ParseFunctionLit() Globals.Expr {
} }
func (P *Parser) ParseExpressionPair() { func (P *Parser) ParseSingleExpressionList(list *Globals.List) {
P.Trace("SingleExpressionList");
list.AddExpr(P.ParseExpression());
for P.tok == Scanner.COMMA {
P.Next();
list.AddExpr(P.ParseExpression());
}
P.Ecart();
}
func (P *Parser) ParseExpressionPair(list *Globals.List) {
P.Trace("ExpressionPair"); P.Trace("ExpressionPair");
P.ParseExpression(); list.AddExpr(P.ParseExpression());
P.Expect(Scanner.COLON); P.Expect(Scanner.COLON);
P.ParseExpression(); list.AddExpr(P.ParseExpression());
P.Ecart(); P.Ecart();
} }
func (P *Parser) ParseExpressionPairList() { func (P *Parser) ParseExpressionPairList(list *Globals.List) {
P.Trace("ExpressionPairList"); P.Trace("ExpressionPairList");
P.ParseExpressionPair(); P.ParseExpressionPair(list);
for (P.tok == Scanner.COMMA) { for (P.tok == Scanner.COMMA) {
P.ParseExpressionPair(); P.ParseExpressionPair(list);
} }
P.Ecart(); P.Ecart();
...@@ -916,20 +929,21 @@ func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr { ...@@ -916,20 +929,21 @@ func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr {
} }
// TODO: should allow trailing ',' // TODO: should allow trailing ','
list := Globals.NewList();
if P.tok != paren { if P.tok != paren {
P.ParseExpression(); list.AddExpr(P.ParseExpression());
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
P.Next(); P.Next();
if P.tok != paren { if P.tok != paren {
P.ParseExpressionList(); P.ParseSingleExpressionList(list);
} }
} else if P.tok == Scanner.COLON { } else if P.tok == Scanner.COLON {
P.Next(); P.Next();
P.ParseExpression(); list.AddExpr(P.ParseExpression());
if P.tok == Scanner.COMMA { if P.tok == Scanner.COMMA {
P.Next(); P.Next();
if P.tok != paren { if P.tok != paren {
P.ParseExpressionPairList(); P.ParseExpressionPairList(list);
} }
} }
} }
...@@ -952,63 +966,109 @@ func (P *Parser) ParseOperand(pos int, ident string) Globals.Expr { ...@@ -952,63 +966,109 @@ func (P *Parser) ParseOperand(pos int, ident string) Globals.Expr {
P.Next(); P.Next();
} }
var res Globals.Expr = AST.Bad;
if pos >= 0 { if pos >= 0 {
// TODO set these up properly in the Universe // TODO set these up properly in the Universe
if ident == "panic" || ident == "print" { if ident == "panic" || ident == "print" {
P.ParseBuiltinCall(); res = P.ParseBuiltinCall();
goto exit;
}
P.ParseQualifiedIdent(pos, ident); } else {
// TODO enable code below obj := P.ParseQualifiedIdent(pos, ident);
/* if P.semantic_checks {
if obj.kind == Object.TYPE { if obj.kind == Object.TYPE {
P.ParseCompositeLit(obj.typ); res = P.ParseCompositeLit(obj.typ);
} else {
res = AST.NewObject(obj);
}
} }
*/
goto exit;
} }
} else {
switch P.tok { switch P.tok {
case Scanner.IDENT: case Scanner.IDENT:
panic "UNREACHABLE"; panic "UNREACHABLE";
case Scanner.LPAREN: case Scanner.LPAREN:
P.Next(); P.Next();
P.ParseExpression(); res = P.ParseExpression();
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
case Scanner.STRING: fallthrough;
case Scanner.NUMBER: fallthrough; case Scanner.INT:
case Scanner.NIL: fallthrough; x := AST.NewLiteral(Universe.int_t);
case Scanner.IOTA: fallthrough; x.i = 42; // TODO set the right value
case Scanner.TRUE: fallthrough; res = x;
P.Next();
case Scanner.FLOAT:
x := AST.NewLiteral(Universe.float_t);
x.f = 42.0; // TODO set the right value
res = x;
P.Next();
case Scanner.STRING:
x := AST.NewLiteral(Universe.string_t);
x.s = P.val; // TODO need to strip quotes, interpret string properly
res = x;
P.Next();
case Scanner.NIL:
P.Next();
res = AST.Nil;
case Scanner.IOTA:
x := AST.NewLiteral(Universe.int_t);
x.i = 42; // TODO set the right value
res = x;
P.Next();
case Scanner.TRUE:
P.Next();
res = AST.True;
case Scanner.FALSE: case Scanner.FALSE:
P.Next(); P.Next();
res = AST.False;
case Scanner.FUNC: case Scanner.FUNC:
P.ParseFunctionLit(); res = P.ParseFunctionLit();
case Scanner.NEW: case Scanner.NEW:
P.ParseNew(); res = P.ParseNew();
default: default:
typ := P.TryType(); typ := P.TryType();
if typ != nil { if typ != nil {
P.ParseCompositeLit(typ); res = P.ParseCompositeLit(typ);
} else { } else {
P.Error(P.pos, "operand expected"); P.Error(P.pos, "operand expected");
P.Next(); // make progress P.Next(); // make progress
} }
} }
exit: }
P.Ecart(); P.Ecart();
return nil; return res;
} }
func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr { func (P *Parser) ParseSelectorOrTypeAssertion(x Globals.Expr) Globals.Expr {
P.Trace("SelectorOrTypeAssertion"); P.Trace("SelectorOrTypeAssertion");
pos := P.pos;
P.Expect(Scanner.PERIOD); P.Expect(Scanner.PERIOD);
if P.semantic_checks {
typ := x.typ();
if typ.form != Type.STRUCT || typ.form != Type.INTERFACE {
P.Error(pos, `"." cannot be applied to this operand`);
}
}
if P.tok == Scanner.IDENT { if P.tok == Scanner.IDENT {
P.ParseIdent(); ident := P.ParseIdent();
} else { } else {
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
P.ParseType(); P.ParseType();
...@@ -1016,11 +1076,11 @@ func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr { ...@@ -1016,11 +1076,11 @@ func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
} }
P.Ecart(); P.Ecart();
return nil; return x;
} }
func (P *Parser) ParseIndexOrSlice() Globals.Expr { func (P *Parser) ParseIndexOrSlice(x Globals.Expr) Globals.Expr {
P.Trace("IndexOrSlice"); P.Trace("IndexOrSlice");
P.Expect(Scanner.LBRACK); P.Expect(Scanner.LBRACK);
...@@ -1032,11 +1092,11 @@ func (P *Parser) ParseIndexOrSlice() Globals.Expr { ...@@ -1032,11 +1092,11 @@ func (P *Parser) ParseIndexOrSlice() Globals.Expr {
P.Expect(Scanner.RBRACK); P.Expect(Scanner.RBRACK);
P.Ecart(); P.Ecart();
return nil; return x;
} }
func (P *Parser) ParseCall() Globals.Expr { func (P *Parser) ParseCall(x Globals.Expr) Globals.Expr {
P.Trace("Call"); P.Trace("Call");
P.Expect(Scanner.LPAREN); P.Expect(Scanner.LPAREN);
...@@ -1046,30 +1106,26 @@ func (P *Parser) ParseCall() Globals.Expr { ...@@ -1046,30 +1106,26 @@ func (P *Parser) ParseCall() Globals.Expr {
P.Expect(Scanner.RPAREN); P.Expect(Scanner.RPAREN);
P.Ecart(); P.Ecart();
return nil; return x;
} }
func (P *Parser) ParsePrimaryExpr(pos int, ident string) Globals.Expr { func (P *Parser) ParsePrimaryExpr(pos int, ident string) Globals.Expr {
P.Trace("PrimaryExpr"); P.Trace("PrimaryExpr");
P.ParseOperand(pos, ident); x := P.ParseOperand(pos, ident);
for { for {
switch P.tok { switch P.tok {
case Scanner.PERIOD: case Scanner.PERIOD: x = P.ParseSelectorOrTypeAssertion(x);
P.ParseSelectorOrTypeAssertion(); case Scanner.LBRACK: x = P.ParseIndexOrSlice(x);
case Scanner.LBRACK: case Scanner.LPAREN: x = P.ParseCall(x);
P.ParseIndexOrSlice(); default: goto exit;
case Scanner.LPAREN:
P.ParseCall();
default:
P.Ecart();
return nil;
} }
} }
exit:
P.Ecart(); P.Ecart();
return nil; return x;
} }
...@@ -1944,10 +2000,10 @@ func (P *Parser) ParseProgram() { ...@@ -1944,10 +2000,10 @@ func (P *Parser) ParseProgram() {
obj := P.ParseIdentDecl(Object.PACKAGE); obj := P.ParseIdentDecl(Object.PACKAGE);
P.Optional(Scanner.SEMICOLON); P.Optional(Scanner.SEMICOLON);
{ if P.level != 0 { { P.OpenScope();
if P.level != 0 {
panic "incorrect scope level"; panic "incorrect scope level";
} }
P.OpenScope();
P.comp.Insert(Globals.NewPackage(P.S.filename, obj, P.top_scope)); P.comp.Insert(Globals.NewPackage(P.S.filename, obj, P.top_scope));
if P.comp.pkg_ref != 1 { if P.comp.pkg_ref != 1 {
...@@ -1966,10 +2022,11 @@ func (P *Parser) ParseProgram() { ...@@ -1966,10 +2022,11 @@ func (P *Parser) ParseProgram() {
P.ResolveUndefTypes(); P.ResolveUndefTypes();
P.MarkExports(); P.MarkExports();
P.CloseScope();
if P.level != 0 { if P.level != 0 {
panic "incorrect scope level"; panic "incorrect scope level";
} }
P.CloseScope();
} }
P.CloseScope(); P.CloseScope();
......
...@@ -10,8 +10,9 @@ export const ( ...@@ -10,8 +10,9 @@ export const (
ILLEGAL = iota; ILLEGAL = iota;
EOF; EOF;
IDENT; IDENT;
INT;
FLOAT;
STRING; STRING;
NUMBER;
COMMA; COMMA;
COLON; COLON;
...@@ -116,8 +117,9 @@ export func TokenName(tok int) string { ...@@ -116,8 +117,9 @@ export func TokenName(tok int) string {
case ILLEGAL: return "illegal"; case ILLEGAL: return "illegal";
case EOF: return "eof"; case EOF: return "eof";
case IDENT: return "ident"; case IDENT: return "ident";
case INT: return "int";
case FLOAT: return "float";
case STRING: return "string"; case STRING: return "string";
case NUMBER: return "number";
case COMMA: return ","; case COMMA: return ",";
case COLON: return ":"; case COLON: return ":";
...@@ -537,10 +539,12 @@ func (S *Scanner) ScanMantissa(base int) { ...@@ -537,10 +539,12 @@ func (S *Scanner) ScanMantissa(base int) {
} }
func (S *Scanner) ScanNumber(seen_decimal_point bool) string { func (S *Scanner) ScanNumber(seen_decimal_point bool) (tok int, val string) {
pos := S.chpos; pos := S.chpos;
tok = INT;
if seen_decimal_point { if seen_decimal_point {
tok = FLOAT;
pos--; // '.' is one byte pos--; // '.' is one byte
S.ScanMantissa(10); S.ScanMantissa(10);
goto exponent; goto exponent;
...@@ -558,6 +562,7 @@ func (S *Scanner) ScanNumber(seen_decimal_point bool) string { ...@@ -558,6 +562,7 @@ func (S *Scanner) ScanNumber(seen_decimal_point bool) string {
S.ScanMantissa(8); S.ScanMantissa(8);
if digit_val(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' { if digit_val(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
// float // float
tok = FLOAT;
goto mantissa; goto mantissa;
} }
// octal int // octal int
...@@ -571,6 +576,7 @@ mantissa: ...@@ -571,6 +576,7 @@ mantissa:
if S.ch == '.' { if S.ch == '.' {
// float // float
tok = FLOAT;
S.Next(); S.Next();
S.ScanMantissa(10) S.ScanMantissa(10)
} }
...@@ -578,6 +584,7 @@ mantissa: ...@@ -578,6 +584,7 @@ mantissa:
exponent: exponent:
if S.ch == 'e' || S.ch == 'E' { if S.ch == 'e' || S.ch == 'E' {
// float // float
tok = FLOAT;
S.Next(); S.Next();
if S.ch == '-' || S.ch == '+' { if S.ch == '-' || S.ch == '+' {
S.Next(); S.Next();
...@@ -586,7 +593,7 @@ exponent: ...@@ -586,7 +593,7 @@ exponent:
} }
exit: exit:
return S.src[pos : S.chpos]; return tok, S.src[pos : S.chpos];
} }
...@@ -735,18 +742,18 @@ func (S *Scanner) Scan() (tok, pos int, val string) { ...@@ -735,18 +742,18 @@ func (S *Scanner) Scan() (tok, pos int, val string) {
switch { switch {
case is_letter(ch): tok, val = S.ScanIdentifier(); case is_letter(ch): tok, val = S.ScanIdentifier();
case digit_val(ch) < 10: tok, val = NUMBER, S.ScanNumber(false); case digit_val(ch) < 10: tok, val = S.ScanNumber(false);
default: default:
S.Next(); // always make progress S.Next(); // always make progress
switch ch { switch ch {
case -1: tok = EOF; case -1: tok = EOF;
case '"': tok, val = STRING, S.ScanString(); case '"': tok, val = STRING, S.ScanString();
case '\'': tok, val = NUMBER, S.ScanChar(); case '\'': tok, val = INT, S.ScanChar();
case '`': tok, val = STRING, S.ScanRawString(); case '`': tok, val = STRING, S.ScanRawString();
case ':': tok = S.Select2(COLON, DEFINE); case ':': tok = S.Select2(COLON, DEFINE);
case '.': case '.':
if digit_val(S.ch) < 10 { if digit_val(S.ch) < 10 {
tok, val = NUMBER, S.ScanNumber(true); tok, val = S.ScanNumber(true);
} else { } else {
tok = PERIOD; tok = PERIOD;
} }
......
...@@ -13,7 +13,7 @@ func Scan(filename, src string) { ...@@ -13,7 +13,7 @@ func Scan(filename, src string) {
for { for {
tok, pos, val := S.Scan(); tok, pos, val := S.Scan();
print pos, ": ", Scanner.TokenName(tok); print pos, ": ", Scanner.TokenName(tok);
if tok == Scanner.IDENT || tok == Scanner.NUMBER || tok == Scanner.STRING { if tok == Scanner.IDENT || tok == Scanner.INT || tok == Scanner.FLOAT || tok == Scanner.STRING {
print " ", val; print " ", val;
} }
print "\n"; print "\n";
......
...@@ -4,11 +4,15 @@ ...@@ -4,11 +4,15 @@
package Type package Type
import Globals "globals"
import Object "object"
export const /* form */ ( export const /* form */ (
// internal types // internal types
UNDEF = iota; BAD; NIL; UNDEF = iota; VOID; BAD; NIL;
// basic types // basic types
BOOL; UINT; INT; FLOAT; STRING; BOOL; UINT; INT; FLOAT; STRING; INTEGER;
// 'any' type // 'any' type
ANY; ANY;
// composite types // composite types
...@@ -30,6 +34,7 @@ export const /* flag */ ( ...@@ -30,6 +34,7 @@ export const /* flag */ (
export func FormStr(form int) string { export func FormStr(form int) string {
switch form { switch form {
case UNDEF: return "UNDEF"; case UNDEF: return "UNDEF";
case VOID: return "VOID";
case BAD: return "BAD"; case BAD: return "BAD";
case NIL: return "NIL"; case NIL: return "NIL";
case BOOL: return "BOOL"; case BOOL: return "BOOL";
...@@ -50,3 +55,111 @@ export func FormStr(form int) string { ...@@ -50,3 +55,111 @@ export func FormStr(form int) string {
} }
return "<unknown Type form>"; return "<unknown Type form>";
} }
export func Equal(x, y *Globals.Type) bool;
func Equal0(x, y *Globals.Type) bool {
if x == y {
return true; // identical types are equal
}
if x.form == BAD || y.form == BAD {
return true; // bad types are always equal (avoid excess error messages)
}
// TODO where to check for *T == nil ?
if x.form != y.form {
return false; // types of different forms are not equal
}
switch x.form {
case UNDEF, BAD:
break;
case NIL, BOOL, STRING, ANY:
return true;
case UINT, INT, FLOAT:
return x.size == y.size;
case ARRAY:
return
x.len_ == y.len_ &&
Equal(x.elt, y.elt);
case MAP:
return
Equal(x.aux, y.aux) &&
Equal(x.elt, y.elt);
case CHANNEL:
return
x.flags == y.flags &&
Equal(x.elt, y.elt);
case FUNCTION:
{ xp := x.scope.entries;
yp := x.scope.entries;
if x.flags != y.flags && // function or method
x.len_ != y.len_ && // number of parameters
xp.len_ != yp.len_ // recv + parameters + results
{
return false;
}
for p, q := xp.first, yp.first; p != nil; p, q = p.next, q.next {
xf := p.obj;
yf := q.obj;
if xf.kind != Object.VAR || yf.kind != Object.VAR {
panic "parameters must be vars";
}
if !Equal(xf.typ, yf.typ) {
return false;
}
}
}
return true;
case STRUCT:
/*
{ ObjList* xl = &x.scope.list;
ObjList* yl = &y.scope.list;
if xl.len() != yl.len() {
return false; // scopes of different sizes are not equal
}
for int i = xl.len(); i-- > 0; {
Object* xf = (*xl)[i];
Object* yf = (*yl)[i];
ASSERT(xf.kind == Object.VAR && yf.kind == Object.VAR);
if xf.name != yf.name) || ! EqualTypes(xf.type(), yf.type() {
return false;
}
}
}
return true;
*/
// Scopes must be identical for them to be equal.
// If we reach here, they weren't.
return false;
case INTERFACE:
panic "UNIMPLEMENTED";
return false;
case POINTER, REFERENCE:
return Equal(x.elt, y.elt);
}
panic "UNREACHABLE";
return false;
}
export func Equal(x, y *Globals.Type) bool {
res := Equal0(x, y);
// TODO should do the check below only in debug mode
if Equal0(y, x) != res {
panic "type equality must be symmetric";
}
return res;
}
...@@ -32,6 +32,7 @@ export var ( ...@@ -32,6 +32,7 @@ export var (
float64_t, float64_t,
float80_t, float80_t,
string_t, string_t,
integer_t,
any_t, any_t,
// alias types // alias types
...@@ -111,6 +112,7 @@ func init() { ...@@ -111,6 +112,7 @@ func init() {
float64_t = Register(DeclType(Type.FLOAT, "float64", 8)); float64_t = Register(DeclType(Type.FLOAT, "float64", 8));
float80_t = Register(DeclType(Type.FLOAT, "float80", 10)); float80_t = Register(DeclType(Type.FLOAT, "float80", 10));
string_t = Register(DeclType(Type.STRING, "string", 8)); string_t = Register(DeclType(Type.STRING, "string", 8));
integer_t = Register(DeclType(Type.INTEGER, "integer", 8));
any_t = Register(DeclType(Type.ANY, "any", 8)); any_t = Register(DeclType(Type.ANY, "any", 8));
// All but 'byte' should be platform-dependent, eventually. // All but 'byte' should be platform-dependent, eventually.
......
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