/* Titanium Parser $Id: parser.yy 1.63 Thu, 03 Oct 2002 08:30:49 -0700 bonachea $ */ /* With the exceptions noted below, the .val fields of terminal */ /* symbols are irrelevant and may be set to NULL by the lexer. */ /* KEYWORDS */ %token ABSTRACT %token BOOLEAN BREAK BROADCAST BYTE %token CASE CATCH CHAR CLASS CONTINUE %token DEFAULT DO DOUBLE %token _DOMAIN /* Titanium */ %token ELSE EXTENDS %token FINAL FINALLY FLOAT FOR FROM %token FOREACH /* Titanium */ %token IF IMPLEMENTS IMPORT INSTANCEOF INT INTERFACE %token IMMUTABLE IN INLINE /* Titanium */ %token LOCAL /* Titanium */ %token LONG %token NATIVE NEW NULL_VAL %token OPERATOR OVERLAP /* Titanium */ %token _PACKAGE PRIVATE PROTECTED PUBLIC %token POLYSHARED NONSHARED /* Titanium */ %token PARTITION POINT /* Titanium */ %token RECTDOMAIN /* Titanium */ %token RETURN %token SHORT STATIC SUPER SWITCH SYNCHRONIZED %token SINGLE SGLOBAL /* Titanium */ %token TEMPLATE /* Titanium */ %token THIS THROW THROWS TRANSIENT TRY %token VOID VOLATILE %token WHILE /* KEYWORDS RESERVED (ILLEGAL AS IDENTIFIERS) BUT NOT USED */ /* %token CONST GOTO */ /* IDENTIFIERS AND LITERALS */ %token TRUE_LITERAL FALSE_LITERAL %token IDENTIFIER %token INT_LITERAL LONG_LITERAL %token FLOAT_LITERAL DOUBLE_LITERAL %token CHARACTER_LITERAL %token STRING_LITERAL /* SEPARATORS */ %token '(' ')' '{' '}' '[' ']' ',' '.' ';' /* OPERATORS */ %token '=' '>' '<' '!' '~' '?' ':' %token '+' '-' '*' '/' '&' '|' '^' '%' %token CAND /* &&: conditional and */ %token COR /* ||: conditional or */ %token EQ /* == */ %token NE /* != */ %token LE /* <= */ %token GE /* >= */ %token LSHIFTL /* << */ %token ASHIFTR /* >> */ %token LSHIFTR /* >>> */ %token PLUS_ASG /* += */ %token MINUS_ASG /* -= */ %token MULT_ASG /* *= */ %token DIV_ASG /* /= */ %token REM_ASG /* %= */ %token LSHIFTL_ASG /* <<= */ %token ASHIFTR_ASG /* >>= */ %token LSHIFTR_ASG /* >>>= */ %token AND_ASG /* &= */ %token XOR_ASG /* ^= */ %token OR_ASG /* |= */ %token PLUSPLUS /* ++ */ %token MINUSMINUS /* -- */ %token GUARDS /* => */ /* Titanium */ /* PRECEDENCES */ /* LOWEST */ /* ']' resolves s/r conflict between op[]= and op[] = ... (we shift because the latter is illegal as operators cannot be field names) */ %right ELSE %left BROADCAST ']' %left '=' PLUS_ASG MINUS_ASG MULT_ASG DIV_ASG REM_ASG LSHIFTL_ASG LSHIFTR_ASG ASHIFTR_ASG AND_ASG OR_ASG XOR_ASG %right '?' ':' %left COR %left CAND %left '|' %left '^' %left '&' %left EQ NE %left '<' '>' LE GE INSTANCEOF %left LSHIFTL LSHIFTR ASHIFTR %left '+' '-' %left '*' '/' '%' %nonassoc PLUSPLUS MINUSMINUS /* HIGHEST */ /* Artificial precedence rules: /* The rule for '.' resolves conflicts with QualifiedNames, */ /* FieldAccesses, and MethodAccesses. The result is that */ /* FieldAccesses and MethodAccesses that look syntactically like */ /* QualifiedNames are parsed as QualifiedNames (see the production for */ /* Name from QualifiedName). The ambiguity must be resolved with */ /* static semantic information at a later stage. */ /* The rule for ')' resolves conflicts between Casts and ComplexPrimaries. */ %right '.' ')' /* Artificial precedence rule to resolve conflicts with */ /* InterfaceModifiers and ClassModifiers */ %right ABSTRACT FINAL PUBLIC /* Artificial precedence rule to favour interpreting [ (id)id ] in ArrayName as [ Expression ] rather than [ Expression IDENTIFIER ] */ %left IDENTIFIER %{ #include #include #include "AST.h" #include "config.h" #include "errors.h" #include "parse.h" #include "tokens.h" #define YYDEBUG 1 #ifdef HAVE_ALLOCA # define YYSTACK_USE_ALLOCA 1 # if HAVE_ALLOCA_H # include # endif // HAVE_ALLOCA_H #if defined(__GNUC__) #ifndef alloca #define alloca __builtin_alloca #endif #else extern "C" char *alloca(size_t size); #endif #endif // HAVE_ALLOCA static void yyerror(const char* msg); static TreeNode *newOperator(char *op, SourcePosn p); /* Routines to check the validity of modifier flags. Each routine */ /* takes a logical `or' of flag values and a source position to which */ /* to refer error messages. */ static void checkFieldModifiers (Common::Modifiers flags, SourcePosn posn); static void checkConstantFieldModifiers (Common::Modifiers flags, SourcePosn posn); static void checkMethodModifiers (Common::Modifiers flags, SourcePosn posn); static void checkConstructorModifiers (Common::Modifiers flags, SourcePosn posn); static void checkMethodSignatureModifiers (Common::Modifiers flags, SourcePosn posn); static void checkInterfaceModifiers(Common::Modifiers flags, SourcePosn posn); static TreeNode *addSynchronized(Common::Modifiers modifiers, TreeNode *body); %} %union { SimpTerminalInfo SimpTerminal; /* Terminal symbols with only position. */ TerminalInfo Terminal; /* Terminal symbols with ASCII string data. */ StrTerminalInfo StrTerminal; /* Terminal symbols with Unicode string data. */ CharTerminalInfo CharTerminal; /* Terminal symbols with Unicode char data. */ long Int; /* Simple integer values */ bool Bool; CompileUnitNode* CompileUnit; TreeNode* Tree; TypeNode* Type; CatchNode* Catch; llist* TreeList; llist* TypeList; llist* CatchList; Common::Modifiers Modifiers; llist* DeclaratorList; TryNode *Try; TypeDeclNode *TypeDecl; } %type CompilationUnit %type Dims DimsOpt %type ArrayName FullArrayName %type Literal PrimaryExpression NotJustName ComplexPrimary %type ArrayAccess IndexExpression MethodCall AllocationExpression %type PostfixExpression PostIncrement PostDecrement UnaryExpression %type PreIncrement PreDecrement RestrictedUnaryExpression %type CastExpression ExpressionOpt Expression Expression1 Assignment %type ConstantExpression DimExpr StatementExpression %type VariableInitializer ArrayInitializer Element RegionOpt %type NoNamePostfixExpression NoNameUnaryExpression %type OtherPostfixExpression %type NoNameRestrictedUnaryExpression NoNameExpression1 %type OtherUnaryExpression %type BinaryExpression1 %type OtherRestrictedPostfixExpression %type ArgumentListOpt ArgumentList %type DimExprs ElementInitializers %type FieldAccess %type QualifiedBaseType BaseType %type TypeName %type Type Void %type NoNameType %type OtherType %type ComplexBaseType PrimitiveType TitaniumType %type SuperOpt ArraySpecifier %type ArraySpecifiers %type TemplateDeclaration %type TemplateInstance %type TemplateFormalList %type TemplateFormal %type TemplateActual %type TemplateActualList %type TypeNameList InterfacesOpt ThrowsOpt Throws %type ExtendsInterfacesOpt ExtendsInterfaces %type Block Statement %type EmptyStatement LabeledStatement %type SelectionStatement IterationStatement JumpStatement %type GuardingStatement MethodBody Finally %type ConstructorCallStatement ExplicitThisConstructorCallStatement %type ExplicitSuperConstructorCallStatement ExpressionStatement %type BlockStatementsOpt BlockStatements BlockStatement SwitchBlock %type LocalVariableDeclarationStatement %type SwitchBlockStatementsOpt %type ForInit ForUpdateOpt %type StatementExpressionsOpt %type StatementExpressions %type ClassModifiersOpt ClassModifiers ClassModifier %type FieldModifiersOpt FieldModifiers FieldModifier %type QualifiersOpt Qualifier %type ClassDeclaration %type InterfaceDeclaration %type BasicTypeDeclaration %type TypeDeclaration %type ImportStatement TypeImportStatement %type TypeImportOnDemandStatement %type Parameter %type MethodDeclaration StaticInitializer ConstructorDeclaration %type MethodSignatureDeclaration %type ClassBody FieldDeclarationsOpt FieldDeclarations %type FieldDeclaration FieldVariableDeclaration %type ConstantFieldDeclaration %type TypeDeclarationsOpt %type ParameterListOpt ParameterList InterfaceBody %type ImportStatementsOpt %type InterfaceMemberDeclaration InterfaceMemberDeclarationsOpt %type SwitchLabel %type SwitchLabels %type SimpleName MethodName OperatorName LabelOpt %type PackageDeclarationOpt Name QualifiedName %type Catch %type Catches %type TryBlock %type VariableDeclarator VariableDeclarators /* Titanium */ %type PartitionStatement ForEachStatement %type PointLiteral DomainLiteral BroadcastExpression %type ForEachClauses PartitionClauses %type DomainPairs DomainTriples OverlapsOpt %type DomainPair DomainTriple OverlapDecl %type OptionalInline OptionalFinal %start Start %% /* The following production passes the translated program to the later */ /* stages of the compiler for processing. */ Start : CompilationUnit { compileAST ($1); } ; /* 1.7 LITERALS */ Literal : INT_LITERAL { $$ = new PrimitiveLitNode (intLiteral(*$1.val), $1.posn); } | LONG_LITERAL { $$ = new PrimitiveLitNode (longLiteral(*$1.val), $1.posn); } | FLOAT_LITERAL { $$ = new PrimitiveLitNode (floatLiteral(*$1.val), $1.posn); } | DOUBLE_LITERAL { $$ = new PrimitiveLitNode (doubleLiteral(*$1.val), $1.posn); } | TRUE_LITERAL { $$ = new PrimitiveLitNode (Literal(true), $1.posn); } | FALSE_LITERAL { $$ = new PrimitiveLitNode (Literal(false), $1.posn); } | CHARACTER_LITERAL { $$ = new PrimitiveLitNode (Literal($1.val), $1.posn); } | STRING_LITERAL { $$ = new StringLitNode (*$1.val, $1.posn); } ; /* 2. TYPES AND VALUES */ Type : ArrayName %prec ')' { $$ = $1->asType(); } | OtherType ; NoNameType : OtherType ; OtherType : ComplexBaseType QualifiersOpt { $$ = $1; $1->modifiers($2); } | ComplexBaseType QualifiersOpt ArraySpecifiers { $1->modifiers($2); $$ = arraySpecifiers2Type($3, $1); } ; QualifiedBaseType : BaseType QualifiersOpt { $$ = $1; $$->modifiers($2); } ; BaseType : PrimitiveType | TypeName | TitaniumType | TemplateInstance ; TypeName : Name %prec ')' { $$ = new TypeNameNode ($1); } ; ComplexBaseType : PrimitiveType | TitaniumType | TemplateInstance ; ArraySpecifiers : ArraySpecifier { $$ = cons($1); } | ArraySpecifier ArraySpecifiers { $$ = cons($1, $2); } ; ArraySpecifier : '[' ']' QualifiersOpt { $$ = new EmptyArrayNode($3, $1.posn); } | '[' IndexExpression ']' QualifiersOpt { $$ = new ExpressionArrayNode($2, $4); } | '[' Expression IDENTIFIER ']' QualifiersOpt { if (*$3.val != "d") { Error($3.posn) << "Unexpected identifier '" << *$3.val << "'" << endl; $$ = new ExpressionArrayNode($2, $5); } else $$ = new TitaniumArrayNode($2, $5); } ; QualifiersOpt : /* empty */ { $$ = (Common::Modifiers)0; } | QualifiersOpt Qualifier { $$ = (Common::Modifiers) ($1 | $2); if (($1 & $2) != 0) Error (lexerPosition()) << "repeated modifier" << endl; } ; Qualifier : SINGLE { $$ = TreeNode::Single; } | LOCAL { $$ = TreeNode::Local; } | NONSHARED { $$ = TreeNode::NonsharedQ; } | POLYSHARED { $$ = TreeNode::PolysharedQ; } ; PrimitiveType : BOOLEAN { $$ = new BoolTypeNode ($1.posn); } | CHAR { $$ = new CharTypeNode ($1.posn); } | BYTE { $$ = new ByteTypeNode ($1.posn); } | SHORT { $$ = new ShortTypeNode ($1.posn); } | INT { $$ = new IntTypeNode ($1.posn); } | FLOAT { $$ = new FloatTypeNode ($1.posn); } | LONG { $$ = new LongTypeNode ($1.posn); } | DOUBLE { $$ = new DoubleTypeNode ($1.posn); } ; /* Titanium */ TitaniumType : POINT '<' Expression1 '>' { $$ = new PointTypeNode($3); } | RECTDOMAIN '<' Expression1 '>' { $$ = new RectDomainTypeNode($3); } | _DOMAIN '<' Expression1 '>' { $$ = new DomainTypeNode($3); } ; /* 5. PROGRAM STRUCTURE */ /* Section 5.4 */ CompilationUnit : PackageDeclarationOpt ImportStatementsOpt TypeDeclarationsOpt { $$ = new CompileUnitNode (NULL, $1, $2, new TreeListNode($3), NULL); } ; PackageDeclarationOpt : _PACKAGE Name ';' { $$ = $2; } | /* empty */ { $$ = TreeNode::omitted; } ; ImportStatementsOpt : /* empty */ { $$ = NULL; } | ImportStatementsOpt ImportStatement { $$ = extend ($1, cons($2)); } ; /* Note: This definition appears to be missing from the 10/30/95 draft. */ TypeDeclarationsOpt : /* empty */ { $$ = NULL; } | TypeDeclaration TypeDeclarationsOpt { if ($1->absent()) $$ = $2; else $$ = cons (static_cast($1), $2); } | ';' TypeDeclarationsOpt { $$ = $2; } ; TypeDeclaration : BasicTypeDeclaration { $$ = $1; } | TemplateDeclaration { $$ = $1; } ; BasicTypeDeclaration : ClassDeclaration { $$ = $1; } | InterfaceDeclaration { $$ = $1; } ; /* Section 5.7 */ ImportStatement : TypeImportStatement | TypeImportOnDemandStatement ; TypeImportStatement : IMPORT Name ';' { $$ = new ImportNode ($2); } ; /* Note: I have combined PackageImportStatement and TypeImportStatement */ /* to avoid syntactic ambiguity. Also, the draft of 10/30/95 appears */ /* to be missing a final ";" in the definition of */ /* PackageImportStatement. */ TypeImportOnDemandStatement : IMPORT Name '.' '*' ';' { $$ = new ImportOnDemandNode ($2); } ; /* 6. CLASS AND INTERFACE TYPE DECLARATIONS */ /* Section 6.1 */ ClassDeclaration : ClassModifiersOpt CLASS SimpleName SuperOpt InterfacesOpt ClassBody { $$ = new ClassDeclNode ($1, $3, $4, $5, $6, $2.posn); } ; /* Section 6.1.1 */ ClassModifiersOpt : ClassModifiers | /* empty */ { $$ = (Common::Modifiers) 0; } ; ClassModifiers : ClassModifier | ClassModifiers ClassModifier { $$ = (Common::Modifiers) ($1 | $2); if (($1 & $2) != 0) Error (lexerPosition()) << "repeated modifier" << endl; } ; ClassModifier : ABSTRACT { $$ = TreeNode::Abstract; } | FINAL { $$ = TreeNode::Final; } | PUBLIC { $$ = TreeNode::Public; } | IMMUTABLE { $$ = TreeNode::Immutable; } ; /* Section 6.1.2 */ SuperOpt : EXTENDS Type { $$ = $2; } | /* empty */ { $$ = TreeNode::omitted; } ; /* Section 6.1.3 */ InterfacesOpt : IMPLEMENTS TypeNameList { $$ = $2; } | /* empty */ { $$ = NULL; } ; /* Section 6.1.4 */ ClassBody : '{' FieldDeclarationsOpt '}' { $$ = cons (TreeNode::omitted, $2); } ; FieldDeclarationsOpt : FieldDeclarations | /* empty */ { $$ = NULL; } ; FieldDeclarations : FieldDeclaration | FieldDeclarations FieldDeclaration { $$ = extend ($1, $2); } ; /* Section 6.2 */ FieldDeclaration : FieldVariableDeclaration | MethodDeclaration { $$ = cons ($1); } | ConstructorDeclaration { $$ = cons ($1); } | StaticInitializer { $$ = cons ($1); } ; /* Section 6.3 */ FieldVariableDeclaration : FieldModifiersOpt Type VariableDeclarators ';' { checkFieldModifiers ($1, $2->position()); $$ = NULL; foreach (decl, llist, *$3) { $$ = cons (static_cast(new FieldDeclNode(makeArrayType($2, (*decl).dims), (*decl).name, $1, (*decl).initExpr)), $$); } free_all ($3); } ; /* Section 6.3.1, 6.4.1, 6.5.1 */ /* Note: The nonterminals ConstructorModifier, MethodModifier, and */ /* VariableModifer are consolidated here into FieldModifier to */ /* resolve the LALR(1) conflicts. Must be distinguished in later */ /* sections of the compiler. */ FieldModifiersOpt : FieldModifiers | /* empty */ { $$ = (Common::Modifiers) 0; } ; FieldModifiers : FieldModifier | FieldModifiers FieldModifier { $$ = (Common::Modifiers) ($1 | $2); if (($1 & $2) != 0) Error (lexerPosition()) << "repeated modifier" << endl; } ; FieldModifier : /* Applicable to methods, constructors, and variables (6.[345].1) */ PUBLIC { $$ = TreeNode::Public; } | PROTECTED { $$ = TreeNode::Protected; } | PRIVATE { $$ = TreeNode::Private; } /* Applicable to methods and variables (6.[34].1) */ | STATIC { $$ = TreeNode::Static; } | FINAL { $$ = TreeNode::Final; } | SINGLE /* Titanium - obsolete */ { $$ = TreeNode::Sglobal; } | SGLOBAL /* Titanium */ { $$ = TreeNode::Sglobal; } /* Applicable to methods (6.4.1) */ | ABSTRACT { $$ = TreeNode::Abstract; } | NATIVE { $$ = TreeNode::Native; } | SYNCHRONIZED { $$ = TreeNode::Synchronized; } /* Applicable to variables (6.3.1) */ | TRANSIENT { $$ = TreeNode::Transient; } | VOLATILE { $$ = TreeNode::Volatile; } | LOCAL { $$ = TreeNode::Local; } | NONSHARED { $$ = TreeNode::NonsharedQ; } | POLYSHARED { $$ = TreeNode::PolysharedQ; } | INLINE { $$ = TreeNode::Inline; } ; /* Section 6.3.2 */ /* This is built up backwards */ VariableDeclarators : VariableDeclarator | VariableDeclarators ',' VariableDeclarator { $$ = $3; $3->tail() = $1; } ; VariableDeclarator : SimpleName DimsOpt { $$ = cons(DeclaratorTuple($2, $1, TreeNode::omitted)); } | SimpleName DimsOpt '=' VariableInitializer { $$ = cons(DeclaratorTuple($2, $1, $4)); } ; /* Section 6.3.3 */ VariableInitializer : Expression | ArrayInitializer ; /* Section 6.4 */ MethodDeclaration : FieldModifiersOpt Type MethodName '(' ParameterListOpt ')' DimsOpt ThrowsOpt OverlapsOpt MethodBody { checkMethodModifiers($1, $3->position()); TreeNode *body = addSynchronized($1, $10); $$ = new MethodDeclNode($1, $5, makeArrayType($2, $7), $3, $8, $9, body); } | FieldModifiersOpt Void MethodName '(' ParameterListOpt ')' DimsOpt ThrowsOpt OverlapsOpt MethodBody { checkMethodModifiers($1, $3->position()); TreeNode *body = addSynchronized($1, $10); $$ = new MethodDeclNode($1, $5, makeArrayType($2, $7), $3, $8, $9, body); if ($7) Error($3->position()) << "cannot return array of void" << endl; } ; MethodName : SimpleName | OperatorName ; Void : VOID { $$ = new VoidTypeNode ($1.posn); } ; OverlapsOpt : /* empty */ { $$ = NULL; } | OverlapDecl OverlapsOpt { $$ = cons($1, $2); } ; OverlapDecl : OVERLAP '(' SimpleName ',' SimpleName ')' { $$ = new OverlapNode($3, $5, $1.posn); } ; /* Note: "Inlined" ResultType to avoid LALR(1) conflict. */ /* Section 6.4.3 */ ParameterListOpt : ParameterList | /* empty */ { $$ = NULL; } ; ParameterList : Parameter { $$ = cons ($1); } | Parameter ',' ParameterList { $$ = cons ($1, $3); } ; Parameter : OptionalFinal Type SimpleName DimsOpt { $$ = new ParameterNode ($1, makeArrayType ($2, $4), $3); } ; OptionalFinal : FINAL { $$ = true; } | /* empty */ { $$ = false; } ; /* Section 6.4.4 */ ThrowsOpt : Throws | /* empty */ { $$ = NULL; } ; Throws : THROWS TypeNameList { $$ = $2; } ; TypeNameList : Type { $$ = cons ($1); } | Type ',' TypeNameList { $$ = cons ($1, $3); } ; /* Section 6.4.5 */ MethodBody : Block | ';' { $$ = TreeNode::omitted; } ; /* Section 6.5 */ ConstructorDeclaration : FieldModifiersOpt SimpleName '(' ParameterListOpt ')' ThrowsOpt '{' ConstructorCallStatement BlockStatementsOpt '}' { checkConstructorModifiers ($1, $2->position()); $$ = new ConstructorDeclNode ($1, $4, $2, $6, $8, new BlockNode ($9, $10.posn)); } | FieldModifiersOpt SimpleName '(' ParameterListOpt ')' ThrowsOpt '{' BlockStatementsOpt '}' { checkConstructorModifiers ($1, $2->position ()); $$ = new ConstructorDeclNode ($1, $4, $2, $6, new SuperConstructorCallNode (NULL, NULL, $2->position()), new BlockNode ($8, $9.posn)); } ; /* Note: We use FieldModifiersOpt to avoid a LALR(1) conflict. */ /* Section 6.5.4 */ ConstructorCallStatement : ExplicitThisConstructorCallStatement | ExplicitSuperConstructorCallStatement ; ExplicitThisConstructorCallStatement : THIS '(' ArgumentListOpt ')' ';' { $$ = new ThisConstructorCallNode ($3, NULL, false, $1.posn); } ; ExplicitSuperConstructorCallStatement : SUPER '(' ArgumentListOpt ')' ';' { $$ = new SuperConstructorCallNode ($3, NULL, $1.posn); } ; /* Section 6.7.2 */ StaticInitializer : STATIC Block { $$ = new StaticInitNode ($2); } ; /* Section 6.8 */ InterfaceDeclaration : ClassModifiersOpt INTERFACE SimpleName ExtendsInterfacesOpt InterfaceBody { checkInterfaceModifiers($1, $2.posn); $$ = new InterfaceDeclNode ($1, $3, $4, $5); } ; /* Section 6.8.2 */ ExtendsInterfacesOpt : ExtendsInterfaces | /* empty */ { $$ = NULL; } ; ExtendsInterfaces : EXTENDS TypeNameList { $$ = $2; } ; /* Section 6.8.3 */ InterfaceBody : '{' InterfaceMemberDeclarationsOpt '}' { $$ = $2; } ; InterfaceMemberDeclarationsOpt : /* empty */ { $$ = NULL; } | InterfaceMemberDeclaration InterfaceMemberDeclarationsOpt { $$ = extend ($1, $2); } ; InterfaceMemberDeclaration : ConstantFieldDeclaration | MethodSignatureDeclaration { $$ = cons ($1); } ; ConstantFieldDeclaration : FieldModifiersOpt Type VariableDeclarators ';' { checkConstantFieldModifiers ($1, $2->position()); $$ = NULL; foreach (decl, llist, *$3) { $$ = cons (static_cast(new FieldDeclNode (makeArrayType ($2, (*decl).dims), (*decl).name, $1, (*decl).initExpr)), $$); } free_all ($3); } ; MethodSignatureDeclaration : FieldModifiersOpt Type MethodName '(' ParameterListOpt ')' DimsOpt ThrowsOpt ';' { checkMethodSignatureModifiers ($1, $2->position()); $$ = new MethodSignatureNode ($1, $5, makeArrayType ($2, $7), $3, $8); } | FieldModifiersOpt Void MethodName '(' ParameterListOpt ')' DimsOpt ThrowsOpt ';' { checkMethodSignatureModifiers ($1, $2->position()); $$ = new MethodSignatureNode ($1, $5, makeArrayType ($2, $7), $3, $8); } ; /* Titanium extension: templates */ TemplateDeclaration : TEMPLATE '<' TemplateFormalList '>' BasicTypeDeclaration { $$ = new TemplateDeclNode( $5, $3, 0 ); } ; TemplateFormalList : TemplateFormal { $$ = cons( $1 ); } | TemplateFormal ',' TemplateFormalList { $$ = cons( $1, $3 ); } ; TemplateFormal : CLASS SimpleName { $$ = new TemplateTypeParamNode( $2 ); } | Type SimpleName { $$ = new TemplateConstParamNode( $1, $2 ); } ; TemplateInstance : TEMPLATE TypeName '<' TemplateActualList '>' { $$ = new TemplateInstanceTypeNode( $2, $4, 0 ); } ; TemplateActualList : TemplateActual { $$ = cons( $1 ); } | TemplateActual ',' TemplateActualList { $$ = cons( $1, $3 ); } ; TemplateActual : NoNameType { $$ = $1; } | NoNameExpression1 { $$ = $1; } | ArrayName { $$ = $1; } ; /* ARRAYS */ /* Section 7.3 */ ArrayInitializer : '{' ElementInitializers '}' { $$ = new ArrayInitNode (dreverse ($2), $1.posn); } | '{' ElementInitializers ',' '}' { $$ = new ArrayInitNode (dreverse ($2), $1.posn); } | '{' '}' { $$ = new ArrayInitNode (NULL, $1.posn); } ; /* Note: I'm going to assume that they didn't intend to allow "{,}". Indeed. (checked with respect to Sun's javac) */ ElementInitializers : Element { $$ = cons ($1); } | ElementInitializers ',' Element { $$ = cons ($3, $1); } ; Element : Expression | ArrayInitializer ; /* BLOCKS AND STATEMENTS */ /* Section 8.1 */ Block : '{' BlockStatementsOpt '}' { $$ = new BlockNode ($2, $3.posn); } ; BlockStatementsOpt : BlockStatements | /* empty */ { $$ = NULL; } ; BlockStatements : BlockStatement { $$ = $1; } | BlockStatements BlockStatement { $$ = extend ($1, $2); } ; BlockStatement : LocalVariableDeclarationStatement { $$ = $1; } | Statement { $$ = cons ($1); } ; /* Section 8.2 */ /* Not LALR(1) if we use OptionalFinal */ LocalVariableDeclarationStatement : FINAL Type VariableDeclarators ';' { $$ = makeVarDeclNodes(true, $2, $3); } | Type VariableDeclarators ';' { $$ = makeVarDeclNodes(false, $1, $2); } ; /* Section 8.3 */ Statement : EmptyStatement | LabeledStatement | ExpressionStatement | SelectionStatement | IterationStatement | JumpStatement | GuardingStatement | Block | PartitionStatement /* Titanium */ ; /* Section 8.4 */ EmptyStatement : ';' { $$ = new EmptyStmtNode ($1.posn); } ; /* Section 8.5 */ LabeledStatement : SimpleName ':' Statement { $$ = new LabeledStmtNode ($1, $3); } ; /* Section 8.6 */ ExpressionStatement : StatementExpression ';' { $$ = new ExpressionStmtNode( $1 ); } ; StatementExpression : Assignment { $$ = $1; } | PreIncrement { $$ = $1; } | PreDecrement { $$ = $1; } | PostIncrement { $$ = $1; } | PostDecrement { $$ = $1; } | MethodCall { $$ = $1; } | AllocationExpression { $$ = $1; } ; /* Section 8.7 */ SelectionStatement : IF '(' Expression ')' Statement %prec ELSE { $$ = new IfStmtNode ($3, $5, TreeNode::omitted); } | IF '(' Expression ')' Statement ELSE Statement { $$ = new IfStmtNode ($3, $5, $7); } | SWITCH '(' Expression ')' SwitchBlock { $$ = new SwitchNode ($3, $5, $1.posn); } ; SwitchBlock : '{' SwitchBlockStatementsOpt '}' { $$ = $2; } ; SwitchBlockStatementsOpt : /* empty */ { $$ = NULL; } | SwitchLabels BlockStatements SwitchBlockStatementsOpt { $$ = cons (static_cast(new SwitchBranchNode ($1, $2)), $3); } ; SwitchLabels : SwitchLabel { $$ = cons ($1); } | SwitchLabel SwitchLabels { $$ = cons ($1, $2); } ; SwitchLabel : CASE ConstantExpression ':' { $$ = new CaseNode ($2, $1.posn); } | DEFAULT ':' { $$ = new CaseNode (TreeNode::omitted, $1.posn); } ; /* Section 8.8 */ IterationStatement : WHILE '(' Expression ')' Statement { $$ = new WhileNode ($3, $5); } | DO Statement WHILE '(' Expression ')' ';' { $$ = new DoNode ($2, $5); } | FOR '(' ForInit ExpressionOpt ';' ForUpdateOpt ')' Statement { $$ = new ForNode ($3, $4, $6, $8); } | ForEachStatement /* Titanium */ ; ForInit : StatementExpressionsOpt ';' { $$ = $1; } | LocalVariableDeclarationStatement { $$ = $1; } ; ForUpdateOpt : StatementExpressions | /* empty */ { $$ = NULL; } ; StatementExpressionsOpt : StatementExpressions | /* empty */ { $$ = NULL; } ; StatementExpressions : StatementExpression { $$ = cons (static_cast(new ExpressionStmtNode($1))); } | StatementExpression ',' StatementExpressions { $$ = cons (static_cast(new ExpressionStmtNode($1)), $3); } ; /* Titanium */ ForEachStatement : FOREACH '(' ForEachClauses ')' OptionalInline Statement { $$ = new ForEachStmtNode ($3, $6, $5, $1.posn); } ; OptionalInline : INLINE { $$ = true; } | /* empty */ { $$ = false; } ; ForEachClauses : SimpleName SpecialIn Expression { $$ = cons(static_cast(new ForEachPairNode($1, $3))); } | SimpleName SpecialIn Expression ',' ForEachClauses { $$ = cons(static_cast(new ForEachPairNode($1, $3)), $5); } ; SpecialIn : IN { } | IDENTIFIER { if (*$1.val != "in") Error(lexerPosition()) << "bad keyword in foreach - expected 'in'" << endl; } ; /* Section 8.9 */ JumpStatement : BREAK LabelOpt ';' { $$ = new BreakNode ($2, NULL, NULL, $1.posn); } | CONTINUE LabelOpt ';' { $$ = new ContinueNode ($2, NULL, NULL, $1.posn); } | RETURN ExpressionOpt ';' { $$ = new ReturnNode ($2, NULL, $1.posn); } | THROW Expression ';' { $$ = new ThrowNode ($2, $1.posn); } ; LabelOpt : SimpleName | /* empty */ { $$ = TreeNode::omitted; } ; /* Section 8.10 */ GuardingStatement : SYNCHRONIZED '(' Expression ')' Statement { $$ = new SynchronizedNode ($3, $5); } | TryBlock Finally { $$ = new TryStmtNode ($1, NULL, $2); } | TryBlock Catches { $$ = new TryStmtNode ($1, $2, TreeNode::omitted); } | TryBlock Catches Finally { $$ = new TryStmtNode ($1, $2, $3); } ; TryBlock : TRY Block { $$ = new TryNode ($2); } ; Catches : Catch { $$ = cons ($1); } | Catch Catches { $$ = cons ($1, $2); } ; Catch : CATCH '(' Parameter ')' Block { $$ = new CatchNode ($3, $5, $1.posn); } ; Finally : FINALLY Block { $$ = new FinallyNode( $2 ); } ; /* Titanium */ PartitionStatement : PARTITION '{' PartitionClauses '}' { $$ = new PartitionStmtNode(TreeNode::omitted, $3, $1.posn); } | PARTITION SimpleName '{' PartitionClauses '}' { $$ = new PartitionStmtNode($2, $4, $1.posn); } ; PartitionClauses: /* empty */ { $$ = NULL; } | Expression GUARDS Statement PartitionClauses { $$ = cons(static_cast(new PartitionClauseNode($1, $3)), $4); } ; /* EXPRESSIONS */ /* Section 9.4 */ PrimaryExpression : ArrayName %prec ')' { $$ = $1->asExpr(); } | NotJustName ; NotJustName : AllocationExpression | ComplexPrimary ; ComplexPrimary : Literal | NULL_VAL { $$ = new NullPntrNode ($1.posn); } | THIS { $$ = new ThisNode (NULL, Common::None, $1.posn); } | '(' Expression ')' { $$ = $2; } | '(' ArrayName ')' { $$ = $2->asExpr(); } | ArrayAccess | FieldAccess { $$ = $1; } | MethodCall ; /* Note: The third production above is redundant, but helps resolve a LALR(1) */ /* lookahead conflict arising in cases like "(T) + x" (Do we reduce Name */ /* T to ClassOrInterfaceType on seeing the ")"?). See also CastExpression */ /* in section 9.10. */ ArrayName : Name QualifiersOpt { $$ = new ArrayNameNode($1, $2, NULL); } | FullArrayName ; FullArrayName : Name QualifiersOpt ArraySpecifiers { $$ = new ArrayNameNode($1, $2, $3); } ; Name : SimpleName | QualifiedName ; SimpleName : IDENTIFIER { $$ = new NameNode (TreeNode::omitted, $1.val, NULL, $1.posn); } ; QualifiedName : Name '.' IDENTIFIER { $$ = new NameNode ($1, $3.val, NULL, $3.posn); } | Name '.' OperatorName { $$ = new NameNode ($1, $3->ident(), NULL, $3->position()); } ; OperatorName : OPERATOR '!' { $$ = newOperator("!", $2.posn); } | OPERATOR '~' { $$ = newOperator("~", $2.posn); } | OPERATOR '<' { $$ = newOperator("<", $2.posn); } | OPERATOR '>' { $$ = newOperator(">", $2.posn); } | OPERATOR LE { $$ = newOperator("<=", $2.posn); } | OPERATOR GE { $$ = newOperator(">=", $2.posn); } | OPERATOR EQ { $$ = newOperator("==", $2.posn); } | OPERATOR NE { $$ = newOperator("!=", $2.posn); } | OPERATOR '+' { $$ = newOperator("+", $2.posn); } | OPERATOR '-' { $$ = newOperator("-", $2.posn); } | OPERATOR '*' { $$ = newOperator("*", $2.posn); } | OPERATOR '/' { $$ = newOperator("/", $2.posn); } | OPERATOR '&' { $$ = newOperator("&", $2.posn); } | OPERATOR '|' { $$ = newOperator("|", $2.posn); } | OPERATOR '^' { $$ = newOperator("^", $2.posn); } | OPERATOR '%' { $$ = newOperator("%", $2.posn); } | OPERATOR LSHIFTL { $$ = newOperator("<<", $2.posn); } | OPERATOR ASHIFTR { $$ = newOperator(">>", $2.posn); } | OPERATOR LSHIFTR { $$ = newOperator(">>>", $2.posn); } | OPERATOR PLUS_ASG { $$ = newOperator("+=", $2.posn); } | OPERATOR MINUS_ASG { $$ = newOperator("-=", $2.posn); } | OPERATOR MULT_ASG { $$ = newOperator("*=", $2.posn); } | OPERATOR DIV_ASG { $$ = newOperator("/=", $2.posn); } | OPERATOR REM_ASG { $$ = newOperator("%=", $2.posn); } | OPERATOR LSHIFTL_ASG { $$ = newOperator("<<=", $2.posn); } | OPERATOR ASHIFTR_ASG { $$ = newOperator(">>=", $2.posn); } | OPERATOR LSHIFTR_ASG { $$ = newOperator(">>>=", $2.posn); } | OPERATOR AND_ASG { $$ = newOperator("&=", $2.posn); } | OPERATOR XOR_ASG { $$ = newOperator("^=", $2.posn); } | OPERATOR OR_ASG { $$ = newOperator("|=", $2.posn); } | OPERATOR '[' ']' { $$ = newOperator("[]", $2.posn); } | OPERATOR '[' ']' '=' { $$ = newOperator("[]=", $2.posn); } ; /* Section 9.5 */ ArrayAccess : ComplexPrimary '[' IndexExpression ']' { $$ = new ArrayAccessNode ($1, $3); } ; IndexExpression : /* titanium - implicit point creation */ ArgumentList { $$ = new PointNode($1); } ; /* Section 9.6 */ FieldAccess : /* The following never matches Name '.' IDENTIFIER */ NotJustName '.' MethodName { $$ = new ObjectFieldAccessNode ($1, $3); } | SUPER '.' MethodName { $$ = new SuperFieldAccessNode (NULL, Common::None, $3); } | ComplexBaseType '.' MethodName { $$ = new TypeFieldAccessNode ($1, $3); } | FullArrayName '.' MethodName { $$ = new ObjectFieldAccessNode ($1->asExpr(), $3); } | OperatorName { $$ = new ThisFieldAccessNode (NULL, Common::None, $1); } ; /* Section 9.7 */ MethodCall : FieldAccess '(' ArgumentListOpt ')' { $$ = new MethodCallNode ($1, $3); } | ArrayName '(' ArgumentListOpt ')' { $$ = new MethodCallNode ($1->asExpr(), $3); } ; ArgumentListOpt : ArgumentList | /* empty */ { $$ = NULL; } ; ArgumentList : Expression { $$ = cons ($1); } | Expression ',' ArgumentList { $$ = cons ($1, $3); } ; /* Section 9.8 */ AllocationExpression : NEW RegionOpt QualifiedBaseType '(' ArgumentListOpt ')' { $$ = new AllocateNode ($2, $3, $5, NULL); } | NEW RegionOpt QualifiedBaseType DimExprs { $$ = new AllocateArrayNode ($2, $3, $4); } ; RegionOpt : '(' Expression ')' { $$ = $2; } | /* empty */ { $$ = TreeNode::omitted; } ; DimExprs : DimExpr { $$ = cons ($1); } | DimExpr DimExprs { $$ = cons ($1, $2); } ; DimExpr : ArraySpecifier { $$ = $1; } | DomainLiteral QualifiersOpt { $$ = new AllocateArrayDimensionNode($1, $2); } ; DimsOpt : Dims | /* empty */ { $$ = 0; } ; Dims : '[' ']' { $$ = 1; } | '[' ']' LOCAL { $$ = 1; } | Dims '[' ']' { $$ = $1 + 1; } | Dims '[' ']' LOCAL { $$ = $1 + 1; } ; /* Section 9.9 */ PostfixExpression : PrimaryExpression | OtherPostfixExpression ; NoNamePostfixExpression : NotJustName | OtherPostfixExpression ; OtherPostfixExpression : PostIncrement | PostDecrement ; PostIncrement : PostfixExpression PLUSPLUS { $$ = new PostIncrNode ($1); } ; PostDecrement : PostfixExpression MINUSMINUS { $$ = new PostDecrNode ($1); } ; /* Section 9.10 */ UnaryExpression : RestrictedUnaryExpression | OtherUnaryExpression ; NoNameUnaryExpression : NoNameRestrictedUnaryExpression | OtherUnaryExpression ; OtherUnaryExpression : PreIncrement | PreDecrement | '+' UnaryExpression { $$ = new UnaryPlusNode ($2, $1.posn); } | '-' UnaryExpression { $$ = new UnaryMinusNode ($2, $1.posn); } | PointLiteral /* Titanium */ | DomainLiteral /* Titanium */ ; PreIncrement : PLUSPLUS UnaryExpression { $$ = new PreIncrNode ($2); } ; PreDecrement : MINUSMINUS UnaryExpression { $$ = new PreDecrNode ($2); } ; RestrictedUnaryExpression : PostfixExpression | OtherRestrictedPostfixExpression ; NoNameRestrictedUnaryExpression : NoNamePostfixExpression | OtherRestrictedPostfixExpression ; OtherRestrictedPostfixExpression : '~' UnaryExpression { $$ = new ComplementNode ($2); } | '!' UnaryExpression { $$ = new NotNode ($2); } | CastExpression ; CastExpression : '(' Type ')' UnaryExpression { $$ = new CastNode ($4, $2); } | '(' ArrayName ')' RestrictedUnaryExpression { $$ = new CastNode ($4, $2->asType()); } ; /* Note: The last production is redundant, but helps resolve a LALR(1) */ /* lookahead conflict arising in cases like "(T) + x" (Do we reduce Name */ /* T to ClassOrInterfaceType on seeing the ")"?). See also ComplexPrimary */ /* in section 9.4. */ /* Titanium */ PointLiteral : '[' ArgumentList ']' { $$ = new PointNode($2); } ; DomainLiteral : '[' DomainPairs ']' { $$ = new DomainNode($2); } | '[' DomainTriples ']' { $$ = new DomainNode($2); } ; DomainPairs : DomainPair { $$ = cons($1); } | DomainPair ',' DomainPairs { $$ = cons($1, $3); } ; DomainPair : Expression ':' Expression { llist* children = cons($1, cons($3)); $$ = new TreeListNode(children); } ; DomainTriples : DomainTriple { $$ = cons($1); } | DomainTriple ',' DomainTriples { $$ = cons($1, $3); } ; DomainTriple : Expression ':' Expression ':' Expression { llist* children = cons($1, cons($3, cons($5))); $$ = new TreeListNode(children); } ; /* Sections 9.11 to 9.19 */ ExpressionOpt : Expression | /* empty */ { $$ = TreeNode::omitted; } ; Expression : Expression1 | BroadcastExpression | Expression '<' Expression { $$ = new LTNode ($1, $3); } | Expression '>' Expression { $$ = new GTNode ($1, $3); } | Expression LE Expression { $$ = new LENode ($1, $3); } | Expression GE Expression { $$ = new GENode ($1, $3); } | Expression INSTANCEOF Type { $$ = new InstanceOfNode ($1, $3); } | Expression EQ Expression { $$ = new EQNode ($1, $3); } | Expression NE Expression { $$ = new NENode ($1, $3); } | Expression '&' Expression { $$ = new BitAndNode ($1, $3); } | Expression '|' Expression { $$ = new BitOrNode ($1, $3); } | Expression '^' Expression { $$ = new BitXorNode ($1, $3); } | Expression CAND Expression { $$ = new CandNode ($1, $3); } | Expression COR Expression { $$ = new CorNode ($1, $3); } | Expression '?' Expression ':' Expression { $$ = new IfExprNode ($1, $3, $5); } | Assignment ; Expression1 : UnaryExpression | BinaryExpression1 ; NoNameExpression1 : NoNameUnaryExpression | BinaryExpression1 ; BinaryExpression1 : Expression1 '*' Expression1 { $$ = new MultNode ($1, $3); } | Expression1 '/' Expression1 { $$ = new DivNode ($1, $3); } | Expression1 '%' Expression1 { $$ = new RemNode ($1, $3); } | Expression1 '+' Expression1 { $$ = new PlusNode ($1, $3); } | Expression1 '-' Expression1 { $$ = new MinusNode ($1, $3); } | Expression1 LSHIFTL Expression1 { $$ = new LeftShiftLogNode ($1, $3); } | Expression1 LSHIFTR Expression1 { $$ = new RightShiftLogNode ($1, $3); } | Expression1 ASHIFTR Expression1 { $$ = new RightShiftArithNode ($1, $3); } ; /* Section 9.20 */ Assignment : UnaryExpression '=' Expression { $$ = new AssignNode ($1, $3); } | UnaryExpression MULT_ASG Expression { $$ = new MultAssignNode ($1, $3); } | UnaryExpression DIV_ASG Expression { $$ = new DivAssignNode ($1, $3); } | UnaryExpression REM_ASG Expression { $$ = new RemAssignNode ($1, $3); } | UnaryExpression PLUS_ASG Expression { $$ = new PlusAssignNode ($1, $3); } | UnaryExpression MINUS_ASG Expression { $$ = new MinusAssignNode ($1, $3); } | UnaryExpression LSHIFTL_ASG Expression { $$ = new LeftShiftLogAssignNode ($1, $3); } | UnaryExpression LSHIFTR_ASG Expression { $$ = new RightShiftLogAssignNode ($1, $3); } | UnaryExpression ASHIFTR_ASG Expression { $$ = new RightShiftArithAssignNode ($1, $3); } | UnaryExpression AND_ASG Expression { $$ = new BitAndAssignNode ($1, $3); } | UnaryExpression XOR_ASG Expression { $$ = new BitXorAssignNode ($1, $3); } | UnaryExpression OR_ASG Expression { $$ = new BitOrAssignNode ($1, $3); } ; /* Section 9.22 */ ConstantExpression : Expression ; BroadcastExpression : BROADCAST Expression FROM Expression %prec BROADCAST { $$ = new BroadcastNode ($2, $4); } ; /* MISCELLANEOUS */ /* Collected error productions */ ImportStatement : IMPORT error ';' { $$ = TreeNode::omitted; } ; PackageDeclarationOpt : _PACKAGE error ';' { $$ = TreeNode::omitted; } ; Block : '{' error '}' { $$ = TreeNode::omitted; } ; Statement : error ';' { $$ = new EmptyStmtNode; } | error Block { $$ = $2; } ; FieldDeclaration : error ';' { $$ = NULL; } ; TypeDeclaration : error ClassBody { $$ = TreeNode::omitted; } ; %% static void yyerror(const char* msg) { Error(yylval.SimpTerminal.posn) << msg << endl; } static TreeNode *newOperator(char *op, SourcePosn p) { return new NameNode(TreeNode::omitted, intern(op), NULL, p); } /* Check that FLAG is not a member of FLAGS. If it is, report an */ /* error at POSN, giving NAME as the name of the offending modifier. */ static void checkModifier(SourcePosn posn, Common::Modifiers flags, Common::Modifiers flag, const char* name) { if (((unsigned long) flags & (unsigned long) flag) != 0) Error (posn) << "illegal modifier: '" << name << "'" << endl; } /* Check that only the modifiers in ... are in FLAGS, reporting an */ /* error at POSN if not. */ static void checkModifiers(SourcePosn posn, Common::Modifiers flags, ...) { unsigned long flag; va_list ap; va_start (ap, flags); while (true) { flag = va_arg (ap, unsigned long); if (flag == 0) break; flags = (Common::Modifiers)((unsigned long)flags & ~flag); } va_end (ap); if ((unsigned long) flags != 0) Error(posn) << "illegal modifiers: " << stringifyModifiers(flags) << endl; } static void checkFieldModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Protected, TreeNode::Private, TreeNode::Static, TreeNode::Final, TreeNode::Transient, TreeNode::Volatile, (Common::Modifiers) 0); } static void checkConstantFieldModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Static, TreeNode::Final, (Common::Modifiers) 0); } static void checkMethodModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Protected, TreeNode::Private, TreeNode::Static, TreeNode::Final, TreeNode::Abstract, TreeNode::Native, TreeNode::Sglobal, TreeNode::Local, TreeNode::NonsharedQ, TreeNode::PolysharedQ, TreeNode::Synchronized, TreeNode::Inline, (Common::Modifiers) 0); } static void checkConstructorModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Protected, TreeNode::Private, TreeNode::NonsharedQ, TreeNode::PolysharedQ, TreeNode::Sglobal, TreeNode::Inline, (Common::Modifiers) 0); } static void checkMethodSignatureModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Abstract, TreeNode::Single, TreeNode::Local, TreeNode::NonsharedQ, TreeNode::PolysharedQ, (Common::Modifiers) 0); } static void checkInterfaceModifiers(Common::Modifiers flags, SourcePosn posn) { checkModifiers(posn, flags, TreeNode::Public, TreeNode::Abstract, (Common::Modifiers) 0); } static TreeNode *addSynchronized(Common::Modifiers modifiers, TreeNode *body) { if ((modifiers & TreeNode::Synchronized) != 0 && !body->absent()) { TreeNode *syncObject; if ((modifiers & TreeNode::Static) != 0) { syncObject = TreeNode::omitted; } else { syncObject = new ThisNode(NULL, Common::None, body->position()); } body = new SynchronizedNode(syncObject, body); } return body; }