# HG changeset patch # User Jan Vrany # Date 1412724824 -3600 # Node ID e2b2ccaa4de69ebcc95dbffd3e3ad46c6915f992 # Parent a409905f7f2d7451264c497d261df800ca8525c2 Commited a island parser support (MC package PetitIslands) Name: PetitIslands-JanKurs.10 Author: JanKurs Time: 06-10-2014, 11:50:57 AM UUID: 19560ad2-4899-43d5-8c69-cf7274ad4f04 Repository: http://smalltalkhub.com/mc/Moose/PetitParser/main diff -r a409905f7f2d -r e2b2ccaa4de6 Make.proto --- a/Make.proto Wed Oct 08 00:08:21 2014 +0100 +++ b/Make.proto Wed Oct 08 00:33:44 2014 +0100 @@ -69,11 +69,11 @@ mc: mkdir mc -mcz: mc - $(TOP)/projects/smalltalk/smalltalk --eval " \ - Smalltalk packagePath add:'$(TOP)' . \ - Smalltalk loadPackage:'stx:goodies/petitparser'. \ - (Smalltalk at: #'stx_goodies_petitparser') exportAsMczTo: 'mc'." +mcz: mc + $(TOP)/projects/smalltalk/smalltalk --eval " \ + Smalltalk packagePath add:'$(TOP)' . \ + Smalltalk loadPackage:'stx:goodies/petitparser'. \ + (Smalltalk at: #'stx_goodies_petitparser') exportAsMczTo: 'mc'." diff -r a409905f7f2d -r e2b2ccaa4de6 PPPredicateObjectParser.st --- a/PPPredicateObjectParser.st Wed Oct 08 00:08:21 2014 +0100 +++ b/PPPredicateObjectParser.st Wed Oct 08 00:33:44 2014 +0100 @@ -171,6 +171,11 @@ ^ '$Header: /cvs/stx/stx/goodies/petitparser/PPPredicateObjectParser.st,v 1.5 2014-03-04 14:33:20 cg Exp $' ! +version_HG + + ^ '$Changeset: $' +! + version_SVN ^ '$Id: PPPredicateObjectParser.st,v 1.5 2014-03-04 14:33:20 cg Exp $' ! ! diff -r a409905f7f2d -r e2b2ccaa4de6 analyzer/analyzer.rc --- a/analyzer/analyzer.rc Wed Oct 08 00:08:21 2014 +0100 +++ b/analyzer/analyzer.rc Wed Oct 08 00:33:44 2014 +0100 @@ -25,7 +25,7 @@ VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0" VALUE "ProductName", "Smalltalk/X\0" VALUE "ProductVersion", "6.2.4.0\0" - VALUE "ProductDate", "Tue, 07 Oct 2014 23:05:01 GMT\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:28 GMT\0" END END diff -r a409905f7f2d -r e2b2ccaa4de6 analyzer/tests/tests.rc --- a/analyzer/tests/tests.rc Wed Oct 08 00:08:21 2014 +0100 +++ b/analyzer/tests/tests.rc Wed Oct 08 00:33:44 2014 +0100 @@ -25,7 +25,7 @@ VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0" VALUE "ProductName", "Smalltalk/X\0" VALUE "ProductVersion", "6.2.4.0\0" - VALUE "ProductDate", "Tue, 07 Oct 2014 23:05:03 GMT\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:30 GMT\0" END END diff -r a409905f7f2d -r e2b2ccaa4de6 islands/JavaParser.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/JavaParser.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,143 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPCompositeParser subclass:#JavaParser + instanceVariableNames:'javaClass classDef classBody methodDef arguments methodBody + methodName block modifiers classId type throws javaClassIsland + methodModifiers semicolon comment singleLineComment string water' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +JavaParser comment:'A JavaParser is a island parser, that can extract method names from a java file. Instance Variables arguments: block: classBody: classDef: classId: javaClass: javaClassIsland: methodBody: methodDef: methodModifiers: methodName: modifiers: semicolon: throws: type: arguments - xxxxx block - xxxxx classBody - xxxxx classDef - xxxxx classId - xxxxx javaClass - xxxxx javaClassIsland - xxxxx methodBody - xxxxx methodDef - xxxxx methodModifiers - xxxxx methodName - xxxxx modifiers - xxxxx semicolon - xxxxx throws - xxxxx type - xxxxx ' +! + +!JavaParser methodsFor:'as yet unclassified'! + +start + ^ javaClassIsland +! ! + +!JavaParser methodsFor:'class'! + +block + ^ (${ asParser, + ((block island: water) plus / nil asParser island), + $} asParser) ==> [:tokens | nil ] + +! + +classBody + ^ + (${ asParser, + ( + ((methodDef island: water) ==> [:tokens | tokens second]) plus / + ((nil asParser island: water) ==> [ :tokens | OrderedCollection new ]) + ), + $} asParser) ==> [:tokens | tokens second select: [:e | e isNil not ]] +! + +classDef + ^ modifiers trim, 'class' asParser, classId trim ==> [:tokens | tokens third ] +! + +classId + ^ (#uppercase asParser, (#letter asParser / #digit asParser) star) flatten +! + +javaClass + ^ classDef, ((classBody island:water) ==> [:tokens | tokens second ]) +! + +javaClassIsland + ^ (javaClass island: water) ==> [:tokens | tokens second] +! + +methodModifiers + ^( ('public' asParser / 'private' asParser / 'protected' asParser) optional, + 'static' asParser trim optional, + 'final' asParser trim optional, + 'abstract' asParser trim optional, + 'synchronized' asParser trim optional, + 'native' asParser trim optional) ==> [ :tokens | nil ] +! + +modifiers + ^ ('public' asParser / 'private' asParser), 'final' asParser trim optional, 'abstract' asParser trim optional +! ! + +!JavaParser methodsFor:'comments and strings'! + +comment + | end | + end := '*/' asParser. + ^ ('/*' asParser, (#any asParser starLazy: end), end) +! + +singleLineComment + | end | + end := #newline asParser. + ^ ('//' asParser, (#any asParser starLazy: end), end) +! + +string + | end | + end := $" asParser. + ^ ($" asParser, (#any asParser starLazy: end), end) + name: 'string'; + yourself. +! ! + +!JavaParser methodsFor:'context'! + +updateContext: aPPContext + super updateContext: aPPContext. +" aPPContext globalAt: #waterObjects put: (OrderedCollection + with: self comment + with: self singleLineComment + with: self string + with: self block)." +! ! + +!JavaParser methodsFor:'method'! + +arguments + ^ $( asParser, nil asParser island, $) asParser trim +! + +methodBody + ^ semicolon / block +! + +methodDef + ^ methodModifiers, (type island: water), (methodName island:water), (arguments island:water), methodBody ==> [:tokens | tokens third second ] +! + +methodName + ^ (#letter asParser, (#letter asParser / #digit asParser) star) flatten +! + +semicolon + ^ ';' asParser +! + +throws + ^ 'throws' asParser trim, type trim, ($, asParser, type trim) star +! + +type + ^ (#letter asParser, (#letter asParser / #digit asParser) star) flatten +! + +water + " + This will allow to skip over + - Strings, + - Comments + - and blocks + when parsing water. This way, comments and strings cannot confuse the result. + " + + ^ comment / string / singleLineComment / block / #any asParser +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/Make.proto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/Make.proto Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,135 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# The Makefile as generated by this Make.proto supports the following targets: +# make - compile all st-files to a classLib +# make clean - clean all temp files +# make clobber - clean all +# +# This file contains definitions for Unix based platforms. +# It shares common definitions with the win32-make in Make.spec. + +# +# position (of this package) in directory hierarchy: +# (must point to ST/X top directory, for tools and includes) +TOP=../../.. +INCLUDE_TOP=$(TOP)/.. + +# subdirectories where targets are to be made: +SUBDIRS= + + +# subdirectories where Makefiles are to be made: +# (only define if different from SUBDIRS) +# ALLSUBDIRS= + +REQUIRED_SUPPORT_DIRS= + +# if your embedded C code requires any system includes, +# add the path(es) here:, +# ********** OPTIONAL: MODIFY the next lines *** +# LOCALINCLUDES=-Ifoo -Ibar +LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/goodies/petitparser -I$(INCLUDE_TOP)/stx/goodies/petitparser/analyzer -I$(INCLUDE_TOP)/stx/libbasic + + +# if you need any additional defines for embedded C code, +# add them here:, +# ********** OPTIONAL: MODIFY the next lines *** +# LOCALDEFINES=-Dfoo -Dbar -DDEBUG +LOCALDEFINES= + +LIBNAME=libstx_goodies_petitparser_islands +STCLOCALOPT='-package=$(PACKAGE)' -I. $(LOCALINCLUDES) $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES) -headerDir=. -varPrefix=$(LIBNAME) + + +# ********** OPTIONAL: MODIFY the next line *** +# additional C-libraries that should be pre-linked with the class-objects +LD_OBJ_LIBS= +LOCAL_SHARED_LIBS= + + +# ********** OPTIONAL: MODIFY the next line *** +# additional C targets or libraries should be added below +LOCAL_EXTRA_TARGETS= + +OBJS= $(COMMON_OBJS) $(UNIX_OBJS) + + + +all:: preMake classLibRule postMake + +pre_objs:: + + + + + + +# Enforce recompilation of package definition class if Mercurial working +# copy state changes. Together with --guessVersion it ensures that package +# definition class always contains correct binary revision string. +ifneq (**NOHG**, $(shell hg root 2> /dev/null || echo -n '**NOHG**')) +stx_goodies_petitparser_islands.$(O): $(shell hg root)/.hg/dirstate +endif + + + + +# run default testsuite for this package +test: $(TOP)/goodies/builder/reports + $(MAKE) -C $(TOP)/goodies/builder/reports -f Makefile.init + $(TOP)/goodies/builder/reports/report-runner.sh -D . -r Builder::TestReport -p $(PACKAGE) + + + +# add more install actions here +install:: + +# add more install actions for aux-files (resources) here +installAux:: + +# add more preMake actions here +preMake:: + +# add more postMake actions here +postMake:: cleanjunk + +# build all mandatory prerequisite packages (containing superclasses) for this package +prereq: + cd ../../../libbasic && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../libbasic2 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../ && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + + + +# build all packages containing referenced classes for this package +# they are nor needed to compile the package +references: + + +cleanjunk:: + -rm -f *.s *.s2 + +clean:: + -rm -f *.o *.H + +clobber:: clean + -rm -f *.so *.dll + + +# BEGINMAKEDEPEND --- do not remove this line; make depend needs it +$(OUTDIR)PPInputEnds.$(O) PPInputEnds.$(H): PPInputEnds.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) +$(OUTDIR)PPIsland.$(O) PPIsland.$(H): PPIsland.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) +$(OUTDIR)PPNonEmptyParser.$(O) PPNonEmptyParser.$(H): PPNonEmptyParser.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPDelegateParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) +$(OUTDIR)PPWater.$(O) PPWater.$(H): PPWater.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPDelegateParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) +$(OUTDIR)stx_goodies_petitparser_islands.$(O) stx_goodies_petitparser_islands.$(H): stx_goodies_petitparser_islands.st $(INCLUDE_TOP)/stx/libbasic/LibraryDefinition.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/ProjectDefinition.$(H) $(STCHDR) +$(OUTDIR)PPMemoizingIsland.$(O) PPMemoizingIsland.$(H): PPMemoizingIsland.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/islands/PPIsland.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) +$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)/stx/goodies/petitparser/PPChoiceParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPContext.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPDelegateParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPEpsilonParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPListParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPLiteralParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPOptionalParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPPredicateParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPRepeatingParser.$(H) $(INCLUDE_TOP)/stx/goodies/petitparser/PPSequenceParser.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(STCHDR) + +# ENDMAKEDEPEND --- do not remove this line + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/Make.spec --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/Make.spec Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,73 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# This file contains specifications which are common to all platforms. +# + +# Do NOT CHANGE THESE DEFINITIONS +# (otherwise, ST/X will have a hard time to find out the packages location from its packageID, +# to find the source code of a class and to find the library for a package) +MODULE=stx +MODULE_DIR=goodies/petitparser/islands +PACKAGE=$(MODULE):$(MODULE_DIR) + + +# Argument(s) to the stc compiler (stc --usage). +# -headerDir=. : create header files locally +# (if removed, they will be created as common +# -Pxxx : defines the package +# -Zxxx : a prefix for variables within the classLib +# -Dxxx : defines passed to to CC for inline C-code +# -Ixxx : include path passed to CC for inline C-code +# +optspace : optimized for space +# +optspace2 : optimized more for space +# +optspace3 : optimized even more for space +# +optinline : generate inline code for some ST constructs +# +inlineNew : additionally inline new +# +inlineMath : additionally inline some floatPnt math stuff +# +# ********** OPTIONAL: MODIFY the next line(s) *** +# STCLOCALOPTIMIZATIONS=+optinline +inlineNew +# STCLOCALOPTIMIZATIONS=+optspace3 +STCLOCALOPTIMIZATIONS=+optspace3 + + +# Argument(s) to the stc compiler (stc --usage). +# -warn : no warnings +# -warnNonStandard : no warnings about ST/X extensions +# -warnEOLComments : no warnings about EOL comment extension +# -warnPrivacy : no warnings about privateClass extension +# +# ********** OPTIONAL: MODIFY the next line(s) *** +# STCWARNINGS=-warn +# STCWARNINGS=-warnNonStandard +# STCWARNINGS=-warnEOLComments +STCWARNINGS=-warnNonStandard + +COMMON_CLASSES= \ + PPInputEnds \ + PPIsland \ + PPNonEmptyParser \ + PPWater \ + stx_goodies_petitparser_islands \ + PPMemoizingIsland \ + + + + +COMMON_OBJS= \ + $(OUTDIR_SLASH)PPInputEnds.$(O) \ + $(OUTDIR_SLASH)PPIsland.$(O) \ + $(OUTDIR_SLASH)PPNonEmptyParser.$(O) \ + $(OUTDIR_SLASH)PPWater.$(O) \ + $(OUTDIR_SLASH)stx_goodies_petitparser_islands.$(O) \ + $(OUTDIR_SLASH)PPMemoizingIsland.$(O) \ + $(OUTDIR_SLASH)extensions.$(O) \ + + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/Makefile.init --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/Makefile.init Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,27 @@ +# +# DO NOT EDIT +# +# make uses this file (Makefile) only, if there is no +# file named "makefile" (lower-case m) in the same directory. +# My only task is to generate the real makefile and call make again. +# Thereafter, I am no longer used and needed. +# +# MACOSX caveat: +# as filenames are not case sensitive (in a default setup), +# we cannot use the above trick. Therefore, this file is now named +# "Makefile.init", and you have to execute "make -f Makefile.init" to +# get the initial makefile. This is now also done by the toplevel CONFIG +# script. + +.PHONY: run + +run: makefile + $(MAKE) -f makefile + +#only needed for the definition of $(TOP) +include Make.proto + +makefile: mf + +mf: + $(TOP)/rules/stmkmf diff -r a409905f7f2d -r e2b2ccaa4de6 islands/PPInputEnds.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/PPInputEnds.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,34 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPParser subclass:#PPInputEnds + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Parsers' +! + +PPInputEnds comment:'' +! + +!PPInputEnds methodsFor:'as yet unclassified'! + +acceptsEpsilon + ^ true +! + +exampleOn: aStream + aStream nextPutAll: '#End Of Input#' +! + +isNullable + ^ true +! + +parseOn: aPPContext + (aPPContext atEnd) ifFalse: + [ + ^ PPFailure message: 'end of input expected' context: aPPContext. + ]. + ^ #inputEnds +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/PPIsland.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/PPIsland.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,201 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPParser subclass:#PPIsland + instanceVariableNames:'island afterWaterParser beforeWaterParser context + afterWaterDelegate beforeWaterDelegate water' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Parsers' +! + +PPIsland comment:'A PPIsland allows for imprecise parsing. One can create it on a parser p by calling: ''p island'' E.g.: p := x, a island, y accepts following inputs: x.....a.....b xab yet fails on: x....a....c xb xac x..b....a....b The input represented by dots is called water and water can appear before and after the island. Use it, if you don''t want to define all the grammar rules and you want to skip something. I am still an experiment, but if you know how to improve me, please contact Jan Kurs at: kurs@iam.unibe.ch Instance Variables afterWaterParser: awp: beforeWaterParser: bwp: context: island: afterWaterParser - xxxxx awp - xxxxx beforeWaterParser - xxxxx bwp - xxxxx context - xxxxx island - xxxxx ' +! + +!PPIsland methodsFor:'accessing'! + +children + + ^ Array with: water with: island with: water +! + +followSet: aPPContext + + ^ aPPContext root followSets at: self. +! + +initialize + super initialize. + water := #any asParser name: 'water'; yourself. +! + +island + + ^ island +! + +island: anObject + island := anObject. +! + +nextSet: aPPContext + + ^ aPPContext root nextSets at: self. +! + +replace: parser with: anotherParser + super replace: parser with: anotherParser. + + (water == parser) ifTrue: [ water := anotherParser ]. + (island == parser) ifTrue: [ island := anotherParser ]. +! + +water + ^ water +! + +water: aPPParser + water := aPPParser +! ! + +!PPIsland methodsFor:'memoization'! + +memoized + ^ PPMemoizingIsland new + island: self island; + water: water; + yourself +! + +reset: aPPContext + context := aPPContext. + beforeWaterParser := nil. + afterWaterParser := nil. +! ! + +!PPIsland methodsFor:'parsing'! + +afterWaterParser: aPPContext + context == aPPContext ifFalse: [ self reset: aPPContext ]. + + afterWaterParser ifNil: [ + afterWaterParser := self createAfterWaterParser: aPPContext. + ]. + ^ afterWaterParser +! + +beforeWaterParser: aPPContext + context == aPPContext ifFalse: [ self reset: aPPContext ]. + + beforeWaterParser ifNil: [ + beforeWaterParser := self createBeforeWaterParser: aPPContext. + ]. + ^ beforeWaterParser +! + +createAfterWaterParser: aPPContext + | nextSet p | + + nextSet := Set new. + nextSet addAll: (self nextSet: aPPContext). + nextSet add: PPInputEnds new. + + nextSet := nextSet collect: [ :e | PPNonEmptyParser on: e ]. + + p := (PPChoiceParser withAll: nextSet) not. + ^ PPWater on: p waterToken: water +! + +createBeforeWaterParser: aPPContext + | nextSet p | + nextSet := Set new. + nextSet addAll: (self nextSet: aPPContext). + nextSet add: PPInputEnds new. + + nextSet := nextSet collect: [:e | PPNonEmptyParser on: e]. + + p := (PPChoiceParser withAll: nextSet) not, (PPNonEmptyParser on: island) not. + ^ PPWater on: p waterToken: water. +! + +exampleOn: aStream + aStream nextPutAll: '~~~~ '. + island exampleOn: aStream . + aStream nextPutAll: ' ~~~~'. +! + +parseAfterWater: aPPContext + ^ (self afterWaterParser: aPPContext) parseOn: aPPContext . +! + +parseBeforeWater: aPPContext + ^ (self beforeWaterParser: aPPContext) parseOn: aPPContext. +! + +parseOn: aPPContext + | bwr awr result retval memento | + + memento := aPPContext remember. + "Halt ifShiftPressed." + + bwr := self parseBeforeWater: aPPContext. + bwr isPetitFailure ifTrue: + [ + self error: 'IMO should never happen'. + ]. + + "JK: HACK ALERT, FIX!!" + (aPPContext waterPosition == aPPContext position) ifTrue:[ + result := (PPNonEmptyParser on: island) parseOn: aPPContext. + ] ifFalse: [ + result := island parseOn: aPPContext. + ]. + + + result isPetitFailure ifTrue: [ + retval := PPFailure message: 'Island not found between ', memento position asString, ' and ', aPPContext position asString context: aPPContext. + aPPContext restore: memento. + ^ retval + ]. + + + awr := self parseAfterWater: aPPContext. + awr isPetitFailure ifTrue: + [ + retval := PPFailure message: 'IMO should not happen :(' context: aPPContext. + aPPContext restore: memento. + ^ retval. + ]. + + retval := OrderedCollection with: bwr with: result with: awr. + ^ retval + + +! + +waterToken + | waterObjects | + self halt: 'deprecated?'. + waterObjects := self globalAt: #waterObjects ifAbsent: [ OrderedCollection new ]. + waterObjects add: #any asParser. + ^ PPChoiceParser withAll: waterObjects. +! ! + +!PPIsland methodsFor:'queries'! + +acceptsEpsilon + "JK: Hack alert?" + "Let us suppose island is always nullable, it helps to sequences of islands" + ^ true + "^ island isNullableOpenSet: (IdentitySet with: self)" +! + +acceptsEpsilonOpenSet: set + "JK: Hack alert?" + ^ true +" ^ island isNullableOpenSet: set" +! + +name + ^ super name ifNil: [ 'an island ']. +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/PPMemoizingIsland.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/PPMemoizingIsland.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,92 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPIsland subclass:#PPMemoizingIsland + instanceVariableNames:'rootParser memoizationDictionaries' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Parsers' +! + +PPMemoizingIsland comment:'A PPMemoizingIsland is memoized version of PPIsland. Use this one, unless you don''t mind really bad performance. If the memoized version is not working flawlessly, its a bug!! Please see help of the PPIsland for how to use... Instance Variables memoizationDictionaries: rootParser: memoizationDictionaries - memoization cache rootParser - used for memoizing, once the root changes, flushes the caches ' +! + +!PPMemoizingIsland class methodsFor:'as yet unclassified'! + +initialize + super initialize +! ! + +!PPMemoizingIsland methodsFor:'accessing'! + +island: anObject + + island ifNil: [ + super island: anObject. + ] ifNotNil: [ + self error: 'JK: I do not want to do this' . + ] +! ! + +!PPMemoizingIsland methodsFor:'initialization'! + +initialize + super initialize. + + memoizationDictionaries := IdentityDictionary new. +! ! + +!PPMemoizingIsland methodsFor:'memoization'! + +memoizationDictionaryForContext: aPPContext + ^ memoizationDictionaries at: aPPContext ifAbsentPut: [IdentityDictionary new]. +! + +memoizeResult: result onContext: aPPContext position: pos + | memento | + + memento := PPMemento new. + memento contextMemento: aPPContext remember. + memento result: result. + + (self memoizationDictionaryForContext: aPPContext) at: pos put: memento. +! + +memoizedResult: aPPContext + ^ (self memoizationDictionaryForContext: aPPContext) at: (aPPContext position) ifAbsent: [ nil ]. + +! ! + +!PPMemoizingIsland methodsFor:'parsing'! + +memoized + "We have our own implementation of memoization" + ^ self +! + +nonMemoized + ^ PPIsland new + island: self island; + yourself +! + +parseOn: aPPContext + | memoizedResult parsingPosition retval | + memoizedResult := self memoizedResult: aPPContext. + memoizedResult ifNotNil: [ + aPPContext restore: memoizedResult contextMemento. + ^ memoizedResult result + ]. + parsingPosition := aPPContext position. + + retval := super parseOn: aPPContext. + + (aPPContext waterPosition == aPPContext position) ifFalse: [ + self memoizeResult: retval onContext: aPPContext position: parsingPosition. + ]. + + ^ retval. + +! ! + + +PPMemoizingIsland initialize! diff -r a409905f7f2d -r e2b2ccaa4de6 islands/PPNonEmptyParser.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/PPNonEmptyParser.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,26 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPDelegateParser subclass:#PPNonEmptyParser + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Parsers' +! + +PPNonEmptyParser comment:'I return failure, if the delegate parser did not consumed any input.' +! + +!PPNonEmptyParser methodsFor:'parsing'! + +parseOn: aPPContext + | position result | + position := aPPContext position. + result := parser parseOn: aPPContext. + + + (((position == aPPContext position) and: [ aPPContext atEnd not ]) and: [ result isPetitFailure not ]) ifTrue: [ + ^ PPFailure message: 'Epsilon parse not allowed' context: aPPContext at: position + ]. + ^ result +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/PPWater.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/PPWater.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,83 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPDelegateParser subclass:#PPWater + instanceVariableNames:'waterToken context' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Parsers' +! + +PPWater comment:'' +! + +!PPWater class methodsFor:'as yet unclassified'! + +on: parser + ^ self on: parser waterToken: #any asParser +! + +on: parser waterToken: waterToken + ^ (super on: parser) + waterToken: waterToken; + yourself +! ! + +!PPWater methodsFor:'as yet unclassified'! + +checkContext: aPPContext + context == aPPContext ifFalse: [ + self reset: aPPContext + ] +! + +children + ^ Array with: waterToken +! + +initialize + super initialize. + waterToken := nil asParser. + context := nil. +! + +parseOn: aPPContext + | waterPosition result | + + (aPPContext waterPosition == aPPContext position) ifFalse: [ + waterPosition := aPPContext waterPosition. + aPPContext waterPosition: aPPContext position. + + "TODO: probably can be rewritten with test in the end!!" + result := parser parseOn: aPPContext. + [result isPetitFailure] whileFalse: [ + waterToken parseOn: aPPContext. + aPPContext waterPosition: aPPContext position. + result := parser parseOn: aPPContext. + ]. + + aPPContext waterPosition: waterPosition. + ]. + + ^ #water +! + +replace: child with: anotherChild + child == waterToken ifTrue: [ + waterToken := anotherChild. + ] +! + +reset: aPPContext + | waterObjects | + + context := aPPContext. + + waterObjects := aPPContext globalAt: #waterObjects ifAbsent: [ OrderedCollection new ]. + waterObjects add: #any asParser. + waterToken := PPChoiceParser withAll: waterObjects. +! + +waterToken: aPPParser + ^ waterToken := aPPParser +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/RobustXmlFeedParser.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/RobustXmlFeedParser.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,26 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +XmlFeedParser subclass:#RobustXmlFeedParser + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +RobustXmlFeedParser comment:'A RobustXmlFeedParser is XmlFeedParser, that can handle error within an xml Item element ' +! + + +!RobustXmlFeedParser methodsFor:'as yet unclassified'! + +itemContent + ^ ((simpleElement island ==> #second) star) ==> self elementsToDictionaryBlock +! ! + +!RobustXmlFeedParser class methodsFor:'documentation'! + +version_HG + + ^ '$Changeset: $' +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/XmlFeedParser.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/XmlFeedParser.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,79 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +PPCompositeParser subclass:#XmlFeedParser + instanceVariableNames:'item openItem itemContent closeItem openShoplist shoplistContent + closeShoplist shoplist simpleElement stringValue' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +XmlFeedParser comment:'A XmlFeedParser is Parser of a fake shop feed. Shop feed is a XML file with information about shop products. Shop feed can be malformed (for any reason) the parser will recover from malformed item and will continue on the next valid item. Instance Variables closeItem: closeName: closeShoplist: item: itemContent: name: nameContent: openItem: openName: openShoplist: shoplist: shoplistContent: simpleElement: stringValue: closeItem - xxxxx closeName - xxxxx closeShoplist - xxxxx item - xxxxx itemContent - xxxxx name - xxxxx nameContent - xxxxx openItem - xxxxx openName - xxxxx openShoplist - xxxxx shoplist - xxxxx shoplistContent - xxxxx simpleElement - xxxxx stringValue - xxxxx ' +! + +!XmlFeedParser methodsFor:'grammar'! + +item + ^ (openItem, itemContent trim, closeItem) trim ==> #second +! + +itemContent + ^ (simpleElement trim star) ==> self elementsToDictionaryBlock +! + +shoplist + ^ (openShoplist, shoplistContent, closeShoplist) trim ==> #second +! + +shoplistContent + ^ (item island ==> #second) star +! + +start + ^ shoplist +! + +stringValue + ^ (#letter asParser / #digit asParser) star flatten trim +! ! + +!XmlFeedParser methodsFor:'tags'! + +closeItem + ^ '' asParser +! + +closeShoplist + ^ '' asParser +! + +openItem + ^ '<' asParser, 'item' asParser trim, '>' asParser +! + +openShoplist + ^ '<' asParser, 'shoplist' asParser trim, '>' asParser +! ! + +!XmlFeedParser methodsFor:'xmlSupport'! + +elementsToDictionaryBlock + ^ [ :elements | | d | + d := Dictionary new. + elements do: [ :e | d at: e first asSymbol put: e second ]. + d + ] +! + +simpleElement + ^ ( + (('<' asParser, stringValue trim, '>' asParser) ==> #second), + stringValue, + (('' asParser) ==> #second) + ) ==> [ :elements | + (elements first = elements third) + ifTrue: [ Array with: elements first with: elements second ] + ifFalse: [ PPFailure message: 'malformed element' ] + ] +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/abbrev.stc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/abbrev.stc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,12 @@ +# automagically generated by the project definition +# this file is needed for stc to be able to compile modules independently. +# it provides information about a classes filename, category and especially namespace. +JavaParser JavaParser stx:goodies/petitparser/islands 'PetitIslands-Examples' 0 +PPInputEnds PPInputEnds stx:goodies/petitparser/islands 'PetitIslands-Parsers' 0 +PPIsland PPIsland stx:goodies/petitparser/islands 'PetitIslands-Parsers' 0 +PPNonEmptyParser PPNonEmptyParser stx:goodies/petitparser/islands 'PetitIslands-Parsers' 0 +PPWater PPWater stx:goodies/petitparser/islands 'PetitIslands-Parsers' 0 +XmlFeedParser XmlFeedParser stx:goodies/petitparser/islands 'PetitIslands-Examples' 0 +stx_goodies_petitparser_islands stx_goodies_petitparser_islands stx:goodies/petitparser/islands '* Projects & Packages *' 3 +PPMemoizingIsland PPMemoizingIsland stx:goodies/petitparser/islands 'PetitIslands-Parsers' 0 +RobustXmlFeedParser RobustXmlFeedParser stx:goodies/petitparser/islands 'PetitIslands-Examples' 0 diff -r a409905f7f2d -r e2b2ccaa4de6 islands/bc.mak --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/bc.mak Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,89 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# Notice, that the name bc.mak is historical (from times, when only borland c was supported). +# This file contains make rules for the win32 platform using either borland-bcc or visual-c. +# It shares common definitions with the unix-make in Make.spec. +# The bc.mak supports the following targets: +# bmake - compile all st-files to a classLib (dll) +# bmake clean - clean all temp files +# bmake clobber - clean all +# +# Historic Note: +# this used to contain only rules to make with borland +# (called via bmake, by "make.exe -f bc.mak") +# this has changed; it is now also possible to build using microsoft visual c +# (called via vcmake, by "make.exe -f bc.mak -DUSEVC") +# +TOP=..\..\.. +INCLUDE_TOP=$(TOP)\.. + + + +!INCLUDE $(TOP)\rules\stdHeader_bc + +!INCLUDE Make.spec + +LIBNAME=libstx_goodies_petitparser_islands +RESFILES=islands.$(RES) + + + +LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\goodies\petitparser -I$(INCLUDE_TOP)\stx\goodies\petitparser\analyzer -I$(INCLUDE_TOP)\stx\libbasic +LOCALDEFINES= + +STCLOCALOPT=-package=$(PACKAGE) -I. $(LOCALINCLUDES) -headerDir=. $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES) -varPrefix=$(LIBNAME) +LOCALLIBS= + +OBJS= $(COMMON_OBJS) $(WIN32_OBJS) + +ALL:: classLibRule + +classLibRule: $(OUTDIR) $(OUTDIR)$(LIBNAME).dll + +!INCLUDE $(TOP)\rules\stdRules_bc + +# build all mandatory prerequisite packages (containing superclasses) for this package +prereq: + pushd ..\..\..\libbasic & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\libbasic2 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd .. & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + + + + + + + +test: $(TOP)\goodies\builder\reports\NUL + pushd $(TOP)\goodies\builder\reports & $(MAKE_BAT) + $(TOP)\goodies\builder\reports\report-runner.bat -D . -r Builder::TestReport -p $(PACKAGE) + +clean:: + del *.$(CSUFFIX) + + +# BEGINMAKEDEPEND --- do not remove this line; make depend needs it +$(OUTDIR)PPInputEnds.$(O) PPInputEnds.$(H): PPInputEnds.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) +$(OUTDIR)PPIsland.$(O) PPIsland.$(H): PPIsland.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) +$(OUTDIR)PPNonEmptyParser.$(O) PPNonEmptyParser.$(H): PPNonEmptyParser.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPDelegateParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) +$(OUTDIR)PPWater.$(O) PPWater.$(H): PPWater.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPDelegateParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) +$(OUTDIR)stx_goodies_petitparser_islands.$(O) stx_goodies_petitparser_islands.$(H): stx_goodies_petitparser_islands.st $(INCLUDE_TOP)\stx\libbasic\LibraryDefinition.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\ProjectDefinition.$(H) $(STCHDR) +$(OUTDIR)PPMemoizingIsland.$(O) PPMemoizingIsland.$(H): PPMemoizingIsland.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\islands\PPIsland.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) +$(OUTDIR)extensions.$(O): extensions.st $(INCLUDE_TOP)\stx\goodies\petitparser\PPChoiceParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPContext.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPDelegateParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPEpsilonParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPListParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPLiteralParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPOptionalParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPPredicateParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPRepeatingParser.$(H) $(INCLUDE_TOP)\stx\goodies\petitparser\PPSequenceParser.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(STCHDR) + +# ENDMAKEDEPEND --- do not remove this line + +# **Must be at end** + +# Enforce recompilation of package definition class if Mercurial working +# copy state changes. Together with --guessVersion it ensures that package +# definition class always contains correct binary revision string. +!IFDEF HGROOT +$(OUTDIR)stx_goodies_petitparser_islands.$(O): $(HGROOT)\.hg\dirstate +!ENDIF diff -r a409905f7f2d -r e2b2ccaa4de6 islands/bmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/bmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,12 @@ +@REM ------- +@REM make using Borland bcc32 +@REM type bmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" +make.exe -N -f bc.mak %DEFINES% %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/extensions.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/extensions.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,201 @@ +"{ Package: 'stx:goodies/petitparser/islands' }"! + +!PPChoiceParser methodsFor:'*petitislands'! + +acceptsEpsilonOpenSet: set + set add: self. + ^ self children anySatisfy: [:e | e acceptsEpsilonOpenSet: set ]. +! ! + +!PPContext methodsFor:'*petitislands'! + +waterPosition + ^ self globalAt: #waterPosition ifAbsentPut: [ nil ] +! ! + +!PPContext methodsFor:'*petitislands'! + +waterPosition: position + ^ self globalAt: #waterPosition put: position +! ! + +!PPDelegateParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ parser acceptsEpsilonOpenSet: (IdentitySet with: self). +! ! + +!PPDelegateParser methodsFor:'*petitislands'! + +acceptsEpsilonOpenSet: set + (set includes: parser) ifFalse: [ + set add: parser. + ^ parser acceptsEpsilonOpenSet: set + ]. + ^ false +! ! + +!PPEpsilonParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ true +! ! + +!PPListParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ self acceptsEpsilonOpenSet: IdentitySet new. +! ! + +!PPLiteralParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ false +! ! + +!PPOptionalParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ true +! ! + +!PPOptionalParser methodsFor:'*petitislands'! + +acceptsEpsilonOpenSet: set + ^ true +! ! + +!PPParser methodsFor:'*petitislands'! + +acceptsEpsilon + "return true, if parser can accept epsilon without failure" + ^ self subclassResponsibility +! ! + +!PPParser methodsFor:'*petitislands'! + +acceptsEpsilonOpenSet: set + "private helper for acceptsEmpsilon that makes sure to avoid cycles (using open set)" + self children isEmpty ifTrue: [ ^ self acceptsEpsilon ]. + + self shouldBeImplemented . +! ! + +!PPParser methodsFor:'*petitislands'! + +island + ^ PPIsland new + island: self; + yourself; + memoized +! ! + +!PPParser methodsFor:'*petitislands'! + +island: water + ^ PPIsland new + island: self; + water: water; + yourself; + memoized +! ! + +!PPParser methodsFor:'*petitislands'! + +nextSets + | nextSets | + + nextSets := IdentityDictionary new. + self allParsersDo: [ :each | nextSets at: each put: IdentitySet new ]. + + (nextSets at: self) add: PPSentinel instance. + + [ | changed | + changed := false. + + nextSets keysAndValuesDo: [:parser :next | + changed := (parser + nextSets: nextSets + into: next) or: [ changed ]. + ]. + changed ] whileTrue. + + ^ nextSets +! ! + +!PPParser methodsFor:'*petitislands'! + +nextSets: aNextDictionary into: aSet + "return true/false, if something has changed or not...." + | childSet change tally | + + change := false. + + self children do: [:each | + childSet := aNextDictionary at: each. + tally := childSet size. + childSet addAll: aSet. + change := change or: [ tally ~= childSet size ]. + ]. + + ^ change + +! ! + +!PPPredicateParser methodsFor:'*petitislands'! + +acceptsEpsilon + ^ false +! ! + +!PPRepeatingParser methodsFor:'*petitislands'! + +nextSets: aNextDictionary into: aSet + | tally childSet change | + + change := super nextSets: aNextDictionary into: aSet. + + childSet := aNextDictionary at: parser. + tally := aSet size. + childSet add: parser. + ^ change or: [ tally ~= aSet size ]. +! ! + +!PPSequenceParser methodsFor:'*petitislands'! + +acceptsEpsilonOpenSet: set + set add: self. + ^ self children allSatisfy: [:e | e acceptsEpsilonOpenSet: set ] +! ! + +!PPSequenceParser methodsFor:'*petitislands'! + +nextSets: aNextDictionary into: aSet + + | nextSet eachNextSet change tally | + nextSet := aSet copy. + + change := false. + + self children reverseDo: [:each | + eachNextSet := aNextDictionary at: each. + tally := eachNextSet size. + eachNextSet addAll: nextSet. + change := change or: [ tally ~= eachNextSet size ]. + + each acceptsEpsilon ifTrue: [ + nextSet add: each. + ] ifFalse: [ + nextSet := IdentitySet with: each. + ]. + ]. + + ^ change +! ! + +!stx_goodies_petitparser_islands class methodsFor:'documentation'! + +extensionsVersion_HG + + ^ '$Changeset: $' +! ! diff -r a409905f7f2d -r e2b2ccaa4de6 islands/islands.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/islands.rc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,37 @@ +// +// DO NOT EDIT +// automagically generated from the projectDefinition: stx_goodies_petitparser_islands. +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION 6,2,32767,32767 + PRODUCTVERSION 6,2,4,0 +#if (__BORLANDC__) + FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE + FILEFLAGS VS_FF_PRERELEASE | VS_FF_SPECIALBUILD + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VS_USER_DEFINED +#endif + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "eXept Software AG\0" + VALUE "FileDescription", "Smalltalk/X Class library (LIB)\0" + VALUE "FileVersion", "6.2.32767.32767\0" + VALUE "InternalName", "stx:goodies/petitparser/islands\0" + VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0" + VALUE "ProductName", "Smalltalk/X\0" + VALUE "ProductVersion", "6.2.4.0\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:31 GMT\0" + END + + END + + BLOCK "VarFileInfo" + BEGIN // Language | Translation + VALUE "Translation", 0x409, 0x4E4 // U.S. English, Windows Multilingual + END +END diff -r a409905f7f2d -r e2b2ccaa4de6 islands/lccmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/lccmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,8 @@ +@REM ------- +@REM make using lcc compiler +@REM type lccmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +make.exe -N -f bc.mak -DUSELCC=1 %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/libInit.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/libInit.cc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,39 @@ +/* + * $Header$ + * + * DO NOT EDIT + * automagically generated from the projectDefinition: stx_goodies_petitparser_islands. + */ +#define __INDIRECTVMINITCALLS__ +#include + +#ifdef WIN32 +# pragma codeseg INITCODE "INITCODE" +#endif + +#if defined(INIT_TEXT_SECTION) || defined(DLL_EXPORT) +DLL_EXPORT void _libstx_goodies_petitparser_islands_Init() INIT_TEXT_SECTION; +DLL_EXPORT void _libstx_goodies_petitparser_islands_InitDefinition() INIT_TEXT_SECTION; +#endif + +void _libstx_goodies_petitparser_islands_InitDefinition(pass, __pRT__, snd) +OBJ snd; struct __vmData__ *__pRT__; { +__BEGIN_PACKAGE2__("libstx_goodies_petitparser_islands__DFN", _libstx_goodies_petitparser_islands_InitDefinition, "stx:goodies/petitparser/islands"); +_stx_137goodies_137petitparser_137islands_Init(pass,__pRT__,snd); + +__END_PACKAGE__(); +} + +void _libstx_goodies_petitparser_islands_Init(pass, __pRT__, snd) +OBJ snd; struct __vmData__ *__pRT__; { +__BEGIN_PACKAGE2__("libstx_goodies_petitparser_islands", _libstx_goodies_petitparser_islands_Init, "stx:goodies/petitparser/islands"); +_PPInputEnds_Init(pass,__pRT__,snd); +_PPIsland_Init(pass,__pRT__,snd); +_PPNonEmptyParser_Init(pass,__pRT__,snd); +_PPWater_Init(pass,__pRT__,snd); +_stx_137goodies_137petitparser_137islands_Init(pass,__pRT__,snd); +_PPMemoizingIsland_Init(pass,__pRT__,snd); + +_stx_137goodies_137petitparser_137islands_extensions_Init(pass,__pRT__,snd); +__END_PACKAGE__(); +} diff -r a409905f7f2d -r e2b2ccaa4de6 islands/mingwmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/mingwmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,16 @@ +@REM ------- +@REM make using mingw gnu compiler +@REM type mingwmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" + +@pushd ..\..\..\rules +@call find_mingw.bat +@popd +make.exe -N -f bc.mak %DEFINES% %USEMINGW_ARG% %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/stx_goodies_petitparser_islands.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/stx_goodies_petitparser_islands.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,182 @@ +"{ Package: 'stx:goodies/petitparser/islands' }" + +LibraryDefinition subclass:#stx_goodies_petitparser_islands + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'* Projects & Packages *' +! + + +!stx_goodies_petitparser_islands class methodsFor:'accessing - monticello'! + +monticelloLastMergedVersionInfo + "The last merged version is: " + + ^ ' + Name: PetitIslands-JanKurs.10 + Author: JanKurs + Time: 06-10-2014, 11:50:57 AM + UUID: 19560ad2-4899-43d5-8c69-cf7274ad4f04 + Repository: http://smalltalkhub.com/mc/Moose/PetitParser/main + ' + + "Created: / 03-10-2014 / 02:27:21 / Jan Vrany " + "Modified: / 08-10-2014 / 00:24:45 / Jan Vrany " +! + +monticelloName + "Return name of the package for Monticello. This is used when package is exported" + + ^ 'PetitIslands' + + "Created: / 03-10-2014 / 01:47:26 / Jan Vrany " + "Modified: / 08-10-2014 / 00:24:23 / Jan Vrany " +! ! + +!stx_goodies_petitparser_islands class methodsFor:'accessing - tests'! + +testSuite + "generate and return a testSuite containing all of my test-classes" + + Smalltalk loadPackage: 'stx:goodies/petitparser/islands/tests'. + ^ 'stx:goodies/petitparser/islands/tests' asPackageId projectDefinitionClass testSuite + + "Modified: / 08-10-2014 / 00:26:14 / Jan Vrany " +! ! + +!stx_goodies_petitparser_islands class methodsFor:'description'! + +excludedFromPreRequisites + "list packages which are to be explicitely excluded from the automatic constructed + prerequisites list. If empty, everything that is found along the inheritance of any of + my classes is considered to be a prerequisite package." + + ^ #( + ) +! + +mandatoryPreRequisites + "list packages which are mandatory as a prerequisite. + This are packages containing superclasses of my classes and classes which + are extended by myself. + They are mandatory, because we need these packages as a prerequisite for loading and compiling. + This method is generated automatically, + by searching along the inheritance chain of all of my classes." + + ^ #( + #'stx:goodies/petitparser' "PPChoiceParser - extended" + #'stx:libbasic' "LibraryDefinition - superclass of stx_goodies_petitparser_islands" + ) +! + +referencedPreRequisites + "list packages which are a prerequisite, because they contain + classes which are referenced by my classes. + We do not need these packages as a prerequisite for loading or compiling. + This method is generated automatically, + by searching all classes (and their packages) which are referenced by my classes." + + ^ #( + #'stx:goodies/petitparser/analyzer' "PPSentinel - referenced by PPParser>>nextSets" + ) +! + +subProjects + "list packages which are known as subprojects. + The generated makefile will enter those and make there as well. + However: they are not forced to be loaded when a package is loaded; + for those, redefine requiredPrerequisites." + + ^ #( + ) +! ! + +!stx_goodies_petitparser_islands class methodsFor:'description - contents'! + +classNamesAndAttributes + "lists the classes which are to be included in the project. + Each entry in the list may be: a single class-name (symbol), + or an array-literal consisting of class name and attributes. + Attributes are: #autoload or # where os is one of win32, unix,..." + + ^ #( + " or ( attributes...) in load order" + (JavaParser autoload) + PPInputEnds + PPIsland + PPNonEmptyParser + PPWater + (XmlFeedParser autoload) + #'stx_goodies_petitparser_islands' + PPMemoizingIsland + (RobustXmlFeedParser autoload) + ) + + "Modified: / 08-10-2014 / 00:30:08 / Jan Vrany " +! + +extensionMethodNames + "list class/selector pairs of extensions. + A correponding method with real names must be present in my concrete subclasses" + + ^ #( + PPChoiceParser acceptsEpsilonOpenSet: + PPContext waterPosition + PPContext waterPosition: + PPDelegateParser acceptsEpsilon + PPDelegateParser acceptsEpsilonOpenSet: + PPEpsilonParser acceptsEpsilon + PPListParser acceptsEpsilon + PPLiteralParser acceptsEpsilon + PPOptionalParser acceptsEpsilon + PPOptionalParser acceptsEpsilonOpenSet: + PPParser acceptsEpsilon + PPParser acceptsEpsilonOpenSet: + PPParser island + PPParser island: + PPParser nextSets + PPParser nextSets:into: + PPPredicateParser acceptsEpsilon + PPRepeatingParser nextSets:into: + PPSequenceParser acceptsEpsilonOpenSet: + PPSequenceParser nextSets:into: + ) +! ! + +!stx_goodies_petitparser_islands class methodsFor:'description - project information'! + +companyName + "Returns a company string which will appear in .rc. + Under win32, this is placed into the dlls file-info" + + ^ 'eXept Software AG' +! + +description + "Returns a description string which will appear in nt.def / bc.def" + + ^ 'Smalltalk/X Class library' +! + +legalCopyright + "Returns a copyright string which will appear in .rc. + Under win32, this is placed into the dlls file-info" + + ^ 'Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014' +! + +productName + "Returns a product name which will appear in .rc. + Under win32, this is placed into the dlls file-info. + This method is usually redefined in a concrete application definition" + + ^ 'Smalltalk/X' +! ! + +!stx_goodies_petitparser_islands class methodsFor:'documentation'! + +version_HG + ^ '$Changeset: $' +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/FirstFollowNextTests.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/FirstFollowNextTests.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,1058 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +TestCase subclass:#FirstFollowNextTests + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Tests' +! + +FirstFollowNextTests comment:'' +! + +!FirstFollowNextTests methodsFor:'support'! + +assert: set allMatches: string + self assert: (set allSatisfy: [:e | e end matches: string]) +! + +assert: set allSatisfy: aBlock + self assert: (set allSatisfy: aBlock) +! + +assert: set anyMatches: string + self assert: (set anySatisfy: [:e | e end matches: string]) +! + +assert: set anySatisfy: aBlock + self assert: (set anySatisfy: aBlock) +! + +assert: set noneMatches: string + self assert: (set noneSatisfy: [:e | e end matches: string]) +! + +assert: set noneSatisfy: aBlock + self assert: (set noneSatisfy: aBlock) +! + +assert: set size: anInteger + self assert: (set size = anInteger ) +! + +first: aParser + ^ aParser firstSet +! + +first: aParser terminalPredicate: predicate + ^ aParser firstSetPredicate: predicate +! + +follow: aParser in: rootParser + ^ rootParser followSets at: aParser + +! + +identifier + ^ ((#letter asParser / $# asParser), (#letter asParser / #digit asParser) star) flatten +! + +next: aParser in: rootParser + ^ rootParser nextSets at: aParser + +! ! + +!FirstFollowNextTests methodsFor:'test first'! + +testFirst1 + | p first | + p := nil asParser / 'a' asParser. + + self assert: (self first: p) anyMatches: ''. + self assert: (self first: p) anyMatches: 'a'. +! + +testFirst2 + | p first | + p := 'a' asParser optional, 'b' asParser. + + self assert: (self first: p) anyMatches: 'a'. + self assert: (self first: p) anyMatches: 'b'. +! + +testFirst3 + | p first | + p := ('a' asParser optional, 'b' asParser asParser optional), 'c' asParser. + + self assert: (self first: p) anyMatches: 'a'. + self assert: (self first: p) anyMatches: 'b'. +! + +testFirst4 + | p first | + p := ('a' asParser plus) optional, 'b' asParser. + + self assert: (self first: p) anyMatches: 'a'. + self assert: (self first: p) anyMatches: 'b'. +! + +testFirstChoice1 + | p first | + p := nil asParser / '' asParser. + + self assert: (self first: p) anySatisfy: [:e | e matches: '']. +! + +testFirstChoice2 + | p first | + p := 'a' asParser / nil asParser. + + first := (self first: p). + + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: '']. +! + +testFirstChoice3 + | p first | + p := 'a' asParser / nil asParser / 'b' asParser. + + first := (self first: p). + + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: 'b']. + self assert: first anySatisfy: [:e | e matches: '']. +! + +testFirstComplex1 + | p first root | + + p := 'a' asParser / nil asParser. + root := p, 'c' asParser. + + first := (self first: root). + + self assert: first size: 2. + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: 'c']. + self assert: first noneSatisfy: [:e | e matches: '']. +! + +testFirstComplex2 + | p first root | + + p := 'a' asParser / nil asParser / 'b' asParser. + root := p, 'c' asParser. + + first := (self first: root). + + self assert: first size: 3. + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: 'b']. + self assert: first anySatisfy: [:e | e matches: 'c']. +! + +testFirstComplex3 + | p first root | + + p := 'a' asParser / nil asParser / 'b' asParser. + root := p, 'c' asParser not. + + first := (self first: root). + + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: 'b']. + self assert: first anySatisfy: [:e | e matches: '']. + self assert: first noneSatisfy: [:e | e end matches: 'c']. +! + +testFirstComplex4 + | p first root | + + p := 'a' asParser / nil asParser / 'b' asParser. + root := (p, 'c' asParser not) wrapped. + + first := (self first: root). + + self assert: first anySatisfy: [:e | e matches: 'a']. + self assert: first anySatisfy: [:e | e matches: 'b']. + self assert: first anySatisfy: [:e | e matches: '']. + self assert: first noneSatisfy: [:e | e end matches: 'c']. +! + +testFirstNegate1 + | p first | + p := 'a' asParser negate, 'b' asParser. + + self assert: (p parse: 'bb') isPetitFailure not. + self assert: (p parse: 'cb') isPetitFailure not. + + self assert: (self first: p) noneSatisfy: [:each | each matches: 'a' ]. + self assert: (self first: p) anySatisfy: [:each | each matches: 'b' ]. + self assert: (self first: p) anySatisfy: [:each | each matches: 'c' ]. +! + +testFirstNot + | p | + p := 'a' asParser not, 'b' asParser. + + self assert: (p parse: 'b') isPetitFailure not. + + self assert: (self first: p) noneSatisfy: [:each | each matches: 'a' ]. + self assert: (self first: p) anySatisfy: [:each | each matches: 'b' ]. + self assert: (self first: p) anySatisfy: [:each | each matches: 'c' ]. +! + +testFirstOptional + | p first result | + p := 'a' asParser optional. + + result := (self first: p). + + self assert: result anySatisfy: [:e | e matches: '' ]. + self assert: result anySatisfy: [:e | e matches: 'a']. +! + +testFirstRepeat1 + | p first | + p := ('a' asParser / nil asParser) plus. + + first := self first: p. + + self assert: first anyMatches: 'a'. + self assert: first anyMatches: ''. +! + +testFirstSequence1 + | p first | + p := 'a' asParser, 'b' asParser . + + first := self first: p. + self assert: first size: 1. + self assert: first allMatches: 'a'. + self assert: first noneMatches: 'b'. +! + +testFirstSequence2 + | p first | + p := nil asParser, 'a' asParser, 'b' asParser . + + first := self first: p. + self assert: first size: 1. + self assert: first allMatches: 'a'. + self assert: first noneMatches: 'b'. + self assert: first noneMatches: ''. +! + +testFirstSequence3 + | p first | + p := nil asParser, nil asParser. + + self assert: (self first: p) anySatisfy: [:e | e end matches: '']. +! + +testFirstSequence4 + | p first | + p := ((nil asParser / 'a' asParser) plus), 'b' asParser. + + first := self first: p. + self assert: first anyMatches: 'b'. + self assert: first anyMatches: 'a'. + self assert: first noneMatches: ''. +! + +testFirstSequence5 + | p first | + p := ((nil asParser / 'a' asParser) star), 'b' asParser. + + first := self first: p. + self assert: first anyMatches: 'b'. + self assert: first anyMatches: 'a'. + self assert: first noneMatches: ''. +! + +testFirstTerminal2 + | p | + p := 'a' asParser not. + + self assert: (self first: p) noneMatches: 'a'. +! + +testFirstTerminal3 + | p | + p := 'a' asParser and. + + self assert: (self first: p) anyMatches: 'a' +! + +testFirstTerminal4 + | p | + p := nil asParser. + + self assert: (self first: p) anySatisfy: [:e | e end matches: '']. +! ! + +!FirstFollowNextTests methodsFor:'test follow'! + +testFollowNot1 + | p followSet terminal | + + terminal := 'a' asParser. + p := terminal, 'b' asParser not. + followSet := self follow: terminal in: p. + + self assert: followSet anySatisfy: [:e | e matches: 'c' ]. + self assert: followSet anySatisfy: [:e | (e matches: 'b') not ]. +! + +testFollowSet1 + | result p root followSet | + + + p := 'a' asParser. + root := (p star, 'b' asParser). + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e literal = 'a']. + self assert: followSet anySatisfy: [:e | e literal = 'b']. +! + +testFollowSet10 + | island1 followSet p root island2 block | + + island1 := ('class' asParser, self identifier) island. + island2 := ('extends' asParser, self identifier) island. + block := '{}' asParser island. + + root := (island1, island2 optional, block) star. + + followSet := self follow: block in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'class']. + self assert: followSet anySatisfy: [:e | e end matches: '']. +! + +testFollowSet11 + | island1 followSet p root island2 block | + + island1 := ('class' asParser, self identifier) island. + island2 := ('extends' asParser, self identifier) island. + block := '{}' asParser island. + + root := (island1, island2 optional, block) plus. + + followSet := self follow: block in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'class']. + self assert: followSet anySatisfy: [:e | e end matches: '']. +! + +testFollowSet12 + | parser followSet | + + + + parser := 'a' asParser. + followSet := self follow: parser in: parser. + + self assert: followSet anySatisfy: [:e | e end matches: '' ]. +! + +testFollowSet13 + | parser followSet a b c | + + a := 'a' asParser. + b := 'b' asParser optional. + c := 'c' asParser. + + + parser := a, b, c. + followSet := self follow: c in: parser. + self assert: followSet anySatisfy: [:e | e end matches: '' ]. + + followSet := self follow: b in: parser. + self assert: followSet anySatisfy: [:e | e end matches: 'c' ]. + + followSet := self follow: a in: parser. + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'c' ]. +! + +testFollowSet14 + | parser followSet a b c | + + a := 'a' asParser. + b := 'b' asParser optional. + c := 'c' asParser. + + + parser := a plus, b, c. + + followSet := self follow: a in: parser. + self assert: followSet anySatisfy: [:e | e end matches: 'a' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'c' ]. + self assert: followSet noneSatisfy: [:e | e end matches: '' ]. +! + +testFollowSet2 + | result p follow root followSets followSet | + + p := 'a' asParser. + follow := 'b' asParser, 'c' asParser. + + root := (p, follow). + + followSet := self follow: p in: root. + + self assert: followSet size: 1. + self assert: followSet anySatisfy: [:e | e end matches: 'b']. + self assert: followSet noneSatisfy: [:e | e matches: 'c']. +! + +testFollowSet3 + | result p follow root followSets followSet | + + p := 'a' asParser. + follow := ('b' asParser, 'c' asParser) / ('d' asParser). + + + root := (p, follow). + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'd' ]. +! + +testFollowSet4 + | result p follow root followSets followSet | + + p := 'a' asParser. + follow := ('b' asParser, 'c' asParser). + + + root := (p star, follow). + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'a' ]. +! + +testFollowSet5 + | result p root followSets followSet follow1 follow2 | + + p := 'a' asParser. + follow1 := ('b' asParser, 'c' asParser) / nil asParser. + follow2 := 'd' asParser. + + + root := (p, follow1, follow2). + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'd' ]. +! + +testFollowSet6 + | result p root followSets followSet follow follow1 follow2 | + + p := 'a' asParser. + follow1 := ('b' asParser, 'c' asParser) / nil asParser. + follow2 := 'd' asParser. + + follow := (follow1, follow2). + + root := (p, follow). + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'd' ]. +! + +testFollowSet7 + | result p root followSets followSet r1 r2 follow1 follow2 | + + p := 'a' asParser. + follow1 := ('b' asParser, 'c' asParser) / nil asParser. + follow2 := 'd' asParser / nil asParser . + + r1 := (p, follow1). + r2 := (r1, follow2). + + root := r2. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b' ]. + self assert: followSet anySatisfy: [:e | e end matches: 'd' ]. +! + +testFollowSet8 + | result p root followSets followSet follow | + + p := 'a' asParser. + follow := PPInputEnds new. + + root := p, follow. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: '']. +! + +testFollowSet9 + | island1 followSet p root island2 block | + + island1 := ('class' asParser, self identifier) island. + island2 := (':' asParser, self identifier) island. + block := '{' asParser, '}' asParser island. + + root := (island1, island2 optional, block) island. + + followSet := self follow: island1 in: root. + + self assert: followSet anySatisfy: [:e | e end matches: '{']. + self assert: followSet anySatisfy: [:e | e end matches: ':']. +! + +testFollowSetChoice1 + | result p root followSets followSet follow | + + p := 'a' asParser. + follow := 'b' asParser / 'c' asParser . + + root := p, follow. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | (e parse: 'b') isPetitFailure not]. + self assert: followSet anySatisfy: [:e | (e parse: 'c') isPetitFailure not]. + self assert: followSet noneSatisfy: [:e | (e parse: 'a') isPetitFailure not]. +! + +testFollowSetChoice2 + | result p root followSet follow b c | + + follow := 'a' asParser / 'd' asParser. + b := 'b' asParser. + c := 'c' asParser. + p := b / c. + + root := p, follow. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | (e parse: 'a') isPetitFailure not]. + self assert: followSet anySatisfy: [:e | (e parse: 'd') isPetitFailure not]. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | (e parse: 'a') isPetitFailure not]. + self assert: followSet noneSatisfy: [:e | (e parse: 'c') isPetitFailure not]. +! + +testFollowSetOptional1 + | result p root followSets followSet follow follow1 follow2 | + + p := 'a' asParser. + follow1 := 'b' asParser optional. + follow2 := 'c' asParser. + + root := p, follow1, follow2. + + followSet := self follow: p in: root. + + self assert: followSet anySatisfy: [:e | e end matches: 'b']. + self assert: followSet anySatisfy: [:e | e end matches: 'c']. + self assert: followSet noneSatisfy: [:e | e end matches: '']. +! + +testFollowSetRepeat1 + | p followSet terminal | + + terminal := 'a' asParser. + p := terminal plus. + + followSet := self follow: terminal in: p. + self assert: followSet anySatisfy: [:e | e end matches: 'a' ]. + self assert: followSet anySatisfy: [:e | e end matches: '' ]. + + followSet := self follow: p in: p. + self assert: followSet anySatisfy: [:e | e end matches: '' ]. +! + +testFollowSetStar1 + | a b p followSet | + + a := 'a' asParser star. + b := 'b' asParser. + p := a, b. + followSet := self follow: a in: p. + + self assert: followSet size: 1. + self assert: followSet anySatisfy: [:e | e end matches: 'b']. + self assert: followSet noneSatisfy: [:e | e end matches: '']. +! + +testFollowSetStar3 + | a b p followSet n | + + a := 'a' asParser star. + p := a. + followSet := self follow: a in: p. + + self assert: followSet noneSatisfy: [:e | e end matches: 'a']. + self assert: followSet anySatisfy: [:e | e end matches: '']. +! + +testFollowSetStar4 + | a b p followSet | + + a := 'a' asParser. + b := 'b' asParser. + p := a star, b. + followSet := self follow: a in: p. + + self assert: followSet size: 2. + self assert: followSet anySatisfy: [:e | e end matches: 'a']. + self assert: followSet anySatisfy: [:e | e end matches: 'b']. + self assert: followSet noneSatisfy: [:e | e end matches: '']. +! + +testFollowSetStar5 + | a b p followSet n | + + a := 'a' asParser. + b := 'b' asParser. + n := nil asParser. + p := a star, (b / n). + followSet := self follow: a in: p. + + + self assert: followSet anySatisfy: [:e | e end matches: 'a']. + self assert: followSet anySatisfy: [:e | e end matches: 'b']. + self assert: followSet anySatisfy: [:e | e end matches: '']. +! + +testFollowSetStar6 + | a b p followSet n | + + a := 'a' asParser. + p := a star. + followSet := self follow: a in: p. + + + self assert: followSet anySatisfy: [:e | e end matches: 'a']. + self assert: followSet anySatisfy: [:e | e end matches: '']. +! ! + +!FirstFollowNextTests methodsFor:'test isNullable'! + +testIsNullable01 + self assert: 'a' asParser acceptsEpsilon not. +! + +testIsNullable02 + self assert: 'a' asParser wrapped acceptsEpsilon not. +! + +testIsNullable03 + self assert: nil asParser acceptsEpsilon. +! + +testIsNullable04 + self assert: nil asParser wrapped acceptsEpsilon. +! + +testIsNullable05 + self assert: 'a' asParser not acceptsEpsilon not. +! + +testIsNullable06 + self assert: 'a' asParser and acceptsEpsilon not. +! + +testIsNullable07 + self assert: 'a' asParser wrapped not acceptsEpsilon not. +! + +testIsNullable08 + self assert: 'a' asParser wrapped and acceptsEpsilon not. +! + +testIsNullable09 + self assert: 'a' asParser optional acceptsEpsilon. +! + +testIsNullable10 + self assert: 'a' asParser wrapped optional acceptsEpsilon. +! + +testIsNullable11 + self assert: 'a' asParser wrapped not optional acceptsEpsilon. +! + +testIsNullable12 + self assert: 'a' asParser optional wrapped acceptsEpsilon. +! + +testIsNullableChoice1 + | a b c p | + a := 'a' asParser. + b := 'b' asParser. + c := 'c' asParser. + + p := a / b / c. + + self assert: p acceptsEpsilon not. +! + +testIsNullableChoice2 + | a b c p | + a := 'a' asParser. + b := 'b' asParser optional. + c := 'c' asParser. + + p := a / b / c. + + self assert: p acceptsEpsilon. +! + +testIsNullableChoice3 + | a b c p | + a := 'a' asParser optional. + b := 'b' asParser optional. + c := 'c' asParser optional. + + p := a / b / c. + + self assert: p acceptsEpsilon. +! + +testIsNullableChoice4 + | a b c p | + a := 'a' asParser optional wrapped. + b := 'b' asParser optional wrapped. + c := 'c' asParser optional wrapped. + + p := a / b / c. + + self assert: p acceptsEpsilon. +! + +testIsNullableCycle1 + | a p | + a := 'a' asParser. + p := PPDelegateParser new. + + p setParser: a / p. + self assert: p acceptsEpsilon not. +! + +testIsNullableCycle2 + | a p e | + a := 'a' asParser. + e := nil asParser. + p := PPDelegateParser new. + + p setParser: (a, p) / e. + + self assert: p acceptsEpsilon. +! + +testIsNullableCycle3 + | a p e | + a := 'a' asParser. + e := nil asParser. + p := PPDelegateParser new. + + p setParser: (a, p), e. + + self assert: p acceptsEpsilon not. +! + +testIsNullableSeq1 + | a b c p | + a := 'a' asParser. + b := 'b' asParser. + c := 'c' asParser. + + p := a, b, c. + + self assert: p acceptsEpsilon not. +! + +testIsNullableSeq2 + | a b c p | + a := 'a' asParser. + b := 'b' asParser optional. + c := 'c' asParser. + + p := a, b, c. + + self assert: p acceptsEpsilon not. +! + +testIsNullableSeq3 + | a b c p | + a := 'a' asParser optional. + b := 'b' asParser optional. + c := 'c' asParser optional. + + p := a, b, c. + + self assert: p acceptsEpsilon. +! + +testIsNullableSeq4 + | a b c p | + a := 'a' asParser optional wrapped. + b := 'b' asParser optional wrapped. + c := 'c' asParser wrapped optional. + + p := a, b, c. + + self assert: p acceptsEpsilon. +! ! + +!FirstFollowNextTests methodsFor:'test next'! + +testNext1 + | p nextSet | + p := 'a' asParser. + + nextSet := (self next: p in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. +! + +testNext2 + | p nextSet a b | + a := 'a' asParser. + b := 'b' asParser. + + p := a, b. + + nextSet := (self next: a in: p). + self assert: nextSet size: 1. + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + + nextSet := (self next: b in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. + + nextSet := (self next: p in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. +! + +testNext3 + | p nextSet a b | + a := 'a' asParser. + b := 'b' asParser. + + p := a / b. + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. + + nextSet := (self next: b in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. + + nextSet := (self next: p in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. +! + +testNext4 + | p nextSet a b n | + a := 'a' asParser. + b := 'b' asParser. + n := nil asParser. + + p := a, n, b. + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + + nextSet := (self next: n in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + + nextSet := (self next: b in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. +! + +testNext5 + | p nextSet a b n a1 a2 | + a1 := 'a1' asParser wrapped. + a2 := 'a2' asParser wrapped. + a := (a1 asParser, a2 asParser) wrapped. + b := 'b' asParser. + n := 'n' asParser optional. + + p := a, n, b. + + nextSet := (self next: a1 in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'a2']. + + nextSet := (self next: a2 in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + "Might be test to match nb -- not sure, what is better" + self assert: nextSet anySatisfy: [:e | e end matches: 'n']. + + + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + "Might be test to match nb -- not sure, what is better" + self assert: nextSet anySatisfy: [:e | e end matches: 'n']. + + nextSet := (self next: n in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + + nextSet := (self next: b in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. + self assert: nextSet noneSatisfy: [:e | e end matches: 'b']. +! + +testNext6 + | p nextSet a b n a1 a2 | + a1 := 'a1' asParser wrapped. + a2 := 'a2' asParser wrapped / nil asParser. + a := (a1 asParser, a2 asParser) wrapped. + b := 'b' asParser. + n := 'nil' asParser optional. + + p := a, n, b. + + nextSet := (self next: a1 in: p). + self assert: nextSet anySatisfy: [:e | e matches: 'a2']. + self assert: nextSet anySatisfy: [:e | e matches: 'nilb']. + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + + nextSet := (self next: a2 in: p). + self assert: nextSet anySatisfy: [:e | e matches: 'nilb']. + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e matches: 'nilb']. + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + + nextSet := (self next: n in: p). + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + + nextSet := (self next: b in: p). + self assert: nextSet anySatisfy: [:e | e end matches: '']. +! + +testNext7 + | p nextSet a b n c | + a := 'a' asParser. + b := 'b' asParser. + c := 'c' asParser. + n := nil asParser. + + p := a, b, a, n, c. + + nextSet := (self next: a in: p). + + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + self assert: nextSet anySatisfy: [:e | e matches: 'c']. + +! + +testNext8 + | p nextSet a b n c | + a := 'a' asParser. + b := 'b' asParser. + c := 'c' asParser. + n := nil asParser. + + p := a, n, a, b, c. + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e matches: 'a']. + self assert: nextSet anySatisfy: [:e | e matches: 'b']. + +! + +testNext9 + | a nextSet | + a := 'a' asParser. + + nextSet := (self next: a in: a). + self assert: nextSet anySatisfy: [:e | e end matches: '']. + + +! + +testNextDelegate1 + + | a nextSet b c p | + a := 'a' asParser optional wrapped. + b := 'b' asParser optional wrapped. + c := 'c' asParser optional wrapped. + p := a, b, c. + + nextSet := (self next: a in: p). + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + self assert: nextSet anySatisfy: [:e | e end matches: 'c']. + + +! + +testNextRepeat1 + | p nextSet a b n c | + a := 'a' asParser star. + + nextSet := (self next: a in: a). + self assert: nextSet size: 1. + self assert: nextSet anySatisfy: [:e | e end matches: ''] +! + +testNextRepeat2 + | p nextSet a b astar | + a := 'a' asParser. + b := 'b' asParser. + astar := a star. + + p := astar, b. + + nextSet := (self next: astar in: p). + + self assert: nextSet size: 1. + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + + +! + +testNextRepeat3 + | p nextSet a b astar | + a := 'a' asParser. + b := 'b' asParser. + + p := a star, b. + + nextSet := (self next: a in: p). + + self assert: nextSet size: 2. + self assert: nextSet anySatisfy: [:e | e end matches: 'b']. + self assert: nextSet anySatisfy: [:e | e end matches: 'a']. +! + +testNextRepeat4 + | a nextSet b p root | + a := 'a' asParser. + b := 'b' asParser optional. + + p := a, b. + root := p plus. + + nextSet := (self next: a in: root). + self assert: nextSet anySatisfy: [:e | e end matches: 'a']. + + +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/JavaParserTest.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/JavaParserTest.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,5664 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +PPCompositeParserTest subclass:#JavaParserTest + instanceVariableNames:'debugResult context' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +JavaParserTest comment:'' +! + + +!JavaParserTest class methodsFor:'as yet unclassified'! + +classJavaLangClass + ^ self new classJavaLangClass +! + +classJavaLangObject + ^ self new classJavaLangObject +! ! + +!JavaParserTest methodsFor:'as yet unclassified'! + +context + context ifNil: [ + context := PPContext new. + ]. + ^ context + + +! + +createContext: anInput + | context | + context := PPContext on: self parserInstance stream: anInput asPetitStream. + self parserInstance updateContext: context. + + ^ context + + +! + +parserClass + ^ JavaParser +! + +setUp + super setUp. + context := nil. +! ! + +!JavaParserTest methodsFor:'src'! + +classJavaIoInputStream + ^ +' +/* + * @(#)InputStream.java 1.45 04/02/19 + * + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. + */ + +package java.io; + +/** + * This abstract class is the superclass of all classes representing + * an input stream of bytes. + * + *

