[Nice-commit] Nice/src/bossa/syntax defaultconstructor.nice,NONE,1.1 niceclass.nice,NONE,1.1 nicefie
Brought to you by:
bonniot
Update of /cvsroot/nice/Nice/src/bossa/syntax In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8798/F:/nice/src/bossa/syntax Modified Files: Constructor.java CustomConstructor.java EnumDefinition.java ImportedConstructor.java MethodBodyDefinition.java NiceClass.java NiceUtils.java dispatch.java.bootstrap new.nice tools.nice Added Files: defaultconstructor.nice niceclass.nice nicefield.nice nicefieldaccess.nice Removed Files: DefaultConstructor.java NiceFieldAccess.java Log Message: Converted NiceClass, DefaultConstructor and Nice field classes to nice code. Index: dispatch.java.bootstrap =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/dispatch.java.bootstrap,v retrieving revision 1.23 retrieving revision 1.24 diff -C2 -d -r1.23 -r1.24 *** dispatch.java.bootstrap 7 Oct 2004 22:03:44 -0000 1.23 --- dispatch.java.bootstrap 5 Nov 2004 14:57:57 -0000 1.24 *************** *** 13,16 **** --- 13,19 ---- public class dispatch { + public static NiceClass createNiceClass(ClassDefinition cdef) + {return null;} + public static Statement createReturnStmt(Expression value, boolean fake) { return null; } Index: Constructor.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/Constructor.java,v retrieving revision 1.13 retrieving revision 1.14 diff -C2 -d -r1.13 -r1.14 *** Constructor.java 7 Oct 2004 19:34:00 -0000 1.13 --- Constructor.java 5 Nov 2004 14:57:57 -0000 1.14 *************** *** 82,86 **** return super.explainWhyMatchFails(arguments); ! String name = classe.getName(); StringBuffer res = new StringBuffer(); --- 82,86 ---- return super.explainWhyMatchFails(arguments); ! String name = classe.getName().toString(); StringBuffer res = new StringBuffer(); *************** *** 143,147 **** private String syntaxExample() { ! String name = classe.getName(); StringBuffer res = new StringBuffer(); res.append("Use the following syntax:\n") --- 143,147 ---- private String syntaxExample() { ! String name = classe.getName().toString(); StringBuffer res = new StringBuffer(); res.append("Use the following syntax:\n") Index: tools.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/tools.nice,v retrieving revision 1.54 retrieving revision 1.55 diff -C2 -d -r1.54 -r1.55 *** tools.nice 14 Oct 2004 09:37:27 -0000 1.54 --- tools.nice 5 Nov 2004 14:57:57 -0000 1.55 *************** *** 176,180 **** Location loc = ident.location(); ! call.function = createOverloadedSymbolExp(classe.getConstructorCallSymbols(), FormalParameters.thisName); notNull(call.function).setLocation(loc); --- 176,180 ---- Location loc = ident.location(); ! call.function = createOverloadedSymbolExp(new ArrayList(cast(classe).getConstructorCallSymbols()), FormalParameters.thisName); notNull(call.function).setLocation(loc); *************** *** 208,212 **** <T> String map(String, String, String, Collection<T>) = native String bossa.util.Util.map(String, String, String, Collection); Stack<bossa.link.Alternative> sortedAlternatives(MethodDeclaration) = native Stack bossa.link.Alternative.sortedAlternatives(MethodDeclaration); - List<VarSymbol> getConstructorCallSymbols(NiceClass) = native List NiceClass.getConstructorCallSymbols(); LinkedList<VarSymbol> getConstructors(mlsub.typing.TypeConstructor) = native LinkedList TypeConstructors.getConstructors(mlsub.typing.TypeConstructor); List<VarSymbol> symbols(EnumDefinition) = native EnumDefinition.symbols; --- 208,211 ---- *************** *** 228,233 **** ?mlsub.typing.Constraint getConstraint(mlsub.typing.Polytype) = native mlsub.typing.Constraint mlsub.typing.Polytype.getConstraint(); MonoSymbol[?] getMonoSymbols(FormalParameters) = native MonoSymbol[] FormalParameters.getMonoSymbols(); ! // Retypings needed since java types are not strict. mlsub.typing.Polytype boolPolytype() = native PrimitiveType.boolPolytype; mlsub.typing.Polytype longPolytype() = native PrimitiveType.longPolytype; --- 227,248 ---- ?mlsub.typing.Constraint getConstraint(mlsub.typing.Polytype) = native mlsub.typing.Constraint mlsub.typing.Polytype.getConstraint(); MonoSymbol[?] getMonoSymbols(FormalParameters) = native MonoSymbol[] FormalParameters.getMonoSymbols(); ! mlsub.typing.AtomicConstraint[?] AtomicConstraint_substitute(java.util.Map<mlsub.typing.TypeSymbol,mlsub.typing.TypeSymbol>, AtomicConstraint[?]) = native mlsub.typing.AtomicConstraint[] mlsub.typing.AtomicConstraint.substitute(java.util.Map, mlsub.typing.AtomicConstraint[]); ! NiceClass classe(Constructor) = native Constructor.classe; ! FormalParameters parameters(MethodDeclaration) = native MethodDeclaration.parameters; ! ?gnu.expr.Expression getInitializer(NiceClass) = native gnu.expr.Expression NiceClass.getInitializer(); ! void addConstructorCallSymbol(NiceClass, MethodDeclaration.Symbol) = native void NiceClass.addConstructorCallSymbol(MethodDeclaration.Symbol); ! gnu.expr.Expression callSuperMethod(NiceClass, gnu.bytecode.Method) = native gnu.expr.Expression NiceClass.callSuperMethod(gnu.bytecode.Method); ! Module module(Definition) = native Definition.module; ! ?Definition importMethod(NiceClass, gnu.bytecode.Method) = native Definition NiceClass.importMethod(gnu.bytecode.Method); ! boolean equals(LocatedString, LocatedString) = native boolean LocatedString.equals(LocatedString); ! ?mlsub.typing.TypeConstructor getSuperClass(ClassDefinition) = native mlsub.typing.TypeConstructor ClassDefinition.getSuperClass(); ! List<mlsub.typing.Interface> interfaces(ClassDefinition) = native ClassDefinition.interfaces; ! List<FormalParameters.Parameter> getParameters(FormalParameters, TypeScope) = native List FormalParameters.getParameters(TypeScope); ! mlsub.typing.AtomicConstraint[?] resolvedConstraints(MethodContainer) = native MethodContainer.resolvedConstraints; ! mlsub.typing.TypeSymbol[?] getBinders(MethodContainer) = native mlsub.typing.TypeSymbol[] MethodContainer.getBinders(); ! ?Expression value(FormalParameters.Parameter) = native Expression FormalParameters.Parameter.value(); ! ?LinkedList<MethodDeclaration.Symbol> getConstructors(TypeConstructor) = native LinkedList TypeConstructors.getConstructors(TypeConstructor); + // Retypings needed since java types are not strict. mlsub.typing.Polytype boolPolytype() = native PrimitiveType.boolPolytype; mlsub.typing.Polytype longPolytype() = native PrimitiveType.longPolytype; Index: ImportedConstructor.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/ImportedConstructor.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** ImportedConstructor.java 7 Oct 2004 15:29:29 -0000 1.1 --- ImportedConstructor.java 5 Nov 2004 14:57:57 -0000 1.2 *************** *** 47,59 **** super(def, Attribute.get(method, "default") != null, ! def.definition.location(), FormalParameters.readBytecodeAttribute (attr, JavaClasses.compilation.parser), ! def.definition.classConstraint == null ? ! null : def.definition.classConstraint.shallowClone(), ! returnType(def.definition)); this.method = method; ! TypeConstructors.addConstructor(classe.definition.tc, this); } --- 47,59 ---- super(def, Attribute.get(method, "default") != null, ! def.getDefinition().location(), FormalParameters.readBytecodeAttribute (attr, JavaClasses.compilation.parser), ! def.getDefinition().classConstraint == null ? ! null : def.getDefinition().classConstraint.shallowClone(), ! returnType(def.getDefinition())); this.method = method; ! TypeConstructors.addConstructor(classe.getDefinition().tc, this); } Index: CustomConstructor.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/CustomConstructor.java,v retrieving revision 1.21 retrieving revision 1.22 diff -C2 -d -r1.21 -r1.22 *** CustomConstructor.java 7 Oct 2004 22:03:43 -0000 1.21 --- CustomConstructor.java 5 Nov 2004 14:57:57 -0000 1.22 *************** *** 158,162 **** if (mlsub.typing.Constraint.hasBinders(cst)) parameters.substitute ! (map(cst.binders(), classe.definition.getTypeParameters())); lambda.addBytecodeAttribute(parameters.asBytecodeAttribute()); --- 158,162 ---- if (mlsub.typing.Constraint.hasBinders(cst)) parameters.substitute ! (map(cst.binders(), classe.getTypeParameters())); lambda.addBytecodeAttribute(parameters.asBytecodeAttribute()); --- NEW FILE: niceclass.nice --- /**************************************************************************/ /* N I C E */ /* A high-level object-oriented research language */ /* (c) Daniel Bonniot 2004 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /**************************************************************************/ package bossa.syntax; import bossa.util.*; /** Concrete Nice Class definition. */ public class CNiceClass extends NiceClass { ClassDefinition definition; private List<NewField> fields = new ArrayList(); private List<OverridenField> overrides = new ArrayList(); private List<ValueOverride> valueOverrides = new ArrayList(); private List<Statement> initializers = new ArrayList(); private ?Long serialVersionUIDValue = null; private ?MonoSymbol thisSymbol = null; private ?gnu.expr.Expression thisExp = null; /** List of symbols for calling constructors of this class. */ private List<MethodDeclaration.Symbol> constructors = new ArrayList(); private Constructor[?] constructorMethod = null; // Used to resolve fields, and constructor constraint. private ?TypeScope localScope = null; /** Reference to the method performing instance initialization for this class. */ private ?gnu.expr.Expression initializerMethod = null; gnu.expr.ClassExp classe = cast(null); { /* We always generate a new ClassExp object, even for classes from already compiled packages. The reason is that we might need to add methods for the multiple dispatch of java methods in the class (and maybe for adding fields, or optimizing the dispatch of Nice methods in the future). However, the ClassExp object refers to the existing ClassType object, and only adds or modifies features when needed. */ classe = notNull(definition.module).getClassExp(this); } getName() = definition.getName(); getDefinition() = definition; getTypeParameters() = definition.getTypeParameters(); addField(sym, value, isFinal, isTransient, isVolatile, docString) { if (this.isInterface()) bossa.util.User.error(sym, "An interface cannot have a field."); if (isFinal && notNull(sym).getName().toString().equals("serialVersionUID")) { if (value instanceof ConstantExp && value.value instanceof Long) serialVersionUIDValue = cast(value.value); else bossa.util.User.error(sym, "the value of an serialVersionUID should a constant of type long"); return; } if (isFinal && isVolatile) throw bossa.util.User.error(sym, "A field cannot be final and volatile"); fields.add(new NewField(declaringClass: this, sym: notNull(sym), value: value, isFinal_: isFinal, isVolatile: isVolatile, isTransient: isTransient, docString: docString)); } public void addOverride(MonoSymbol sym, ?Expression value) { if (this.isInterface()) bossa.util.User.error(sym, "An interface cannot have a field."); overrides.add(new OverridenField(declaringClass: this, sym: sym, value: value)); } public void addValueOverride(LocatedString fname, Expression value) { if (this.isInterface()) bossa.util.User.error(fname, "An interface cannot have a field."); valueOverrides.add(new ValueOverride(declaringClass: this, name: fname, value: value)); } isInterface() = definition instanceof ClassDefinition.Interface; ?CNiceClass getParent() { return cast(NiceClass.get(definition.getSuperClass())); } addConstructorCallSymbol(sym) { constructors.add(sym); } List<MethodDeclaration.Symbol> getConstructorCallSymbols() = new LinkedList(constructors); resolveClass() { classe.supers = cast(this.computeSupers()); localScope = definition.getLocalScope(); definition.setJavaType(classe.getType()); this.resolveFields(); this.resolveIntitializers(); this.createDefaultConstructors(); this.addPublicCloneMethod(); } private void resolveFields() { for (field : fields) field.resolve(notNull(definition.scope), notNull(localScope)); for (o : overrides) o.resolve(notNull(definition.scope), notNull(localScope)); for (valueOverride : valueOverrides) valueOverride.resolve(notNull(definition.scope), notNull(localScope)); } private ?gnu.expr.Declaration getOverridenField (OverridenField field, boolean checkValue) { let name = field.getName(); for (original : fields) if (original.hasName(name)) { if (! original.isFinal()) bossa.util.User.error(name, "The original field in class " + this + " is not final, so its type cannot be overriden"); checkValue = field.checkOverride(original, checkValue); return original.method.fieldDecl; } for (original : overrides) if (original.hasName(name)) checkValue = field.checkOverride(original, checkValue); if (checkValue) for (original : valueOverrides) if (original.hasName(name)) { field.checkOverride(original); checkValue = false; break; } let parent = this.getParent(); if (parent != null) return parent.getOverridenField(field, checkValue); else return null; } private boolean checkValueOverride(LocatedString name, Expression value) { ?NiceField original = null; for (field : fields) if (field.hasName(name)) original = field; for (or : overrides) if (or.hasName(name)) original = or; if (original != null) { this.enterTypingContext(); let declaredType = original.sym.getType(); value = value.resolveOverloading(declaredType); typecheck(value); try { Typing.leq(value.getType(), declaredType); } catch (mlsub.typing.TypingEx ex) { bossa.util.User.error(name, "Value does not fit in the overriden field of type " + declaredType); } return true; } let parent = this.getParent(); if (parent != null) return parent.checkValueOverride(name, value); else return false; } /**************************************************************** * Initializers ****************************************************************/ public void addInitializer(Statement init) { initializers.add(init); } private void resolveIntitializers() { if (initializers.isEmpty()) return; VarScope scope = notNull(definition.scope); mlsub.typing.Monotype thisType = Monotype.sure(new mlsub.typing.MonotypeConstructor(definition.tc, definition.getTypeParameters())); thisSymbol = new ThisSymbol(FormalParameters.thisName, thisType, declaringClass: this); Node.thisExp = new SymbolExp(thisSymbol, definition.location()); scope.addSymbol(thisSymbol); for (int i = 0; i < initializers.size(); i++) initializers[i] = analyse(initializers[i], notNull(definition.scope), notNull(localScope), false); Node.thisExp = null; scope.removeSymbol(thisSymbol); } getInitializer() { if (initializerMethod != null) return notNull(initializerMethod); ?gnu.expr.Expression parentInitializer = null; let parent = this.getParent(); if (parent != null) { parentInitializer = parent.getInitializer(); } if (initializers.size() == 0 && parentInitializer == null) return null; gnu.expr.Expression[] params = cast(new gnu.expr.Expression[1]); let lambda = nice.tools.code.Gen.createMemberMethod("$init", classe.getType(), null, gnu.bytecode.Type.void_type, params); thisExp = params[0]; List<gnu.expr.Expression> body = new ArrayList(); if (parentInitializer != null) body.add(nice.tools.code.Gen.superCall(parentInitializer, [notNull(thisExp)])); for (init : initializers) body.add(init.generateCode()); nice.tools.code.Gen.setMethodBody(lambda, new gnu.expr.BeginExp(body.toArray())); initializerMethod = this.addJavaMethod(lambda); return initializerMethod; } /**************************************************************** * Type checking ****************************************************************/ typecheck() { try { for (field : fields) field.typecheck(); for (or : overrides) or.typecheck(); for (valueOverride : valueOverrides) valueOverride.typecheck(); if (! initializers.isEmpty()) { this.enterTypingContext(); Node.thisExp = new SymbolExp(thisSymbol, definition.location()); for (init : initializers) typecheck(init); } } finally { if (entered) { entered = false; Node.thisExp = null; try { mlsub.typing.Typing.leave(); } catch(TypingEx ex) { User.error(this.definition, "Type error in field declarations"); } } } } private boolean entered = false; private void enterTypingContext() { if (entered || definition.classConstraint == null) return; mlsub.typing.Typing.enter(); entered = true; mlsub.typing.lowlevel.Element[] typeParameters = cast(notNull(definition.classConstraint).typeParameters); mlsub.typing.Typing.introduce(typeParameters); try { mlsub.typing.Typing.implies(); } catch(mlsub.typing.TypingEx ex) { bossa.util.Internal.error(ex); } } printInterface(s) { notNull(s).print(" {\n" + Util.map("", ";\n", ";\n", fields) + Util.map("", ";\n", ";\n", overrides) + ((serialVersionUIDValue == null) ? "" : ("final long serialVersionUID = " + serialVersionUIDValue + "L;\n")) + "}\n\n" ); } private void addPublicCloneMethod() { if (! definition.implementsJavaInterface("java.lang.Cloneable")) return; gnu.expr.Expression[] params = cast(new gnu.expr.Expression[1]); let lambda = this.createJavaMethod("clone", cloneMethod, params); nice.tools.code.Gen.setMethodBody (lambda, new gnu.expr.ApplyExp(nice.tools.code.Gen.superCaller(cloneMethod), params)); this.addJavaMethod(lambda); } createClassExp() { gnu.expr.ClassExp res = new gnu.expr.ClassExp(); res.setName(this.getName().toString()); definition.location().write(res); res.setSimple(true); res.setAccessFlags(definition.getBytecodeFlags()); definition.module.addUserClass(res); return res; } getClassExp() = classe; /** Collect in 'constraints' the constraints set by each class on the type parameters. */ private List<(?MethodDeclaration, List<FormalParameters.Parameter>)> getNativeConstructorParameters(TypeConstructor tc) { let constructors = TypeConstructors.getConstructors(tc); if (constructors == null) { // null stands for the Object() constructor return new ArrayList([(null, new ArrayList())]); } List<(?MethodDeclaration, List<FormalParameters.Parameter>)> res = new ArrayList(constructors.size()); for (msym : constructors) { let m = msym.getMethodDeclaration(); // Only consider parent methods for which a call from this class // is legal. if (m instanceof JavaMethod) { let thisClass = classe.getClassType(); if (! gnu.bytecode.Access.legal(thisClass, m.reflectMethod, thisClass)) continue; } List<FormalParameters.Parameter> params = new ArrayList(); for (arg : m.getArgTypes()) params.add(new FormalParameters.Parameter(Monotype.create(arg))); res.add((m, params)); } return res; } private List<(?MethodDeclaration, List<FormalParameters.Parameter>)> getParentConstructorParameters(mlsub.typing.Monotype[?] typeParameters, ?List<mlsub.typing.AtomicConstraint> constraints) { TypeScope scope = Node.getGlobalTypeScope(); ?Map<TypeSymbol,TypeSymbol> map = null; if (typeParameters != null) { // Constructs a type scope that maps the type parameters of this // class to the corresponding symbol in the constructor. scope = new TypeScope(scope); map = new HashMap(); let ourTypeParameters = definition.getTypeParameters(); for (int i = 0; i < ourTypeParameters.length; i++) try { TypeSymbol ourSym = asTypeSymbol(ourTypeParameters[i]); TypeSymbol sym = asTypeSymbol(typeParameters[i]); scope.addMapping(ourSym.toString(), sym); notNull(map).put(ourSym, sym); } catch(TypeScope.DuplicateName e) {} } List<(?MethodDeclaration, List<FormalParameters.Parameter>)> res = new ArrayList(); for (msym : constructors) { let decl = msym.getMethodDeclaration(); res.add((decl, decl.formalParameters().getParameters(scope))); } if (definition.classConstraint != null) { let newAtoms = mlsub.typing.AtomicConstraint.substitute(notNull(map), cast(definition.resolvedConstraints)); if (newAtoms != null) notNull(constraints).addAll(newAtoms); } return res; } private List<(?MethodDeclaration, List<FormalParameters.Parameter>)> getConstructorParameters(?List<mlsub.typing.AtomicConstraint> constraints, mlsub.typing.Monotype[] typeParameters) { let supTC = definition.getSuperClass(); let ?NiceClass sup = (supTC == null) ? null : NiceClass.get(supTC); List<(?MethodDeclaration, List<FormalParameters.Parameter>)> res; if (sup == null) res = this.getNativeConstructorParameters(cast(supTC)); else res = cast(sup).getParentConstructorParameters(typeParameters, constraints); /** This must be done in a given class for every subclass, since they have different type parameters. */ if ((! overrides.isEmpty()) || (! valueOverrides.isEmpty())) for (cparams : res) { (?MethodDeclaration m, List<FormalParameters.Parameter> params) = cparams; for (or : overrides) or.updateConstructorParameter(params); for (valueOverride : valueOverrides) valueOverride.updateConstructorParameter(params); } if (! fields.isEmpty()) for (cparams : res) { (?MethodDeclaration m, List<FormalParameters.Parameter> params) = cparams; for (field : fields) params.add(field.asParameter()); } if (definition.resolvedConstraints != null) notNull(constraints).addAll(notNull(definition.resolvedConstraints)); return res; } /** This must be done only once per class. */ private void checkFields(List<FormalParameters.Parameter> allFields) { for (int f = 0; f < fields.size(); f++) fields[f].checkNoDuplicate(allFields, f); List<LocatedString> names = overrides.map(OverridenField o => o.sym.getName()); names.addAll(valueOverrides.map(ValueOverride o => o.name())); for (int i = 0; i < names.size(); i++) for (int k = i+1; k < names.size(); k++) if (names[i].equals(names[k])) User.error(names[k], "A field override of the same field exists in this class"); } private void createDefaultConstructors() { if (definition.inInterfaceFile()) // The constructors are loaded from the compiled package. return; if (this.isInterface()) return; ?List<mlsub.typing.AtomicConstraint> constraints; let binders = definition.getBinders(); if (binders == null) constraints = null; else constraints = new LinkedList(); mlsub.typing.Monotype[] typeParameters = definition.getTypeParameters(); List<(?MethodDeclaration, List<FormalParameters.Parameter>)> allConstructorParams = this.getConstructorParameters(constraints, typeParameters); mlsub.typing.Constraint cst; if (binders != null) cst = new mlsub.typing.Constraint(binders, constraints == null ? null : constraints.toArray()); else cst = mlsub.typing.Constraint.True; constructorMethod = cast(new Constructor[allConstructorParams.size()]); for (int i = 0; i < allConstructorParams.size(); i++) { (?MethodDeclaration parent, List<FormalParameters.Parameter> params) = allConstructorParams[i]; // Check only once. if (i == 0) this.checkFields(params); FormalParameters values = new FormalParameters(params.toArray()); notNull(constructorMethod)[i] = new DefaultConstructor (this, true, definition.location(), values, cst, Monotype.resolve(definition.getLocalScope(), values.types()), Monotype.sure(new mlsub.typing.MonotypeConstructor(definition.tc, definition.getTypeParameters())), fields: fields, parent: parent); TypeConstructors.addConstructor(definition.tc, notNull(constructorMethod)[i]); } } precompile() { // We have to do this after resolution, so that bytecode types are known, // but before compilation. for (field : fields) field.createField(); } compile() { this.recompile(); this.createSerialUIDField(); } /** Called instead of compile if the package is up-to-date. */ recompile() { // This needs to be done even if we don't recompile, // since classes are always regenerated. if (constructorMethod != null) for (int i = 0; i < notNull(constructorMethod).length; i++) notNull(constructorMethod)[i].getCode(); // Take into account external interface implementations, which // can add new interfaces to implement in the bytecode. classe.supers = cast(this.computeSupers()); classe.recomputeInterfaces(); } private gnu.expr.Expression[?] computeSupers() { List<gnu.expr.Expression> res = new ArrayList(); let superClass = definition.getSuperClass(); if (superClass != null) res.add(typeExpression(superClass)); for (intf : definition.interfaces) { let ?mlsub.typing.TypeConstructor assocTC = intf.associatedTC(); if (assocTC != null) res.add(typeExpression(assocTC)); } if (definition.javaInterfaces != null) for (itf : notNull(definition.javaInterfaces)) res.add(typeExpression(notNull(itf))); if (res.isEmpty()) return null; return res.toArray(); } /** This native method is redefined for this Nice class. */ addJavaMethod(method) = classe.addMethod(method); private gnu.expr.LambdaExp createJavaMethod(String name, gnu.bytecode.Method likeMethod, gnu.expr.Expression[] params) { return nice.tools.code.Gen.createMemberMethod(name, this.getClassExp().getType(), likeMethod.getParameterTypes(), likeMethod.getReturnType(), params); } /** Returns an expression to call a super method from outside a class method. This is needed because the JVM restricts call to a specific implementation to occur inside a method of the same class. So this generates a stub class method that calls the desired super method, and return a reference to this stub. */ callSuperMethod(superMethod) { gnu.expr.Expression[] params = cast(new gnu.expr.Expression [superMethod.getParameterTypes().length + 1]); let lambda = this.createJavaMethod("$super$" + superMethod.getName(), superMethod, params); nice.tools.code.Gen.setMethodBody(lambda, new gnu.expr.ApplyExp(new gnu.expr.QuoteExp( gnu.expr.PrimProcedure.specialCall(superMethod)), params)); return this.addJavaMethod(lambda); } void createSerialUIDField() { if (serialVersionUIDValue == null) return; let fieldDecl = classe.addDeclaration("serialVersionUID", nice.tools.code.SpecialTypes.longType); fieldDecl.setSimple(false); fieldDecl.setCanRead(true); fieldDecl.setFlag(gnu.expr.Declaration.IS_CONSTANT); fieldDecl.setSpecifiedPrivate(true); fieldDecl.setFlag(gnu.expr.Declaration.STATIC_SPECIFIED); fieldDecl.setFlag(gnu.expr.Declaration.TYPE_SPECIFIED); fieldDecl.noteValue(new gnu.expr.QuoteExp(serialVersionUIDValue, nice.tools.code.SpecialTypes.longType)); } importMethod(gnu.bytecode.Method method) { if (method.isConstructor()) return ImportedConstructor.load(this, method); if (method.getArity() == 0 && method.getName().equals("$init")) initializerMethod = nice.tools.code.Gen.superCaller(method); return null; } toString() = definition.toString(); } let gnu.bytecode.Method cloneMethod = notNull(gnu.bytecode.Type.pointer_type).getDeclaredMethod("clone", 0); class ThisSymbol extends MonoSymbol { compile() = notNull(declaringClass.thisExp); final CNiceClass declaringClass; } NiceClass createNiceClass(ClassDefinition cdef) = new CNiceClass(definition: cdef); private TypeSymbol asTypeSymbol(mlsub.typing.Monotype type) { if (type instanceof TypeSymbol) return type; assert (type instanceof mlsub.typing.MonotypeConstructor); return type.getTC(); } private gnu.expr.Expression typeExpression(TypeConstructor tc) { let c = ClassDefinition.get(tc); if (c != null && c.implementation instanceof NiceClass) { CNiceClass nc = cast(c.implementation); return nc.classe; } else return new gnu.expr.QuoteExp(nice.tools.code.Types.javaType(tc)); } Index: NiceClass.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/NiceClass.java,v retrieving revision 1.91 retrieving revision 1.92 diff -C2 -d -r1.91 -r1.92 *** NiceClass.java 15 Oct 2004 12:56:21 -0000 1.91 --- NiceClass.java 5 Nov 2004 14:57:57 -0000 1.92 *************** *** 2,6 **** /* N I C E */ /* A high-level object-oriented research language */ ! /* (c) Daniel Bonniot 2002 */ /* */ /* This program is free software; you can redistribute it and/or modify */ --- 2,6 ---- /* N I C E */ /* A high-level object-oriented research language */ ! /* (c) Daniel Bonniot 2004 */ /* */ [...1219 lines suppressed...] ! /**************************************************************** ! * Misc. ! ****************************************************************/ ! public String toString() { return definition.toString(); } ! private NewField[] fields; ! private OverridenField[] overrides; ! private List valueOverrides; ! private Long serialVersionUIDValue; } --- 80,87 ---- stub. */ ! abstract gnu.expr.Expression callSuperMethod(gnu.bytecode.Method superMethod); ! abstract public Definition importMethod(gnu.bytecode.Method method); ! abstract public mlsub.typing.Monotype[] getTypeParameters(); } --- NEW FILE: nicefield.nice --- /**************************************************************************/ /* N I C E */ /* A high-level object-oriented research language */ /* (c) Daniel Bonniot 2004 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /**************************************************************************/ /** A field or field override in a Nice class. */ abstract class NiceField { CNiceClass declaringClass; MonoSymbol sym; ?Expression value; NiceFieldAccess method = cast(null); { sym.propagate = Node.none; method = createNiceFieldAccess(this); declaringClass.definition.addChild(method); } ClassDefinition getClassDefinition() = declaringClass.definition; LocatedString getName() = sym.getName(); boolean hasName(LocatedString name) = sym.hasName(name); boolean isFinal(); void resolve(VarScope scope, TypeScope typeScope) { sym.type = notNull(sym.syntacticType).resolve(typeScope); if (nice.tools.typing.Types.isVoid(sym.type)) bossa.util.User.error(sym, "A field cannot have void type"); value = dispatch.analyse(value, scope, typeScope); } FormalParameters.Parameter asParameter() { Monotype type = notNull(sym.syntacticType); if (value == null) return new FormalParameters.NamedParameter(type, sym.getName(), true); else return new FormalParameters.OptionalParameter (type, sym.getName(), true, value); } void typecheck() { if (value != null) { declaringClass.enterTypingContext(); mlsub.typing.Polytype declaredType = sym.getType(); value = notNull(value).resolveOverloading(declaredType); dispatch.typecheck(notNull(value)); try { Typing.leq(notNull(value).getType(), declaredType); } catch (mlsub.typing.TypingEx ex) { throw assignmentError(notNull(value), sym.getName().toString(), sym.getType().toString(), notNull(value)); } } } toString() = sym + (value == null ? "" : " = " + value); } final class NewField extends NiceField { boolean isFinal_; boolean isTransient; boolean isVolatile; public ?String docString; isFinal() = isFinal_; void createField() { let decl = declaringClass.classe.addField (sym.name.toString(), nice.tools.code.Types.javaType(sym.type)); method.fieldDecl = decl; decl.setFlag(isFinal_, gnu.expr.Declaration.IS_CONSTANT); decl.setFlag(isTransient, gnu.expr.Declaration.TRANSIENT); decl.setFlag(isVolatile , gnu.expr.Declaration.VOLATILE); if (! declaringClass.definition.inInterfaceFile()) { String fname = sym.getName().toString(); String suffix = Character.toUpperCase(fname.charAt(0)) + fname.substring(1); this.createGetter(suffix); if (!isFinal_) this.createSetter(suffix); } } void createGetter(String nameSuffix) { gnu.expr.Expression[] params = cast(new gnu.expr.Expression[1]); let getter = nice.tools.code.Gen.createMemberMethod("get"+nameSuffix, declaringClass.classe.getType(), null, notNull(method.fieldDecl).getType(), params); nice.tools.code.Gen.setMethodBody(getter, NiceUtils.doInline(new nice.tools.code.GetFieldProc(method.fieldDecl), params[0])); declaringClass.classe.addMethod(getter); } void createSetter(String nameSuffix) { gnu.expr.Expression[] params = cast(new gnu.expr.Expression[2]); gnu.bytecode.Type[] argTypes = [notNull(method.fieldDecl).getType()]; let setter = nice.tools.code.Gen.createMemberMethod("set"+nameSuffix, declaringClass.classe.getType(), argTypes, notNull(method.fieldDecl).getType(), params); nice.tools.code.Gen.setMethodBody(setter, NiceUtils.doInline(new nice.tools.code.SetFieldProc(method.fieldDecl), params[0], params[1])); declaringClass.classe.addMethod(setter); } void checkNoDuplicate(List<FormalParameters.Parameter> fields, int rankInThisClass) { /* We check that there is no duplicate in all the inherited fields, but also in the fields of this class stricly before this one. */ int max = fields.size() - declaringClass.fields.size() + rankInThisClass; String name = sym.getName().toString(); for (int i = 0; i < max; i++) if (fields[i].match(name)) bossa.util.User.error(sym, (max - i >= declaringClass.fields.size()) ? "A field with the same name exists in a super-class" : "A field with the same name exists in this class"); } toString()= (isFinal_ ? "final " : "") + super; } final class OverridenField extends NiceField { isFinal() = true; /** Update the type and default values for the constructor, according to this overriding. */ void updateConstructorParameter(List<FormalParameters.Parameter> inherited) { String name = sym.getName().toString(); Monotype type = notNull(sym.syntacticType); for (int i = 0; i < inherited.size(); i++) { let param = inherited[i]; if (param.match(name)) { if (value != null) inherited[i] = new FormalParameters.OptionalParameter(type, sym.getName(), true, value, param.value() == null || param.isOverriden()); else param.resetType(type); } } } typecheck() { ?gnu.expr.Declaration decl = null; let parent = declaringClass.getParent(); if (parent != null) decl = parent.getOverridenField(this, value == null); if (decl == null) throw bossa.util.User.error(sym, "No field with this name exists in a super-class"); method.fieldDecl = decl; super; } /** @param checkValue Whether to check that the original field's value, if it exists, must be checked against the overriden type. @return the checkValue to be used for other versions of this field higher up in the hierarchy. */ boolean checkOverride(NiceField original, boolean checkValue) { declaringClass.enterTypingContext(); mlsub.typing.Monotype originalType = notNull(original.sym.syntacticType).resolve (original.declaringClass.translationScope(declaringClass)); try { Typing.leq(this.sym.type, originalType); } catch (TypingEx ex) { User.error(this.sym, "The new type must be a subtype of the original type declared in " + original.declaringClass + ".\n" + "Original type: " + originalType); } if (checkValue && original.value != null) { this.checkValue(notNull(original.value), original.declaringClass); return false; } return checkValue; } void checkOverride(ValueOverride original) { this.checkValue(original.value, original.declaringClass); } private void checkValue(Expression value, NiceClass location) { try { Typing.leq(value.getType(), this.sym.getType()); } catch (mlsub.typing.TypingEx ex) { User.error(sym, "The default value declared in " + location + "\nis not compatible with the overriden type"); } } toString() = "override " + super; } public final class ValueOverride { CNiceClass declaringClass; LocatedString name; Expression value; boolean hasName(LocatedString name) = this.name.equals(name); void updateConstructorParameter(List<FormalParameters.Parameter> inherited) { for (int i = 0; i < inherited.size(); i++) { let param = inherited[i]; if (param.match(name.toString())) inherited[i] = new FormalParameters.OptionalParameter(param.type, name, true, value, param.value() == null || param.isOverriden()); } } void resolve(VarScope scope, TypeScope typeScope) { value = analyse(value, scope, typeScope); } void typecheck() { boolean exists = false; let parent = declaringClass.getParent(); if (parent != null) exists = parent.checkValueOverride(name, value); if (! exists) throw bossa.util.User.error(name, "No field with this name exists in a super-class"); } } /** @return the scope that maps the type parameters of the other class to the corresponding symbol in the constructor of this class. */ private TypeScope translationScope(CNiceClass this, CNiceClass other) { let binders = other.definition.getBinders(); let ourBinders = this.definition.getBinders(); TypeScope scope = Node.getGlobalTypeScope(); if (binders != null) { scope = new TypeScope(scope); for (int i = 0; i < binders.length; i++) try { scope.addMapping(notNull(ourBinders)[i].toString(), binders[i]); } catch(TypeScope.DuplicateName e) {} } return scope; } --- NEW FILE: defaultconstructor.nice --- /**************************************************************************/ /* N I C E */ /* A high-level object-oriented research language */ /* (c) Daniel Bonniot 2004 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /**************************************************************************/ package bossa.syntax; import bossa.util.*; /** A constructor automatically generated from the list of field of the class whose instances it constructs. */ class DefaultConstructor extends Constructor { { this.addConstructorCallSymbol(); } List<NewField> fields; ?MethodDeclaration parent; /** Call the constructor, with all the arguments. */ private ?gnu.expr.Expression initialize = null; /** Call the constructor, with all the arguments, with an implicit this argument. */ private ?gnu.expr.Expression initializeFromConstructor = null; /** Call the constructor, with only non-default arguments. */ private ?gnu.expr.Expression initializeOmitDefaults = null; /** Instantiate the class, calling the constructor with all the arguments. */ private ?gnu.expr.Expression instantiate = null; getInitializationCode(implicitThis) { this.getCode(); return notNull(initializeFromConstructor); } getConstructorInvocation(omitDefaults) { this.getCode(); return // lambdaOmitDefaults is null if the two versions are identical omitDefaults && initializeOmitDefaults != null ? notNull(initializeOmitDefaults) : notNull(initialize); } computeCode() { this.createBytecode(true); this.createBytecode(false); return notNull(instantiate); } /** @param omitDefaults if true, do not take the value of fields with default values as parameters, but use that default instead. */ private void createBytecode(boolean omitDefaults) { gnu.bytecode.ClassType thisType = cast(this.javaReturnType()); let thisDecl = new gnu.expr.Declaration("this"); thisDecl.setType(thisType); let thisExp = new gnu.expr.ThisExp(thisDecl); let fullArgs = notNull(parameters.getMonoSymbols()); let fullArgTypes = this.javaArgTypes(); List<MonoSymbol> args = new LinkedList(); List<gnu.bytecode.Type> argTypes = new LinkedList(); for (int i = 0; i < parameters.size; i++) { if (omitDefaults && parameters.hasDefaultValue(i)) continue; args.add(fullArgs[i]); argTypes.add(fullArgTypes[i]); } // Do not create a second constructor omiting defaults if there is // no default to omit! if (omitDefaults && args.size() == fullArgs.length) return; gnu.bytecode.Type[] argTypesArray = argTypes.toArray(); MonoSymbol[] argsArray = args.toArray(); if (classe.getDefinition().inInterfaceFile()) throw new Error("Constructors are loaded from the compiled package"); let lambda = nice.tools.code.Gen.createConstructor (thisDecl, argTypesArray, argsArray); lambda.setSuperCall(this.callSuper(thisExp, fullArgs, omitDefaults)); nice.tools.code.Gen.setMethodBody(lambda, this.body(thisExp, fullArgs, omitDefaults)); classe.getClassExp().addMethod(lambda); // Add attributes useful for the nice compiler. These are not needed // for the version omitting defaults, since that one is only there for // Java users' sake. if (! omitDefaults) { lambda.addBytecodeAttribute(parameters.asBytecodeAttribute()); lambda.addBytecodeAttribute(new gnu.bytecode.MiscAttr("default")); } if (omitDefaults) { initializeOmitDefaults = new gnu.expr.QuoteExp(new gnu.expr.InitializeProc(lambda)); } else { initialize = new gnu.expr.QuoteExp(new gnu.expr.InitializeProc(lambda)); initializeFromConstructor = new gnu.expr.QuoteExp(new gnu.expr.InitializeProc(lambda, true)); instantiate = new gnu.expr.QuoteExp(new gnu.expr.InstantiateProc(lambda)); } } private gnu.expr.Expression callSuper(gnu.expr.Expression thisExp, MonoSymbol[] args, boolean omitDefaults) { int len = args.length - fields.size(); List<gnu.expr.Expression> superArgs = new LinkedList(); superArgs.add(thisExp); for (int i = 0; i < len; i++) { if (! (omitDefaults && parameters.hasDefaultValue(i))) superArgs.add(args[i].compile()); } // A null parent means no parent class: call the Object constructor. let superExp = parent == null ? objectConstructor : notNull(parent).getConstructorInvocation(omitDefaults); return new gnu.expr.ApplyExp(superExp, superArgs.toArray()); } private gnu.expr.Expression body(gnu.expr.Expression thisExp, MonoSymbol[] fullArgs, boolean omitDefaults) { List<gnu.expr.Expression> body = new ArrayList(); let superArgs = fullArgs.length - fields.size(); for (int i = 0; i < fields.size(); i++) { let value = fields[i].value; gnu.expr.Expression fieldValue; if (!omitDefaults || value == null) // Use the provided parameter. fieldValue = fullArgs[superArgs + i].compile(); else // Use the default value. fieldValue = value.compile(); body.add(fields[i].method.compileAssign(thisExp, fieldValue)); } let initializer = classe.getInitializer(); if (initializer != null) body.add(new gnu.expr.IfExp( nice.tools.code.Gen.isOfClass(thisExp, classe.getClassExp().getType(), false), new gnu.expr.ApplyExp(initializer, [thisExp]), gnu.expr.QuoteExp.voidExp)); if (body.isEmpty()) return gnu.expr.QuoteExp.voidExp; return new gnu.expr.BeginExp(body.toArray()); } } let gnu.expr.Expression objectConstructor = new gnu.expr.QuoteExp (new gnu.expr.InitializeProc( notNull(gnu.bytecode.Type.pointer_type).getDeclaredMethod("<init>", 0))); Index: NiceUtils.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/NiceUtils.java,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** NiceUtils.java 28 Jul 2004 14:40:33 -0000 1.1 --- NiceUtils.java 5 Nov 2004 14:57:57 -0000 1.2 *************** *** 20,23 **** --- 20,28 ---- } + public static gnu.expr.Expression doInline(gnu.mapping.Procedure2 proc, gnu.expr.Expression arg1, gnu.expr.Expression arg2) + { + return nice.tools.code.Inline.inline(proc, arg1, arg2); + } + } Index: new.nice =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/new.nice,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** new.nice 13 Oct 2004 23:22:22 -0000 1.4 --- new.nice 5 Nov 2004 14:57:57 -0000 1.5 *************** *** 60,64 **** definition.resolve(); ! ?LinkedList<VarSymbol> constructors = TypeConstructors.getConstructors(tc); if (constructors == null) { --- 60,64 ---- definition.resolve(); ! ?LinkedList<MethodDeclaration.Symbol> constructors = TypeConstructors.getConstructors(tc); if (constructors == null) { *************** *** 73,79 **** // the list of constructors must be cloned, as // OverloadedSymbolExp removes elements from it ! constructors = constructors.clone(); ! ! function = createOverloadedSymbolExp(notNull(constructors), new LocatedString("new " + tc, this.location())); } --- 73,77 ---- // the list of constructors must be cloned, as // OverloadedSymbolExp removes elements from it ! function = createOverloadedSymbolExp(new LinkedList(notNull(constructors)), new LocatedString("new " + tc, this.location())); } Index: EnumDefinition.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/EnumDefinition.java,v retrieving revision 1.16 retrieving revision 1.17 diff -C2 -d -r1.16 -r1.17 *** EnumDefinition.java 14 Oct 2004 15:42:11 -0000 1.16 --- EnumDefinition.java 5 Nov 2004 14:57:57 -0000 1.17 *************** *** 2,6 **** /* N I C E */ /* A high-level object-oriented research language */ ! /* (c) Daniel Bonniot 2003 */ /* */ /* This program is free software; you can redistribute it and/or modify */ --- 2,6 ---- /* N I C E */ /* A high-level object-oriented research language */ ! /* (c) Daniel Bonniot 2004 */ /* */ /* This program is free software; you can redistribute it and/or modify */ *************** *** 36,40 **** new MonotypeConstructor(new TypeIdent(new LocatedString("nice.lang.Enum",name.location())), null, this.location()), interfaces,null); ! NiceClass impl = new NiceClass(classDef); int fieldsCount = fields.size(); if (fieldsCount > 0) --- 36,40 ---- new MonotypeConstructor(new TypeIdent(new LocatedString("nice.lang.Enum",name.location())), null, this.location()), interfaces,null); ! NiceClass impl = dispatch.createNiceClass(classDef); int fieldsCount = fields.size(); if (fieldsCount > 0) *************** *** 42,55 **** List newFields = new ArrayList(fieldsCount); for (Iterator it = fields.iterator(); it.hasNext(); ) ! newFields.add(impl.makeField((MonoSymbol)it.next(), null, true, ! false, false, null)); - impl.setFields(newFields); } - else - impl.setFields(null); - - impl.setOverrides(null); - impl.setValueOverrides(null); if (! inInterfaceFile()) --- 42,49 ---- List newFields = new ArrayList(fieldsCount); for (Iterator it = fields.iterator(); it.hasNext(); ) ! impl.addField((MonoSymbol)it.next(), null, true, ! false, false, null); } if (! inInterfaceFile()) --- DefaultConstructor.java DELETED --- --- NEW FILE: nicefieldaccess.nice --- /**************************************************************************/ /* N I C E */ /* A high-level object-oriented research language */ /* (c) Daniel Bonniot 2004 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* */ /**************************************************************************/ package bossa.syntax; import bossa.util.*; /** A field access in a Nice class. In terms of scoping, this is the symbol that is returned when the access to a field is done, either a 'get' or a 'set'. */ public class NiceFieldAccess extends FieldAccess { final NiceField field; isFinal() = field.isFinal(); printInterface(s) { bossa.util.Internal.error("Should not be part of the module interface"); } toString() { return "" + field.sym.type + " " + field.getClassDefinition().name + "." + field.getName(); } } NiceFieldAccess createNiceFieldAccess(NiceField field) { let classDef = field.getClassDefinition(); let argType = Monotype.sure(classDef.lowlevelMonotype()); return new NiceFieldAccess(field.getName(), Constraint.create(classDef.getBinders()), new FormalParameters([new FormalParameters.Parameter(Monotype.create(argType))]), field.sym.syntacticType, field: field); } private FormalParameters makeList(mlsub.typing.Monotype t) { return new FormalParameters([new FormalParameters.Parameter(Monotype.create(t))]); } Index: MethodBodyDefinition.java =================================================================== RCS file: /cvsroot/nice/Nice/src/bossa/syntax/MethodBodyDefinition.java,v retrieving revision 1.154 retrieving revision 1.155 diff -C2 -d -r1.154 -r1.155 *** MethodBodyDefinition.java 11 Oct 2004 13:55:35 -0000 1.154 --- MethodBodyDefinition.java 5 Nov 2004 14:57:57 -0000 1.155 *************** *** 76,80 **** Pattern[] res = new Pattern[formals.size() + 1]; res[0] = bossa.syntax.dispatch.createPattern(new LocatedString("this", loc), ! new TypeIdent(container.definition.getName())); int n = 1; for(Iterator f = formals.iterator(); f.hasNext(); n++) --- 76,80 ---- Pattern[] res = new Pattern[formals.size() + 1]; res[0] = bossa.syntax.dispatch.createPattern(new LocatedString("this", loc), ! new TypeIdent(container.getName())); int n = 1; for(Iterator f = formals.iterator(); f.hasNext(); n++) --- NiceFieldAccess.java DELETED --- |