diff --git a/usr/gri/gosrc/ast.go b/usr/gri/gosrc/ast.go index 8b565e5816..4fe91fa1b1 100644 --- a/usr/gri/gosrc/ast.go +++ b/usr/gri/gosrc/ast.go @@ -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); +} diff --git a/usr/gri/gosrc/globals.go b/usr/gri/gosrc/globals.go index 3624ede13a..a6695daccd 100644 --- a/usr/gri/gosrc/globals.go +++ b/usr/gri/gosrc/globals.go @@ -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 diff --git a/usr/gri/gosrc/parser.go b/usr/gri/gosrc/parser.go index 503a4cf51e..b5a57501a7 100644 --- a/usr/gri/gosrc/parser.go +++ b/usr/gri/gosrc/parser.go @@ -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(); diff --git a/usr/gri/gosrc/scanner.go b/usr/gri/gosrc/scanner.go index 8298b8b340..add320e4af 100644 --- a/usr/gri/gosrc/scanner.go +++ b/usr/gri/gosrc/scanner.go @@ -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; } diff --git a/usr/gri/gosrc/test_scanner.go b/usr/gri/gosrc/test_scanner.go index 931adb9bc6..2ce097fd19 100644 --- a/usr/gri/gosrc/test_scanner.go +++ b/usr/gri/gosrc/test_scanner.go @@ -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"; diff --git a/usr/gri/gosrc/type.go b/usr/gri/gosrc/type.go index 1f8a0b1d2e..b872a1cda6 100644 --- a/usr/gri/gosrc/type.go +++ b/usr/gri/gosrc/type.go @@ -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 ""; } + + +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; +} diff --git a/usr/gri/gosrc/universe.go b/usr/gri/gosrc/universe.go index c167e67d07..9d99442884 100755 --- a/usr/gri/gosrc/universe.go +++ b/usr/gri/gosrc/universe.go @@ -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.