private Node parseNameExpression(JsDocToken token) { if (token != JsDocToken.STRING) { return reportGenericTypeSyntaxWarning(); } String typeName = stream.getString(); int lineno = stream.getLineno(); int charno = stream.getCharno(); while (match(JsDocToken.EOL) && typeName.charAt(typeName.length() - 1) == '.') { skipEOLs(); if (match(JsDocToken.STRING)) { next(); typeName += stream.getString(); } } return newStringNode(typeName, lineno, charno); }
/** * ParamTypeExpressionAnnotation := '{' ParamTypeExpression '}' */ private Node parseParamTypeExpressionAnnotation(JsDocToken token) { checkArgument(token == JsDocToken.LEFT_CURLY); skipEOLs(); Node typeNode = parseParamTypeExpression(next()); if (typeNode != null) { if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; }
/** * ParamTypeExpressionAnnotation := '{' ParamTypeExpression '}' */ private Node parseParamTypeExpressionAnnotation(JsDocToken token) { Preconditions.checkArgument(token == JsDocToken.LEFT_CURLY); skipEOLs(); Node typeNode = parseParamTypeExpression(next()); if (typeNode != null) { if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; }
/** * ResultType := <empty> | ':' void | ':' TypeExpression */ private Node parseResultType() { skipEOLs(); if (!match(JsDocToken.COLON)) { return newNode(Token.EMPTY); } next(); skipEOLs(); if (match(JsDocToken.STRING) && "void".equals(stream.getString())) { next(); return newNode(Token.VOID); } else { return parseTypeExpression(next()); } }
/** * ResultType := <empty> | ':' void | ':' TypeExpression */ private Node parseResultType() { skipEOLs(); if (!match(JsDocToken.COLON)) { return newNode(Token.EMPTY); } next(); skipEOLs(); if (match(JsDocToken.STRING) && "void".equals(stream.getString())) { next(); return newNode(Token.VOID); } else { return parseTypeExpression(next()); } }
/** * TopLevelTypeExpression := TypeExpression * | TypeUnionList * * We made this rule up, for the sake of backwards compatibility. */ private Node parseTopLevelTypeExpression(JsDocToken token) { Node typeExpr = parseTypeExpression(token); if (typeExpr != null) { // top-level unions are allowed if (match(JsDocToken.PIPE)) { next(); skipEOLs(); token = next(); return parseUnionTypeWithAlternate(token, typeExpr); } } return typeExpr; }
/** * TopLevelTypeExpression := TypeExpression * | TypeUnionList * * We made this rule up, for the sake of backwards compatibility. */ private Node parseTopLevelTypeExpression(JsDocToken token) { Node typeExpr = parseTypeExpression(token); if (typeExpr != null) { // top-level unions are allowed if (match(JsDocToken.PIPE)) { next(); skipEOLs(); token = next(); return parseUnionTypeWithAlternate(token, typeExpr); } } return typeExpr; }
/** * Parse a TypeName: * * <pre>{@code * TypeName := NameExpression | NameExpression TypeApplication * TypeApplication := '.'? '<' TypeExpressionList '>' * }</pre> */ private Node parseTypeName(JsDocToken token) { Node typeNameNode = parseNameExpression(token); if (match(JsDocToken.LEFT_ANGLE)) { next(); skipEOLs(); Node memberType = parseTypeExpressionList(typeNameNode.getString(), next()); if (memberType != null) { typeNameNode.addChildToFront(memberType); skipEOLs(); if (!match(JsDocToken.RIGHT_ANGLE)) { return reportTypeSyntaxWarning("msg.jsdoc.missing.gt"); } next(); } } return typeNameNode; }
/** * RecordType := '{' FieldTypeList '}' */ private Node parseRecordType(JsDocToken token) { Node recordType = newNode(Token.LC); Node fieldTypeList = parseFieldTypeList(token); if (fieldTypeList == null) { return reportGenericTypeSyntaxWarning(); } skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { return reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } next(); recordType.addChildToBack(fieldTypeList); return recordType; }
/** * RecordType := '{' FieldTypeList '}' */ private Node parseRecordType(JsDocToken token) { Node recordType = newNode(Token.LC); Node fieldTypeList = parseFieldTypeList(token); if (fieldTypeList == null) { return reportGenericTypeSyntaxWarning(); } skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { return reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } next(); recordType.addChildToBack(fieldTypeList); return recordType; }
/** * TypeNameAnnotation := TypeName | '{' TypeName '}' */ private Node parseTypeNameAnnotation(JsDocToken token) { if (token == JsDocToken.LEFT_CURLY) { skipEOLs(); Node typeNode = parseTypeName(next()); if (typeNode != null) { skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; } else { return parseTypeName(token); } }
/** * TypeNameAnnotation := TypeName | '{' TypeName '}' */ private Node parseTypeNameAnnotation(JsDocToken token) { if (token == JsDocToken.LEFT_CURLY) { skipEOLs(); Node typeNode = parseTypeName(next()); if (typeNode != null) { skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; } else { return parseTypeName(token); } }
/** * TypeExpressionList := TopLevelTypeExpression * | TopLevelTypeExpression ',' TypeExpressionList */ private Node parseTypeExpressionList(String typeName, JsDocToken token) { Node typeExpr = parseTopLevelTypeExpression(token); if (typeExpr == null) { return null; } Node typeList = IR.block(); int numTypeExprs = 1; typeList.addChildToBack(typeExpr); while (match(JsDocToken.COMMA)) { next(); skipEOLs(); typeExpr = parseTopLevelTypeExpression(next()); if (typeExpr == null) { return null; } numTypeExprs++; typeList.addChildToBack(typeExpr); } if (typeName.equals("Object") && numTypeExprs == 1) { // Unlike other generic types, Object<V> means Object<?, V>, not Object<V, ?>. typeList.addChildToFront(newNode(Token.QMARK)); } return typeList; }
/** * TypeExpressionList := TopLevelTypeExpression * | TopLevelTypeExpression ',' TypeExpressionList */ private Node parseTypeExpressionList(JsDocToken token) { Node typeExpr = parseTopLevelTypeExpression(token); if (typeExpr == null) { return null; } Node typeList = IR.block(); typeList.addChildToBack(typeExpr); while (match(JsDocToken.COMMA)) { next(); skipEOLs(); typeExpr = parseTopLevelTypeExpression(next()); if (typeExpr == null) { return null; } typeList.addChildToBack(typeExpr); } return typeList; }
/** * TypeExpressionAnnotation := TypeExpression | * '{' TopLevelTypeExpression '}' */ private Node parseTypeExpressionAnnotation(JsDocToken token) { if (token == JsDocToken.LEFT_CURLY) { skipEOLs(); Node typeNode = parseTopLevelTypeExpression(next()); if (typeNode != null) { skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; } else { // TODO(tbreisacher): Add a SuggestedFix for this warning. reportTypeSyntaxWarning("msg.jsdoc.missing.braces"); return parseTypeExpression(token); } }
/** * TypeExpressionAnnotation := TypeExpression | * '{' TopLevelTypeExpression '}' */ private Node parseTypeExpressionAnnotation(JsDocToken token) { if (token == JsDocToken.LEFT_CURLY) { skipEOLs(); Node typeNode = parseTopLevelTypeExpression(next()); if (typeNode != null) { skipEOLs(); if (!match(JsDocToken.RIGHT_CURLY)) { reportTypeSyntaxWarning("msg.jsdoc.missing.rc"); } else { next(); } } return typeNode; } else { // TODO(tbreisacher): Add a SuggestedFix for this warning. reportTypeSyntaxWarning("msg.jsdoc.missing.braces"); return parseTypeExpression(token); } }
/** * FieldType := FieldName | FieldName ':' TypeExpression */ private Node parseFieldType(JsDocToken token) { Node fieldName = parseFieldName(token); if (fieldName == null) { return null; } skipEOLs(); if (!match(JsDocToken.COLON)) { return fieldName; } // Move to the colon. next(); // Move to the token after the colon and parse // the type expression. skipEOLs(); Node typeExpression = parseTypeExpression(next()); if (typeExpression == null) { return null; } Node fieldType = newNode(Token.COLON); fieldType.addChildToBack(fieldName); fieldType.addChildToBack(typeExpression); return fieldType; }
/** * FieldType := FieldName | FieldName ':' TypeExpression */ private Node parseFieldType(JsDocToken token) { Node fieldName = parseFieldName(token); if (fieldName == null) { return null; } skipEOLs(); if (!match(JsDocToken.COLON)) { return fieldName; } // Move to the colon. next(); // Move to the token after the colon and parse // the type expression. skipEOLs(); Node typeExpression = parseTypeExpression(next()); if (typeExpression == null) { return null; } Node fieldType = newNode(Token.COLON); fieldType.addChildToBack(fieldName); fieldType.addChildToBack(typeExpression); return fieldType; }