diff --git a/ChangeLog b/ChangeLog index dc5b2b8..d6a9892 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,29 @@ +Wed Jan 2 01:24:05 2008 Minero Aoki + + * net/loveruby/cflat/compiler/TypeChecker.java: check member + validity for s.memb, s->memb, u.memb, u->memb. + + * net/loveruby/cflat/type/Type.java: new method #isComplexType. + + * net/loveruby/cflat/type/ComplexType.java: override it. + + * net/loveruby/cflat/compiler/LocalReferenceResolver.java: should + resolve variable initializer. + + * net/loveruby/cflat/ast/DefinedVariable.java: new method + #hasInitializer. + + * test/test.sh: run tests. + + * test/struct-semcheck5.cb: check if member is valid on s.memb. + + * test/struct-semcheck6.cb: check if member is valid on + sptr->memb. + + * test/union-semcheck5.cb: check if member is valid on u.memb. + + * test/union-semcheck6.cb: check if member is valid on uptr->memb. + Wed Jan 2 00:38:48 2008 Minero Aoki * net/loveruby/cflat/compiler/TypeChecker.java: check aref base diff --git a/ToDo b/ToDo index c3867a8..c20a762 100644 --- a/ToDo +++ b/ToDo @@ -155,13 +155,23 @@ - warn unused static variables - warn unused local variables - warn unused static functions + - check if aref base expr is indexable (a must be indeable where a[0]) + - check if funcall base expr is callable (a must be callable where a()) * semantic check (type) + - simple type check (binary ops, unary ops) + - a[0] + - *ptr + - ct.memb + - ptr->memb + - funcall args - prohibit circular struct/union definition - * type check - * implicit cast - * check return type + - implicit cast + - validate struct/union member (ct.memb) + - validate struct/union member (ct->memb) * check duplicated struct/union members - * validate struct/union member + * ptr + int; ptr - int + * check return type + * check if assignable - op for various types - signed char - signed short @@ -186,6 +196,7 @@ * warn no return * data flow graph * --dump-dflow + * warn unused variable * warn uninitialized use of variables * semantic check (dflow) * register allocation diff --git a/net/loveruby/cflat/ast/DefinedVariable.java b/net/loveruby/cflat/ast/DefinedVariable.java index f25171a..a56bcec 100644 --- a/net/loveruby/cflat/ast/DefinedVariable.java +++ b/net/loveruby/cflat/ast/DefinedVariable.java @@ -18,10 +18,14 @@ public class DefinedVariable extends Variable { return true; } - public boolean isInitialized() { + public boolean hasInitializer() { return (initializer != null); } + public boolean isInitialized() { + return hasInitializer(); + } + public Node initializer() { return initializer; } diff --git a/net/loveruby/cflat/compiler/LocalReferenceResolver.java b/net/loveruby/cflat/compiler/LocalReferenceResolver.java index 15250f7..d60e660 100644 --- a/net/loveruby/cflat/compiler/LocalReferenceResolver.java +++ b/net/loveruby/cflat/compiler/LocalReferenceResolver.java @@ -74,6 +74,7 @@ public class LocalReferenceResolver extends Visitor { public void visit(BlockNode node) { pushScope(node.variables()); + resolveInitializers(node.variables()); super.visit(node); node.setScope(popScope()); } @@ -100,6 +101,15 @@ public class LocalReferenceResolver extends Visitor { return (Scope)scopeStack.getLast(); } + protected void resolveInitializers(Iterator vars) { + while (vars.hasNext()) { + DefinedVariable var = (DefinedVariable)vars.next(); + if (var.hasInitializer()) { + resolve(var.initializer()); + } + } + } + public void visit(StringLiteralNode node) { node.setEntry(constantTable.intern(node.value())); } diff --git a/net/loveruby/cflat/compiler/TypeChecker.java b/net/loveruby/cflat/compiler/TypeChecker.java index 700ff87..2c41177 100644 --- a/net/loveruby/cflat/compiler/TypeChecker.java +++ b/net/loveruby/cflat/compiler/TypeChecker.java @@ -320,19 +320,39 @@ class TypeChecker extends Visitor { } public void visit(MemberNode node) { - super.visit(node); - // FIXME: validate member here? + resolve(node.expr()); + checkMemberRef(node.expr().type(), node.name()); } public void visit(PtrMemberNode node) { - super.visit(node); - // FIXME: validate member here? + resolve(node.expr()); + if (! node.expr().type().isPointer()) { + notPointerError(node.type()); + return; + } + PointerType pt = (PointerType)node.expr().type(); + checkMemberRef(pt.base(), node.name()); + } + + protected void checkMemberRef(Type t, String memb) { + if (! t.isComplexType()) { + errorHandler.error("is not struct/union: " + t.textize()); + return; + } + ComplexType type = (ComplexType)t; + if (! type.hasMember(memb)) { + errorHandler.error(type.textize() + + " does not have member " + memb); + return; + } } public void visit(DereferenceNode node) { super.visit(node); - if (node.type().isPointer()) return; - notPointerError(node.type()); + if (! node.expr().type().isPointer()) { + notPointerError(node.type()); + return; + } } public void visit(AddressNode node) { diff --git a/net/loveruby/cflat/type/ComplexType.java b/net/loveruby/cflat/type/ComplexType.java index 7726b26..0ac7a32 100644 --- a/net/loveruby/cflat/type/ComplexType.java +++ b/net/loveruby/cflat/type/ComplexType.java @@ -16,6 +16,10 @@ abstract public class ComplexType extends Type { isRecursiveChecked = false; } + public boolean isComplexType() { + return true; + } + public String name() { return name; } @@ -31,6 +35,10 @@ abstract public class ComplexType extends Type { return members.iterator(); } + public boolean hasMember(String name) { + return (get(name) != null); + } + public Type memberType(String name) { return fetch(name).type(); } diff --git a/net/loveruby/cflat/type/Type.java b/net/loveruby/cflat/type/Type.java index 0e8f93a..a042c78 100644 --- a/net/loveruby/cflat/type/Type.java +++ b/net/loveruby/cflat/type/Type.java @@ -9,69 +9,24 @@ public abstract class Type { public abstract long size(); - public boolean isReferable() { - return false; - } - - public boolean isVoid() { - return false; - } - - public boolean isInt() { - return false; - } - - public boolean isInteger() { - return false; - } - - public boolean isSigned() { - throw new Error("#isSigned for non-integer type"); - } - - public boolean isNumeric() { - return false; - } - - public boolean isPointer() { - return false; - } - - public boolean isArray() { - return false; - } - - public boolean isStruct() { - return false; - } - - public boolean isUnion() { - return false; - } - - public boolean isUserType() { - return false; - } - - public boolean isFunction() { - return false; - } + public boolean isVoid() { return false; } + public boolean isInt() { return false; } + public boolean isInteger() { return false; } + public boolean isSigned() + { throw new Error("#isSigned for non-integer type"); } + public boolean isNumeric() { return false; } + public boolean isPointer() { return false; } + public boolean isArray() { return false; } + public boolean isStruct() { return false; } + public boolean isUnion() { return false; } + public boolean isComplexType() { return false; } + public boolean isUserType() { return false; } + public boolean isFunction() { return false; } + public boolean isCompatible(Type other) { return false; } + public boolean isCastableTo(Type target) { return equals(target); } + public boolean isReferable() { return false; } + public boolean isCallable() { return false; } + public boolean isIndexable() { return false; } public abstract String textize(); - - public boolean isCompatible(Type other) { - return false; - } - - public boolean isCastableTo(Type target) { - return equals(target); - } - - public boolean isCallable() { - return false; - } - - public boolean isIndexable() { - return false; - } } diff --git a/test/struct-semcheck5.cb b/test/struct-semcheck5.cb new file mode 100644 index 0000000..a1cb5c0 --- /dev/null +++ b/test/struct-semcheck5.cb @@ -0,0 +1,10 @@ +struct a { + int x; +}; + +int main(int argc, char **argv) +{ + struct a s; + s.x = 1; + return s.nosuchmember; +} diff --git a/test/struct-semcheck6.cb b/test/struct-semcheck6.cb new file mode 100644 index 0000000..b790cd3 --- /dev/null +++ b/test/struct-semcheck6.cb @@ -0,0 +1,11 @@ +struct a { + int x; +}; + +int main(int argc, char **argv) +{ + struct a s; + struct a *ptr = &s; + ptr->x = 1; + return ptr->nosuchmember; +} diff --git a/test/test.sh b/test/test.sh index e269ef4..7ceca45 100755 --- a/test/test.sh +++ b/test/test.sh @@ -122,12 +122,16 @@ assert_status 0 ./struct-semcheck assert_error $CBC struct-semcheck2.cb assert_error $CBC struct-semcheck3.cb assert_error $CBC struct-semcheck4.cb +assert_error $CBC struct-semcheck5.cb +assert_error $CBC struct-semcheck6.cb assert_out "1;2;513" ./union # little endian assert_status 0 ./union-semcheck assert_error $CBC union-semcheck2.cb assert_error $CBC union-semcheck3.cb assert_error $CBC union-semcheck4.cb +assert_error $CBC union-semcheck5.cb +assert_error $CBC union-semcheck6.cb assert_out "5;5" ./pointer assert_out "1;2" ./ptrmemb diff --git a/test/union-semcheck5.cb b/test/union-semcheck5.cb new file mode 100644 index 0000000..82bcb8e --- /dev/null +++ b/test/union-semcheck5.cb @@ -0,0 +1,10 @@ +union a { + int x; +}; + +int main(int argc, char **argv) +{ + union a u; + u.x = 1; + return u.nosuchmember; +} diff --git a/test/union-semcheck6.cb b/test/union-semcheck6.cb new file mode 100644 index 0000000..fa38825 --- /dev/null +++ b/test/union-semcheck6.cb @@ -0,0 +1,11 @@ +union a { + int x; +}; + +int main(int argc, char **argv) +{ + union a u; + union a* ptr = &u; + ptr->x = 1; + return ptr->nosuchmember; +}