Applications that need to define a subclass of InputStream + * must always provide a method that returns the next byte of input. + * + * @author Arthur van Hoff + * @version 1.45, 02/19/04 + * @see java.io.BufferedInputStream + * @see java.io.ByteArrayInputStream + * @see java.io.DataInputStream + * @see java.io.FilterInputStream + * @see java.io.InputStream#read() + * @see java.io.OutputStream + * @see java.io.PushbackInputStream + * @since JDK1.0 + */ +public abstract class InputStream implements Closeable { + + // SKIP_BUFFER_SIZE is used to determine the size of skipBuffer + private static final int SKIP_BUFFER_SIZE = 2048; + // skipBuffer is initialized in skip(long), if needed. + private static byte[] skipBuffer; + + /** + * Reads the next byte of data from the input stream. The value byte is + * returned as an int in the range 0 to + * 255. If no byte is available because the end of the stream + * has been reached, the value -1 is returned. This method + * blocks until input data is available, the end of the stream is detected, + * or an exception is thrown. + * + *

A subclass must provide an implementation of this method. + * + * @return the next byte of data, or -1 if the end of the + * stream is reached. + * @exception IOException if an I/O error occurs. + */ + public abstract int read() throws IOException; + + /** + * Reads some number of bytes from the input stream and stores them into + * the buffer array b. The number of bytes actually read is + * returned as an integer. This method blocks until input data is + * available, end of file is detected, or an exception is thrown. + * + *

If b is null, a + * NullPointerException is thrown. If the length of + * b is zero, then no bytes are read and 0 is + * returned; otherwise, there is an attempt to read at least one byte. If + * no byte is available because the stream is at end of file, the value + * -1 is returned; otherwise, at least one byte is read and + * stored into b. + * + *

The first byte read is stored into element b[0], the + * next one into b[1], and so on. The number of bytes read is, + * at most, equal to the length of b. Let k be the + * number of bytes actually read; these bytes will be stored in elements + * b[0] through b[k-1], + * leaving elements b[k] through + * b[b.length-1] unaffected. + * + *

If the first byte cannot be read for any reason other than end of + * file, then an IOException is thrown. In particular, an + * IOException is thrown if the input stream has been closed. + * + *

The read(b) method for class InputStream + * has the same effect as:

 read(b, 0, b.length) 
+ * + * @param b the buffer into which the data is read. + * @return the total number of bytes read into the buffer, or + * -1 is there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @exception NullPointerException if b is null. + * @see java.io.InputStream#read(byte[], int, int) + */ + public int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from the input stream into + * an array of bytes. An attempt is made to read as many as + * len bytes, but a smaller number may be read. + * The number of bytes actually read is returned as an integer. + * + *

