Browse Source

+ support for local enum types (defined in procedures), by stuffing their
corresponding classes into the global symtable ("local classes" don't
exist/work)

git-svn-id: branches/jvmbackend@18649 -

Jonas Maebe 14 years ago
parent
commit
112d17af84
1 changed files with 42 additions and 9 deletions
  1. 42 9
      compiler/pjvm.pas

+ 42 - 9
compiler/pjvm.pas

@@ -213,13 +213,31 @@ implementation
         sstate: tscannerstate;
         sstate: tscannerstate;
         sl: tpropaccesslist;
         sl: tpropaccesslist;
         temptypesym: ttypesym;
         temptypesym: ttypesym;
+        oldsymtablestack: tsymtablestack;
+        islocal: boolean;
       begin
       begin
         { if it's a subrange type, don't create a new class }
         { if it's a subrange type, don't create a new class }
         if assigned(tenumdef(def).basedef) then
         if assigned(tenumdef(def).basedef) then
           exit;
           exit;
         replace_scanner('jvm_enum_class',sstate);
         replace_scanner('jvm_enum_class',sstate);
-        { create new class (different internal name than enum to prevent name clash) }
-        enumclass:=tobjectdef.create(odt_javaclass,'$'+name+'$InternEnum',java_jlenum);
+        oldsymtablestack:=symtablestack;
+        islocal:=symtablestack.top.symtablelevel>=normal_function_level;
+        if islocal then
+          begin
+            { we cannot add a class local to a procedure -> insert it in the
+              static symtable. This is not ideal because this means that it will
+              be saved to the ppu file for no good reason, and loaded again
+              even though it contains a reference to a type that was never
+              saved to the ppu file (the locally defined enum type). Since this
+              alias for the locally defined enumtype is only used while
+              implementing the class' methods, this is however no problem. }
+            symtablestack:=symtablestack.getcopyuntil(current_module.localsymtable);
+          end;
+
+        { create new class (different internal name than enum to prevent name
+          clash; at unit level because we don't want its methods to be nested
+          inside a function in case its a local type) }
+        enumclass:=tobjectdef.create(odt_javaclass,'$'+current_module.realmodulename^+'$'+name+'$InternEnum$'+tostr(def.defid),java_jlenum);
         tenumdef(def).classdef:=enumclass;
         tenumdef(def).classdef:=enumclass;
         include(enumclass.objectoptions,oo_is_enum_class);
         include(enumclass.objectoptions,oo_is_enum_class);
         include(enumclass.objectoptions,oo_is_sealed);
         include(enumclass.objectoptions,oo_is_sealed);
@@ -227,25 +245,35 @@ implementation
           name that can be used in generated Pascal code without risking an
           name that can be used in generated Pascal code without risking an
           identifier conflict (since it is local to this class; the global name
           identifier conflict (since it is local to this class; the global name
           is unique because it's an identifier that contains $-signs) }
           is unique because it's an identifier that contains $-signs) }
-
-        temptypesym:=ttypesym.create('__FPC_TEnumClassAlias',nil);
-        { don't pass enumclass to the ttypesym constructor, because then it
-          will replace the current (real) typesym of that def with the alias }
-        temptypesym.typedef:=enumclass;
-        enumclass.symtable.insert(temptypesym);
+        enumclass.symtable.insert(ttypesym.create('__FPC_TEnumClassAlias',enumclass));
 
 
         { also create an alias for the enum type so that we can iterate over
         { also create an alias for the enum type so that we can iterate over
           all enum values when creating the body of the class constructor }
           all enum values when creating the body of the class constructor }
         temptypesym:=ttypesym.create('__FPC_TEnumAlias',nil);
         temptypesym:=ttypesym.create('__FPC_TEnumAlias',nil);
+        { don't pass def to the ttypesym constructor, because then it
+          will replace the current (real) typesym of that def with the alias }
         temptypesym.typedef:=def;
         temptypesym.typedef:=def;
         enumclass.symtable.insert(temptypesym);
         enumclass.symtable.insert(temptypesym);
         { but the name of the class as far as the JVM is concerned will match
         { but the name of the class as far as the JVM is concerned will match
           the enum's original name (the enum type itself won't be output in
           the enum's original name (the enum type itself won't be output in
           any class file, so no conflict there) }
           any class file, so no conflict there) }
-        enumclass.objextname:=stringdup(name);
+        if not islocal then
+          enumclass.objextname:=stringdup(name)
+        else
+          { for local types, use a unique name to prevent conflicts (since such
+            types are not visible outside the routine anyway, it doesn't matter
+          }
+          begin
+            enumclass.objextname:=stringdup(enumclass.objrealname^);
+            { also mark it as private (not strict private, because the class
+              is not a subclass of the unit in which it is declared, so then
+              the unit's procedures would not be able to use it) }
+            enumclass.typesym.visibility:=vis_private;
+          end;
         { now add a bunch of extra things to the enum class }
         { now add a bunch of extra things to the enum class }
         old_current_structdef:=current_structdef;
         old_current_structdef:=current_structdef;
         current_structdef:=enumclass;
         current_structdef:=enumclass;
+
         symtablestack.push(enumclass.symtable);
         symtablestack.push(enumclass.symtable);
         { create static fields representing all enums }
         { create static fields representing all enums }
         for i:=0 to tenumdef(def).symtable.symlist.count-1 do
         for i:=0 to tenumdef(def).symtable.symlist.count-1 do
@@ -337,6 +365,11 @@ implementation
         pd.synthetickind:=tsk_jvm_enum_classconstr;
         pd.synthetickind:=tsk_jvm_enum_classconstr;
 
 
         symtablestack.pop(enumclass.symtable);
         symtablestack.pop(enumclass.symtable);
+        if islocal then
+          begin
+            symtablestack.free;
+            symtablestack:=oldsymtablestack;
+          end;
         current_structdef:=old_current_structdef;
         current_structdef:=old_current_structdef;
         restore_scanner(sstate);
         restore_scanner(sstate);
       end;
       end;