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";
}
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`);
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;
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();
}
-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.ParseExpression();
+ list.AddExpr(P.ParseExpression());
P.Expect(Scanner.COLON);
- P.ParseExpression();
+ list.AddExpr(P.ParseExpression());
P.Ecart();
}
-func (P *Parser) ParseExpressionPairList() {
+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();
}
// 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);
}
}
}
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;
+ res = P.ParseBuiltinCall();
+
+ } else {
+ 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 {
- P.ParseQualifiedIdent(pos, ident);
- // TODO enable code below
- /*
- if obj.kind == Object.TYPE {
- P.ParseCompositeLit(obj.typ);
+ 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
+ }
}
- */
- 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);
- } else {
- P.Error(P.pos, "operand expected");
- P.Next(); // make progress
- }
}
-
-exit:
+
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();
}
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);
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);
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;
}
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 {
P.ResolveUndefTypes();
P.MarkExports();
- P.CloseScope();
+
if P.level != 0 {
panic "incorrect scope level";
}
+ P.CloseScope();
}
P.CloseScope();
ILLEGAL = iota;
EOF;
IDENT;
+ INT;
+ FLOAT;
STRING;
- NUMBER;
COMMA;
COLON;
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 ":";
}
-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;
S.ScanMantissa(8);
if digit_val(S.ch) < 10 || S.ch == '.' || S.ch == 'e' || S.ch == 'E' {
// float
+ tok = FLOAT;
goto mantissa;
}
// octal int
if S.ch == '.' {
// float
+ tok = FLOAT;
S.Next();
S.ScanMantissa(10)
}
exponent:
if S.ch == 'e' || S.ch == 'E' {
// float
+ tok = FLOAT;
S.Next();
if S.ch == '-' || S.ch == '+' {
S.Next();
}
exit:
- return S.src[pos : S.chpos];
+ return tok, S.src[pos : S.chpos];
}
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;
}
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
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";
}
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;
+}