This method blocks until input data is available, end of file is + * detected, or an exception is thrown. + * + *

If b is null, a + * NullPointerException is thrown. + * + *

If off is negative, or len is negative, or + * off+len is greater than the length of the array + * b, then an IndexOutOfBoundsException is + * thrown. + * + *

If len is zero, then no bytes are read and + * 0 is returned; otherwise, there is an attempt to read at + * least one byte. If no byte is available because the stream is at end of + * file, the value -1 is returned; otherwise, at least one + * byte is read and stored into b. + * + *

The first byte read is stored into element b[off], the + * next one into b[off+1], and so on. The number of bytes read + * is, at most, equal to len. Let k be the number of + * bytes actually read; these bytes will be stored in elements + * b[off] through b[off+k-1], + * leaving elements b[off+k] through + * b[off+len-1] unaffected. + * + *

In every case, elements b[0] through + * b[off] and elements b[off+len] through + * b[b.length-1] are unaffected. + * + *

If the first byte cannot be read for any reason other than end of + * file, then an IOException is thrown. In particular, an + * IOException is thrown if the input stream has been closed. + * + *

The read(b, off, len) method + * for class InputStream simply calls the method + * read() repeatedly. If the first such call results in an + * IOException, that exception is returned from the call to + * the read(b, off, len) method. If + * any subsequent call to read() results in a + * IOException, the exception is caught and treated as if it + * were end of file; the bytes read up to that point are stored into + * b and the number of bytes read before the exception + * occurred is returned. Subclasses are encouraged to provide a more + * efficient implementation of this method. + * + * @param b the buffer into which the data is read. + * @param off the start offset in array b + * at which the data is written. + * @param len the maximum number of bytes to read. + * @return the total number of bytes read into the buffer, or + * -1 if there is no more data because the end of + * the stream has been reached. + * @exception IOException if an I/O error occurs. + * @exception NullPointerException if b is null. + * @see java.io.InputStream#read() + */ + public int read(byte b[], int off, int len) throws IOException { + if (b == null) { + throw new NullPointerException(); + } else if ((off < 0) || (off > b.length) || (len < 0) || + ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return 0; + } + + int c = read(); + if (c == -1) { + return -1; + } + b[off] = (byte)c; + + int i = 1; + try { + for (; i < len ; i++) { + c = read(); + if (c == -1) { + break; + } + if (b !!= null) { + b[off + i] = (byte)c; + } + } + } catch (IOException ee) { + } + return i; + } + + /** + * Skips over and discards n bytes of data from this input + * stream. The skip method may, for a variety of reasons, end + * up skipping over some smaller number of bytes, possibly 0. + * This may result from any of a number of conditions; reaching end of file + * before n bytes have been skipped is only one possibility. + * The actual number of bytes skipped is returned. If n is + * negative, no bytes are skipped. + * + *

