mirror of
https://github.com/golang/go
synced 2024-11-13 18:30:26 -07:00
- added more semantic checks - more to come
- distinguish float/int literals syntactically - fixed a tracing bug R=r OCL=13906 CL=13906
This commit is contained in:
parent
044a3b1a5e
commit
687f387c0b
@ -11,6 +11,61 @@ import Universe "universe"
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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 {
|
||||
typ_ *Globals.Type;
|
||||
op int;
|
||||
@ -18,7 +73,6 @@ export type BinaryExpr struct {
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (x *BinaryExpr) typ() *Globals.Type {
|
||||
return x.typ_;
|
||||
}
|
||||
@ -37,3 +91,14 @@ export type IfStat struct {
|
||||
then_ 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 {
|
||||
}
|
||||
|
||||
|
||||
// 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 {
|
||||
len_ int;
|
||||
first, last *Elem;
|
||||
@ -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
|
||||
|
||||
@ -249,6 +250,11 @@ func (L *List) AddTyp(typ *Type) {
|
||||
}
|
||||
|
||||
|
||||
func (L *List) AddExpr(expr Expr) {
|
||||
L.Add().expr = expr;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Scope methods
|
||||
|
||||
|
@ -47,14 +47,14 @@ func (P *Parser) Trace(msg string) {
|
||||
if P.verbose > 0 {
|
||||
P.PrintIndent();
|
||||
print msg, " {\n";
|
||||
P.indent++;
|
||||
}
|
||||
P.indent++;
|
||||
}
|
||||
|
||||
|
||||
func (P *Parser) Ecart() {
|
||||
P.indent--;
|
||||
if P.verbose > 0 {
|
||||
P.indent--;
|
||||
P.PrintIndent();
|
||||
print "}\n";
|
||||
}
|
||||
@ -132,6 +132,9 @@ func (P *Parser) DeclareInScope(scope *Globals.Scope, obj *Globals.Object) {
|
||||
if !P.semantic_checks {
|
||||
return;
|
||||
}
|
||||
if P.level > 0 {
|
||||
panic "cannot declare objects in other packages";
|
||||
}
|
||||
obj.pnolev = P.level;
|
||||
if scope.Lookup(obj.ident) != nil {
|
||||
P.Error(obj.pos, `"` + obj.ident + `" is declared already`);
|
||||
@ -200,26 +203,25 @@ func (P *Parser) DeclareFunc(ident string, typ *Globals.Type) *Globals.Object {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// obj != NULL: possibly a forward declaration.
|
||||
// obj != NULL: possibly a forward declaration
|
||||
if obj.kind != Object.FUNC {
|
||||
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.typ = typ;
|
||||
// TODO do we need to set the primary type? probably...
|
||||
return obj;
|
||||
}
|
||||
|
||||
// We have a function with the same name.
|
||||
/*
|
||||
if !EqualTypes(type, obj->type()) {
|
||||
this->Error("type of \"%s\" does not match its forward declaration", name.cstr());
|
||||
// Continue but do not insert this function into the scope.
|
||||
NewObject(Object::FUNC, name);
|
||||
obj->set_type(type);
|
||||
// we have a function with the same name
|
||||
if !Type.Equal(typ, obj.typ) {
|
||||
P.Error(-1, `type of "` + ident + `" does not match its forward declaration`);
|
||||
// continue but do not insert this function into the scope
|
||||
obj = Globals.NewObject(-1, Object.FUNC, ident);
|
||||
obj.typ = typ;
|
||||
// TODO do we need to set the primary type? probably...
|
||||
return obj;
|
||||
}
|
||||
*/
|
||||
|
||||
// We have a matching forward declaration. Use it.
|
||||
return obj;
|
||||
@ -826,12 +828,10 @@ func (P *Parser) ParseExpressionList() *Globals.List {
|
||||
P.Trace("ExpressionList");
|
||||
|
||||
list := Globals.NewList();
|
||||
P.ParseExpression();
|
||||
list.AddInt(0); // TODO fix this - add correct list element
|
||||
list.AddExpr(P.ParseExpression());
|
||||
for P.tok == Scanner.COMMA {
|
||||
P.Next();
|
||||
P.ParseExpression();
|
||||
list.AddInt(0); // TODO fix this - add correct list element
|
||||
list.AddExpr(P.ParseExpression());
|
||||
}
|
||||
|
||||
P.Ecart();
|
||||
@ -867,23 +867,36 @@ func (P *Parser) ParseFunctionLit() Globals.Expr {
|
||||
}
|
||||
|
||||
|
||||
func (P *Parser) ParseExpressionPair() {
|
||||
P.Trace("ExpressionPair");
|
||||
|
||||
P.ParseExpression();
|
||||
P.Expect(Scanner.COLON);
|
||||
P.ParseExpression();
|
||||
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) ParseExpressionPairList() {
|
||||
func (P *Parser) ParseExpressionPair(list *Globals.List) {
|
||||
P.Trace("ExpressionPair");
|
||||
|
||||
list.AddExpr(P.ParseExpression());
|
||||
P.Expect(Scanner.COLON);
|
||||
list.AddExpr(P.ParseExpression());
|
||||
|
||||
P.Ecart();
|
||||
}
|
||||
|
||||
|
||||
func (P *Parser) ParseExpressionPairList(list *Globals.List) {
|
||||
P.Trace("ExpressionPairList");
|
||||
|
||||
P.ParseExpressionPair();
|
||||
P.ParseExpressionPair(list);
|
||||
for (P.tok == Scanner.COMMA) {
|
||||
P.ParseExpressionPair();
|
||||
P.ParseExpressionPair(list);
|
||||
}
|
||||
|
||||
P.Ecart();
|
||||
@ -916,20 +929,21 @@ func (P *Parser) ParseCompositeLit(typ *Globals.Type) Globals.Expr {
|
||||
}
|
||||
|
||||
// TODO: should allow trailing ','
|
||||
list := Globals.NewList();
|
||||
if P.tok != paren {
|
||||
P.ParseExpression();
|
||||
list.AddExpr(P.ParseExpression());
|
||||
if P.tok == Scanner.COMMA {
|
||||
P.Next();
|
||||
if P.tok != paren {
|
||||
P.ParseExpressionList();
|
||||
P.ParseSingleExpressionList(list);
|
||||
}
|
||||
} else if P.tok == Scanner.COLON {
|
||||
P.Next();
|
||||
P.ParseExpression();
|
||||
list.AddExpr(P.ParseExpression());
|
||||
if P.tok == Scanner.COMMA {
|
||||
P.Next();
|
||||
if P.tok != paren {
|
||||
P.ParseExpressionPairList();
|
||||
P.ParseExpressionPairList(list);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -951,64 +965,110 @@ func (P *Parser) ParseOperand(pos int, ident string) Globals.Expr {
|
||||
ident = P.val;
|
||||
P.Next();
|
||||
}
|
||||
|
||||
|
||||
var res Globals.Expr = AST.Bad;
|
||||
|
||||
if pos >= 0 {
|
||||
// TODO set these up properly in the Universe
|
||||
if ident == "panic" || ident == "print" {
|
||||
P.ParseBuiltinCall();
|
||||
goto exit;
|
||||
}
|
||||
|
||||
P.ParseQualifiedIdent(pos, ident);
|
||||
// TODO enable code below
|
||||
/*
|
||||
if obj.kind == Object.TYPE {
|
||||
P.ParseCompositeLit(obj.typ);
|
||||
}
|
||||
*/
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch P.tok {
|
||||
case Scanner.IDENT:
|
||||
panic "UNREACHABLE";
|
||||
case Scanner.LPAREN:
|
||||
P.Next();
|
||||
P.ParseExpression();
|
||||
P.Expect(Scanner.RPAREN);
|
||||
case Scanner.STRING: fallthrough;
|
||||
case Scanner.NUMBER: fallthrough;
|
||||
case Scanner.NIL: fallthrough;
|
||||
case Scanner.IOTA: fallthrough;
|
||||
case Scanner.TRUE: fallthrough;
|
||||
case Scanner.FALSE:
|
||||
P.Next();
|
||||
case Scanner.FUNC:
|
||||
P.ParseFunctionLit();
|
||||
case Scanner.NEW:
|
||||
P.ParseNew();
|
||||
default:
|
||||
typ := P.TryType();
|
||||
if typ != nil {
|
||||
P.ParseCompositeLit(typ);
|
||||
res = P.ParseBuiltinCall();
|
||||
|
||||
} else {
|
||||
P.Error(P.pos, "operand expected");
|
||||
P.Next(); // make progress
|
||||
obj := P.ParseQualifiedIdent(pos, ident);
|
||||
if P.semantic_checks {
|
||||
if obj.kind == Object.TYPE {
|
||||
res = P.ParseCompositeLit(obj.typ);
|
||||
} else {
|
||||
res = AST.NewObject(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
exit:
|
||||
switch P.tok {
|
||||
case Scanner.IDENT:
|
||||
panic "UNREACHABLE";
|
||||
|
||||
case Scanner.LPAREN:
|
||||
P.Next();
|
||||
res = P.ParseExpression();
|
||||
P.Expect(Scanner.RPAREN);
|
||||
|
||||
case Scanner.INT:
|
||||
x := AST.NewLiteral(Universe.int_t);
|
||||
x.i = 42; // TODO set the right value
|
||||
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:
|
||||
P.Next();
|
||||
res = AST.False;
|
||||
|
||||
case Scanner.FUNC:
|
||||
res = P.ParseFunctionLit();
|
||||
|
||||
case Scanner.NEW:
|
||||
res = P.ParseNew();
|
||||
|
||||
default:
|
||||
typ := P.TryType();
|
||||
if typ != nil {
|
||||
res = P.ParseCompositeLit(typ);
|
||||
} else {
|
||||
P.Error(P.pos, "operand expected");
|
||||
P.Next(); // make progress
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
P.Ecart();
|
||||
return nil;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
|
||||
func (P *Parser) ParseSelectorOrTypeAssertion(x Globals.Expr) Globals.Expr {
|
||||
P.Trace("SelectorOrTypeAssertion");
|
||||
|
||||
|
||||
pos := P.pos;
|
||||
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 {
|
||||
P.ParseIdent();
|
||||
ident := P.ParseIdent();
|
||||
|
||||
} else {
|
||||
P.Expect(Scanner.LPAREN);
|
||||
P.ParseType();
|
||||
@ -1016,11 +1076,11 @@ func (P *Parser) ParseSelectorOrTypeAssertion() Globals.Expr {
|
||||
}
|
||||
|
||||
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.Expect(Scanner.LBRACK);
|
||||
@ -1032,11 +1092,11 @@ func (P *Parser) ParseIndexOrSlice() Globals.Expr {
|
||||
P.Expect(Scanner.RBRACK);
|
||||
|
||||
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.Expect(Scanner.LPAREN);
|
||||
@ -1046,30 +1106,26 @@ func (P *Parser) ParseCall() Globals.Expr {
|
||||
P.Expect(Scanner.RPAREN);
|
||||
|
||||
P.Ecart();
|
||||
return nil;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
func (P *Parser) ParsePrimaryExpr(pos int, ident string) Globals.Expr {
|
||||
P.Trace("PrimaryExpr");
|
||||
|
||||
P.ParseOperand(pos, ident);
|
||||
x := P.ParseOperand(pos, ident);
|
||||
for {
|
||||
switch P.tok {
|
||||
case Scanner.PERIOD:
|
||||
P.ParseSelectorOrTypeAssertion();
|
||||
case Scanner.LBRACK:
|
||||
P.ParseIndexOrSlice();
|
||||
case Scanner.LPAREN:
|
||||
P.ParseCall();
|
||||
default:
|
||||
P.Ecart();
|
||||
return nil;
|
||||
case Scanner.PERIOD: x = P.ParseSelectorOrTypeAssertion(x);
|
||||
case Scanner.LBRACK: x = P.ParseIndexOrSlice(x);
|
||||
case Scanner.LPAREN: x = P.ParseCall(x);
|
||||
default: goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
exit:
|
||||
P.Ecart();
|
||||
return nil;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
@ -1944,10 +2000,10 @@ func (P *Parser) ParseProgram() {
|
||||
obj := P.ParseIdentDecl(Object.PACKAGE);
|
||||
P.Optional(Scanner.SEMICOLON);
|
||||
|
||||
{ if P.level != 0 {
|
||||
{ P.OpenScope();
|
||||
if P.level != 0 {
|
||||
panic "incorrect scope level";
|
||||
}
|
||||
P.OpenScope();
|
||||
|
||||
P.comp.Insert(Globals.NewPackage(P.S.filename, obj, P.top_scope));
|
||||
if P.comp.pkg_ref != 1 {
|
||||
@ -1966,10 +2022,11 @@ func (P *Parser) ParseProgram() {
|
||||
|
||||
P.ResolveUndefTypes();
|
||||
P.MarkExports();
|
||||
P.CloseScope();
|
||||
|
||||
if P.level != 0 {
|
||||
panic "incorrect scope level";
|
||||
}
|
||||
P.CloseScope();
|
||||
}
|
||||
|
||||
P.CloseScope();
|
||||
|
@ -10,8 +10,9 @@ export const (
|
||||
ILLEGAL = iota;
|
||||
EOF;
|
||||
IDENT;
|
||||
INT;
|
||||
FLOAT;
|
||||
STRING;
|
||||
NUMBER;
|
||||
|
||||
COMMA;
|
||||
COLON;
|
||||
@ -116,8 +117,9 @@ export func TokenName(tok int) string {
|
||||
case ILLEGAL: return "illegal";
|
||||
case EOF: return "eof";
|
||||
case IDENT: return "ident";
|
||||
case INT: return "int";
|
||||
case FLOAT: return "float";
|
||||
case STRING: return "string";
|
||||
case NUMBER: return "number";
|
||||
|
||||
case COMMA: return ",";
|
||||
case COLON: return ":";
|
||||
@ -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;
|
||||
tok = INT;
|
||||
|
||||
if seen_decimal_point {
|
||||
tok = FLOAT;
|
||||
pos--; // '.' is one byte
|
||||
S.ScanMantissa(10);
|
||||
goto exponent;
|
||||
@ -558,6 +562,7 @@ func (S *Scanner) ScanNumber(seen_decimal_point bool) string {
|
||||
S.ScanMantissa(8);
|
||||
if digit_val(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
|
||||
// float
|
||||
tok = FLOAT;
|
||||
goto mantissa;
|
||||
}
|
||||
// octal int
|
||||
@ -571,6 +576,7 @@ mantissa:
|
||||
|
||||
if S.ch == '.' {
|
||||
// float
|
||||
tok = FLOAT;
|
||||
S.Next();
|
||||
S.ScanMantissa(10)
|
||||
}
|
||||
@ -578,6 +584,7 @@ mantissa:
|
||||
exponent:
|
||||
if S.ch == 'e' || S.ch == 'E' {
|
||||
// float
|
||||
tok = FLOAT;
|
||||
S.Next();
|
||||
if S.ch == '-' || S.ch == '+' {
|
||||
S.Next();
|
||||
@ -586,7 +593,7 @@ exponent:
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
switch {
|
||||
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:
|
||||
S.Next(); // always make progress
|
||||
switch ch {
|
||||
case -1: tok = EOF;
|
||||
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 = S.Select2(COLON, DEFINE);
|
||||
case '.':
|
||||
if digit_val(S.ch) < 10 {
|
||||
tok, val = NUMBER, S.ScanNumber(true);
|
||||
tok, val = S.ScanNumber(true);
|
||||
} else {
|
||||
tok = PERIOD;
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ func Scan(filename, src string) {
|
||||
for {
|
||||
tok, pos, val := S.Scan();
|
||||
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 "\n";
|
||||
|
@ -4,11 +4,15 @@
|
||||
|
||||
package Type
|
||||
|
||||
import Globals "globals"
|
||||
import Object "object"
|
||||
|
||||
|
||||
export const /* form */ (
|
||||
// internal types
|
||||
UNDEF = iota; BAD; NIL;
|
||||
UNDEF = iota; VOID; BAD; NIL;
|
||||
// basic types
|
||||
BOOL; UINT; INT; FLOAT; STRING;
|
||||
BOOL; UINT; INT; FLOAT; STRING; INTEGER;
|
||||
// 'any' type
|
||||
ANY;
|
||||
// composite types
|
||||
@ -30,6 +34,7 @@ export const /* flag */ (
|
||||
export func FormStr(form int) string {
|
||||
switch form {
|
||||
case UNDEF: return "UNDEF";
|
||||
case VOID: return "VOID";
|
||||
case BAD: return "BAD";
|
||||
case NIL: return "NIL";
|
||||
case BOOL: return "BOOL";
|
||||
@ -50,3 +55,111 @@ export func FormStr(form int) string {
|
||||
}
|
||||
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 (
|
||||
float64_t,
|
||||
float80_t,
|
||||
string_t,
|
||||
integer_t,
|
||||
any_t,
|
||||
|
||||
// alias types
|
||||
@ -111,6 +112,7 @@ func init() {
|
||||
float64_t = Register(DeclType(Type.FLOAT, "float64", 8));
|
||||
float80_t = Register(DeclType(Type.FLOAT, "float80", 10));
|
||||
string_t = Register(DeclType(Type.STRING, "string", 8));
|
||||
integer_t = Register(DeclType(Type.INTEGER, "integer", 8));
|
||||
any_t = Register(DeclType(Type.ANY, "any", 8));
|
||||
|
||||
// All but 'byte' should be platform-dependent, eventually.
|
||||
|
Loading…
Reference in New Issue
Block a user