The skip method of InputStream creates a + * byte array and then repeatedly reads into it until n bytes + * have been read or the end of the stream has been reached. Subclasses are + * encouraged to provide a more efficient implementation of this method. + * + * @param n the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException if an I/O error occurs. + */ + public long skip(long n) throws IOException { + + long remaining = n; + int nr; + if (skipBuffer == null) + skipBuffer = new byte[SKIP_BUFFER_SIZE]; + + byte[] localSkipBuffer = skipBuffer; + + if (n <= 0) { + return 0; + } + + while (remaining > 0) { + nr = read(localSkipBuffer, 0, + (int) Math.min(SKIP_BUFFER_SIZE, remaining)); + if (nr < 0) { + break; + } + remaining -= nr; + } + + return n - remaining; + } + + /** + * Returns the number of bytes that can be read (or skipped over) from + * this input stream without blocking by the next caller of a method for + * this input stream. The next caller might be the same thread or + * another thread. + * + *

The available method for class InputStream + * always returns 0. + * + *

This method should be overridden by subclasses. + * + * @return the number of bytes that can be read from this input stream + * without blocking. + * @exception IOException if an I/O error occurs. + */ + public int available() throws IOException { + return 0; + } + + /** + * Closes this input stream and releases any system resources associated + * with the stream. + * + *

The close method of InputStream does + * nothing. + * + * @exception IOException if an I/O error occurs. + */ + public void close() throws IOException {} + + /** + * Marks the current position in this input stream. A subsequent call to + * the reset method repositions this stream at the last marked + * position so that subsequent reads re-read the same bytes. + * + *

The readlimit arguments tells this input stream to + * allow that many bytes to be read before the mark position gets + * invalidated. + * + *

The general contract of mark is that, if the method + * markSupported returns true, the stream somehow + * remembers all the bytes read after the call to mark and + * stands ready to supply those same bytes again if and whenever the method + * reset is called. However, the stream is not required to + * remember any data at all if more than readlimit bytes are + * read from the stream before reset is called. + * + *

The mark method of InputStream does + * nothing. + * + * @param readlimit the maximum limit of bytes that can be read before + * the mark position becomes invalid. + * @see java.io.InputStream#reset() + */ + public synchronized void mark(int readlimit) {} + + /** + * Repositions this stream to the position at the time the + * mark method was last called on this input stream. + * + *

The general contract of reset is: + * + *

    + * + *
  • If the method markSupported returns + * true, then: + * + *
    • If the method mark has not been called since + * the stream was created, or the number of bytes read from the stream + * since mark was last called is larger than the argument + * to mark at that last call, then an + * IOException might be thrown. + * + *
    • If such an IOException is not thrown, then the + * stream is reset to a state such that all the bytes read since the + * most recent call to mark (or since the start of the + * file, if mark has not been called) will be resupplied + * to subsequent callers of the read method, followed by + * any bytes that otherwise would have been the next input data as of + * the time of the call to reset.
    + * + *
  • If the method markSupported returns + * false, then: + * + *
    • The call to reset may throw an + * IOException. + * + *
    • If an IOException is not thrown, then the stream + * is reset to a fixed state that depends on the particular type of the + * input stream and how it was created. The bytes that will be supplied + * to subsequent callers of the read method depend on the + * particular type of the input stream.
+ * + *

The method reset for class InputStream + * does nothing except throw an IOException. + * + * @exception IOException if this stream has not been marked or if the + * mark has been invalidated. + * @see java.io.InputStream#mark(int) + * @see java.io.IOException + */ + public synchronized void reset() throws IOException { + throw new IOException("mark/reset not supported"); + } + + /** + * Tests if this input stream supports the mark and + * reset methods. Whether or not mark and + * reset are supported is an invariant property of a + * particular input stream instance. The markSupported method + * of InputStream returns false. + * + * @return true if this stream instance supports the mark + * and reset methods; false otherwise. + * @see java.io.InputStream#mark(int) + * @see java.io.InputStream#reset() + */ + public boolean markSupported() { + return false; + } + +} +' +! + +classJavaLangClass + ^ +'/* + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Member; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.InvocationTargetException; +import java.lang.ref.SoftReference; +import java.io.InputStream; +import java.io.ObjectStreamField; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.Map; +import java.util.HashMap; +import sun.misc.Unsafe; +import sun.reflect.ConstantPool; +import sun.reflect.Reflection; +import sun.reflect.ReflectionFactory; +import sun.reflect.SignatureIterator; +import sun.reflect.generics.factory.CoreReflectionFactory; +import sun.reflect.generics.factory.GenericsFactory; +import sun.reflect.generics.repository.ClassRepository; +import sun.reflect.generics.repository.MethodRepository; +import sun.reflect.generics.repository.ConstructorRepository; +import sun.reflect.generics.scope.ClassScope; +import sun.security.util.SecurityConstants; +import java.lang.annotation.Annotation; +import sun.reflect.annotation.*; + +/** + * Instances of the class {@code Class} represent classes and + * interfaces in a running Java application. An enum is a kind of + * class and an annotation is a kind of interface. Every array also + * belongs to a class that is reflected as a {@code Class} object + * that is shared by all arrays with the same element type and number + * of dimensions. The primitive Java types ({@code boolean}, + * {@code byte}, {@code char}, {@code short}, + * {@code int}, {@code long}, {@code float}, and + * {@code double}), and the keyword {@code void} are also + * represented as {@code Class} objects. + * + *

{@code Class} has no public constructor. Instead {@code Class} + * objects are constructed automatically by the Java Virtual Machine as classes + * are loaded and by calls to the {@code defineClass} method in the class + * loader. + * + *

The following example uses a {@code Class} object to print the + * class name of an object: + * + *

+ *     void printClassName(Object obj) {
+ *         System.out.println("The class of " + obj +
+ *                            " is " + obj.getClass().getName());
+ *     }
+ * 
+ * + *

It is also possible to get the {@code Class} object for a named + * type (or for void) using a class literal + * (JLS Section 15.8.2). + * For example: + * + *

+ * {@code System.out.println("The name of class Foo is: "+Foo.class.getName());} + *
+ * + * @param the type of the class modeled by this {@code Class} + * object. For example, the type of {@code String.class} is {@code + * Class}. Use {@code Class} if the class being modeled is + * unknown. + * + * @author unascribed + * @see java.lang.ClassLoader#defineClass(byte[], int, int) + * @since JDK1.0 + */ +public final + class Class implements java.io.Serializable, + java.lang.reflect.GenericDeclaration, + java.lang.reflect.Type, + java.lang.reflect.AnnotatedElement { + private static final int ANNOTATION= 0x00002000; + private static final int ENUM = 0x00004000; + private static final int SYNTHETIC = 0x00001000; + + private static native void registerNatives(); + static { + registerNatives(); + } + + /* + * Constructor. Only the Java Virtual Machine creates Class + * objects. + */ + private Class() {} + + + /** + * Converts the object to a string. The string representation is the + * string "class" or "interface", followed by a space, and then by the + * fully qualified name of the class in the format returned by + * {@code getName}. If this {@code Class} object represents a + * primitive type, this method returns the name of the primitive type. If + * this {@code Class} object represents void this method returns + * "void". + * + * @return a string representation of this class object. + */ + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } + + + /** + * Returns the {@code Class} object associated with the class or + * interface with the given string name. Invoking this method is + * equivalent to: + * + *
+ * {@code Class.forName(className, true, currentLoader)} + *
+ * + * where {@code currentLoader} denotes the defining class loader of + * the current class. + * + *

For example, the following code fragment returns the + * runtime {@code Class} descriptor for the class named + * {@code java.lang.Thread}: + * + *

+ * {@code Class t = Class.forName("java.lang.Thread")} + *
+ *

+ * A call to {@code forName("X")} causes the class named + * {@code X} to be initialized. + * + * @param className the fully qualified name of the desired class. + * @return the {@code Class} object for the class with the + * specified name. + * @exception LinkageError if the linkage fails + * @exception ExceptionInInitializerError if the initialization provoked + * by this method fails + * @exception ClassNotFoundException if the class cannot be located + */ + public static Class forName(String className) + throws ClassNotFoundException { + return forName0(className, true, ClassLoader.getCallerClassLoader()); + } + + + /** + * Returns the {@code Class} object associated with the class or + * interface with the given string name, using the given class loader. + * Given the fully qualified name for a class or interface (in the same + * format returned by {@code getName}) this method attempts to + * locate, load, and link the class or interface. The specified class + * loader is used to load the class or interface. If the parameter + * {@code loader} is null, the class is loaded through the bootstrap + * class loader. The class is initialized only if the + * {@code initialize} parameter is {@code true} and if it has + * not been initialized earlier. + * + *

If {@code name} denotes a primitive type or void, an attempt + * will be made to locate a user-defined class in the unnamed package whose + * name is {@code name}. Therefore, this method cannot be used to + * obtain any of the {@code Class} objects representing primitive + * types or void. + * + *

If {@code name} denotes an array class, the component type of + * the array class is loaded but not initialized. + * + *

For example, in an instance method the expression: + * + *

+ * {@code Class.forName("Foo")} + *
+ * + * is equivalent to: + * + *
+ * {@code Class.forName("Foo", true, this.getClass().getClassLoader())} + *
+ * + * Note that this method throws errors related to loading, linking or + * initializing as specified in Sections 12.2, 12.3 and 12.4 of The + * Java Language Specification. + * Note that this method does not check whether the requested class + * is accessible to its caller. + * + *

If the {@code loader} is {@code null}, and a security + * manager is present, and the caller''s class loader is not null, then this + * method calls the security manager''s {@code checkPermission} method + * with a {@code RuntimePermission("getClassLoader")} permission to + * ensure it''s ok to access the bootstrap class loader. + * + * @param name fully qualified name of the desired class + * @param initialize whether the class must be initialized + * @param loader class loader from which the class must be loaded + * @return class object representing the desired class + * + * @exception LinkageError if the linkage fails + * @exception ExceptionInInitializerError if the initialization provoked + * by this method fails + * @exception ClassNotFoundException if the class cannot be located by + * the specified class loader + * + * @see java.lang.Class#forName(String) + * @see java.lang.ClassLoader + * @since 1.2 + */ + public static Class forName(String name, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) { + SecurityManager sm = System.getSecurityManager(); + if (sm !!= null) { + ClassLoader ccl = ClassLoader.getCallerClassLoader(); + if (ccl !!= null) { + sm.checkPermission( + SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + return forName0(name, initialize, loader); + } + + /** Called after security checks have been made. */ + private static native Class forName0(String name, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException; + + /** + * Creates a new instance of the class represented by this {@code Class} + * object. The class is instantiated as if by a {@code new} + * expression with an empty argument list. The class is initialized if it + * has not already been initialized. + * + *

Note that this method propagates any exception thrown by the + * nullary constructor, including a checked exception. Use of + * this method effectively bypasses the compile-time exception + * checking that would otherwise be performed by the compiler. + * The {@link + * java.lang.reflect.Constructor#newInstance(java.lang.Object...) + * Constructor.newInstance} method avoids this problem by wrapping + * any exception thrown by the constructor in a (checked) {@link + * java.lang.reflect.InvocationTargetException}. + * + * @return a newly allocated instance of the class represented by this + * object. + * @exception IllegalAccessException if the class or its nullary + * constructor is not accessible. + * @exception InstantiationException + * if this {@code Class} represents an abstract class, + * an interface, an array class, a primitive type, or void; + * or if the class has no nullary constructor; + * or if the instantiation fails for some other reason. + * @exception ExceptionInInitializerError if the initialization + * provoked by this method fails. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * creation of new instances of this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + */ + public T newInstance() + throws InstantiationException, IllegalAccessException + { + if (System.getSecurityManager() !!= null) { + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + } + return newInstance0(); + } + + private T newInstance0() + throws InstantiationException, IllegalAccessException + { + // NOTE: the following code may not be strictly correct under + // the current Java memory model. + + // Constructor lookup + if (cachedConstructor == null) { + if (this == Class.class) { + throw new IllegalAccessException( + "Can not call newInstance() on the Class for java.lang.Class" + ); + } + try { + Class[] empty = {}; + final Constructor c = getConstructor0(empty, Member.DECLARED); + // Disable accessibility checks on the constructor + // since we have to do the security check here anyway + // (the stack depth is wrong for the Constructor''s + // security check to work) + java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + c.setAccessible(true); + return null; + } + }); + cachedConstructor = c; + } catch (NoSuchMethodException e) { + throw new InstantiationException(getName()); + } + } + Constructor tmpConstructor = cachedConstructor; + // Security check (same as in java.lang.reflect.Constructor) + int modifiers = tmpConstructor.getModifiers(); + if (!!Reflection.quickCheckMemberAccess(this, modifiers)) { + Class caller = Reflection.getCallerClass(3); + if (newInstanceCallerCache !!= caller) { + Reflection.ensureMemberAccess(caller, this, null, modifiers); + newInstanceCallerCache = caller; + } + } + // Run constructor + try { + return tmpConstructor.newInstance((Object[])null); + } catch (InvocationTargetException e) { + Unsafe.getUnsafe().throwException(e.getTargetException()); + // Not reached + return null; + } + } + private volatile transient Constructor cachedConstructor; + private volatile transient Class newInstanceCallerCache; + + + /** + * Determines if the specified {@code Object} is assignment-compatible + * with the object represented by this {@code Class}. This method is + * the dynamic equivalent of the Java language {@code instanceof} + * operator. The method returns {@code true} if the specified + * {@code Object} argument is non-null and can be cast to the + * reference type represented by this {@code Class} object without + * raising a {@code ClassCastException.} It returns {@code false} + * otherwise. + * + *

Specifically, if this {@code Class} object represents a + * declared class, this method returns {@code true} if the specified + * {@code Object} argument is an instance of the represented class (or + * of any of its subclasses); it returns {@code false} otherwise. If + * this {@code Class} object represents an array class, this method + * returns {@code true} if the specified {@code Object} argument + * can be converted to an object of the array class by an identity + * conversion or by a widening reference conversion; it returns + * {@code false} otherwise. If this {@code Class} object + * represents an interface, this method returns {@code true} if the + * class or any superclass of the specified {@code Object} argument + * implements this interface; it returns {@code false} otherwise. If + * this {@code Class} object represents a primitive type, this method + * returns {@code false}. + * + * @param obj the object to check + * @return true if {@code obj} is an instance of this class + * + * @since JDK1.1 + */ + public native boolean isInstance(Object obj); + + + /** + * Determines if the class or interface represented by this + * {@code Class} object is either the same as, or is a superclass or + * superinterface of, the class or interface represented by the specified + * {@code Class} parameter. It returns {@code true} if so; + * otherwise it returns {@code false}. If this {@code Class} + * object represents a primitive type, this method returns + * {@code true} if the specified {@code Class} parameter is + * exactly this {@code Class} object; otherwise it returns + * {@code false}. + * + *

Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * or via a widening reference conversion. See The Java Language + * Specification, sections 5.1.1 and 5.1.4 , for details. + * + * @param cls the {@code Class} object to be checked + * @return the {@code boolean} value indicating whether objects of the + * type {@code cls} can be assigned to objects of this class + * @exception NullPointerException if the specified Class parameter is + * null. + * @since JDK1.1 + */ + public native boolean isAssignableFrom(Class cls); + + + /** + * Determines if the specified {@code Class} object represents an + * interface type. + * + * @return {@code true} if this object represents an interface; + * {@code false} otherwise. + */ + public native boolean isInterface(); + + + /** + * Determines if this {@code Class} object represents an array class. + * + * @return {@code true} if this object represents an array class; + * {@code false} otherwise. + * @since JDK1.1 + */ + public native boolean isArray(); + + + /** + * Determines if the specified {@code Class} object represents a + * primitive type. + * + *

There are nine predefined {@code Class} objects to represent + * the eight primitive types and void. These are created by the Java + * Virtual Machine, and have the same names as the primitive types that + * they represent, namely {@code boolean}, {@code byte}, + * {@code char}, {@code short}, {@code int}, + * {@code long}, {@code float}, and {@code double}. + * + *

These objects may only be accessed via the following public static + * final variables, and are the only {@code Class} objects for which + * this method returns {@code true}. + * + * @return true if and only if this class represents a primitive type + * + * @see java.lang.Boolean#TYPE + * @see java.lang.Character#TYPE + * @see java.lang.Byte#TYPE + * @see java.lang.Short#TYPE + * @see java.lang.Integer#TYPE + * @see java.lang.Long#TYPE + * @see java.lang.Float#TYPE + * @see java.lang.Double#TYPE + * @see java.lang.Void#TYPE + * @since JDK1.1 + */ + public native boolean isPrimitive(); + + /** + * Returns true if this {@code Class} object represents an annotation + * type. Note that if this method returns true, {@link #isInterface()} + * would also return true, as all annotation types are also interfaces. + * + * @return {@code true} if this class object represents an annotation + * type; {@code false} otherwise + * @since 1.5 + */ + public boolean isAnnotation() { + return (getModifiers() & ANNOTATION) !!= 0; + } + + /** + * Returns {@code true} if this class is a synthetic class; + * returns {@code false} otherwise. + * @return {@code true} if and only if this class is a synthetic class as + * defined by the Java Language Specification. + * @since 1.5 + */ + public boolean isSynthetic() { + return (getModifiers() & SYNTHETIC) !!= 0; + } + + /** + * Returns the name of the entity (class, interface, array class, + * primitive type, or void) represented by this {@code Class} object, + * as a {@code String}. + * + *

If this class object represents a reference type that is not an + * array type then the binary name of the class is returned, as specified + * by the Java Language Specification, Second Edition. + * + *

If this class object represents a primitive type or void, then the + * name returned is a {@code String} equal to the Java language + * keyword corresponding to the primitive type or void. + * + *

If this class object represents a class of arrays, then the internal + * form of the name consists of the name of the element type preceded by + * one or more ''{@code [}'' characters representing the depth of the array + * nesting. The encoding of element type names is as follows: + * + *

+ *
Element Type     Encoding + *
boolean     Z + *
byte     B + *
char     C + *
class or interface + *     Lclassname; + *
double     D + *
float     F + *
int     I + *
long     J + *
short     S + *
+ * + *

The class or interface name classname is the binary name of + * the class specified above. + * + *

Examples: + *

+     * String.class.getName()
+     *     returns "java.lang.String"
+     * byte.class.getName()
+     *     returns "byte"
+     * (new Object[3]).getClass().getName()
+     *     returns "[Ljava.lang.Object;"
+     * (new int[3][4][5][6][7][8][9]).getClass().getName()
+     *     returns "[[[[[[[I"
+     * 
+ * + * @return the name of the class or interface + * represented by this object. + */ + public String getName() { + if (name == null) + name = getName0(); + return name; + } + + // cache the name to reduce the number of calls into the VM + private transient String name; + private native String getName0(); + + /** + * Returns the class loader for the class. Some implementations may use + * null to represent the bootstrap class loader. This method will return + * null in such implementations if this class was loaded by the bootstrap + * class loader. + * + *

If a security manager is present, and the caller''s class loader is + * not null and the caller''s class loader is not the same as or an ancestor of + * the class loader for the class whose class loader is requested, then + * this method calls the security manager''s {@code checkPermission} + * method with a {@code RuntimePermission("getClassLoader")} + * permission to ensure it''s ok to access the class loader for the class. + * + *

If this object + * represents a primitive type or void, null is returned. + * + * @return the class loader that loaded the class or interface + * represented by this object. + * @throws SecurityException + * if a security manager exists and its + * {@code checkPermission} method denies + * access to the class loader for the class. + * @see java.lang.ClassLoader + * @see SecurityManager#checkPermission + * @see java.lang.RuntimePermission + */ + public ClassLoader getClassLoader() { + ClassLoader cl = getClassLoader0(); + if (cl == null) + return null; + SecurityManager sm = System.getSecurityManager(); + if (sm !!= null) { + ClassLoader ccl = ClassLoader.getCallerClassLoader(); + if (ccl !!= null && ccl !!= cl && !!cl.isAncestor(ccl)) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + return cl; + } + + // Package-private to allow ClassLoader access + native ClassLoader getClassLoader0(); + + + /** + * Returns an array of {@code TypeVariable} objects that represent the + * type variables declared by the generic declaration represented by this + * {@code GenericDeclaration} object, in declaration order. Returns an + * array of length 0 if the underlying generic declaration declares no type + * variables. + * + * @return an array of {@code TypeVariable} objects that represent + * the type variables declared by this generic declaration + * @throws GenericSignatureFormatError if the generic + * signature of this generic declaration does not conform to + * the format specified in the Java Virtual Machine Specification, + * 3rd edition + * @since 1.5 + */ + public TypeVariable>[] getTypeParameters() { + if (getGenericSignature() !!= null) + return (TypeVariable>[])getGenericInfo().getTypeParameters(); + else + return (TypeVariable>[])new TypeVariable[0]; + } + + + /** + * Returns the {@code Class} representing the superclass of the entity + * (class, interface, primitive type or void) represented by this + * {@code Class}. If this {@code Class} represents either the + * {@code Object} class, an interface, a primitive type, or void, then + * null is returned. If this object represents an array class then the + * {@code Class} object representing the {@code Object} class is + * returned. + * + * @return the superclass of the class represented by this object. + */ + public native Class getSuperclass(); + + + /** + * Returns the {@code Type} representing the direct superclass of + * the entity (class, interface, primitive type or void) represented by + * this {@code Class}. + * + *

If the superclass is a parameterized type, the {@code Type} + * object returned must accurately reflect the actual type + * parameters used in the source code. The parameterized type + * representing the superclass is created if it had not been + * created before. See the declaration of {@link + * java.lang.reflect.ParameterizedType ParameterizedType} for the + * semantics of the creation process for parameterized types. If + * this {@code Class} represents either the {@code Object} + * class, an interface, a primitive type, or void, then null is + * returned. If this object represents an array class then the + * {@code Class} object representing the {@code Object} class is + * returned. + * + * @throws GenericSignatureFormatError if the generic + * class signature does not conform to the format specified in the + * Java Virtual Machine Specification, 3rd edition + * @throws TypeNotPresentException if the generic superclass + * refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if the + * generic superclass refers to a parameterized type that cannot be + * instantiated for any reason + * @return the superclass of the class represented by this object + * @since 1.5 + */ + public Type getGenericSuperclass() { + if (getGenericSignature() !!= null) { + // Historical irregularity: + // Generic signature marks interfaces with superclass = Object + // but this API returns null for interfaces + if (isInterface()) + return null; + return getGenericInfo().getSuperclass(); + } else + return getSuperclass(); + } + + /** + * Gets the package for this class. The class loader of this class is used + * to find the package. If the class was loaded by the bootstrap class + * loader the set of packages loaded from CLASSPATH is searched to find the + * package of the class. Null is returned if no package object was created + * by the class loader of this class. + * + *

Packages have attributes for versions and specifications only if the + * information was defined in the manifests that accompany the classes, and + * if the class loader created the package instance with the attributes + * from the manifest. + * + * @return the package of the class, or null if no package + * information is available from the archive or codebase. + */ + public Package getPackage() { + return Package.getPackage(this); + } + + + /** + * Determines the interfaces implemented by the class or interface + * represented by this object. + * + *

If this object represents a class, the return value is an array + * containing objects representing all interfaces implemented by the + * class. The order of the interface objects in the array corresponds to + * the order of the interface names in the {@code implements} clause + * of the declaration of the class represented by this object. For + * example, given the declaration: + *

+ * {@code class Shimmer implements FloorWax, DessertTopping { ... }} + *
+ * suppose the value of {@code s} is an instance of + * {@code Shimmer}; the value of the expression: + *
+ * {@code s.getClass().getInterfaces()[0]} + *
+ * is the {@code Class} object that represents interface + * {@code FloorWax}; and the value of: + *
+ * {@code s.getClass().getInterfaces()[1]} + *
+ * is the {@code Class} object that represents interface + * {@code DessertTopping}. + * + *

If this object represents an interface, the array contains objects + * representing all interfaces extended by the interface. The order of the + * interface objects in the array corresponds to the order of the interface + * names in the {@code extends} clause of the declaration of the + * interface represented by this object. + * + *

If this object represents a class or interface that implements no + * interfaces, the method returns an array of length 0. + * + *

If this object represents a primitive type or void, the method + * returns an array of length 0. + * + * @return an array of interfaces implemented by this class. + */ + public native Class[] getInterfaces(); + + /** + * Returns the {@code Type}s representing the interfaces + * directly implemented by the class or interface represented by + * this object. + * + *

If a superinterface is a parameterized type, the + * {@code Type} object returned for it must accurately reflect + * the actual type parameters used in the source code. The + * parameterized type representing each superinterface is created + * if it had not been created before. See the declaration of + * {@link java.lang.reflect.ParameterizedType ParameterizedType} + * for the semantics of the creation process for parameterized + * types. + * + *

If this object represents a class, the return value is an + * array containing objects representing all interfaces + * implemented by the class. The order of the interface objects in + * the array corresponds to the order of the interface names in + * the {@code implements} clause of the declaration of the class + * represented by this object. In the case of an array class, the + * interfaces {@code Cloneable} and {@code Serializable} are + * returned in that order. + * + *

If this object represents an interface, the array contains + * objects representing all interfaces directly extended by the + * interface. The order of the interface objects in the array + * corresponds to the order of the interface names in the + * {@code extends} clause of the declaration of the interface + * represented by this object. + * + *

If this object represents a class or interface that + * implements no interfaces, the method returns an array of length + * 0. + * + *

If this object represents a primitive type or void, the + * method returns an array of length 0. + * + * @throws GenericSignatureFormatError + * if the generic class signature does not conform to the format + * specified in the Java Virtual Machine Specification, 3rd edition + * @throws TypeNotPresentException if any of the generic + * superinterfaces refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if any of the + * generic superinterfaces refer to a parameterized type that cannot + * be instantiated for any reason + * @return an array of interfaces implemented by this class + * @since 1.5 + */ + public Type[] getGenericInterfaces() { + if (getGenericSignature() !!= null) + return getGenericInfo().getSuperInterfaces(); + else + return getInterfaces(); + } + + + /** + * Returns the {@code Class} representing the component type of an + * array. If this class does not represent an array class this method + * returns null. + * + * @return the {@code Class} representing the component type of this + * class if this class is an array + * @see java.lang.reflect.Array + * @since JDK1.1 + */ + public native Class getComponentType(); + + + /** + * Returns the Java language modifiers for this class or interface, encoded + * in an integer. The modifiers consist of the Java Virtual Machine''s + * constants for {@code public}, {@code protected}, + * {@code private}, {@code final}, {@code static}, + * {@code abstract} and {@code interface}; they should be decoded + * using the methods of class {@code Modifier}. + * + *

If the underlying class is an array class, then its + * {@code public}, {@code private} and {@code protected} + * modifiers are the same as those of its component type. If this + * {@code Class} represents a primitive type or void, its + * {@code public} modifier is always {@code true}, and its + * {@code protected} and {@code private} modifiers are always + * {@code false}. If this object represents an array class, a + * primitive type or void, then its {@code final} modifier is always + * {@code true} and its interface modifier is always + * {@code false}. The values of its other modifiers are not determined + * by this specification. + * + *

The modifier encodings are defined in The Java Virtual Machine + * Specification, table 4.1. + * + * @return the {@code int} representing the modifiers for this class + * @see java.lang.reflect.Modifier + * @since JDK1.1 + */ + public native int getModifiers(); + + + /** + * Gets the signers of this class. + * + * @return the signers of this class, or null if there are no signers. In + * particular, this method returns null if this object represents + * a primitive type or void. + * @since JDK1.1 + */ + public native Object[] getSigners(); + + + /** + * Set the signers of this class. + */ + native void setSigners(Object[] signers); + + + /** + * If this {@code Class} object represents a local or anonymous + * class within a method, returns a {@link + * java.lang.reflect.Method Method} object representing the + * immediately enclosing method of the underlying class. Returns + * {@code null} otherwise. + * + * In particular, this method returns {@code null} if the underlying + * class is a local or anonymous class immediately enclosed by a type + * declaration, instance initializer or static initializer. + * + * @return the immediately enclosing method of the underlying class, if + * that class is a local or anonymous class; otherwise {@code null}. + * @since 1.5 + */ + public Method getEnclosingMethod() { + EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); + + if (enclosingInfo == null) + return null; + else { + if (!!enclosingInfo.isMethod()) + return null; + + MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(), + getFactory()); + Class returnType = toClass(typeInfo.getReturnType()); + Type [] parameterTypes = typeInfo.getParameterTypes(); + Class[] parameterClasses = new Class[parameterTypes.length]; + + // Convert Types to Classes; returned types *should* + // be class objects since the methodDescriptor''s used + // don''t have generics information + for(int i = 0; i < parameterClasses.length; i++) + parameterClasses[i] = toClass(parameterTypes[i]); + + /* + * Loop over all declared methods; match method name, + * number of and type of parameters, *and* return + * type. Matching return type is also necessary + * because of covariant returns, etc. + */ + for(Method m: enclosingInfo.getEnclosingClass().getDeclaredMethods()) { + if (m.getName().equals(enclosingInfo.getName()) ) { + Class[] candidateParamClasses = m.getParameterTypes(); + if (candidateParamClasses.length == parameterClasses.length) { + boolean matches = true; + for(int i = 0; i < candidateParamClasses.length; i++) { + if (!!candidateParamClasses[i].equals(parameterClasses[i])) { + matches = false; + break; + } + } + + if (matches) { // finally, check return type + if (m.getReturnType().equals(returnType) ) + return m; + } + } + } + } + + throw new InternalError("Enclosing method not found"); + } + } + + private native Object[] getEnclosingMethod0(); + + private EnclosingMethodInfo getEnclosingMethodInfo() { + Object[] enclosingInfo = getEnclosingMethod0(); + if (enclosingInfo == null) + return null; + else { + return new EnclosingMethodInfo(enclosingInfo); + } + } + + private final static class EnclosingMethodInfo { + private Class enclosingClass; + private String name; + private String descriptor; + + private EnclosingMethodInfo(Object[] enclosingInfo) { + if (enclosingInfo.length !!= 3) + throw new InternalError("Malformed enclosing method information"); + try { + // The array is expected to have three elements: + + // the immediately enclosing class + enclosingClass = (Class) enclosingInfo[0]; + assert(enclosingClass !!= null); + + // the immediately enclosing method or constructor''s + // name (can be null). + name = (String) enclosingInfo[1]; + + // the immediately enclosing method or constructor''s + // descriptor (null iff name is). + descriptor = (String) enclosingInfo[2]; + assert((name !!= null && descriptor !!= null) || name == descriptor); + } catch (ClassCastException cce) { + throw new InternalError("Invalid type in enclosing method information"); + } + } + + boolean isPartial() { + return enclosingClass == null || name == null || descriptor == null; + } + + boolean isConstructor() { return !!isPartial() && "".equals(name); } + + boolean isMethod() { return !!isPartial() && !!isConstructor() && !!"".equals(name); } + + Class getEnclosingClass() { return enclosingClass; } + + String getName() { return name; } + + String getDescriptor() { return descriptor; } + + } + + private static Class toClass(Type o) { + if (o instanceof GenericArrayType) + return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()), + 0) + .getClass(); + return (Class)o; + } + + /** + * If this {@code Class} object represents a local or anonymous + * class within a constructor, returns a {@link + * java.lang.reflect.Constructor Constructor} object representing + * the immediately enclosing constructor of the underlying + * class. Returns {@code null} otherwise. In particular, this + * method returns {@code null} if the underlying class is a local + * or anonymous class immediately enclosed by a type declaration, + * instance initializer or static initializer. + * + * @return the immediately enclosing constructor of the underlying class, if + * that class is a local or anonymous class; otherwise {@code null}. + * @since 1.5 + */ + public Constructor getEnclosingConstructor() { + EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); + + if (enclosingInfo == null) + return null; + else { + if (!!enclosingInfo.isConstructor()) + return null; + + ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(), + getFactory()); + Type [] parameterTypes = typeInfo.getParameterTypes(); + Class[] parameterClasses = new Class[parameterTypes.length]; + + // Convert Types to Classes; returned types *should* + // be class objects since the methodDescriptor''s used + // don''t have generics information + for(int i = 0; i < parameterClasses.length; i++) + parameterClasses[i] = toClass(parameterTypes[i]); + + /* + * Loop over all declared constructors; match number + * of and type of parameters. + */ + for(Constructor c: enclosingInfo.getEnclosingClass().getDeclaredConstructors()) { + Class[] candidateParamClasses = c.getParameterTypes(); + if (candidateParamClasses.length == parameterClasses.length) { + boolean matches = true; + for(int i = 0; i < candidateParamClasses.length; i++) { + if (!!candidateParamClasses[i].equals(parameterClasses[i])) { + matches = false; + break; + } + } + + if (matches) + return c; + } + } + + throw new InternalError("Enclosing constructor not found"); + } + } + + + /** + * If the class or interface represented by this {@code Class} object + * is a member of another class, returns the {@code Class} object + * representing the class in which it was declared. This method returns + * null if this class or interface is not a member of any other class. If + * this {@code Class} object represents an array class, a primitive + * type, or void,then this method returns null. + * + * @return the declaring class for this class + * @since JDK1.1 + */ + public native Class getDeclaringClass(); + + + /** + * Returns the immediately enclosing class of the underlying + * class. If the underlying class is a top level class this + * method returns {@code null}. + * @return the immediately enclosing class of the underlying class + * @since 1.5 + */ + public Class getEnclosingClass() { + // There are five kinds of classes (or interfaces): + // a) Top level classes + // b) Nested classes (static member classes) + // c) Inner classes (non-static member classes) + // d) Local classes (named classes declared within a method) + // e) Anonymous classes + + + // JVM Spec 4.8.6: A class must have an EnclosingMethod + // attribute if and only if it is a local class or an + // anonymous class. + EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); + + if (enclosingInfo == null) { + // This is a top level or a nested class or an inner class (a, b, or c) + return getDeclaringClass(); + } else { + Class enclosingClass = enclosingInfo.getEnclosingClass(); + // This is a local class or an anonymous class (d or e) + if (enclosingClass == this || enclosingClass == null) + throw new InternalError("Malformed enclosing method information"); + else + return enclosingClass; + } + } + + /** + * Returns the simple name of the underlying class as given in the + * source code. Returns an empty string if the underlying class is + * anonymous. + * + *

The simple name of an array is the simple name of the + * component type with "[]" appended. In particular the simple + * name of an array whose component type is anonymous is "[]". + * + * @return the simple name of the underlying class + * @since 1.5 + */ + public String getSimpleName() { + if (isArray()) + return getComponentType().getSimpleName()+"[]"; + + String simpleName = getSimpleBinaryName(); + if (simpleName == null) { // top level class + simpleName = getName(); + return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name + } + // According to JLS3 "Binary Compatibility" (13.1) the binary + // name of non-package classes (not top level) is the binary + // name of the immediately enclosing class followed by a ''$'' followed by: + // (for nested and inner classes): the simple name. + // (for local classes): 1 or more digits followed by the simple name. + // (for anonymous classes): 1 or more digits. + + // Since getSimpleBinaryName() will strip the binary name of + // the immediatly enclosing class, we are now looking at a + // string that matches the regular expression "\$[0-9]*" + // followed by a simple name (considering the simple of an + // anonymous class to be the empty string). + + // Remove leading "\$[0-9]*" from the name + int length = simpleName.length(); + if (length < 1 || simpleName.charAt(0) !!= ''$'') + throw new InternalError("Malformed class name"); + int index = 1; + while (index < length && isAsciiDigit(simpleName.charAt(index))) + index++; + // Eventually, this is the empty string iff this is an anonymous class + return simpleName.substring(index); + } + + /** + * Character.isDigit answers {@code true} to some non-ascii + * digits. This one does not. + */ + private static boolean isAsciiDigit(char c) { + return ''0'' <= c && c <= ''9''; + } + + /** + * Returns the canonical name of the underlying class as + * defined by the Java Language Specification. Returns null if + * the underlying class does not have a canonical name (i.e., if + * it is a local or anonymous class or an array whose component + * type does not have a canonical name). + * @return the canonical name of the underlying class if it exists, and + * {@code null} otherwise. + * @since 1.5 + */ + public String getCanonicalName() { + if (isArray()) { + String canonicalName = getComponentType().getCanonicalName(); + if (canonicalName !!= null) + return canonicalName + "[]"; + else + return null; + } + if (isLocalOrAnonymousClass()) + return null; + Class enclosingClass = getEnclosingClass(); + if (enclosingClass == null) { // top level class + return getName(); + } else { + String enclosingName = enclosingClass.getCanonicalName(); + if (enclosingName == null) + return null; + return enclosingName + "." + getSimpleName(); + } + } + + /** + * Returns {@code true} if and only if the underlying class + * is an anonymous class. + * + * @return {@code true} if and only if this class is an anonymous class. + * @since 1.5 + */ + public boolean isAnonymousClass() { + return "".equals(getSimpleName()); + } + + /** + * Returns {@code true} if and only if the underlying class + * is a local class. + * + * @return {@code true} if and only if this class is a local class. + * @since 1.5 + */ + public boolean isLocalClass() { + return isLocalOrAnonymousClass() && !!isAnonymousClass(); + } + + /** + * Returns {@code true} if and only if the underlying class + * is a member class. + * + * @return {@code true} if and only if this class is a member class. + * @since 1.5 + */ + public boolean isMemberClass() { + return getSimpleBinaryName() !!= null && !!isLocalOrAnonymousClass(); + } + + /** + * Returns the "simple binary name" of the underlying class, i.e., + * the binary name without the leading enclosing class name. + * Returns {@code null} if the underlying class is a top level + * class. + */ + private String getSimpleBinaryName() { + Class enclosingClass = getEnclosingClass(); + if (enclosingClass == null) // top level class + return null; + // Otherwise, strip the enclosing class'' name + try { + return getName().substring(enclosingClass.getName().length()); + } catch (IndexOutOfBoundsException ex) { + throw new InternalError("Malformed class name"); + } + } + + /** + * Returns {@code true} if this is a local class or an anonymous + * class. Returns {@code false} otherwise. + */ + private boolean isLocalOrAnonymousClass() { + // JVM Spec 4.8.6: A class must have an EnclosingMethod + // attribute if and only if it is a local class or an + // anonymous class. + return getEnclosingMethodInfo() !!= null; + } + + /** + * Returns an array containing {@code Class} objects representing all + * the public classes and interfaces that are members of the class + * represented by this {@code Class} object. This includes public + * class and interface members inherited from superclasses and public class + * and interface members declared by the class. This method returns an + * array of length 0 if this {@code Class} object has no public member + * classes or interfaces. This method also returns an array of length 0 if + * this {@code Class} object represents a primitive type, an array + * class, or void. + * + * @return the array of {@code Class} objects representing the public + * members of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} method + * denies access to the classes within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Class[] getClasses() { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + + // Privileged so this implementation can look at DECLARED classes, + // something the caller might not have privilege to do. The code here + // is allowed to look at DECLARED classes because (1) it does not hand + // out anything other than public members and (2) public member access + // has already been ok''d by the SecurityManager. + + Class[] result = (Class[]) java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + java.util.List list = new java.util.ArrayList(); + Class currentClass = Class.this; + while (currentClass !!= null) { + Class[] members = currentClass.getDeclaredClasses(); + for (int i = 0; i < members.length; i++) { + if (Modifier.isPublic(members[i].getModifiers())) { + list.add(members[i]); + } + } + currentClass = currentClass.getSuperclass(); + } + Class[] empty = {}; + return list.toArray(empty); + } + }); + + return result; + } + + + /** + * Returns an array containing {@code Field} objects reflecting all + * the accessible public fields of the class or interface represented by + * this {@code Class} object. The elements in the array returned are + * not sorted and are not in any particular order. This method returns an + * array of length 0 if the class or interface has no accessible public + * fields, or if it represents an array class, a primitive type, or void. + * + *

Specifically, if this {@code Class} object represents a class, + * this method returns the public fields of this class and of all its + * superclasses. If this {@code Class} object represents an + * interface, this method returns the fields of this interface and of all + * its superinterfaces. + * + *

The implicit length field for array class is not reflected by this + * method. User code should use the methods of class {@code Array} to + * manipulate arrays. + * + *

See The Java Language Specification, sections 8.2 and 8.3. + * + * @return the array of {@code Field} objects representing the + * public fields + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the fields within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Field[] getFields() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + return copyFields(privateGetPublicFields(null)); + } + + + /** + * Returns an array containing {@code Method} objects reflecting all + * the public member methods of the class or interface represented + * by this {@code Class} object, including those declared by the class + * or interface and those inherited from superclasses and + * superinterfaces. Array classes return all the (public) member methods + * inherited from the {@code Object} class. The elements in the array + * returned are not sorted and are not in any particular order. This + * method returns an array of length 0 if this {@code Class} object + * represents a class or interface that has no public member methods, or if + * this {@code Class} object represents a primitive type or void. + * + *

The class initialization method {@code } is not + * included in the returned array. If the class declares multiple public + * member methods with the same parameter types, they are all included in + * the returned array. + * + *

See The Java Language Specification, sections 8.2 and 8.4. + * + * @return the array of {@code Method} objects representing the + * public methods of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the methods within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Method[] getMethods() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + return copyMethods(privateGetPublicMethods()); + } + + + /** + * Returns an array containing {@code Constructor} objects reflecting + * all the public constructors of the class represented by this + * {@code Class} object. An array of length 0 is returned if the + * class has no public constructors, or if the class is an array class, or + * if the class reflects a primitive type or void. + * + * Note that while this method returns an array of {@code + * Constructor} objects (that is an array of constructors from + * this class), the return type of this method is {@code + * Constructor[]} and not {@code Constructor[]} as + * might be expected. This less informative return type is + * necessary since after being returned from this method, the + * array could be modified to hold {@code Constructor} objects for + * different classes, which would violate the type guarantees of + * {@code Constructor[]}. + * + * @return the array of {@code Constructor} objects representing the + * public constructors of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the constructors within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor[] getConstructors() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + return copyConstructors(privateGetDeclaredConstructors(true)); + } + + + /** + * Returns a {@code Field} object that reflects the specified public + * member field of the class or interface represented by this + * {@code Class} object. The {@code name} parameter is a + * {@code String} specifying the simple name of the desired field. + * + *

The field to be reflected is determined by the algorithm that + * follows. Let C be the class represented by this object: + *

    + *
  1. If C declares a public field with the name specified, that is the + * field to be reflected.
  2. + *
  3. If no field was found in step 1 above, this algorithm is applied + * recursively to each direct superinterface of C. The direct + * superinterfaces are searched in the order they were declared.
  4. + *
  5. If no field was found in steps 1 and 2 above, and C has a + * superclass S, then this algorithm is invoked recursively upon S. + * If C has no superclass, then a {@code NoSuchFieldException} + * is thrown.
  6. + *
+ * + *

See The Java Language Specification, sections 8.2 and 8.3. + * + * @param name the field name + * @return the {@code Field} object of this class specified by + * {@code name} + * @exception NoSuchFieldException if a field with the specified name is + * not found. + * @exception NullPointerException if {@code name} is {@code null} + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the field + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Field getField(String name) + throws NoSuchFieldException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + Field field = getField0(name); + if (field == null) { + throw new NoSuchFieldException(name); + } + return field; + } + + + /** + * Returns a {@code Method} object that reflects the specified public + * member method of the class or interface represented by this + * {@code Class} object. The {@code name} parameter is a + * {@code String} specifying the simple name of the desired method. The + * {@code parameterTypes} parameter is an array of {@code Class} + * objects that identify the method''s formal parameter types, in declared + * order. If {@code parameterTypes} is {@code null}, it is + * treated as if it were an empty array. + * + *

If the {@code name} is "{@code };"or "{@code }" a + * {@code NoSuchMethodException} is raised. Otherwise, the method to + * be reflected is determined by the algorithm that follows. Let C be the + * class represented by this object: + *

    + *
  1. C is searched for any matching methods. If no matching + * method is found, the algorithm of step 1 is invoked recursively on + * the superclass of C.
  2. + *
  3. If no method was found in step 1 above, the superinterfaces of C + * are searched for a matching method. If any such method is found, it + * is reflected.
  4. + *
+ * + * To find a matching method in a class C:  If C declares exactly one + * public method with the specified name and exactly the same formal + * parameter types, that is the method reflected. If more than one such + * method is found in C, and one of these methods has a return type that is + * more specific than any of the others, that method is reflected; + * otherwise one of the methods is chosen arbitrarily. + * + *

Note that there may be more than one matching method in a + * class because while the Java language forbids a class to + * declare multiple methods with the same signature but different + * return types, the Java virtual machine does not. This + * increased flexibility in the virtual machine can be used to + * implement various language features. For example, covariant + * returns can be implemented with {@linkplain + * java.lang.reflect.Method#isBridge bridge methods}; the bridge + * method and the method being overridden would have the same + * signature but different return types. + * + *

See The Java Language Specification, sections 8.2 and 8.4. + * + * @param name the name of the method + * @param parameterTypes the list of parameters + * @return the {@code Method} object that matches the specified + * {@code name} and {@code parameterTypes} + * @exception NoSuchMethodException if a matching method is not found + * or if the name is "<init>"or "<clinit>". + * @exception NullPointerException if {@code name} is {@code null} + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the method + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Method getMethod(String name, Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + Method method = getMethod0(name, parameterTypes); + if (method == null) { + throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); + } + return method; + } + + + /** + * Returns a {@code Constructor} object that reflects the specified + * public constructor of the class represented by this {@code Class} + * object. The {@code parameterTypes} parameter is an array of + * {@code Class} objects that identify the constructor''s formal + * parameter types, in declared order. + * + * If this {@code Class} object represents an inner class + * declared in a non-static context, the formal parameter types + * include the explicit enclosing instance as the first parameter. + * + *

The constructor to reflect is the public constructor of the class + * represented by this {@code Class} object whose formal parameter + * types match those specified by {@code parameterTypes}. + * + * @param parameterTypes the parameter array + * @return the {@code Constructor} object of the public constructor that + * matches the specified {@code parameterTypes} + * @exception NoSuchMethodException if a matching method is not found. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * access to the constructor + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor getConstructor(Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + return getConstructor0(parameterTypes, Member.PUBLIC); + } + + + /** + * Returns an array of {@code Class} objects reflecting all the + * classes and interfaces declared as members of the class represented by + * this {@code Class} object. This includes public, protected, default + * (package) access, and private classes and interfaces declared by the + * class, but excludes inherited classes and interfaces. This method + * returns an array of length 0 if the class declares no classes or + * interfaces as members, or if this {@code Class} object represents a + * primitive type, an array class, or void. + * + * @return the array of {@code Class} objects representing all the + * declared members of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared classes within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Class[] getDeclaredClasses() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + return getDeclaredClasses0(); + } + + + /** + * Returns an array of {@code Field} objects reflecting all the fields + * declared by the class or interface represented by this + * {@code Class} object. This includes public, protected, default + * (package) access, and private fields, but excludes inherited fields. + * The elements in the array returned are not sorted and are not in any + * particular order. This method returns an array of length 0 if the class + * or interface declares no fields, or if this {@code Class} object + * represents a primitive type, an array class, or void. + * + *

See The Java Language Specification, sections 8.2 and 8.3. + * + * @return the array of {@code Field} objects representing all the + * declared fields of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared fields within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Field[] getDeclaredFields() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + return copyFields(privateGetDeclaredFields(false)); + } + + + /** + * Returns an array of {@code Method} objects reflecting all the + * methods declared by the class or interface represented by this + * {@code Class} object. This includes public, protected, default + * (package) access, and private methods, but excludes inherited methods. + * The elements in the array returned are not sorted and are not in any + * particular order. This method returns an array of length 0 if the class + * or interface declares no methods, or if this {@code Class} object + * represents a primitive type, an array class, or void. The class + * initialization method {@code } is not included in the + * returned array. If the class declares multiple public member methods + * with the same parameter types, they are all included in the returned + * array. + * + *

See The Java Language Specification, section 8.2. + * + * @return the array of {@code Method} objects representing all the + * declared methods of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared methods within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Method[] getDeclaredMethods() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + return copyMethods(privateGetDeclaredMethods(false)); + } + + + /** + * Returns an array of {@code Constructor} objects reflecting all the + * constructors declared by the class represented by this + * {@code Class} object. These are public, protected, default + * (package) access, and private constructors. The elements in the array + * returned are not sorted and are not in any particular order. If the + * class has a default constructor, it is included in the returned array. + * This method returns an array of length 0 if this {@code Class} + * object represents an interface, a primitive type, an array class, or + * void. + * + *

See The Java Language Specification, section 8.2. + * + * @return the array of {@code Constructor} objects representing all the + * declared constructors of this class + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared constructors within this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor[] getDeclaredConstructors() throws SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + return copyConstructors(privateGetDeclaredConstructors(false)); + } + + + /** + * Returns a {@code Field} object that reflects the specified declared + * field of the class or interface represented by this {@code Class} + * object. The {@code name} parameter is a {@code String} that + * specifies the simple name of the desired field. Note that this method + * will not reflect the {@code length} field of an array class. + * + * @param name the name of the field + * @return the {@code Field} object for the specified field in this + * class + * @exception NoSuchFieldException if a field with the specified name is + * not found. + * @exception NullPointerException if {@code name} is {@code null} + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared field + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Field getDeclaredField(String name) + throws NoSuchFieldException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + Field field = searchFields(privateGetDeclaredFields(false), name); + if (field == null) { + throw new NoSuchFieldException(name); + } + return field; + } + + + /** + * Returns a {@code Method} object that reflects the specified + * declared method of the class or interface represented by this + * {@code Class} object. The {@code name} parameter is a + * {@code String} that specifies the simple name of the desired + * method, and the {@code parameterTypes} parameter is an array of + * {@code Class} objects that identify the method''s formal parameter + * types, in declared order. If more than one method with the same + * parameter types is declared in a class, and one of these methods has a + * return type that is more specific than any of the others, that method is + * returned; otherwise one of the methods is chosen arbitrarily. If the + * name is "<init>"or "<clinit>" a {@code NoSuchMethodException} + * is raised. + * + * @param name the name of the method + * @param parameterTypes the parameter array + * @return the {@code Method} object for the method of this class + * matching the specified name and parameters + * @exception NoSuchMethodException if a matching method is not found. + * @exception NullPointerException if {@code name} is {@code null} + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared method + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Method getDeclaredMethod(String name, Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes); + if (method == null) { + throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); + } + return method; + } + + + /** + * Returns a {@code Constructor} object that reflects the specified + * constructor of the class or interface represented by this + * {@code Class} object. The {@code parameterTypes} parameter is + * an array of {@code Class} objects that identify the constructor''s + * formal parameter types, in declared order. + * + * If this {@code Class} object represents an inner class + * declared in a non-static context, the formal parameter types + * include the explicit enclosing instance as the first parameter. + * + * @param parameterTypes the parameter array + * @return The {@code Constructor} object for the constructor with the + * specified parameter list + * @exception NoSuchMethodException if a matching method is not found. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *
    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.DECLARED)} denies + * access to the declared constructor + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + * @since JDK1.1 + */ + public Constructor getDeclaredConstructor(Class... parameterTypes) + throws NoSuchMethodException, SecurityException { + // be very careful not to change the stack depth of this + // checkMemberAccess call for security reasons + // see java.lang.SecurityManager.checkMemberAccess + checkMemberAccess(Member.DECLARED, ClassLoader.getCallerClassLoader()); + return getConstructor0(parameterTypes, Member.DECLARED); + } + + /** + * Finds a resource with a given name. The rules for searching resources + * associated with a given class are implemented by the defining + * {@linkplain ClassLoader class loader} of the class. This method + * delegates to this object''s class loader. If this object was loaded by + * the bootstrap class loader, the method delegates to {@link + * ClassLoader#getSystemResourceAsStream}. + * + *

Before delegation, an absolute resource name is constructed from the + * given resource name using this algorithm: + * + *

    + * + *
  • If the {@code name} begins with a {@code ''/''} + * (''\u002f''), then the absolute name of the resource is the + * portion of the {@code name} following the {@code ''/''}. + * + *
  • Otherwise, the absolute name is of the following form: + * + *
    + * {@code modified_package_name/name} + *
    + * + *

    Where the {@code modified_package_name} is the package name of this + * object with {@code ''/''} substituted for {@code ''.''} + * (''\u002e''). + * + *

+ * + * @param name name of the desired resource + * @return A {@link java.io.InputStream} object or {@code null} if + * no resource with this name is found + * @throws NullPointerException If {@code name} is {@code null} + * @since JDK1.1 + */ + public InputStream getResourceAsStream(String name) { + name = resolveName(name); + ClassLoader cl = getClassLoader0(); + if (cl==null) { + // A system class. + return ClassLoader.getSystemResourceAsStream(name); + } + return cl.getResourceAsStream(name); + } + + /** + * Finds a resource with a given name. The rules for searching resources + * associated with a given class are implemented by the defining + * {@linkplain ClassLoader class loader} of the class. This method + * delegates to this object''s class loader. If this object was loaded by + * the bootstrap class loader, the method delegates to {@link + * ClassLoader#getSystemResource}. + * + *

Before delegation, an absolute resource name is constructed from the + * given resource name using this algorithm: + * + *

    + * + *
  • If the {@code name} begins with a {@code ''/''} + * (''\u002f''), then the absolute name of the resource is the + * portion of the {@code name} following the {@code ''/''}. + * + *
  • Otherwise, the absolute name is of the following form: + * + *
    + * {@code modified_package_name/name} + *
    + * + *

    Where the {@code modified_package_name} is the package name of this + * object with {@code ''/''} substituted for {@code ''.''} + * (''\u002e''). + * + *

+ * + * @param name name of the desired resource + * @return A {@link java.net.URL} object or {@code null} if no + * resource with this name is found + * @since JDK1.1 + */ + public java.net.URL getResource(String name) { + name = resolveName(name); + ClassLoader cl = getClassLoader0(); + if (cl==null) { + // A system class. + return ClassLoader.getSystemResource(name); + } + return cl.getResource(name); + } + + + + /** protection domain returned when the internal domain is null */ + private static java.security.ProtectionDomain allPermDomain; + + + /** + * Returns the {@code ProtectionDomain} of this class. If there is a + * security manager installed, this method first calls the security + * manager''s {@code checkPermission} method with a + * {@code RuntimePermission("getProtectionDomain")} permission to + * ensure it''s ok to get the + * {@code ProtectionDomain}. + * + * @return the ProtectionDomain of this class + * + * @throws SecurityException + * if a security manager exists and its + * {@code checkPermission} method doesn''t allow + * getting the ProtectionDomain. + * + * @see java.security.ProtectionDomain + * @see SecurityManager#checkPermission + * @see java.lang.RuntimePermission + * @since 1.2 + */ + public java.security.ProtectionDomain getProtectionDomain() { + SecurityManager sm = System.getSecurityManager(); + if (sm !!= null) { + sm.checkPermission(SecurityConstants.GET_PD_PERMISSION); + } + java.security.ProtectionDomain pd = getProtectionDomain0(); + if (pd == null) { + if (allPermDomain == null) { + java.security.Permissions perms = + new java.security.Permissions(); + perms.add(SecurityConstants.ALL_PERMISSION); + allPermDomain = + new java.security.ProtectionDomain(null, perms); + } + pd = allPermDomain; + } + return pd; + } + + + /** + * Returns the ProtectionDomain of this class. + */ + private native java.security.ProtectionDomain getProtectionDomain0(); + + + /** + * Set the ProtectionDomain for this class. Called by + * ClassLoader.defineClass. + */ + native void setProtectionDomain0(java.security.ProtectionDomain pd); + + + /* + * Return the Virtual Machine''s Class object for the named + * primitive type. + */ + static native Class getPrimitiveClass(String name); + + + /* + * Check if client is allowed to access members. If access is denied, + * throw a SecurityException. + * + * Be very careful not to change the stack depth of this checkMemberAccess + * call for security reasons. + * See java.lang.SecurityManager.checkMemberAccess. + * + *

Default policy: allow all clients access with normal Java access + * control. + */ + private void checkMemberAccess(int which, ClassLoader ccl) { + SecurityManager s = System.getSecurityManager(); + if (s !!= null) { + s.checkMemberAccess(this, which); + ClassLoader cl = getClassLoader0(); + if ((ccl !!= null) && (ccl !!= cl) && + ((cl == null) || !!cl.isAncestor(ccl))) { + String name = this.getName(); + int i = name.lastIndexOf(''.''); + if (i !!= -1) { + s.checkPackageAccess(name.substring(0, i)); + } + } + } + } + + /** + * Add a package name prefix if the name is not absolute Remove leading "/" + * if name is absolute + */ + private String resolveName(String name) { + if (name == null) { + return name; + } + if (!!name.startsWith("/")) { + Class c = this; + while (c.isArray()) { + c = c.getComponentType(); + } + String baseName = c.getName(); + int index = baseName.lastIndexOf(''.''); + if (index !!= -1) { + name = baseName.substring(0, index).replace(''.'', ''/'') + +"/"+name; + } + } else { + name = name.substring(1); + } + return name; + } + + /** + * Reflection support. + */ + + // Caches for certain reflective results + private static boolean useCaches = true; + private volatile transient SoftReference declaredFields; + private volatile transient SoftReference publicFields; + private volatile transient SoftReference declaredMethods; + private volatile transient SoftReference publicMethods; + private volatile transient SoftReference declaredConstructors; + private volatile transient SoftReference publicConstructors; + // Intermediate results for getFields and getMethods + private volatile transient SoftReference declaredPublicFields; + private volatile transient SoftReference declaredPublicMethods; + + // Incremented by the VM on each call to JVM TI RedefineClasses() + // that redefines this class or a superclass. + private volatile transient int classRedefinedCount = 0; + + // Value of classRedefinedCount when we last cleared the cached values + // that are sensitive to class redefinition. + private volatile transient int lastRedefinedCount = 0; + + // Clears cached values that might possibly have been obsoleted by + // a class redefinition. + private void clearCachesOnClassRedefinition() { + if (lastRedefinedCount !!= classRedefinedCount) { + declaredFields = publicFields = declaredPublicFields = null; + declaredMethods = publicMethods = declaredPublicMethods = null; + declaredConstructors = publicConstructors = null; + annotations = declaredAnnotations = null; + + // Use of "volatile" (and synchronization by caller in the case + // of annotations) ensures that no thread sees the update to + // lastRedefinedCount before seeing the caches cleared. + // We do not guard against brief windows during which multiple + // threads might redundantly work to fill an empty cache. + lastRedefinedCount = classRedefinedCount; + } + } + + // Generic signature handling + private native String getGenericSignature(); + + // Generic info repository; lazily initialized + private transient ClassRepository genericInfo; + + // accessor for factory + private GenericsFactory getFactory() { + // create scope and factory + return CoreReflectionFactory.make(this, ClassScope.make(this)); + } + + // accessor for generic info repository + private ClassRepository getGenericInfo() { + // lazily initialize repository if necessary + if (genericInfo == null) { + // create and cache generic info repository + genericInfo = ClassRepository.make(getGenericSignature(), + getFactory()); + } + return genericInfo; //return cached repository + } + + // Annotations handling + private native byte[] getRawAnnotations(); + + native ConstantPool getConstantPool(); + + // + // + // java.lang.reflect.Field handling + // + // + + // Returns an array of "root" fields. These Field objects must NOT + // be propagated to the outside world, but must instead be copied + // via ReflectionFactory.copyField. + private Field[] privateGetDeclaredFields(boolean publicOnly) { + checkInitted(); + Field[] res = null; + if (useCaches) { + clearCachesOnClassRedefinition(); + if (publicOnly) { + if (declaredPublicFields !!= null) { + res = (Field[]) declaredPublicFields.get(); + } + } else { + if (declaredFields !!= null) { + res = (Field[]) declaredFields.get(); + } + } + if (res !!= null) return res; + } + // No cached value available; request value from VM + res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); + if (useCaches) { + if (publicOnly) { + declaredPublicFields = new SoftReference(res); + } else { + declaredFields = new SoftReference(res); + } + } + return res; + } + + // Returns an array of "root" fields. These Field objects must NOT + // be propagated to the outside world, but must instead be copied + // via ReflectionFactory.copyField. + private Field[] privateGetPublicFields(Set traversedInterfaces) { + checkInitted(); + Field[] res = null; + if (useCaches) { + clearCachesOnClassRedefinition(); + if (publicFields !!= null) { + res = (Field[]) publicFields.get(); + } + if (res !!= null) return res; + } + + // No cached value available; compute value recursively. + // Traverse in correct order for getField(). + List fields = new ArrayList(); + if (traversedInterfaces == null) { + traversedInterfaces = new HashSet(); + } + + // Local fields + Field[] tmp = privateGetDeclaredFields(true); + addAll(fields, tmp); + + // Direct superinterfaces, recursively + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Class c = interfaces[i]; + if (!!traversedInterfaces.contains(c)) { + traversedInterfaces.add(c); + addAll(fields, c.privateGetPublicFields(traversedInterfaces)); + } + } + + // Direct superclass, recursively + if (!!isInterface()) { + Class c = getSuperclass(); + if (c !!= null) { + addAll(fields, c.privateGetPublicFields(traversedInterfaces)); + } + } + + res = new Field[fields.size()]; + fields.toArray(res); + if (useCaches) { + publicFields = new SoftReference(res); + } + return res; + } + + private static void addAll(Collection c, Field[] o) { + for (int i = 0; i < o.length; i++) { + c.add(o[i]); + } + } + + + // + // + // java.lang.reflect.Constructor handling + // + // + + // Returns an array of "root" constructors. These Constructor + // objects must NOT be propagated to the outside world, but must + // instead be copied via ReflectionFactory.copyConstructor. + private Constructor[] privateGetDeclaredConstructors(boolean publicOnly) { + checkInitted(); + Constructor[] res = null; + if (useCaches) { + clearCachesOnClassRedefinition(); + if (publicOnly) { + if (publicConstructors !!= null) { + res = (Constructor[]) publicConstructors.get(); + } + } else { + if (declaredConstructors !!= null) { + res = (Constructor[]) declaredConstructors.get(); + } + } + if (res !!= null) return res; + } + // No cached value available; request value from VM + if (isInterface()) { + res = new Constructor[0]; + } else { + res = getDeclaredConstructors0(publicOnly); + } + if (useCaches) { + if (publicOnly) { + publicConstructors = new SoftReference(res); + } else { + declaredConstructors = new SoftReference(res); + } + } + return res; + } + + // + // + // java.lang.reflect.Method handling + // + // + + // Returns an array of "root" methods. These Method objects must NOT + // be propagated to the outside world, but must instead be copied + // via ReflectionFactory.copyMethod. + private Method[] privateGetDeclaredMethods(boolean publicOnly) { + checkInitted(); + Method[] res = null; + if (useCaches) { + clearCachesOnClassRedefinition(); + if (publicOnly) { + if (declaredPublicMethods !!= null) { + res = (Method[]) declaredPublicMethods.get(); + } + } else { + if (declaredMethods !!= null) { + res = (Method[]) declaredMethods.get(); + } + } + if (res !!= null) return res; + } + // No cached value available; request value from VM + res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); + if (useCaches) { + if (publicOnly) { + declaredPublicMethods = new SoftReference(res); + } else { + declaredMethods = new SoftReference(res); + } + } + return res; + } + + static class MethodArray { + private Method[] methods; + private int length; + + MethodArray() { + methods = new Method[20]; + length = 0; + } + + void add(Method m) { + if (length == methods.length) { + methods = Arrays.copyOf(methods, 2 * methods.length); + } + methods[length++] = m; + } + + void addAll(Method[] ma) { + for (int i = 0; i < ma.length; i++) { + add(ma[i]); + } + } + + void addAll(MethodArray ma) { + for (int i = 0; i < ma.length(); i++) { + add(ma.get(i)); + } + } + + void addIfNotPresent(Method newMethod) { + for (int i = 0; i < length; i++) { + Method m = methods[i]; + if (m == newMethod || (m !!= null && m.equals(newMethod))) { + return; + } + } + add(newMethod); + } + + void addAllIfNotPresent(MethodArray newMethods) { + for (int i = 0; i < newMethods.length(); i++) { + Method m = newMethods.get(i); + if (m !!= null) { + addIfNotPresent(m); + } + } + } + + int length() { + return length; + } + + Method get(int i) { + return methods[i]; + } + + void removeByNameAndSignature(Method toRemove) { + for (int i = 0; i < length; i++) { + Method m = methods[i]; + if (m !!= null && + m.getReturnType() == toRemove.getReturnType() && + m.getName() == toRemove.getName() && + arrayContentsEq(m.getParameterTypes(), + toRemove.getParameterTypes())) { + methods[i] = null; + } + } + } + + void compactAndTrim() { + int newPos = 0; + // Get rid of null slots + for (int pos = 0; pos < length; pos++) { + Method m = methods[pos]; + if (m !!= null) { + if (pos !!= newPos) { + methods[newPos] = m; + } + newPos++; + } + } + if (newPos !!= methods.length) { + methods = Arrays.copyOf(methods, newPos); + } + } + + Method[] getArray() { + return methods; + } + } + + + // Returns an array of "root" methods. These Method objects must NOT + // be propagated to the outside world, but must instead be copied + // via ReflectionFactory.copyMethod. + private Method[] privateGetPublicMethods() { + checkInitted(); + Method[] res = null; + if (useCaches) { + clearCachesOnClassRedefinition(); + if (publicMethods !!= null) { + res = (Method[]) publicMethods.get(); + } + if (res !!= null) return res; + } + + // No cached value available; compute value recursively. + // Start by fetching public declared methods + MethodArray methods = new MethodArray(); + { + Method[] tmp = privateGetDeclaredMethods(true); + methods.addAll(tmp); + } + // Now recur over superclass and direct superinterfaces. + // Go over superinterfaces first so we can more easily filter + // out concrete implementations inherited from superclasses at + // the end. + MethodArray inheritedMethods = new MethodArray(); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + inheritedMethods.addAll(interfaces[i].privateGetPublicMethods()); + } + if (!!isInterface()) { + Class c = getSuperclass(); + if (c !!= null) { + MethodArray supers = new MethodArray(); + supers.addAll(c.privateGetPublicMethods()); + // Filter out concrete implementations of any + // interface methods + for (int i = 0; i < supers.length(); i++) { + Method m = supers.get(i); + if (m !!= null && !!Modifier.isAbstract(m.getModifiers())) { + inheritedMethods.removeByNameAndSignature(m); + } + } + // Insert superclass''s inherited methods before + // superinterfaces'' to satisfy getMethod''s search + // order + supers.addAll(inheritedMethods); + inheritedMethods = supers; + } + } + // Filter out all local methods from inherited ones + for (int i = 0; i < methods.length(); i++) { + Method m = methods.get(i); + inheritedMethods.removeByNameAndSignature(m); + } + methods.addAllIfNotPresent(inheritedMethods); + methods.compactAndTrim(); + res = methods.getArray(); + if (useCaches) { + publicMethods = new SoftReference(res); + } + return res; + } + + + // + // Helpers for fetchers of one field, method, or constructor + // + + private Field searchFields(Field[] fields, String name) { + String internedName = name.intern(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].getName() == internedName) { + return getReflectionFactory().copyField(fields[i]); + } + } + return null; + } + + private Field getField0(String name) throws NoSuchFieldException { + // Note: the intent is that the search algorithm this routine + // uses be equivalent to the ordering imposed by + // privateGetPublicFields(). It fetches only the declared + // public fields for each class, however, to reduce the number + // of Field objects which have to be created for the common + // case where the field being requested is declared in the + // class which is being queried. + Field res = null; + // Search declared public fields + if ((res = searchFields(privateGetDeclaredFields(true), name)) !!= null) { + return res; + } + // Direct superinterfaces, recursively + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Class c = interfaces[i]; + if ((res = c.getField0(name)) !!= null) { + return res; + } + } + // Direct superclass, recursively + if (!!isInterface()) { + Class c = getSuperclass(); + if (c !!= null) { + if ((res = c.getField0(name)) !!= null) { + return res; + } + } + } + return null; + } + + private static Method searchMethods(Method[] methods, + String name, + Class[] parameterTypes) + { + Method res = null; + String internedName = name.intern(); + for (int i = 0; i < methods.length; i++) { + Method m = methods[i]; + if (m.getName() == internedName + && arrayContentsEq(parameterTypes, m.getParameterTypes()) + && (res == null + || res.getReturnType().isAssignableFrom(m.getReturnType()))) + res = m; + } + + return (res == null ? res : getReflectionFactory().copyMethod(res)); + } + + + private Method getMethod0(String name, Class[] parameterTypes) { + // Note: the intent is that the search algorithm this routine + // uses be equivalent to the ordering imposed by + // privateGetPublicMethods(). It fetches only the declared + // public methods for each class, however, to reduce the + // number of Method objects which have to be created for the + // common case where the method being requested is declared in + // the class which is being queried. + Method res = null; + // Search declared public methods + if ((res = searchMethods(privateGetDeclaredMethods(true), + name, + parameterTypes)) !!= null) { + return res; + } + // Search superclass''s methods + if (!!isInterface()) { + Class c = getSuperclass(); + if (c !!= null) { + if ((res = c.getMethod0(name, parameterTypes)) !!= null) { + return res; + } + } + } + // Search superinterfaces'' methods + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) { + Class c = interfaces[i]; + if ((res = c.getMethod0(name, parameterTypes)) !!= null) { + return res; + } + } + // Not found + return null; + } + + private Constructor getConstructor0(Class[] parameterTypes, + int which) throws NoSuchMethodException + { + Constructor[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); + for (int i = 0; i < constructors.length; i++) { + if (arrayContentsEq(parameterTypes, + constructors[i].getParameterTypes())) { + return getReflectionFactory().copyConstructor(constructors[i]); + } + } + throw new NoSuchMethodException(getName() + "." + argumentTypesToString(parameterTypes)); + } + + // + // Other helpers and base implementation + // + + private static boolean arrayContentsEq(Object[] a1, Object[] a2) { + if (a1 == null) { + return a2 == null || a2.length == 0; + } + + if (a2 == null) { + return a1.length == 0; + } + + if (a1.length !!= a2.length) { + return false; + } + + for (int i = 0; i < a1.length; i++) { + if (a1[i] !!= a2[i]) { + return false; + } + } + + return true; + } + + private static Field[] copyFields(Field[] arg) { + Field[] out = new Field[arg.length]; + ReflectionFactory fact = getReflectionFactory(); + for (int i = 0; i < arg.length; i++) { + out[i] = fact.copyField(arg[i]); + } + return out; + } + + private static Method[] copyMethods(Method[] arg) { + Method[] out = new Method[arg.length]; + ReflectionFactory fact = getReflectionFactory(); + for (int i = 0; i < arg.length; i++) { + out[i] = fact.copyMethod(arg[i]); + } + return out; + } + + private static Constructor[] copyConstructors(Constructor[] arg) { + Constructor[] out = new Constructor[arg.length]; + ReflectionFactory fact = getReflectionFactory(); + for (int i = 0; i < arg.length; i++) { + out[i] = fact.copyConstructor(arg[i]); + } + return out; + } + + private native Field[] getDeclaredFields0(boolean publicOnly); + private native Method[] getDeclaredMethods0(boolean publicOnly); + private native Constructor[] getDeclaredConstructors0(boolean publicOnly); + private native Class[] getDeclaredClasses0(); + + private static String argumentTypesToString(Class[] argTypes) { + StringBuilder buf = new StringBuilder(); + buf.append("("); + if (argTypes !!= null) { + for (int i = 0; i < argTypes.length; i++) { + if (i > 0) { + buf.append(", "); + } + Class c = argTypes[i]; + buf.append((c == null) ? "null" : c.getName()); + } + } + buf.append(")"); + return buf.toString(); + } + + /** use serialVersionUID from JDK 1.1 for interoperability */ + private static final long serialVersionUID = 3206093459760846163L; + + + /** + * Class Class is special cased within the Serialization Stream Protocol. + * + * A Class instance is written initially into an ObjectOutputStream in the + * following format: + *

+     *      {@code TC_CLASS} ClassDescriptor
+     *      A ClassDescriptor is a special cased serialization of
+     *      a {@code java.io.ObjectStreamClass} instance.
+     * 
+ * A new handle is generated for the initial time the class descriptor + * is written into the stream. Future references to the class descriptor + * are written as references to the initial class descriptor instance. + * + * @see java.io.ObjectStreamClass + */ + private static final ObjectStreamField[] serialPersistentFields = + new ObjectStreamField[0]; + + + /** + * Returns the assertion status that would be assigned to this + * class if it were to be initialized at the time this method is invoked. + * If this class has had its assertion status set, the most recent + * setting will be returned; otherwise, if any package default assertion + * status pertains to this class, the most recent setting for the most + * specific pertinent package default assertion status is returned; + * otherwise, if this class is not a system class (i.e., it has a + * class loader) its class loader''s default assertion status is returned; + * otherwise, the system class default assertion status is returned. + *

+ * Few programmers will have any need for this method; it is provided + * for the benefit of the JRE itself. (It allows a class to determine at + * the time that it is initialized whether assertions should be enabled.) + * Note that this method is not guaranteed to return the actual + * assertion status that was (or will be) associated with the specified + * class when it was (or will be) initialized. + * + * @return the desired assertion status of the specified class. + * @see java.lang.ClassLoader#setClassAssertionStatus + * @see java.lang.ClassLoader#setPackageAssertionStatus + * @see java.lang.ClassLoader#setDefaultAssertionStatus + * @since 1.4 + */ + public boolean desiredAssertionStatus() { + ClassLoader loader = getClassLoader(); + // If the loader is null this is a system class, so ask the VM + if (loader == null) + return desiredAssertionStatus0(this); + + synchronized(loader) { + // If the classloader has been initialized with + // the assertion directives, ask it. Otherwise, + // ask the VM. + return (loader.classAssertionStatus == null ? + desiredAssertionStatus0(this) : + loader.desiredAssertionStatus(getName())); + } + } + + // Retrieves the desired assertion status of this class from the VM + private static native boolean desiredAssertionStatus0(Class clazz); + + /** + * Returns true if and only if this class was declared as an enum in the + * source code. + * + * @return true if and only if this class was declared as an enum in the + * source code + * @since 1.5 + */ + public boolean isEnum() { + // An enum must both directly extend java.lang.Enum and have + // the ENUM bit set; classes for specialized enum constants + // don''t do the former. + return (this.getModifiers() & ENUM) !!= 0 && + this.getSuperclass() == java.lang.Enum.class; + } + + // Fetches the factory for reflective objects + private static ReflectionFactory getReflectionFactory() { + if (reflectionFactory == null) { + reflectionFactory = (ReflectionFactory) + java.security.AccessController.doPrivileged + (new sun.reflect.ReflectionFactory.GetReflectionFactoryAction()); + } + return reflectionFactory; + } + private static ReflectionFactory reflectionFactory; + + // To be able to query system properties as soon as they''re available + private static boolean initted = false; + private static void checkInitted() { + if (initted) return; + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + // Tests to ensure the system properties table is fully + // initialized. This is needed because reflection code is + // called very early in the initialization process (before + // command-line arguments have been parsed and therefore + // these user-settable properties installed.) We assume that + // if System.out is non-null then the System class has been + // fully initialized and that the bulk of the startup code + // has been run. + + if (System.out == null) { + // java.lang.System not yet fully initialized + return null; + } + + String val = + System.getProperty("sun.reflect.noCaches"); + if (val !!= null && val.equals("true")) { + useCaches = false; + } + + initted = true; + return null; + } + }); + } + + /** + * Returns the elements of this enum class or null if this + * Class object does not represent an enum type. + * + * @return an array containing the values comprising the enum class + * represented by this Class object in the order they''re + * declared, or null if this Class object does not + * represent an enum type + * @since 1.5 + */ + public T[] getEnumConstants() { + T[] values = getEnumConstantsShared(); + return (values !!= null) ? values.clone() : null; + } + + /** + * Returns the elements of this enum class or null if this + * Class object does not represent an enum type; + * identical to getEnumConstantsShared except that + * the result is uncloned, cached, and shared by all callers. + */ + T[] getEnumConstantsShared() { + if (enumConstants == null) { + if (!!isEnum()) return null; + try { + final Method values = getMethod("values"); + java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + values.setAccessible(true); + return null; + } + }); + enumConstants = (T[])values.invoke(null); + } + // These can happen when users concoct enum-like classes + // that don''t comply with the enum spec. + catch (InvocationTargetException ex) { return null; } + catch (NoSuchMethodException ex) { return null; } + catch (IllegalAccessException ex) { return null; } + } + return enumConstants; + } + private volatile transient T[] enumConstants = null; + + /** + * Returns a map from simple name to enum constant. This package-private + * method is used internally by Enum to implement + * public static > T valueOf(Class, String) + * efficiently. Note that the map is returned by this method is + * created lazily on first use. Typically it won''t ever get created. + */ + Map enumConstantDirectory() { + if (enumConstantDirectory == null) { + T[] universe = getEnumConstantsShared(); + if (universe == null) + throw new IllegalArgumentException( + getName() + " is not an enum type"); + Map m = new HashMap(2 * universe.length); + for (T constant : universe) + m.put(((Enum)constant).name(), constant); + enumConstantDirectory = m; + } + return enumConstantDirectory; + } + private volatile transient Map enumConstantDirectory = null; + + /** + * Casts an object to the class or interface represented + * by this {@code Class} object. + * + * @param obj the object to be cast + * @return the object after casting, or null if obj is null + * + * @throws ClassCastException if the object is not + * null and is not assignable to the type T. + * + * @since 1.5 + */ + public T cast(Object obj) { + if (obj !!= null && !!isInstance(obj)) + throw new ClassCastException(cannotCastMsg(obj)); + return (T) obj; + } + + private String cannotCastMsg(Object obj) { + return "Cannot cast " + obj.getClass().getName() + " to " + getName(); + } + + /** + * Casts this {@code Class} object to represent a subclass of the class + * represented by the specified class object. Checks that that the cast + * is valid, and throws a {@code ClassCastException} if it is not. If + * this method succeeds, it always returns a reference to this class object. + * + *

This method is useful when a client needs to "narrow" the type of + * a {@code Class} object to pass it to an API that restricts the + * {@code Class} objects that it is willing to accept. A cast would + * generate a compile-time warning, as the correctness of the cast + * could not be checked at runtime (because generic types are implemented + * by erasure). + * + * @return this {@code Class} object, cast to represent a subclass of + * the specified class object. + * @throws ClassCastException if this {@code Class} object does not + * represent a subclass of the specified class (here "subclass" includes + * the class itself). + * @since 1.5 + */ + public Class asSubclass(Class clazz) { + if (clazz.isAssignableFrom(this)) + return (Class) this; + else + throw new ClassCastException(this.toString()); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + public A getAnnotation(Class annotationClass) { + if (annotationClass == null) + throw new NullPointerException(); + + initAnnotationsIfNecessary(); + return (A) annotations.get(annotationClass); + } + + /** + * @throws NullPointerException {@inheritDoc} + * @since 1.5 + */ + public boolean isAnnotationPresent( + Class annotationClass) { + if (annotationClass == null) + throw new NullPointerException(); + + return getAnnotation(annotationClass) !!= null; + } + + + private static Annotation[] EMPTY_ANNOTATIONS_ARRAY = new Annotation[0]; + + /** + * @since 1.5 + */ + public Annotation[] getAnnotations() { + initAnnotationsIfNecessary(); + return annotations.values().toArray(EMPTY_ANNOTATIONS_ARRAY); + } + + /** + * @since 1.5 + */ + public Annotation[] getDeclaredAnnotations() { + initAnnotationsIfNecessary(); + return declaredAnnotations.values().toArray(EMPTY_ANNOTATIONS_ARRAY); + } + + // Annotations cache + private transient Map annotations; + private transient Map declaredAnnotations; + + private synchronized void initAnnotationsIfNecessary() { + clearCachesOnClassRedefinition(); + if (annotations !!= null) + return; + declaredAnnotations = AnnotationParser.parseAnnotations( + getRawAnnotations(), getConstantPool(), this); + Class superClass = getSuperclass(); + if (superClass == null) { + annotations = declaredAnnotations; + } else { + annotations = new HashMap(); + superClass.initAnnotationsIfNecessary(); + for (Map.Entry e : superClass.annotations.entrySet()) { + Class annotationClass = e.getKey(); + if (AnnotationType.getInstance(annotationClass).isInherited()) + annotations.put(annotationClass, e.getValue()); + } + annotations.putAll(declaredAnnotations); + } + } + + // Annotation types cache their internal (AnnotationType) form + + private AnnotationType annotationType; + + void setAnnotationType(AnnotationType type) { + annotationType = type; + } + + AnnotationType getAnnotationType() { + return annotationType; + } +}' +! + +classJavaLangObject + ^ +'/* + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +/** + * Class Object is the root of the class hierarchy. + * Every class has Object as a superclass. All objects, + * including arrays, implement the methods of this class. + * + * @author unascribed + * @see java.lang.Class + * @since JDK1.0 + */ +public class Object { + + private static native void registerNatives(); + static { + registerNatives(); + } + + /** + * Returns the runtime class of this {@code Object}. The returned + * {@code Class} object is the object that is locked by {@code + * static synchronized} methods of the represented class. + * + *

The actual result type is {@code Class} + * where {@code |X|} is the erasure of the static type of the + * expression on which {@code getClass} is called. For + * example, no cast is required in this code fragment:

+ * + *

+ * {@code Number n = 0; }
+ * {@code Class c = n.getClass(); } + *

+ * + * @return The {@code Class} object that represents the runtime + * class of this object. + * @see
The Java + * Language Specification, Third Edition (15.8.2 Class + * Literals) + */ + public final native Class getClass(); + + /** + * Returns a hash code value for the object. This method is + * supported for the benefit of hashtables such as those provided by + * java.util.Hashtable. + *

+ * The general contract of hashCode is: + *

    + *
  • Whenever it is invoked on the same object more than once during + * an execution of a Java application, the hashCode method + * must consistently return the same integer, provided no information + * used in equals comparisons on the object is modified. + * This integer need not remain consistent from one execution of an + * application to another execution of the same application. + *
  • If two objects are equal according to the equals(Object) + * method, then calling the hashCode method on each of + * the two objects must produce the same integer result. + *
  • It is not required that if two objects are unequal + * according to the {@link java.lang.Object#equals(java.lang.Object)} + * method, then calling the hashCode method on each of the + * two objects must produce distinct integer results. However, the + * programmer should be aware that producing distinct integer results + * for unequal objects may improve the performance of hashtables. + *
+ *

+ * As much as is reasonably practical, the hashCode method defined by + * class Object does return distinct integers for distinct + * objects. (This is typically implemented by converting the internal + * address of the object into an integer, but this implementation + * technique is not required by the + * JavaTM programming language.) + * + * @return a hash code value for this object. + * @see java.lang.Object#equals(java.lang.Object) + * @see java.util.Hashtable + */ + public native int hashCode(); + + /** + * Indicates whether some other object is "equal to" this one. + *

+ * The equals method implements an equivalence relation + * on non-null object references: + *

    + *
  • It is reflexive: for any non-null reference value + * x, x.equals(x) should return + * true. + *
  • It is symmetric: for any non-null reference values + * x and y, x.equals(y) + * should return true if and only if + * y.equals(x) returns true. + *
  • It is transitive: for any non-null reference values + * x, y, and z, if + * x.equals(y) returns true and + * y.equals(z) returns true, then + * x.equals(z) should return true. + *
  • It is consistent: for any non-null reference values + * x and y, multiple invocations of + * x.equals(y) consistently return true + * or consistently return false, provided no + * information used in equals comparisons on the + * objects is modified. + *
  • For any non-null reference value x, + * x.equals(null) should return false. + *
+ *

+ * The equals method for class Object implements + * the most discriminating possible equivalence relation on objects; + * that is, for any non-null reference values x and + * y, this method returns true if and only + * if x and y refer to the same object + * (x == y has the value true). + *

+ * Note that it is generally necessary to override the hashCode + * method whenever this method is overridden, so as to maintain the + * general contract for the hashCode method, which states + * that equal objects must have equal hash codes. + * + * @param obj the reference object with which to compare. + * @return true if this object is the same as the obj + * argument; false otherwise. + * @see #hashCode() + * @see java.util.Hashtable + */ + public boolean equals(Object obj) { + return (this == obj); + } + + /** + * Creates and returns a copy of this object. The precise meaning + * of "copy" may depend on the class of the object. The general + * intent is that, for any object x, the expression: + *

+ *
+     * x.clone() !!= x
+ * will be true, and that the expression: + *
+ *
+     * x.clone().getClass() == x.getClass()
+ * will be true, but these are not absolute requirements. + * While it is typically the case that: + *
+ *
+     * x.clone().equals(x)
+ * will be true, this is not an absolute requirement. + *

+ * By convention, the returned object should be obtained by calling + * super.clone. If a class and all of its superclasses (except + * Object) obey this convention, it will be the case that + * x.clone().getClass() == x.getClass(). + *

+ * By convention, the object returned by this method should be independent + * of this object (which is being cloned). To achieve this independence, + * it may be necessary to modify one or more fields of the object returned + * by super.clone before returning it. Typically, this means + * copying any mutable objects that comprise the internal "deep structure" + * of the object being cloned and replacing the references to these + * objects with references to the copies. If a class contains only + * primitive fields or references to immutable objects, then it is usually + * the case that no fields in the object returned by super.clone + * need to be modified. + *

+ * The method clone for class Object performs a + * specific cloning operation. First, if the class of this object does + * not implement the interface Cloneable, then a + * CloneNotSupportedException is thrown. Note that all arrays + * are considered to implement the interface Cloneable. + * Otherwise, this method creates a new instance of the class of this + * object and initializes all its fields with exactly the contents of + * the corresponding fields of this object, as if by assignment; the + * contents of the fields are not themselves cloned. Thus, this method + * performs a "shallow copy" of this object, not a "deep copy" operation. + *

+ * The class Object does not itself implement the interface + * Cloneable, so calling the clone method on an object + * whose class is Object will result in throwing an + * exception at run time. + * + * @return a clone of this instance. + * @exception CloneNotSupportedException if the object''s class does not + * support the Cloneable interface. Subclasses + * that override the clone method can also + * throw this exception to indicate that an instance cannot + * be cloned. + * @see java.lang.Cloneable + */ + protected native Object clone() throws CloneNotSupportedException; + + /** + * Returns a string representation of the object. In general, the + * toString method returns a string that + * "textually represents" this object. The result should + * be a concise but informative representation that is easy for a + * person to read. + * It is recommended that all subclasses override this method. + *

+ * The toString method for class Object + * returns a string consisting of the name of the class of which the + * object is an instance, the at-sign character `@'', and + * the unsigned hexadecimal representation of the hash code of the + * object. In other words, this method returns a string equal to the + * value of: + *

+ *
+     * getClass().getName() + ''@'' + Integer.toHexString(hashCode())
+     * 
+ * + * @return a string representation of the object. + */ + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } + + /** + * Wakes up a single thread that is waiting on this object''s + * monitor. If any threads are waiting on this object, one of them + * is chosen to be awakened. The choice is arbitrary and occurs at + * the discretion of the implementation. A thread waits on an object''s + * monitor by calling one of the wait methods. + *

+ * The awakened thread will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened thread will + * compete in the usual manner with any other threads that might be + * actively competing to synchronize on this object; for example, the + * awakened thread enjoys no reliable privilege or disadvantage in being + * the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object''s monitor. A thread becomes the owner of the + * object''s monitor in one of three ways: + *

    + *
  • By executing a synchronized instance method of that object. + *
  • By executing the body of a synchronized statement + * that synchronizes on the object. + *
  • For objects of type Class, by executing a + * synchronized static method of that class. + *
+ *

+ * Only one thread at a time can own an object''s monitor. + * + * @exception IllegalMonitorStateException if the current thread is not + * the owner of this object''s monitor. + * @see java.lang.Object#notifyAll() + * @see java.lang.Object#wait() + */ + public final native void notify(); + + /** + * Wakes up all threads that are waiting on this object''s monitor. A + * thread waits on an object''s monitor by calling one of the + * wait methods. + *

+ * The awakened threads will not be able to proceed until the current + * thread relinquishes the lock on this object. The awakened threads + * will compete in the usual manner with any other threads that might + * be actively competing to synchronize on this object; for example, + * the awakened threads enjoy no reliable privilege or disadvantage in + * being the next thread to lock this object. + *

+ * This method should only be called by a thread that is the owner + * of this object''s monitor. See the notify method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @exception IllegalMonitorStateException if the current thread is not + * the owner of this object''s monitor. + * @see java.lang.Object#notify() + * @see java.lang.Object#wait() + */ + public final native void notifyAll(); + + /** + * Causes the current thread to wait until either another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object, or a + * specified amount of time has elapsed. + *

+ * The current thread must own this object''s monitor. + *

+ * This method causes the current thread (call it T) to + * place itself in the wait set for this object and then to relinquish + * any and all synchronization claims on this object. Thread T + * becomes disabled for thread scheduling purposes and lies dormant + * until one of four things happens: + *

    + *
  • Some other thread invokes the notify method for this + * object and thread T happens to be arbitrarily chosen as + * the thread to be awakened. + *
  • Some other thread invokes the notifyAll method for this + * object. + *
  • Some other thread {@linkplain Thread#interrupt() interrupts} + * thread T. + *
  • The specified amount of real time has elapsed, more or less. If + * timeout is zero, however, then real time is not taken into + * consideration and the thread simply waits until notified. + *
+ * The thread T is then removed from the wait set for this + * object and re-enabled for thread scheduling. It then competes in the + * usual manner with other threads for the right to synchronize on the + * object; once it has gained control of the object, all its + * synchronization claims on the object are restored to the status quo + * ante - that is, to the situation as of the time that the wait + * method was invoked. Thread T then returns from the + * invocation of the wait method. Thus, on return from the + * wait method, the synchronization state of the object and of + * thread T is exactly as it was when the wait method + * was invoked. + *

+ * A thread can also wake up without being notified, interrupted, or + * timing out, a so-called spurious wakeup. While this will rarely + * occur in practice, applications must guard against it by testing for + * the condition that should have caused the thread to be awakened, and + * continuing to wait if the condition is not satisfied. In other words, + * waits should always occur in loops, like this one: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait(timeout);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * (For more information on this topic, see Section 3.2.3 in Doug Lea''s + * "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, + * 2000), or Item 50 in Joshua Bloch''s "Effective Java Programming + * Language Guide" (Addison-Wesley, 2001). + * + *

If the current thread is {@linkplain java.lang.Thread#interrupt() + * interrupted} by any thread before or while it is waiting, then an + * InterruptedException is thrown. This exception is not + * thrown until the lock status of this object has been restored as + * described above. + * + *

+ * Note that the wait method, as it places the current thread + * into the wait set for this object, unlocks only this object; any + * other objects on which the current thread may be synchronized remain + * locked while the thread waits. + *

+ * This method should only be called by a thread that is the owner + * of this object''s monitor. See the notify method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @param timeout the maximum time to wait in milliseconds. + * @exception IllegalArgumentException if the value of timeout is + * negative. + * @exception IllegalMonitorStateException if the current thread is not + * the owner of the object''s monitor. + * @exception InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + * @see java.lang.Object#notify() + * @see java.lang.Object#notifyAll() + */ + public final native void wait(long timeout) throws InterruptedException; + + /** + * Causes the current thread to wait until another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object, or + * some other thread interrupts the current thread, or a certain + * amount of real time has elapsed. + *

+ * This method is similar to the wait method of one + * argument, but it allows finer control over the amount of time to + * wait for a notification before giving up. The amount of real time, + * measured in nanoseconds, is given by: + *

+ *
+     * 1000000*timeout+nanos
+ *

+ * In all other respects, this method does the same thing as the + * method {@link #wait(long)} of one argument. In particular, + * wait(0, 0) means the same thing as wait(0). + *

+ * The current thread must own this object''s monitor. The thread + * releases ownership of this monitor and waits until either of the + * following two conditions has occurred: + *

    + *
  • Another thread notifies threads waiting on this object''s monitor + * to wake up either through a call to the notify method + * or the notifyAll method. + *
  • The timeout period, specified by timeout + * milliseconds plus nanos nanoseconds arguments, has + * elapsed. + *
+ *

+ * The thread then waits until it can re-obtain ownership of the + * monitor and resumes execution. + *

+ * As in the one argument version, interrupts and spurious wakeups are + * possible, and this method should always be used in a loop: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait(timeout, nanos);
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * This method should only be called by a thread that is the owner + * of this object''s monitor. See the notify method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @param timeout the maximum time to wait in milliseconds. + * @param nanos additional time, in nanoseconds range + * 0-999999. + * @exception IllegalArgumentException if the value of timeout is + * negative or the value of nanos is + * not in the range 0-999999. + * @exception IllegalMonitorStateException if the current thread is not + * the owner of this object''s monitor. + * @exception InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + */ + public final void wait(long timeout, int nanos) throws InterruptedException { + if (timeout < 0) { + throw new IllegalArgumentException("timeout value is negative"); + } + + if (nanos < 0 || nanos > 999999) { + throw new IllegalArgumentException( + "nanosecond timeout value out of range"); + } + + if (nanos >= 500000 || (nanos !!= 0 && timeout == 0)) { + timeout++; + } + + wait(timeout); + } + + /** + * Causes the current thread to wait until another thread invokes the + * {@link java.lang.Object#notify()} method or the + * {@link java.lang.Object#notifyAll()} method for this object. + * In other words, this method behaves exactly as if it simply + * performs the call wait(0). + *

+ * The current thread must own this object''s monitor. The thread + * releases ownership of this monitor and waits until another thread + * notifies threads waiting on this object''s monitor to wake up + * either through a call to the notify method or the + * notifyAll method. The thread then waits until it can + * re-obtain ownership of the monitor and resumes execution. + *

+ * As in the one argument version, interrupts and spurious wakeups are + * possible, and this method should always be used in a loop: + *

+     *     synchronized (obj) {
+     *         while (<condition does not hold>)
+     *             obj.wait();
+     *         ... // Perform action appropriate to condition
+     *     }
+     * 
+ * This method should only be called by a thread that is the owner + * of this object''s monitor. See the notify method for a + * description of the ways in which a thread can become the owner of + * a monitor. + * + * @exception IllegalMonitorStateException if the current thread is not + * the owner of the object''s monitor. + * @exception InterruptedException if any thread interrupted the + * current thread before or while the current thread + * was waiting for a notification. The interrupted + * status of the current thread is cleared when + * this exception is thrown. + * @see java.lang.Object#notify() + * @see java.lang.Object#notifyAll() + */ + public final void wait() throws InterruptedException { + wait(0); + } + + /** + * Called by the garbage collector on an object when garbage collection + * determines that there are no more references to the object. + * A subclass overrides the finalize method to dispose of + * system resources or to perform other cleanup. + *

+ * The general contract of finalize is that it is invoked + * if and when the JavaTM virtual + * machine has determined that there is no longer any + * means by which this object can be accessed by any thread that has + * not yet died, except as a result of an action taken by the + * finalization of some other object or class which is ready to be + * finalized. The finalize method may take any action, including + * making this object available again to other threads; the usual purpose + * of finalize, however, is to perform cleanup actions before + * the object is irrevocably discarded. For example, the finalize method + * for an object that represents an input/output connection might perform + * explicit I/O transactions to break the connection before the object is + * permanently discarded. + *

+ * The finalize method of class Object performs no + * special action; it simply returns normally. Subclasses of + * Object may override this definition. + *

+ * The Java programming language does not guarantee which thread will + * invoke the finalize method for any given object. It is + * guaranteed, however, that the thread that invokes finalize will not + * be holding any user-visible synchronization locks when finalize is + * invoked. If an uncaught exception is thrown by the finalize method, + * the exception is ignored and finalization of that object terminates. + *

+ * After the finalize method has been invoked for an object, no + * further action is taken until the Java virtual machine has again + * determined that there is no longer any means by which this object can + * be accessed by any thread that has not yet died, including possible + * actions by other objects or classes which are ready to be finalized, + * at which point the object may be discarded. + *

+ * The finalize method is never invoked more than once by a Java + * virtual machine for any given object. + *

+ * Any exception thrown by the finalize method causes + * the finalization of this object to be halted, but is otherwise + * ignored. + * + * @throws Throwable the Exception raised by this method + */ + protected void finalize() throws Throwable { } +}' +! + +file1 + ^ +'package org.test; + +import java.util.*; + +public class Foo +{ + // I am only empty class +}' +! + +file2 + ^ +' +public class Foo +{ + public void methodA() {} + + public Bar methodB(Some argument, and another) {} +}' +! + +file3 + ^ +'package org.test; + +import java.util.*; + +public class Foo extends Zorg +{ + // some comment + + public void methodA() { + System.out.println(); + } + + private InnerClass {} + + /** + * + */ + public Bar methodB(Some argument, and another) + { + return new Bar(); + } +}' +! + +file4 + ^ +'package java.lang; + +import java.lang.reflect.Array; +/** + * Instances of the class {@code Class} represent classes and + * interfaces in a running Java application. + *

The following example uses a {@code Class} object to print the + * class name of an object: + * + *

+ *     void printClassName(Object obj) {
+ *         System.out.println("The class of " + obj +
+ *                            " is " + obj.getClass().getName());
+ *     }
+ * 
+ * + *

It is also possible to get the {@code Class} object for a named + * type (or for void) using a class literal + * (JLS Section 15.8.2). + * For example: + * + *

+ * {@code System.out.println("The name of class Foo is: "+Foo.class.getName());} + *
+ * + * @param the type of the class modeled by this {@code Class} + * object. For example, the type of {@code String.class} is {@code + * Class}. Use {@code Class} if the class being modeled is + * unknown. + * + * @author unascribed + * @see java.lang.ClassLoader#defineClass(byte[], int, int) + * @since JDK1.0 + */ +public final + class Class implements java.io.Serializable, + java.lang.reflect.GenericDeclaration, + java.lang.reflect.Type, + java.lang.reflect.AnnotatedElement { + private static final int ANNOTATION= 0x00002000; + private static final int ENUM = 0x00004000; + private static final int SYNTHETIC = 0x00001000; + + private static native void registerNatives(); + static { + registerNatives(); + } + + /* + * Constructor. Only the Java Virtual Machine creates Class + * objects. + */ + private Class() {} + + + /** + * Converts the object to a string. The string representation is the + * string "class" or "interface", followed by a space, and then by the + * fully qualified name of the class in the format returned by + * {@code getName}. If this {@code Class} object represents a + * primitive type, this method returns the name of the primitive type. If + * this {@code Class} object represents void this method returns + * "void". + * + * @return a string representation of this class object. + */ + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } +}' +! + +file5 + ^ +'package java.lang; + +import java.lang.reflect.Array; + +/** + * This is a class that has a comment!! + * public class Bar { public void bar() { } } } + * + * @author unascribed + * @since JDK1.0 + */ +public final class Foo implements java.io.Serializable { + /* + * Constructor. Only the Java Virtual Machine creates Class + * objects. + */ + private Foo() {} + + + /** + * Converts the object to a string. The string representation is the + * string "class" or "interface", followed by a space, and then by the + * fully qualified name of the class in the format returned by + * {@code getName}. If this {@code Class} object represents a + * primitive type, this method returns the name of the primitive type. If + * this {@code Class} object represents void this method returns + * "void". + * + * @return a string representation of this class object. + */ + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } +}' +! + +file6 + ^ +'/* + * Copyright (c) 1994, 2006, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang; + +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Member; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Modifier; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.InvocationTargetException; +import java.lang.ref.SoftReference; +import java.io.InputStream; +import java.io.ObjectStreamField; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.LinkedList; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.Map; +import java.util.HashMap; +import sun.misc.Unsafe; +import sun.reflect.ConstantPool; +import sun.reflect.Reflection; +import sun.reflect.ReflectionFactory; +import sun.reflect.SignatureIterator; +import sun.reflect.generics.factory.CoreReflectionFactory; +import sun.reflect.generics.factory.GenericsFactory; +import sun.reflect.generics.repository.ClassRepository; +import sun.reflect.generics.repository.MethodRepository; +import sun.reflect.generics.repository.ConstructorRepository; +import sun.reflect.generics.scope.ClassScope; +import sun.security.util.SecurityConstants; +import java.lang.annotation.Annotation; +import sun.reflect.annotation.*; + +/** + * Instances of the class {@code Class} represent classes and + * interfaces in a running Java application. An enum is a kind of + * class and an annotation is a kind of interface. Every array also + * belongs to a class that is reflected as a {@code Class} object + * that is shared by all arrays with the same element type and number + * of dimensions. The primitive Java types ({@code boolean}, + * {@code byte}, {@code char}, {@code short}, + * {@code int}, {@code long}, {@code float}, and + * {@code double}), and the keyword {@code void} are also + * represented as {@code Class} objects. + * + *

{@code Class} has no public constructor. Instead {@code Class} + * objects are constructed automatically by the Java Virtual Machine as classes + * are loaded and by calls to the {@code defineClass} method in the class + * loader. + * + *

The following example uses a {@code Class} object to print the + * class name of an object: + * + *

+ *     void printClassName(Object obj) {
+ *         System.out.println("The class of " + obj +
+ *                            " is " + obj.getClass().getName());
+ *     }
+ * 
+ * + *

It is also possible to get the {@code Class} object for a named + * type (or for void) using a class literal + * (JLS Section 15.8.2). + * For example: + * + *

+ * {@code System.out.println("The name of class Foo is: "+Foo.class.getName());} + *
+ * + * @param the type of the class modeled by this {@code Class} + * object. For example, the type of {@code String.class} is {@code + * Class}. Use {@code Class} if the class being modeled is + * unknown. + * + * @author unascribed + * @see java.lang.ClassLoader#defineClass(byte[], int, int) + * @since JDK1.0 + */ +public final + class Class implements java.io.Serializable, + java.lang.reflect.GenericDeclaration, + java.lang.reflect.Type, + java.lang.reflect.AnnotatedElement { + private static final int ANNOTATION= 0x00002000; + private static final int ENUM = 0x00004000; + private static final int SYNTHETIC = 0x00001000; + + private static native void registerNatives(); + static { + registerNatives(); + } + + /* + * Constructor. Only the Java Virtual Machine creates Class + * objects. + */ + private Class() {} + + + /** + * Converts the object to a string. The string representation is the + * string "class" or "interface", followed by a space, and then by the + * fully qualified name of the class in the format returned by + * {@code getName}. If this {@code Class} object represents a + * primitive type, this method returns the name of the primitive type. If + * this {@code Class} object represents void this method returns + * "void". + * + * @return a string representation of this class object. + */ + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } + + + /** + * Returns the {@code Class} object associated with the class or + * interface with the given string name. Invoking this method is + * equivalent to: + * + *
+ * {@code Class.forName(className, true, currentLoader)} + *
+ * + * where {@code currentLoader} denotes the defining class loader of + * the current class. + * + *

For example, the following code fragment returns the + * runtime {@code Class} descriptor for the class named + * {@code java.lang.Thread}: + * + *

+ * {@code Class t = Class.forName("java.lang.Thread")} + *
+ *

+ * A call to {@code forName("X")} causes the class named + * {@code X} to be initialized. + * + * @param className the fully qualified name of the desired class. + * @return the {@code Class} object for the class with the + * specified name. + * @exception LinkageError if the linkage fails + * @exception ExceptionInInitializerError if the initialization provoked + * by this method fails + * @exception ClassNotFoundException if the class cannot be located + */ + public static Class forName(String className) + throws ClassNotFoundException { + return forName0(className, true, ClassLoader.getCallerClassLoader()); + } + + + /** + * Returns the {@code Class} object associated with the class or + * interface with the given string name, using the given class loader. + * Given the fully qualified name for a class or interface (in the same + * format returned by {@code getName}) this method attempts to + * locate, load, and link the class or interface. The specified class + * loader is used to load the class or interface. If the parameter + * {@code loader} is null, the class is loaded through the bootstrap + * class loader. The class is initialized only if the + * {@code initialize} parameter is {@code true} and if it has + * not been initialized earlier. + * + *

If {@code name} denotes a primitive type or void, an attempt + * will be made to locate a user-defined class in the unnamed package whose + * name is {@code name}. Therefore, this method cannot be used to + * obtain any of the {@code Class} objects representing primitive + * types or void. + * + *

If {@code name} denotes an array class, the component type of + * the array class is loaded but not initialized. + * + *

For example, in an instance method the expression: + * + *

+ * {@code Class.forName("Foo")} + *
+ * + * is equivalent to: + * + *
+ * {@code Class.forName("Foo", true, this.getClass().getClassLoader())} + *
+ * + * Note that this method throws errors related to loading, linking or + * initializing as specified in Sections 12.2, 12.3 and 12.4 of The + * Java Language Specification. + * Note that this method does not check whether the requested class + * is accessible to its caller. + * + *

If the {@code loader} is {@code null}, and a security + * manager is present, and the caller''s class loader is not null, then this + * method calls the security manager''s {@code checkPermission} method + * with a {@code RuntimePermission("getClassLoader")} permission to + * ensure it''s ok to access the bootstrap class loader. + * + * @param name fully qualified name of the desired class + * @param initialize whether the class must be initialized + * @param loader class loader from which the class must be loaded + * @return class object representing the desired class + * + * @exception LinkageError if the linkage fails + * @exception ExceptionInInitializerError if the initialization provoked + * by this method fails + * @exception ClassNotFoundException if the class cannot be located by + * the specified class loader + * + * @see java.lang.Class#forName(String) + * @see java.lang.ClassLoader + * @since 1.2 + */ + public static Class forName(String name, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) { + SecurityManager sm = System.getSecurityManager(); + if (sm !!= null) { + ClassLoader ccl = ClassLoader.getCallerClassLoader(); + if (ccl !!= null) { + sm.checkPermission( + SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + return forName0(name, initialize, loader); + } + + /** Called after security checks have been made. */ + private static native Class forName0(String name, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException; + + /** + * Creates a new instance of the class represented by this {@code Class} + * object. The class is instantiated as if by a {@code new} + * expression with an empty argument list. The class is initialized if it + * has not already been initialized. + * + *

Note that this method propagates any exception thrown by the + * nullary constructor, including a checked exception. Use of + * this method effectively bypasses the compile-time exception + * checking that would otherwise be performed by the compiler. + * The {@link + * java.lang.reflect.Constructor#newInstance(java.lang.Object...) + * Constructor.newInstance} method avoids this problem by wrapping + * any exception thrown by the constructor in a (checked) {@link + * java.lang.reflect.InvocationTargetException}. + * + * @return a newly allocated instance of the class represented by this + * object. + * @exception IllegalAccessException if the class or its nullary + * constructor is not accessible. + * @exception InstantiationException + * if this {@code Class} represents an abstract class, + * an interface, an array class, a primitive type, or void; + * or if the class has no nullary constructor; + * or if the instantiation fails for some other reason. + * @exception ExceptionInInitializerError if the initialization + * provoked by this method fails. + * @exception SecurityException + * If a security manager, s, is present and any of the + * following conditions is met: + * + *

    + * + *
  • invocation of + * {@link SecurityManager#checkMemberAccess + * s.checkMemberAccess(this, Member.PUBLIC)} denies + * creation of new instances of this class + * + *
  • the caller''s class loader is not the same as or an + * ancestor of the class loader for the current class and + * invocation of {@link SecurityManager#checkPackageAccess + * s.checkPackageAccess()} denies access to the package + * of this class + * + *
+ * + */ + public T newInstance() + throws InstantiationException, IllegalAccessException + { + if (System.getSecurityManager() !!= null) { + checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader()); + } + return newInstance0(); + } + + private T newInstance0() + throws InstantiationException, IllegalAccessException + { + // NOTE: the following code may not be strictly correct under + // the current Java memory model. + + // Constructor lookup + if (cachedConstructor == null) { + if (this == Class.class) { + throw new IllegalAccessException( + "Can not call newInstance() on the Class for java.lang.Class" + ); + } + try { + Class[] empty = {}; + final Constructor c = getConstructor0(empty, Member.DECLARED); + // Disable accessibility checks on the constructor + // since we have to do the security check here anyway + // (the stack depth is wrong for the Constructor''s + // security check to work) + java.security.AccessController.doPrivileged + (new java.security.PrivilegedAction() { + public Object run() { + c.setAccessible(true); + return null; + } + }); + cachedConstructor = c; + } catch (NoSuchMethodException e) { + throw new InstantiationException(getName()); + } + } + Constructor tmpConstructor = cachedConstructor; + // Security check (same as in java.lang.reflect.Constructor) + int modifiers = tmpConstructor.getModifiers(); + if (!!Reflection.quickCheckMemberAccess(this, modifiers)) { + Class caller = Reflection.getCallerClass(3); + if (newInstanceCallerCache !!= caller) { + Reflection.ensureMemberAccess(caller, this, null, modifiers); + newInstanceCallerCache = caller; + } + } + // Run constructor + try { + return tmpConstructor.newInstance((Object[])null); + } catch (InvocationTargetException e) { + Unsafe.getUnsafe().throwException(e.getTargetException()); + // Not reached + return null; + } + } + private volatile transient Constructor cachedConstructor; + private volatile transient Class newInstanceCallerCache; + + + /** + * Determines if the specified {@code Object} is assignment-compatible + * with the object represented by this {@code Class}. This method is + * the dynamic equivalent of the Java language {@code instanceof} + * operator. The method returns {@code true} if the specified + * {@code Object} argument is non-null and can be cast to the + * reference type represented by this {@code Class} object without + * raising a {@code ClassCastException.} It returns {@code false} + * otherwise. + * + *

Specifically, if this {@code Class} object represents a + * declared class, this method returns {@code true} if the specified + * {@code Object} argument is an instance of the represented class (or + * of any of its subclasses); it returns {@code false} otherwise. If + * this {@code Class} object represents an array class, this method + * returns {@code true} if the specified {@code Object} argument + * can be converted to an object of the array class by an identity + * conversion or by a widening reference conversion; it returns + * {@code false} otherwise. If this {@code Class} object + * represents an interface, this method returns {@code true} if the + * class or any superclass of the specified {@code Object} argument + * implements this interface; it returns {@code false} otherwise. If + * this {@code Class} object represents a primitive type, this method + * returns {@code false}. + * + * @param obj the object to check + * @return true if {@code obj} is an instance of this class + * + * @since JDK1.1 + */ + public native boolean isInstance(Object obj); + + + /** + * Determines if the class or interface represented by this + * {@code Class} object is either the same as, or is a superclass or + * superinterface of, the class or interface represented by the specified + * {@code Class} parameter. It returns {@code true} if so; + * otherwise it returns {@code false}. If this {@code Class} + * object represents a primitive type, this method returns + * {@code true} if the specified {@code Class} parameter is + * exactly this {@code Class} object; otherwise it returns + * {@code false}. + * + *

Specifically, this method tests whether the type represented by the + * specified {@code Class} parameter can be converted to the type + * represented by this {@code Class} object via an identity conversion + * or via a widening reference conversion. See The Java Language + * Specification, sections 5.1.1 and 5.1.4 , for details. + * + * @param cls the {@code Class} object to be checked + * @return the {@code boolean} value indicating whether objects of the + * type {@code cls} can be assigned to objects of this class + * @exception NullPointerException if the specified Class parameter is + * null. + * @since JDK1.1 + */ + public native boolean isAssignableFrom(Class cls); + + + /** + * Determines if the specified {@code Class} object represents an + * interface type. + * + * @return {@code true} if this object represents an interface; + * {@code false} otherwise. + */ + public native boolean isInterface(); + + + /** + * Determines if this {@code Class} object represents an array class. + * + * @return {@code true} if this object represents an array class; + * {@code false} otherwise. + * @since JDK1.1 + */ + public native boolean isArray(); + + + /** + * Determines if the specified {@code Class} object represents a + * primitive type. + * + *

There are nine predefined {@code Class} objects to represent + * the eight primitive types and void. These are created by the Java + * Virtual Machine, and have the same names as the primitive types that + * they represent, namely {@code boolean}, {@code byte}, + * {@code char}, {@code short}, {@code int}, + * {@code long}, {@code float}, and {@code double}. + * + *

These objects may only be accessed via the following public static + * final variables, and are the only {@code Class} objects for which + * this method returns {@code true}. + * + * @return true if and only if this class represents a primitive type + * + * @see java.lang.Boolean#TYPE + * @see java.lang.Character#TYPE + * @see java.lang.Byte#TYPE + * @see java.lang.Short#TYPE + * @see java.lang.Integer#TYPE + * @see java.lang.Long#TYPE + * @see java.lang.Float#TYPE + * @see java.lang.Double#TYPE + * @see java.lang.Void#TYPE + * @since JDK1.1 + */ + public native boolean isPrimitive(); + + /** + * Returns true if this {@code Class} object represents an annotation + * type. Note that if this method returns true, {@link #isInterface()} + * would also return true, as all annotation types are also interfaces. + * + * @return {@code true} if this class object represents an annotation + * type; {@code false} otherwise + * @since 1.5 + */ + public boolean isAnnotation() { + return (getModifiers() & ANNOTATION) !!= 0; + } + + /** + * Returns {@code true} if this class is a synthetic class; + * returns {@code false} otherwise. + * @return {@code true} if and only if this class is a synthetic class as + * defined by the Java Language Specification. + * @since 1.5 + */ + public boolean isSynthetic() { + return (getModifiers() & SYNTHETIC) !!= 0; + } + + /** + * Returns the name of the entity (class, interface, array class, + * primitive type, or void) represented by this {@code Class} object, + * as a {@code String}. + * + *

If this class object represents a reference type that is not an + * array type then the binary name of the class is returned, as specified + * by the Java Language Specification, Second Edition. + * + *

If this class object represents a primitive type or void, then the + * name returned is a {@code String} equal to the Java language + * keyword corresponding to the primitive type or void. + * + *

If this class object represents a class of arrays, then the internal + * form of the name consists of the name of the element type preceded by + * one or more ''{@code [}'' characters representing the depth of the array + * nesting. The encoding of element type names is as follows: + * + *

+ *
Element Type     Encoding + *
boolean     Z + *
byte     B + *
char     C + *
class or interface + *     Lclassname; + *
double     D + *
float     F + *
int     I + *
long     J + *
short     S + *
+ * + *

The class or interface name classname is the binary name of + * the class specified above. + * + *

Examples: + *

+     * String.class.getName()
+     *     returns "java.lang.String"
+     * byte.class.getName()
+     *     returns "byte"
+     * (new Object[3]).getClass().getName()
+     *     returns "[Ljava.lang.Object;"
+     * (new int[3][4][5][6][7][8][9]).getClass().getName()
+     *     returns "[[[[[[[I"
+     * 
+ * + * @return the name of the class or interface + * represented by this object. + */ + public String getName() { + if (name == null) + name = getName0(); + return name; + } + + // cache the name to reduce the number of calls into the VM + private transient String name; + private native String getName0(); + + /** + * Returns the class loader for the class. Some implementations may use + * null to represent the bootstrap class loader. This method will return + * null in such implementations if this class was loaded by the bootstrap + * class loader. + * + *

If a security manager is present, and the caller''s class loader is + * not null and the caller''s class loader is not the same as or an ancestor of + * the class loader for the class whose class loader is requested, then + * this method calls the security manager''s {@code checkPermission} + * method with a {@code RuntimePermission("getClassLoader")} + * permission to ensure it''s ok to access the class loader for the class. + * + *

If this object + * represents a primitive type or void, null is returned. + * + * @return the class loader that loaded the class or interface + * represented by this object. + * @throws SecurityException + * if a security manager exists and its + * {@code checkPermission} method denies + * access to the class loader for the class. + * @see java.lang.ClassLoader + * @see SecurityManager#checkPermission + * @see java.lang.RuntimePermission + */ + public ClassLoader getClassLoader() { + ClassLoader cl = getClassLoader0(); + if (cl == null) + return null; + SecurityManager sm = System.getSecurityManager(); + if (sm !!= null) { + ClassLoader ccl = ClassLoader.getCallerClassLoader(); + if (ccl !!= null && ccl !!= cl && !!cl.isAncestor(ccl)) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + return cl; + } + + // Package-private to allow ClassLoader access + native ClassLoader getClassLoader0(); + + + /** + * Returns an array of {@code TypeVariable} objects that represent the + * type variables declared by the generic declaration represented by this + * {@code GenericDeclaration} object, in declaration order. Returns an + * array of length 0 if the underlying generic declaration declares no type + * variables. + * + * @return an array of {@code TypeVariable} objects that represent + * the type variables declared by this generic declaration + * @throws GenericSignatureFormatError if the generic + * signature of this generic declaration does not conform to + * the format specified in the Java Virtual Machine Specification, + * 3rd edition + * @since 1.5 + */ + public TypeVariable>[] getTypeParameters() { + if (getGenericSignature() !!= null) + return (TypeVariable>[])getGenericInfo().getTypeParameters(); + else + return (TypeVariable>[])new TypeVariable[0]; + } + + + /** + * Returns the {@code Class} representing the superclass of the entity + * (class, interface, primitive type or void) represented by this + * {@code Class}. If this {@code Class} represents either the + * {@code Object} class, an interface, a primitive type, or void, then + * null is returned. If this object represents an array class then the + * {@code Class} object representing the {@code Object} class is + * returned. + * + * @return the superclass of the class represented by this object. + */ + public native Class getSuperclass(); + + + /** + * Returns the {@code Type} representing the direct superclass of + * the entity (class, interface, primitive type or void) represented by + * this {@code Class}. + * + *

If the superclass is a parameterized type, the {@code Type} + * object returned must accurately reflect the actual type + * parameters used in the source code. The parameterized type + * representing the superclass is created if it had not been + * created before. See the declaration of {@link + * java.lang.reflect.ParameterizedType ParameterizedType} for the + * semantics of the creation process for parameterized types. If + * this {@code Class} represents either the {@code Object} + * class, an interface, a primitive type, or void, then null is + * returned. If this object represents an array class then the + * {@code Class} object representing the {@code Object} class is + * returned. + * + * @throws GenericSignatureFormatError if the generic + * class signature does not conform to the format specified in the + * Java Virtual Machine Specification, 3rd edition + * @throws TypeNotPresentException if the generic superclass + * refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if the + * generic superclass refers to a parameterized type that cannot be + * instantiated for any reason + * @return the superclass of the class represented by this object + * @since 1.5 + */ + public Type getGenericSuperclass() { + if (getGenericSignature() !!= null) { + // Historical irregularity: + // Generic signature marks interfaces with superclass = Object + // but this API returns null for interfaces + if (isInterface()) + return null; + return getGenericInfo().getSuperclass(); + } else + return getSuperclass(); + } + + /** + * Gets the package for this class. The class loader of this class is used + * to find the package. If the class was loaded by the bootstrap class + * loader the set of packages loaded from CLASSPATH is searched to find the + * package of the class. Null is returned if no package object was created + * by the class loader of this class. + * + *

Packages have attributes for versions and specifications only if the + * information was defined in the manifests that accompany the classes, and + * if the class loader created the package instance with the attributes + * from the manifest. + * + * @return the package of the class, or null if no package + * information is available from the archive or codebase. + */ + public Package getPackage() { + return Package.getPackage(this); + } + + + /** + * Determines the interfaces implemented by the class or interface + * represented by this object. + * + *

If this object represents a class, the return value is an array + * containing objects representing all interfaces implemented by the + * class. The order of the interface objects in the array corresponds to + * the order of the interface names in the {@code implements} clause + * of the declaration of the class represented by this object. For + * example, given the declaration: + *

+ * {@code class Shimmer implements FloorWax, DessertTopping { ... }} + *
+ * suppose the value of {@code s} is an instance of + * {@code Shimmer}; the value of the expression: + *
+ * {@code s.getClass().getInterfaces()[0]} + *
+ * is the {@code Class} object that represents interface + * {@code FloorWax}; and the value of: + *
+ * {@code s.getClass().getInterfaces()[1]} + *
+ * is the {@code Class} object that represents interface + * {@code DessertTopping}. + * + *

If this object represents an interface, the array contains objects + * representing all interfaces extended by the interface. The order of the + * interface objects in the array corresponds to the order of the interface + * names in the {@code extends} clause of the declaration of the + * interface represented by this object. + * + *

If this object represents a class or interface that implements no + * interfaces, the method returns an array of length 0. + * + *

If this object represents a primitive type or void, the method + * returns an array of length 0. + * + * @return an array of interfaces implemented by this class. + */ + public native Class[] getInterfaces(); + + /** + * Returns the {@code Type}s representing the interfaces + * directly implemented by the class or interface represented by + * this object. + * + *

If a superinterface is a parameterized type, the + * {@code Type} object returned for it must accurately reflect + * the actual type parameters used in the source code. The + * parameterized type representing each superinterface is created + * if it had not been created before. See the declaration of + * {@link java.lang.reflect.ParameterizedType ParameterizedType} + * for the semantics of the creation process for parameterized + * types. + * + *

If this object represents a class, the return value is an + * array containing objects representing all interfaces + * implemented by the class. The order of the interface objects in + * the array corresponds to the order of the interface names in + * the {@code implements} clause of the declaration of the class + * represented by this object. In the case of an array class, the + * interfaces {@code Cloneable} and {@code Serializable} are + * returned in that order. + * + *

If this object represents an interface, the array contains + * objects representing all interfaces directly extended by the + * interface. The order of the interface objects in the array + * corresponds to the order of the interface names in the + * {@code extends} clause of the declaration of the interface + * represented by this object. + * + *

If this object represents a class or interface that + * implements no interfaces, the method returns an array of length + * 0. + * + *

If this object represents a primitive type or void, the + * method returns an array of length 0. + * + * @throws GenericSignatureFormatError + * if the generic class signature does not conform to the format + * specified in the Java Virtual Machine Specification, 3rd edition + * @throws TypeNotPresentException if any of the generic + * superinterfaces refers to a non-existent type declaration + * @throws MalformedParameterizedTypeException if any of the + * generic superinterfaces refer to a parameterized type that cannot + * be instantiated for any reason + * @return an array of interfaces implemented by this class + * @since 1.5 + */ + public Type[] getGenericInterfaces() { + if (getGenericSignature() !!= null) + return getGenericInfo().getSuperInterfaces(); + else + return getInterfaces(); + } + +/** + * Returns the {@code Class} representing the component type of an + * array. If this class does not represent an array class this method + * returns null. + * + * @return the {@code Class} representing the component type of this + * class if this class is an array + * @see java.lang.reflect.Array + * @since JDK1.1 + */ + public native Class getComponentType(); + + + /** + * Returns the Java language modifiers for this class or interface, encoded + * in an integer. The modifiers consist of the Java Virtual Machine''s + * constants for {@code public}, {@code protected}, + * {@code private}, {@code final}, {@code static}, + * {@code abstract} and {@code interface}; they should be decoded + * using the methods of class {@code Modifier}. + * + *

If the underlying class is an array class, then its + * {@code public}, {@code private} and {@code protected} + * modifiers are the same as those of its component type. If this + * {@code Class} represents a primitive type or void, its + * {@code public} modifier is always {@code true}, and its + * {@code protected} and {@code private} modifiers are always + * {@code false}. If this object represents an array class, a + * primitive type or void, then its {@code final} modifier is always + * {@code true} and its interface modifier is always + * {@code false}. The values of its other modifiers are not determined + * by this specification. + * + *

The modifier encodings are defined in The Java Virtual Machine + * Specification, table 4.1. + * + * @return the {@code int} representing the modifiers for this class + * @see java.lang.reflect.Modifier + * @since JDK1.1 + */ + public native int getModifiers(); + + + /** + * Gets the signers of this class. + * + * @return the signers of this class, or null if there are no signers. In + * particular, this method returns null if this object represents + * a primitive type or void. + * @since JDK1.1 + */ + public native Object[] getSigners(); + + + /** + * Set the signers of this class. + */ + native void setSigners(Object[] signers); + + + /** + * If this {@code Class} object represents a local or anonymous + * class within a method, returns a {@link + * java.lang.reflect.Method Method} object representing the + * immediately enclosing method of the underlying class. Returns + * {@code null} otherwise. + * + * In particular, this method returns {@code null} if the underlying + * class is a local or anonymous class immediately enclosed by a type + * declaration, instance initializer or static initializer. + * + * @return the immediately enclosing method of the underlying class, if + * that class is a local or anonymous class; otherwise {@code null}. + * @since 1.5 + */ + public Method getEnclosingMethod() { + EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo(); + + if (enclosingInfo == null) + return null; + else { + if (!!enclosingInfo.isMethod()) + return null; + + MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(), + getFactory()); + Class returnType = toClass(typeInfo.getReturnType()); + Type [] parameterTypes = typeInfo.getParameterTypes(); + Class[] parameterClasses = new Class[parameterTypes.length]; + + // Convert Types to Classes; returned types *should* + // be class objects since the methodDescriptor''s used + // don''t have generics information + for(int i = 0; i < parameterClasses.length; i++) + parameterClasses[i] = toClass(parameterTypes[i]); + + /* + * Loop over all declared methods; match method name, + * number of and type of parameters, *and* return + * type. Matching return type is also necessary + * because of covariant returns, etc. + */ + for(Method m: enclosingInfo.getEnclosingClass().getDeclaredMethods()) { + if (m.getName().equals(enclosingInfo.getName()) ) { + Class[] candidateParamClasses = m.getParameterTypes(); + if (candidateParamClasses.length == parameterClasses.length) { + boolean matches = true; + for(int i = 0; i < candidateParamClasses.length; i++) { + if (!!candidateParamClasses[i].equals(parameterClasses[i])) { + matches = false; + break; + } + } + + if (matches) { // finally, check return type + if (m.getReturnType().equals(returnType) ) + return m; + } + } + } + } + + throw new InternalError("Enclosing method not found"); + } + } + + + private AnnotationType annotationType; + + void setAnnotationType(AnnotationType type) { + annotationType = type; + } + + AnnotationType getAnnotationType() { + return annotationType; + } +}' +! + +file7 + ^ +' + +package java.lang; + +import sun.reflect.annotation.*; + +/** + * @author unascribed + * @see java.lang.ClassLoader#defineClass(byte[], int, int) + * @since JDK1.0 + */ +public final + class Class implements java.io.Serializable, + java.lang.reflect.GenericDeclaration, + java.lang.reflect.Type, + java.lang.reflect.AnnotatedElement { + + private static native void registerNatives(); + + static { + registerNatives(); + } + + /* + * Constructor. Only the Java Virtual Machine creates Class + * objects. + */ + private Class() { } + + + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } + + + + + AnnotationType getAnnotationType() { + return annotationType; + } +}' +! ! + +!JavaParserTest methodsFor:'tests'! + +test1 + self parse: self file1. + self assert: result first = 'Foo'. + self assert: result second size = 0. +! + +test2 + self parse: self file2. + + self assert: result first = 'Foo'. + self assert: result second size = 2. + + self assert: result second first = 'methodA'. + self assert: result second second = 'methodB'. +! + +test3 + self parse: self file3. + + self assert: result first = 'Foo'. + self assert: result second size = 2. + + self assert: result second first = 'methodA'. + self assert: result second second = 'methodB'. +! + +test4 + self parse: self file4. + + self assert: result first = 'Class'. + self assert: result second size > 2. + + self assert: (result second anySatisfy: [ :e | e = 'Class' ]). + self assert: (result second anySatisfy: [ :e | e = 'toString' ]). +! + +test5 + self parse: self file5. + + self assert: result first = 'Foo'. + self assert: result second size = 2. + + self assert: result second first = 'Foo'. + self assert: result second second = 'toString'. +! + +test6 + self parse: self file6. + + self assert: result first = 'Class'. + self assert: result second size > 2. + + self assert: (result second anySatisfy: [ :e | e = 'registerNatives' ]). + self assert: (result second anySatisfy: [ :e | e = 'Class' ]). + self assert: (result second anySatisfy: [ :e | e = 'toString' ]). + self assert: (result second anySatisfy: [ :e | e = 'getGenericInterfaces' ]). + self assert: (result second anySatisfy: [ :e | e = 'getAnnotationType' ]) +! + +test7 + self parse: self file7. + + self assert: result first = 'Class'. + self assert: result second size > 2. + + self assert: (result second anySatisfy: [ :e | e = 'Class' ]). + self assert: (result second anySatisfy: [ :e | e = 'toString' ]). + self assert: (result second anySatisfy: [ :e | e = 'getAnnotationType' ]) +! + +testBlock + self parse: '{}' rule: #block. + + self assert: result isPetitFailure not. +! + +testBlock2 + self parse: '{ }' rule: #block. + + self assert: result isPetitFailure not. +! + +testBlock3 + self parse: '{ {} }' rule: #block. + + self assert: result isPetitFailure not. +! + +testClass1 + self parse: 'private final class Foo + { + // I am only empty class + }' + rule: #javaClass. + + self assert: result first = 'Foo'. +! + +testClass2 + self parse: 'public class Foo extends Zorg implements Qwark, Bark + { + // I am only empty class + }' + rule: #javaClass. + + self assert: result first = 'Foo'. +! + +testClass3 + self parse: 'private class Bar extends Zorg implements Qwark, Bark + { + public static void methodA() { /* is empty */ } + }' + rule: #javaClass. + + self assert: result first = 'Bar'. + self assert: result second first = 'methodA'. +! + +testClassBody1 + self parse: '{ + // some comment + public void methodA() + { + } + }' + rule: #classBody. + + self assert: result first = 'methodA'. +! + +testClassBody10 + self parse: '{ + private static final int SKIP_BUFFER_SIZE = 2048; + public int read(byte b[]) throws IOException { + return read(b, 0, b.length); + } +}' + rule: #classBody. + + self assert: result isPetitFailure not. + self assert: result size = 1. + self assert: result first = 'read'. +! + +testClassBody2 + self parse: '{ + // some comment + public void methodA() { + } + + private Another methodB( ) + { + return new Another(); + } + }' + rule: #classBody. + + self assert: result first = 'methodA'. + self assert: result second = 'methodB'. +! + +testClassBody3 + self parse: '{ + // some comment + + public void methodA() { + System.out.println(); + } + + /** + * + */ + public Bar methodB(Some argument, and another) + { + return new Bar(); + } + }' + rule: #classBody. + + self assert: result first = 'methodA'. + self assert: result second = 'methodB'. +! + +testClassBody4 + self parse: '{ + public void methodA() { + System.out.println(); + } + private InnerClass { } + + public Bar methodB(Some argument, and another) + { + return new Bar(); + } + }' + rule: #classBody. + + self assert: result first = 'methodA'. + self assert: result second = 'methodB'. +! + +testClassBody5 + self parse: '{ + // I am only empty class +}' + rule: #classBody. + + self assert: result size = 0. +! + +testClassBody6 + self parse: '{ + static { int i; } +}' + rule: #classBody. + + + self assert: result size = 0. +! + +testClassBody7 + self parse: '{ + static { int i; } + + public String[] getStrings() { } +}' + rule: #classBody. + + + self assert: result size = 1. +! + +testClassBody8 + self parse: '{ + private static final int ANNOTATION= 0x00002000; + static { int i; } + + public String[] getStrings() { } +}' + rule: #classBody. + + + self assert: result size = 1. + self assert: result first = 'getStrings'. +! + +testClassBody9 + self parse: '{ + private static final int ANNOTATION= 0x00002000; + + private static native void registerNatives(); + static { + registerNatives(); + } + + public String toString() { + return (isInterface() ? "interface " : (isPrimitive() ? "" : "class ")) + + getName(); + } +}' + rule: #classBody. + + "debugResult inspect." + self assert: result isPetitFailure not. + self assert: result first = 'registerNatives'. + self assert: result second = 'toString'. +! + +testClassDef1 + self parse: 'public class Foo' rule: #classDef +! + +testComment + | input res | + input := '/* hello there */'. + res := self parserInstance comment end parse: input. + self assert: res isPetitFailure not. +! + +testComment02 + | input res | + input := '/** + *

If the {@code name} is "{@code };"or "{@code }" a + * @since JDK1.1 + */'. + res := self parserInstance comment end parse: input. + self assert: res isPetitFailure not. +! + +testJavaIoInputStream + self parse: self classJavaIoInputStream. + + self assert: result first = 'InputStream'. + + self assert: result second size = 9. + + + self assert: (result second anySatisfy: [ :e | e = 'reset' ]). + self assert: (result second anySatisfy: [ :e | e = 'read' ]). + self assert: (result second anySatisfy: [ :e | e = 'available' ]). + self assert: (result second anySatisfy: [ :e | e = 'markSupported' ]). +! + +testJavaLangClass + self parse: self classJavaLangClass. + + self assert: result first = 'Class'. + + self assert: result second size > 2. + + self assert: (result second anySatisfy: [ :e | e = 'Class' ]). + self assert: (result second anySatisfy: [ :e | e = 'toString' ]). + self assert: (result second anySatisfy: [ :e | e = 'getGenericInterfaces' ]). + self assert: (result second anySatisfy: [ :e | e = 'getAnnotationType' ]) +! + +testJavaLangObject + self parse: self classJavaLangObject. + + self assert: result first = 'Object'. + + self assert: result second size > 2. + + + self assert: (result second anySatisfy: [ :e | e = 'equals' ]). + self assert: (result second anySatisfy: [ :e | e = 'toString' ]). + self assert: (result second anySatisfy: [ :e | e = 'wait' ]). + self assert: (result second anySatisfy: [ :e | e = 'finalize' ]). +! + +testMethod1 + self parse: 'void foo() { }' rule: #methodDef. + + self assert: result = 'foo'. +! + +testMethod2 + self parse: 'Foo m() { /** method body */ }' rule: #methodDef. + + self assert: result = 'm'. +! + +testMethod3 + self parse: 'Bar methodB(Some argument, and another) + { + return new Bar(); + }' + rule: #methodDef. + + self assert: result = 'methodB'. +! + +testMethod4 + self parse: 'void finalize() throws Throwable { }' + rule: #methodDef. + + self assert: result = 'finalize'. +! + +testMethod5 + self parse: 'public void methodA() + { + }' + rule: #methodDef. + + self assert: result = 'methodA'. +! + +testMethod6 + self fail: 'private InnerClass { } + + public void methodA() + { + }' + rule: #methodDef. + +! + +testMethod7 + self parse: 'public int read(byte b) throws IOException { + return b; + }' + rule: #methodDef. + + self assert: result isPetitFailure not. + self assert: result = 'read'. +! + +testSingleLineComment + | input res | + input := '// hello there +'. + res := self parserInstance singleLineComment end parse: input. + self assert: res isPetitFailure not. +! ! + +!JavaParserTest class methodsFor:'documentation'! + +version_HG + + ^ '$Changeset: $' +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/Make.proto --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/Make.proto Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,134 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands_tests. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# The Makefile as generated by this Make.proto supports the following targets: +# make - compile all st-files to a classLib +# make clean - clean all temp files +# make clobber - clean all +# +# This file contains definitions for Unix based platforms. +# It shares common definitions with the win32-make in Make.spec. + +# +# position (of this package) in directory hierarchy: +# (must point to ST/X top directory, for tools and includes) +TOP=../../../.. +INCLUDE_TOP=$(TOP)/.. + +# subdirectories where targets are to be made: +SUBDIRS= + + +# subdirectories where Makefiles are to be made: +# (only define if different from SUBDIRS) +# ALLSUBDIRS= + +REQUIRED_SUPPORT_DIRS= + +# if your embedded C code requires any system includes, +# add the path(es) here:, +# ********** OPTIONAL: MODIFY the next lines *** +# LOCALINCLUDES=-Ifoo -Ibar +LOCALINCLUDES= -I$(INCLUDE_TOP)/stx/goodies/petitparser -I$(INCLUDE_TOP)/stx/goodies/petitparser/islands -I$(INCLUDE_TOP)/stx/goodies/petitparser/tests -I$(INCLUDE_TOP)/stx/goodies/sunit -I$(INCLUDE_TOP)/stx/libbasic + + +# if you need any additional defines for embedded C code, +# add them here:, +# ********** OPTIONAL: MODIFY the next lines *** +# LOCALDEFINES=-Dfoo -Dbar -DDEBUG +LOCALDEFINES= + +LIBNAME=libstx_goodies_petitparser_islands_tests +STCLOCALOPT='-package=$(PACKAGE)' -I. $(LOCALINCLUDES) $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES) -headerDir=. -varPrefix=$(LIBNAME) + + +# ********** OPTIONAL: MODIFY the next line *** +# additional C-libraries that should be pre-linked with the class-objects +LD_OBJ_LIBS= +LOCAL_SHARED_LIBS= + + +# ********** OPTIONAL: MODIFY the next line *** +# additional C targets or libraries should be added below +LOCAL_EXTRA_TARGETS= + +OBJS= $(COMMON_OBJS) $(UNIX_OBJS) + + + +all:: preMake classLibRule postMake + +pre_objs:: + + + + + + +# Enforce recompilation of package definition class if Mercurial working +# copy state changes. Together with --guessVersion it ensures that package +# definition class always contains correct binary revision string. +ifneq (**NOHG**, $(shell hg root 2> /dev/null || echo -n '**NOHG**')) +stx_goodies_petitparser_islands_tests.$(O): $(shell hg root)/.hg/dirstate +endif + + + + +# run default testsuite for this package +test: $(TOP)/goodies/builder/reports + $(MAKE) -C $(TOP)/goodies/builder/reports -f Makefile.init + $(TOP)/goodies/builder/reports/report-runner.sh -D . -r Builder::TestReport -p $(PACKAGE) + + + +# add more install actions here +install:: + +# add more install actions for aux-files (resources) here +installAux:: + +# add more preMake actions here +preMake:: + +# add more postMake actions here +postMake:: cleanjunk + +# build all mandatory prerequisite packages (containing superclasses) for this package +prereq: + cd ../../../../libbasic && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../../libbasic2 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../../libbasic3 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../../libview && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../ && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../../libview2 && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../../sunit && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + cd ../../tests && $(MAKE) "CFLAGS_LOCAL=$(GLOBALDEFINES)" + + + +# build all packages containing referenced classes for this package +# they are nor needed to compile the package +references: + + +cleanjunk:: + -rm -f *.s *.s2 + +clean:: + -rm -f *.o *.H + +clobber:: clean + -rm -f *.so *.dll + + +# BEGINMAKEDEPEND --- do not remove this line; make depend needs it +$(OUTDIR)stx_goodies_petitparser_islands_tests.$(O) stx_goodies_petitparser_islands_tests.$(H): stx_goodies_petitparser_islands_tests.st $(INCLUDE_TOP)/stx/libbasic/LibraryDefinition.$(H) $(INCLUDE_TOP)/stx/libbasic/Object.$(H) $(INCLUDE_TOP)/stx/libbasic/ProjectDefinition.$(H) $(STCHDR) + +# ENDMAKEDEPEND --- do not remove this line + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/Make.spec --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/Make.spec Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,62 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands_tests. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# This file contains specifications which are common to all platforms. +# + +# Do NOT CHANGE THESE DEFINITIONS +# (otherwise, ST/X will have a hard time to find out the packages location from its packageID, +# to find the source code of a class and to find the library for a package) +MODULE=stx +MODULE_DIR=goodies/petitparser/islands/tests +PACKAGE=$(MODULE):$(MODULE_DIR) + + +# Argument(s) to the stc compiler (stc --usage). +# -headerDir=. : create header files locally +# (if removed, they will be created as common +# -Pxxx : defines the package +# -Zxxx : a prefix for variables within the classLib +# -Dxxx : defines passed to to CC for inline C-code +# -Ixxx : include path passed to CC for inline C-code +# +optspace : optimized for space +# +optspace2 : optimized more for space +# +optspace3 : optimized even more for space +# +optinline : generate inline code for some ST constructs +# +inlineNew : additionally inline new +# +inlineMath : additionally inline some floatPnt math stuff +# +# ********** OPTIONAL: MODIFY the next line(s) *** +# STCLOCALOPTIMIZATIONS=+optinline +inlineNew +# STCLOCALOPTIMIZATIONS=+optspace3 +STCLOCALOPTIMIZATIONS=+optspace3 + + +# Argument(s) to the stc compiler (stc --usage). +# -warn : no warnings +# -warnNonStandard : no warnings about ST/X extensions +# -warnEOLComments : no warnings about EOL comment extension +# -warnPrivacy : no warnings about privateClass extension +# +# ********** OPTIONAL: MODIFY the next line(s) *** +# STCWARNINGS=-warn +# STCWARNINGS=-warnNonStandard +# STCWARNINGS=-warnEOLComments +STCWARNINGS=-warnNonStandard + +COMMON_CLASSES= \ + stx_goodies_petitparser_islands_tests \ + + + + +COMMON_OBJS= \ + $(OUTDIR_SLASH)stx_goodies_petitparser_islands_tests.$(O) \ + + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/Makefile.init --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/Makefile.init Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,27 @@ +# +# DO NOT EDIT +# +# make uses this file (Makefile) only, if there is no +# file named "makefile" (lower-case m) in the same directory. +# My only task is to generate the real makefile and call make again. +# Thereafter, I am no longer used and needed. +# +# MACOSX caveat: +# as filenames are not case sensitive (in a default setup), +# we cannot use the above trick. Therefore, this file is now named +# "Makefile.init", and you have to execute "make -f Makefile.init" to +# get the initial makefile. This is now also done by the toplevel CONFIG +# script. + +.PHONY: run + +run: makefile + $(MAKE) -f makefile + +#only needed for the definition of $(TOP) +include Make.proto + +makefile: mf + +mf: + $(TOP)/rules/stmkmf diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/PPIslandTest.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/PPIslandTest.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,723 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +PPAbstractParserTest subclass:#PPIslandTest + instanceVariableNames:'result context' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Tests' +! + +PPIslandTest comment:'' +! + +!PPIslandTest methodsFor:'as yet unclassified'! + +context + context ifNil: [ ^ super context ]. + ^ context +! + +setUp + super setUp. + context := nil +! ! + +!PPIslandTest methodsFor:'parse support'! + +identifier + ^ ((#letter asParser / $# asParser), (#letter asParser / #digit asParser) star) flatten +! + +island: parser + ^ self islandInstance island: parser. +! + +island: parser water: water + ^ self islandInstance + island: parser; + water: water; + yourself + +! + +islandClass + ^ PPIsland +! + +islandInstance + ^ self islandClass new +! + +nestedBlock + | blockIsland block nilIsland | + blockIsland := self islandInstance. + nilIsland := self nilIsland. + + block := PPDelegateParser new. + block setParser: (${ asParser, (blockIsland plus / nilIsland), $} asParser). + block name: 'block'. + + blockIsland island: block. + blockIsland name: 'block island'. + ^ block +! + +nilIsland + | nilIsland | + nilIsland := self islandInstance. + + nilIsland island: nil asParser. + nilIsland name: 'nil island'. + + ^ nilIsland +! ! + +!PPIslandTest methodsFor:'parsing'! + +assert: parser parse: input + result := super assert: parser parse: input +! ! + +!PPIslandTest methodsFor:'testing'! + +testBlock + | block | + + block := self nestedBlock. + + self assert: block parse: '{}'. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. + + self assert: block parse: '{ }'. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. + + self assert: block parse: '{ { } }'. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. + + + self assert: block parse: '{ { {{} } } }'. + self assert: result isCollection. + self assert: result size = 3. + self assert: result first = ${. + self assert: result second first second first = ${. + self assert: result second first second second first second first = ${. + self assert: result second first second second first second third = $}. + self assert: result second first second third = $}. + self assert: result third = $}. + + + self assert: block parse: '{ { + {{} } + } }'. + self assert: result isCollection. + self assert: result size = 3. + self assert: result first = ${. + self assert: result second first second first = ${. + self assert: result second first second second first second first = ${. + self assert: result second first second second first second third = $}. + self assert: result second first second third = $}. + self assert: result third = $}. +! + +testBoundary + | p end body start | + + "use non-trivial end-of-class a complex end" + end := 'end' asParser trimBlanks, 'of' asParser trimBlanks, 'class' asParser trimBlanks ==> [:args | #eoc]. + body := self nilIsland. + start := 'class' asParser trim, self identifier. + p := start, body, end. + + self assert: p parse: 'class Foo end of class'. + self assert: result size = 4. + self assert: result second = 'Foo'. + + self assert: p parse: 'class Foo .... end of class'. + self assert: result size = 4. + self assert: result second = 'Foo'. + + self assert: p parse: 'class Foo .... end ... end of class'. + self assert: result size = 4. + self assert: result second = 'Foo'. + + self assert: p parse: 'class Foo .... end of ... end of class'. + self assert: result size = 4. + self assert: result second = 'Foo'. +! + +testBoundary2 + + | epilog id p | + "use optional boundary" + epilog := 'end' asParser optional. + id := self identifier. + p := ((self island: id), epilog) plus. + + self assert: p parse: '...foo..end...bar...end'. + + self assert: result first first second = 'foo'. + self assert: result first second = 'end'. + + self assert: result second first second = 'bar'. + self assert: result second second = 'end'. +! + +testIslandAfterIslandPlus + + | island2 islandParser2 island1 islandParser1 parser | + island1 := 'aa' asParser, 'bb' asParser. + islandParser1 := self islandInstance. + islandParser1 island: island1. + + island2 := 'cc' asParser. + islandParser2 := self islandInstance. + islandParser2 island: island2. + + parser := (islandParser1, islandParser2) plus. + + result := islandParser1 parse: '__ aabb __ cc __'. + self assert: result isPetitFailure not. +! + +testIslandAfterIslandPlus2 + + | island2 islandParser2 island1 islandParser1 parser | + + island1 := 'aa' asParser, 'bb' asParser. + islandParser1 := self islandInstance. + islandParser1 island: island1. + + island2 := 'cc' asParser. + islandParser2 := self islandInstance. + islandParser2 island: island2. + + parser := (islandParser1, islandParser2) plus. + + result := islandParser1 parse: '__ aaxx __ cc __'. + self assert: result isPetitFailure. +! + +testIslandDetection + | island parser | + island := 'class' asParser, self identifier trim, 'endclass' asParser. + parser := self island: island. + + self assert: parser parse: 'class Foo endclass'. + self assert: result size = 3. + self assert: result second second = 'Foo'. + + self assert: parser parse: '/*comment*/ class Foo endclass'. + self assert: result size = 3. + self assert: result second second = 'Foo'. + + self assert: parser parse: '/*comment class Bar */ class Foo endclass'. + self assert: result size = 3. + self assert: result second second = 'Foo'. + + self assert: parser parse: '/*comment class Bar */ class Foo endclass //something more'. + self assert: result size = 3. + self assert: result second second = 'Foo'. + + self assert: parser parse: '/*comment class Bar endclass */ class Foo endclass //something more'. + self assert: result size = 3. + self assert: result second second = 'Bar'. +! + +testIslandPlus + + | island parser | + island := self island: 'X' asParser. + parser := island plus. + + self assert: parser parse: '....X....'. + self assert: result size = 1. + + self assert: parser parse: '...X...X...XX'. + self assert: result size = 4. + + self assert: parser fail: '.....'. +! + +testIslandPlus2 + + | island parser | + island := self island: ('class' asParser, self identifier trim). + parser := island plus. + + self assert: parser parse: '....class Foo....'. + self assert: result size = 1. + self assert: result first second second = 'Foo'. + + + self assert: parser parse: '....class . class Foo....'. + self assert: result size = 1. + self assert: result first second second = 'Foo'. + + self assert: parser parse: '....class . class Foo class Bar....'. + self assert: result size = 2. + self assert: result first second second = 'Foo'. + self assert: result second second second = 'Bar'. + + + + self assert: parser fail: '.....'. +! + +testIslandSequence + + | parser a b c | + "Island sequence will never cross the boundery of 'c'" + a := 'a' asParser. + b := 'b' asParser. + c := 'c' asParser. + + parser := (self island: a), (self island: b), c. + + self assert: parser parse: '..a...b...c'. + self assert: parser fail: '..a..c...b..c'. + self assert: parser fail: '..c..a.....b..c'. +! + +testIslandSequence2 + | p a b | + + a := self island: ('a' asParser plus). + a name: 'a island'. + + b := self island: 'b' asParser. + b name: 'b island'. + + p := a optional, (b / self nilIsland). + self assert: p parse: 'a'. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = nil. + + self assert: p parse: '..ab'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = 'b'. + + self assert: p parse: 'a..b'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = 'b'. + + self assert: p parse: 'ab...'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = 'b'. + + self assert: p parse: '...a...b...'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = 'b'. + + self assert: p parse: '...a...b...'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first notNil. + self assert: result second size = 3. + self assert: result second second = 'b'. + + self assert: p end parse: '...b...'. + + self assert: result isPetitFailure not. + self assert: result size = 2. + self assert: result first isNil. + self assert: result second size = 3. + self assert: result second second = 'b'. +! + +testIslandSequence3 + + | parser body class extends | + class := self island: 'class' asParser trim, self identifier trim. + extends := self island: 'extends' asParser trim, self identifier trim. + body := self island: self nestedBlock. + + parser := (class, extends optional, body) plus. + self assert: parser parse: ' + /* lorem ipsum */ + class Foo { whatever } + + // something more + class Bar extends Zorg { blah blah bla } + // this is the end'. + + self assert: result isPetitFailure not. + self assert: result size = 2. +! + +testIslandStar + | p | + + + p := (self island: 'a' asParser) star, 'b' asParser. + self assert: p parse: 'b'. + self assert: result size = 2. + self assert: result first size = 0. + + self assert: p parse: 'ab'. + self assert: result size = 2. + self assert: result first size = 1. + + self assert: p parse: 'aab'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...aab'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...aa...b'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...b'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...aa...b'. + self assert: result size = 2. + self assert: result first size = 4. + + "Thats the question, if I want this:" + self assert: p fail: '...b'. +! + +testIslandStar2 + | p | + + + p := (self island: 'a' asParser) star, 'b' asParser optional. + self assert: p parse: 'aa'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '....aa'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...b'. + self assert: result size = 2. + self assert: result first size = 2. + self assert: result second = 'b'. +! + +testIslandStar3 + | p | + + + p := (self island: 'a' asParser) star, (self island: nil asParser). + + self assert: p parse: '....'. + self assert: result size = 2. + self assert: result first size = 0. + + self assert: p parse: 'aa'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '....aa'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...'. + self assert: result size = 2. + self assert: result first size = 2. + + self assert: p parse: '...a...a...b'. + self assert: result size = 2. + self assert: result first size = 2. + self assert: result second second = nil. +! + +testNestedIsland + + | nestedIsland before after topIsland | + nestedIsland := self island: 'X' asParser. + + before := 'before' asParser. + after := 'after' asParser. + topIsland := self island: (before, nestedIsland, after). + + self assert: nestedIsland parse: 'before...X...ater'. + self assert: topIsland parse: 'beforeXafter'. + + self assert: topIsland parse: '....before..X..after....'. + self assert: result size = 3. + self assert: result second size = 3. + self assert: result second second size = 3. + self assert: result second second second = 'X'. + + self assert: topIsland parse: '....X....before...X....after'. + self assert: topIsland parse: '....before.......after....before..X...after'. + + self assert: topIsland fail: '....before.......after...'. + self assert: topIsland fail: '....before.......after...X'. + self assert: topIsland fail: '....before.......after...X...after'. +! + +testNilIsland + + | nilIsland p | + + nilIsland := self nilIsland. + + + p := ${ asParser, nilIsland, $} asParser. + + self assert: p parse: '{}'. + + self assert: result isCollection. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. + + + self assert: p parse: '{ }'. + self assert: result isCollection. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. + + + self assert: p parse: '{ ... }'. + self assert: result isCollection. + self assert: result size = 3. + self assert: result first = ${. + self assert: result third = $}. +! + +testOptionalIsland + + | island parser | + + island := self island: ('a' asParser / 'b' asParser optional). + parser := island, 'c' asParser. + + self assert: parser parse: '....a....b...c'. + self assert: result first second = 'a'. + self assert: result second = 'c'. + + self assert: parser parse: '....d....b...c'. + self assert: result first second = 'b'. + self assert: result second = 'c'. + + self assert: parser parse: '....d....d...c'. + self assert: result first second = nil. + self assert: result second = 'c'. + + self assert: parser parse: '...c'. +! ! + +!PPIslandTest methodsFor:'tests - complex'! + +testClass + | text file class | + text := ' +// some comment +namespace cde { + +public class Foo +endclass + +public class 123 // invalid class +public struct {} + +class bar endclass +class Zorg endclass +} + '. + + class := ('public' asParser trim optional, 'class' asParser trim, self identifier, 'endclass' asParser trim) + ==> [:t | t third] . + file := ((self island: class) ==> [:t | t second ]) plus. + + result := file parse: text. + self assert: result size = 3. + self assert: result first = 'Foo'. + self assert: result second = 'bar'. + self assert: result third = 'Zorg'. +! + +testFile + | text using imports class file | + text := ' + +using a.b.c; +using c.d.e; +// some comment +namespace cde { + +public class Foo +endclass + +public class 123 // invalid class +public struct {} + +class bar endclass +} + '. + + using := 'using' asParser trim, (self identifier, ('.' asParser, self identifier) star) flatten ==> [:t | t second]. + + imports := (self island: using) star. + + class := ('public' asParser trim optional, 'class' asParser trim, self identifier, 'endclass' asParser trim) + ==> [:t | t third] . + file := imports, ((self island: class) ==> [:t | t second ]) plus. + + result := file parse: text. + + self assert: result isPetitFailure not. +! + +testFile2 + | text using imports class file | + text := ' + +using a.b.c; +using c.d.e; +// some comment +namespace cde { + +class Foo +endclass + +public class 123 // invalid class +public struct {} + +class bar endclass +} + '. + + using := 'using' asParser trim, (self identifier, ('.' asParser, self identifier) star) flatten ==> [:t | t second]. + + imports := (self island: using) star. + + class := ('public' asParser trim optional, 'class' asParser trim, self identifier, 'endclass' asParser trim) + ==> [:t | t third] . + file := imports, ((self island: class) ==> [:t | t second ]) plus. + + result := file parse: text. + + self assert: result isPetitFailure not. +! + +testImports + | text using imports | + text := ' + +/** whatever */ +using a.b.c; +// another comment +using c.d.e; +// some comment +namespace cde { +} + '. + + using := 'using' asParser trim, (self identifier, ('.' asParser, self identifier) star) flatten ==> [:t | t second]. + imports := ((self island: using) ==> [:t | t second ]) star. + + result := imports parse: text. + + self assert: result size = 2. + self assert: result first = 'a.b.c'. + self assert: result second = 'c.d.e'. +! ! + +!PPIslandTest methodsFor:'tests - water objects'! + +multilineCommentParser + ^ '/*' asParser, (#any asParser starLazy: '*/' asParser), '*/' asParser. +! + +singleCommentParser + | nl | + nl := #newline asParser. + ^ '//' asParser, (#any asParser starLazy: nl), nl. +! + +testMultilineComment + | parser | + parser := self multilineCommentParser. + + self assert: parser parse: '/* hello there */'. + self assert: parser parse: '/* class Bar endclass */'. +! + +testWaterObjects + | parser | + context := PPContext new. + parser := (self island: ('class' asParser, self identifier trim, 'endclass' asParser ==> #second)) star. + + self assert: parser parse: ' /* hello there */ class Foo endclass'. + self assert: result size = 1. + self assert: result first second = 'Foo'. + + context := PPContext new. + self assert: parser parse: ' /* class Bar endclass */ class Foo endclass'. + self assert: result size = 2. + self assert: result first second = 'Bar'. + self assert: result second second = 'Foo'. + + context := PPContext new. + parser := (self island: ('class' asParser, self identifier trim, 'endclass' asParser ==> #second) water: self multilineCommentParser / #any asParser) star. + + self assert: parser parse: ' /* class Bar endclass */ class Foo endclass'. + self assert: result size = 1. + self assert: result first second = 'Foo'. +! + +testWaterObjects2 + | parser source | + context := PPContext new. + + parser := (self island: ('class' asParser, self identifier trim, 'endclass' asParser ==> #second) + water: self multilineCommentParser / self singleCommentParser / #any asParser) star. + + source := ' /* class Bar endclass */ + class Foo + endclass + /* + class Borg + endclass + */ + // class Qwark endclass + class Zorg + endclass + '. + + self assert: parser parse: source. + self assert: result size = 2. + self assert: result first second = 'Foo'. + self assert: result second second = 'Zorg'. +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/PPMemoizingIslandTest.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/PPMemoizingIslandTest.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,39 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +PPIslandTest subclass:#PPMemoizingIslandTest + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Tests' +! + +PPMemoizingIslandTest comment:'' +! + +!PPMemoizingIslandTest class methodsFor:'as yet unclassified'! + +shouldInheritSelectors + ^ true. +! ! + +!PPMemoizingIslandTest methodsFor:'as yet unclassified'! + +islandClass + ^ PPMemoizingIsland +! ! + +!PPMemoizingIslandTest methodsFor:'testing'! + +testMemo + | parser result1 result2 context input | + + parser := self island: ('class' asParser, self identifier, 'endclass' asParser). + input := 'class Foo endclass' asPetitStream. + + context := PPContext new. + + result1 := parser parse: input withContext: context. + result2 := parser parse: input withContext: context. + self assert: (result1 == result2 ). +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/RobustXmlFeedParserTest.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/RobustXmlFeedParserTest.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,64 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +PPCompositeParserTest subclass:#RobustXmlFeedParserTest + instanceVariableNames:'debugResult' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +RobustXmlFeedParserTest comment:'' +! + +!RobustXmlFeedParserTest methodsFor:'as yet unclassified'! + +feed03 +^' + +ABC Shop +

Here and there 123, 123 45 Somewhere
+ + socks + 123 + 1 + + + + + shoes + 2345 + + 1 + + + shoes + 3456 + 0 + + + + +' +! + +parserClass + ^ RobustXmlFeedParser +! + +testXmlFeed03 + self parse: self feed03. + + self assert: result size = 3. + self assert: (result first at:#name) = 'socks'. + self assert: (result first at:#price) = '123'. + self assert: (result first at:#availability) = '1'. + + self assert: (result second at:#name) = 'shoes'. + self assert: (result second at:#price) = '2345'. + + self assert: (result third at:#name) = 'shoes'. + self assert: (result third at:#price) = '3456'. + self assert: (result third at:#availability) = '0'. +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/XmlFeedParserTest.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/XmlFeedParserTest.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,256 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +PPCompositeParserTest subclass:#XmlFeedParserTest + instanceVariableNames:'debugResult' + classVariableNames:'' + poolDictionaries:'' + category:'PetitIslands-Examples' +! + +XmlFeedParserTest comment:'' +! + +!XmlFeedParserTest methodsFor:'as yet unclassified'! + +debug: aString rule: aSymbol + | production | + production := self parserInstanceFor: aSymbol. + debugResult := production end debug: aString. + result := debugResult children first result. + self + deny: result isPetitFailure + description: 'Unable to parse ' , aString printString. + ^ result +! + +feed01 +^' + +ABC Shop +
Here and there 123, 123 45 Somewhere
+ + socks + 123 + 1 + +
+' +! + +feed02 +^' + +ABC Shop +
Here and there 123, 123 45 Somewhere
+ + socks + 123 + 1 + + + + + shoes + 2345 + 1 + + +
+' +! + +feed03 +^' + +ABC Shop +
Here and there 123, 123 45 Somewhere
+ + socks + 123 + 1 + + + + + shoes + 2345 + + 1 + + + shoes + 3456 + 0 + + + +
+' +! + +parse: aString rule: aSymbol to: anObject + | production | + production := self parserInstanceFor: aSymbol. + result := production end parse: aString. + self + deny: result isPetitFailure + description: 'Unable to parse ' , aString printString. + self assert: result = anObject. + + ^ result +! + +parserClass + ^ XmlFeedParser +! + +testItem + self testItem01. + self testItem02. + self testItem03. + +! + +testItem01 + self debug: ' + + abc + + ' rule: #item. + + self assert: (result at: #name) = 'abc'. + +! + +testItem02 + self debug: ' + + abc + 123 + + ' rule: #item. + + self assert: (result at: #name) = 'abc'. + self assert: (result at: #price) = '123'. + +! + +testItem03 + self debug: ' + + 123 + abc + + ' rule: #item. + + self assert: (result at: #name) = 'abc'. + self assert: (result at: #price) = '123'. + +! + +testShoplist + self testShoplist01. + self testShoplist02. + self testShoplist03. +! + +testShoplist01 + self debug: ' + + + abc + + + ' rule: #shoplist. + + self assert: result size = 1. + +! + +testShoplist02 + self debug: ' + + xyz + + abc + 123 + + + ' rule: #shoplist. + + self assert: result size = 1. + +! + +testShoplist03 + self debug: ' + + xyz + + abc + 123 + + + cde + 345 + + + ' rule: #shoplist. + + self assert: result size = 2. + +! + +testSimpleElement + self parse: 'b' rule: #simpleElement to: #('a' 'b'). + self parse: ' def ' rule: #simpleElement to: #('abc' 'def'). + + self fail: 'b' rule: #simpleElement. + +! + +testStringValue + self parse: 'abc' rule: #stringValue to: 'abc'. + self parse: ' def ' rule: #stringValue to: 'def'. + +! + +testXmlFeed01 + self parse: self feed01. + + self assert: result size = 1. + self assert: (result first at:#name) = 'socks'. + self assert: (result first at:#price) = '123'. + self assert: (result first at:#availability) = '1'. + +! + +testXmlFeed02 + self parse: self feed02. + + self assert: result size = 2. + self assert: (result first at:#name) = 'socks'. + self assert: (result first at:#price) = '123'. + self assert: (result first at:#availability) = '1'. + + self assert: (result second at:#name) = 'shoes'. + self assert: (result second at:#price) = '2345'. + self assert: (result second at:#availability) = '1'. + +! + +testXmlFeed03 + self parse: self feed03. + + self assert: result size = 2. + self assert: (result first at:#name) = 'socks'. + self assert: (result first at:#price) = '123'. + self assert: (result first at:#availability) = '1'. + + self assert: (result second at:#name) = 'shoes'. + self assert: (result second at:#price) = '3456'. + self assert: (result second at:#availability) = '0'. + +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/abbrev.stc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/abbrev.stc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,10 @@ +# automagically generated by the project definition +# this file is needed for stc to be able to compile modules independently. +# it provides information about a classes filename, category and especially namespace. +FirstFollowNextTests FirstFollowNextTests stx:goodies/petitparser/islands/tests 'PetitIslands-Tests' 1 +JavaParserTest JavaParserTest stx:goodies/petitparser/islands/tests 'PetitIslands-Examples' 1 +PPIslandTest PPIslandTest stx:goodies/petitparser/islands/tests 'PetitIslands-Tests' 1 +RobustXmlFeedParserTest RobustXmlFeedParserTest stx:goodies/petitparser/islands/tests 'PetitIslands-Examples' 1 +XmlFeedParserTest XmlFeedParserTest stx:goodies/petitparser/islands/tests 'PetitIslands-Examples' 1 +stx_goodies_petitparser_islands_tests stx_goodies_petitparser_islands_tests stx:goodies/petitparser/islands/tests '* Projects & Packages *' 3 +PPMemoizingIslandTest PPMemoizingIslandTest stx:goodies/petitparser/islands/tests 'PetitIslands-Tests' 1 diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/bc.mak --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/bc.mak Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,88 @@ +# $Header$ +# +# DO NOT EDIT +# automagically generated from the projectDefinition: stx_goodies_petitparser_islands_tests. +# +# Warning: once you modify this file, do not rerun +# stmkmp or projectDefinition-build again - otherwise, your changes are lost. +# +# Notice, that the name bc.mak is historical (from times, when only borland c was supported). +# This file contains make rules for the win32 platform using either borland-bcc or visual-c. +# It shares common definitions with the unix-make in Make.spec. +# The bc.mak supports the following targets: +# bmake - compile all st-files to a classLib (dll) +# bmake clean - clean all temp files +# bmake clobber - clean all +# +# Historic Note: +# this used to contain only rules to make with borland +# (called via bmake, by "make.exe -f bc.mak") +# this has changed; it is now also possible to build using microsoft visual c +# (called via vcmake, by "make.exe -f bc.mak -DUSEVC") +# +TOP=..\..\..\.. +INCLUDE_TOP=$(TOP)\.. + + + +!INCLUDE $(TOP)\rules\stdHeader_bc + +!INCLUDE Make.spec + +LIBNAME=libstx_goodies_petitparser_islands_tests +RESFILES=tests.$(RES) + + + +LOCALINCLUDES= -I$(INCLUDE_TOP)\stx\goodies\petitparser -I$(INCLUDE_TOP)\stx\goodies\petitparser\islands -I$(INCLUDE_TOP)\stx\goodies\petitparser\tests -I$(INCLUDE_TOP)\stx\goodies\sunit -I$(INCLUDE_TOP)\stx\libbasic +LOCALDEFINES= + +STCLOCALOPT=-package=$(PACKAGE) -I. $(LOCALINCLUDES) -headerDir=. $(STCLOCALOPTIMIZATIONS) $(STCWARNINGS) $(LOCALDEFINES) -varPrefix=$(LIBNAME) +LOCALLIBS= + +OBJS= $(COMMON_OBJS) $(WIN32_OBJS) + +ALL:: classLibRule + +classLibRule: $(OUTDIR) $(OUTDIR)$(LIBNAME).dll + +!INCLUDE $(TOP)\rules\stdRules_bc + +# build all mandatory prerequisite packages (containing superclasses) for this package +prereq: + pushd ..\..\..\..\libbasic & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\..\libbasic2 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\..\libbasic3 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\..\libview & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\.. & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\..\libview2 & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\..\sunit & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + pushd ..\..\tests & $(MAKE_BAT) "CFLAGS_LOCAL=$(GLOBALDEFINES) " + + + + + + + +test: $(TOP)\goodies\builder\reports\NUL + pushd $(TOP)\goodies\builder\reports & $(MAKE_BAT) + $(TOP)\goodies\builder\reports\report-runner.bat -D . -r Builder::TestReport -p $(PACKAGE) + +clean:: + del *.$(CSUFFIX) + + +# BEGINMAKEDEPEND --- do not remove this line; make depend needs it +$(OUTDIR)stx_goodies_petitparser_islands_tests.$(O) stx_goodies_petitparser_islands_tests.$(H): stx_goodies_petitparser_islands_tests.st $(INCLUDE_TOP)\stx\libbasic\LibraryDefinition.$(H) $(INCLUDE_TOP)\stx\libbasic\Object.$(H) $(INCLUDE_TOP)\stx\libbasic\ProjectDefinition.$(H) $(STCHDR) + +# ENDMAKEDEPEND --- do not remove this line + +# **Must be at end** + +# Enforce recompilation of package definition class if Mercurial working +# copy state changes. Together with --guessVersion it ensures that package +# definition class always contains correct binary revision string. +!IFDEF HGROOT +$(OUTDIR)stx_goodies_petitparser_islands_tests.$(O): $(HGROOT)\.hg\dirstate +!ENDIF diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/bmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/bmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,12 @@ +@REM ------- +@REM make using Borland bcc32 +@REM type bmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" +make.exe -N -f bc.mak %DEFINES% %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/lccmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/lccmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,8 @@ +@REM ------- +@REM make using lcc compiler +@REM type lccmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +make.exe -N -f bc.mak -DUSELCC=1 %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/libInit.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/libInit.cc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,34 @@ +/* + * $Header$ + * + * DO NOT EDIT + * automagically generated from the projectDefinition: stx_goodies_petitparser_islands_tests. + */ +#define __INDIRECTVMINITCALLS__ +#include + +#ifdef WIN32 +# pragma codeseg INITCODE "INITCODE" +#endif + +#if defined(INIT_TEXT_SECTION) || defined(DLL_EXPORT) +DLL_EXPORT void _libstx_goodies_petitparser_islands_tests_Init() INIT_TEXT_SECTION; +DLL_EXPORT void _libstx_goodies_petitparser_islands_tests_InitDefinition() INIT_TEXT_SECTION; +#endif + +void _libstx_goodies_petitparser_islands_tests_InitDefinition(pass, __pRT__, snd) +OBJ snd; struct __vmData__ *__pRT__; { +__BEGIN_PACKAGE2__("libstx_goodies_petitparser_islands_tests__DFN", _libstx_goodies_petitparser_islands_tests_InitDefinition, "stx:goodies/petitparser/islands/tests"); +_stx_137goodies_137petitparser_137islands_137tests_Init(pass,__pRT__,snd); + +__END_PACKAGE__(); +} + +void _libstx_goodies_petitparser_islands_tests_Init(pass, __pRT__, snd) +OBJ snd; struct __vmData__ *__pRT__; { +__BEGIN_PACKAGE2__("libstx_goodies_petitparser_islands_tests", _libstx_goodies_petitparser_islands_tests_Init, "stx:goodies/petitparser/islands/tests"); +_stx_137goodies_137petitparser_137islands_137tests_Init(pass,__pRT__,snd); + + +__END_PACKAGE__(); +} diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/mingwmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/mingwmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,16 @@ +@REM ------- +@REM make using mingw gnu compiler +@REM type mingwmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" + +@pushd ..\..\..\..\rules +@call find_mingw.bat +@popd +make.exe -N -f bc.mak %DEFINES% %USEMINGW_ARG% %* + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/stx_goodies_petitparser_islands_tests.st --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/stx_goodies_petitparser_islands_tests.st Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,151 @@ +"{ Package: 'stx:goodies/petitparser/islands/tests' }" + +LibraryDefinition subclass:#stx_goodies_petitparser_islands_tests + instanceVariableNames:'' + classVariableNames:'' + poolDictionaries:'' + category:'* Projects & Packages *' +! + + +!stx_goodies_petitparser_islands_tests class methodsFor:'accessing - monticello'! + +monticelloLastMergedVersionInfo + "The last merged version is: " + + ^ ' + Name: PetitIslands-JanKurs.10 + Author: JanKurs + Time: 06-10-2014, 11:50:57 AM + UUID: 19560ad2-4899-43d5-8c69-cf7274ad4f04 + Repository: http://smalltalkhub.com/mc/Moose/PetitParser/main + ' + + "Created: / 03-10-2014 / 02:27:21 / Jan Vrany " + "Modified: / 08-10-2014 / 00:24:45 / Jan Vrany " +! + +monticelloName + "Return name of the package for Monticello. This is used when package is exported" + + ^ 'PetitIslandsTests' + + "Created: / 03-10-2014 / 01:47:26 / Jan Vrany " + "Modified: / 08-10-2014 / 00:25:21 / Jan Vrany " +! ! + +!stx_goodies_petitparser_islands_tests class methodsFor:'description'! + +excludedFromPreRequisites + "list packages which are to be explicitely excluded from the automatic constructed + prerequisites list. If empty, everything that is found along the inheritance of any of + my classes is considered to be a prerequisite package." + + ^ #( + ) +! + +mandatoryPreRequisites + "list packages which are mandatory as a prerequisite. + This are packages containing superclasses of my classes and classes which + are extended by myself. + They are mandatory, because we need these packages as a prerequisite for loading and compiling. + This method is generated automatically, + by searching along the inheritance chain of all of my classes." + + ^ #( + #'stx:goodies/petitparser/tests' "PPAbstractParserTest - superclass of JavaParserTest" + #'stx:goodies/sunit' "TestAsserter - superclass of FirstFollowNextTests" + #'stx:libbasic' "LibraryDefinition - superclass of stx_goodies_petitparser_islands_tests" + ) +! + +referencedPreRequisites + "list packages which are a prerequisite, because they contain + classes which are referenced by my classes. + We do not need these packages as a prerequisite for loading or compiling. + This method is generated automatically, + by searching all classes (and their packages) which are referenced by my classes." + + ^ #( + #'stx:goodies/petitparser' "PPContext - referenced by JavaParserTest>>context" + #'stx:goodies/petitparser/islands' "JavaParser - referenced by JavaParserTest>>parserClass" + ) +! + +subProjects + "list packages which are known as subprojects. + The generated makefile will enter those and make there as well. + However: they are not forced to be loaded when a package is loaded; + for those, redefine requiredPrerequisites." + + ^ #( + ) +! ! + +!stx_goodies_petitparser_islands_tests class methodsFor:'description - contents'! + +classNamesAndAttributes + "lists the classes which are to be included in the project. + Each entry in the list may be: a single class-name (symbol), + or an array-literal consisting of class name and attributes. + Attributes are: #autoload or # where os is one of win32, unix,..." + + ^ #( + " or ( attributes...) in load order" + (FirstFollowNextTests autoload) + (JavaParserTest autoload) + (PPIslandTest autoload) + (RobustXmlFeedParserTest autoload) + (XmlFeedParserTest autoload) + #'stx_goodies_petitparser_islands_tests' + (PPMemoizingIslandTest autoload) + ) + + "Modified: / 08-10-2014 / 00:27:59 / Jan Vrany " +! + +extensionMethodNames + "list class/selector pairs of extensions. + A correponding method with real names must be present in my concrete subclasses" + + ^ #( + ) +! ! + +!stx_goodies_petitparser_islands_tests class methodsFor:'description - project information'! + +companyName + "Returns a company string which will appear in .rc. + Under win32, this is placed into the dlls file-info" + + ^ 'eXept Software AG' +! + +description + "Returns a description string which will appear in nt.def / bc.def" + + ^ 'Smalltalk/X Class library' +! + +legalCopyright + "Returns a copyright string which will appear in .rc. + Under win32, this is placed into the dlls file-info" + + ^ 'Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014' +! + +productName + "Returns a product name which will appear in .rc. + Under win32, this is placed into the dlls file-info. + This method is usually redefined in a concrete application definition" + + ^ 'Smalltalk/X' +! ! + +!stx_goodies_petitparser_islands_tests class methodsFor:'documentation'! + +version_HG + ^ '$Changeset: $' +! ! + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/tests.rc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/tests.rc Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,37 @@ +// +// DO NOT EDIT +// automagically generated from the projectDefinition: stx_goodies_petitparser_islands_tests. +// +VS_VERSION_INFO VERSIONINFO + FILEVERSION 6,2,32767,32767 + PRODUCTVERSION 6,2,4,0 +#if (__BORLANDC__) + FILEFLAGSMASK VS_FF_DEBUG | VS_FF_PRERELEASE + FILEFLAGS VS_FF_PRERELEASE | VS_FF_SPECIALBUILD + FILEOS VOS_NT_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE VS_USER_DEFINED +#endif + +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + BEGIN + VALUE "CompanyName", "eXept Software AG\0" + VALUE "FileDescription", "Smalltalk/X Class library (LIB)\0" + VALUE "FileVersion", "6.2.32767.32767\0" + VALUE "InternalName", "stx:goodies/petitparser/islands/tests\0" + VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0" + VALUE "ProductName", "Smalltalk/X\0" + VALUE "ProductVersion", "6.2.4.0\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:33 GMT\0" + END + + END + + BLOCK "VarFileInfo" + BEGIN // Language | Translation + VALUE "Translation", 0x409, 0x4E4 // U.S. English, Windows Multilingual + END +END diff -r a409905f7f2d -r e2b2ccaa4de6 islands/tests/vcmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/tests/vcmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,20 @@ +@REM ------- +@REM make using Microsoft Visual C compiler +@REM type vcmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- + +@if not defined VSINSTALLDIR ( + pushd ..\..\..\..\rules + call vcsetup.bat + popd +) +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" +make.exe -N -f bc.mak -DUSEVC=1 %DEFINES% %* + + + + diff -r a409905f7f2d -r e2b2ccaa4de6 islands/vcmake.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/islands/vcmake.bat Wed Oct 08 00:33:44 2014 +0100 @@ -0,0 +1,20 @@ +@REM ------- +@REM make using Microsoft Visual C compiler +@REM type vcmake, and wait... +@REM do not edit - automatically generated from ProjectDefinition +@REM ------- + +@if not defined VSINSTALLDIR ( + pushd ..\..\..\rules + call vcsetup.bat + popd +) +@SET DEFINES= +@REM Kludge got Mercurial, cannot be implemented in Borland make +@FOR /F "tokens=*" %%i in ('hg root') do SET HGROOT=%%i +@IF "%HGROOT%" NEQ "" SET DEFINES=%DEFINES% "-DHGROOT=%HGROOT%" +make.exe -N -f bc.mak -DUSEVC=1 %DEFINES% %* + + + + diff -r a409905f7f2d -r e2b2ccaa4de6 petitparser.rc --- a/petitparser.rc Wed Oct 08 00:08:21 2014 +0100 +++ b/petitparser.rc Wed Oct 08 00:33:44 2014 +0100 @@ -25,7 +25,7 @@ VALUE "LegalCopyright", "(C) Lukas Renggli\0" VALUE "ProductName", "Petit Parser\0" VALUE "ProductVersion", "6.2.4.0\0" - VALUE "ProductDate", "Tue, 07 Oct 2014 08:24:04 GMT\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:24 GMT\0" END END diff -r a409905f7f2d -r e2b2ccaa4de6 stx_goodies_petitparser.st --- a/stx_goodies_petitparser.st Wed Oct 08 00:08:21 2014 +0100 +++ b/stx_goodies_petitparser.st Wed Oct 08 00:33:44 2014 +0100 @@ -125,10 +125,10 @@ mkdir mc mcz: mc - $(TOP)/projects/smalltalk/smalltalk --eval " \ - Smalltalk packagePath add:''$(TOP)'' . \ - Smalltalk loadPackage:''stx:goodies/petitparser''. \ - (Smalltalk at: #''stx_goodies_petitparser'') exportAsMczTo: ''mc''." + $(TOP)/projects/smalltalk/smalltalk --eval " \ + Smalltalk packagePath add:''$(TOP)'' . \ + Smalltalk loadPackage:''stx:goodies/petitparser''. \ + (Smalltalk at: #''stx_goodies_petitparser'') exportAsMczTo: ''mc''." ' diff -r a409905f7f2d -r e2b2ccaa4de6 tests/tests.rc --- a/tests/tests.rc Wed Oct 08 00:08:21 2014 +0100 +++ b/tests/tests.rc Wed Oct 08 00:33:44 2014 +0100 @@ -25,7 +25,7 @@ VALUE "LegalCopyright", "Copyright Claus Gittinger 1988-2014\nCopyright eXept Software AG 1998-2014\0" VALUE "ProductName", "Smalltalk/X\0" VALUE "ProductVersion", "6.2.4.0\0" - VALUE "ProductDate", "Tue, 07 Oct 2014 23:04:59 GMT\0" + VALUE "ProductDate", "Tue, 07 Oct 2014 23:30:26 GMT\0" END END