Example

Java Code Fragments

Small Java-like fragments.

Parse a small Java-like subset into semantic code fragments.

What it shows

  • Type distinguishes reference types, primitive types, and arrays.
  • Expression covers literals, identifiers, method calls, arithmetic, and comparisons.
  • CodeElement composes blocks, if/else, methods, classes, and comments.
  • Method parameters, modifiers, statements, and block contents are repeatable fields.

Try adding a simple declaration or another System.out.println(...) call.

Specs

spec.yml
$flags: [ 'WORD_BOUNDARY', 'FLEXIBLE_WHITESPACE' ]

Comment: ['//.*', '(?s)/\*.*?\*/']

Keyword:
  Class: 'class'
  If: 'if'
  Else: 'else'
  For: 'for'
  While: 'while'
  Try: 'try'
  Catch: 'catch'
  Finally: 'finally'
  Return: 'return'
  Throw: 'throw'

Modifier:
  Public: 'public'
  Private: 'private'
  Protected: 'protected'
  Static: 'static'
  Final: 'final'
  Abstract: 'abstract'

Type:

  Reference:
    String: 'String'
    System: 'System'
    ArithmeticException: 'ArithmeticException'

  Primitive:
    Void: 'void'
    Boolean: 'boolean'
    Int: 'int'
    Long: 'long'
    Double: 'double'
    Char: 'char'

  Array:
    $fields:
      elementType: Type
    $patterns: '#{elementType}\[\]'

Expression:

  Identifier: '${!Keyword}[A-Za-z_][A-Za-z0-9_]*'

  StringLiteral: '"([^"\\]|\\.)*"'

  NumberLiteral: '\d+(\.\d+)?'

  BooleanLiteral: 'true|false'

  NullLiteral: 'null'

  MethodCall:
    $flags: OPTIONAL_WHITESPACE
    $types:
      MethodReceiver: '(${Type::Reference}|${Expression::Identifier})(\.${Expression::Identifier})*'
    $fields:
      receiver: MethodReceiver
      methodName: Expression::Identifier
      arguments: Expression[]
    $patterns:
      - '#{receiver}\.#{methodName}\((#{arguments}(, #{arguments})*)?\)'
      - '#{methodName}\((#{arguments}(, #{arguments})*)?\)'

  Operation:

    Binary:
      $flags: OPTIONAL_WHITESPACE
      $fields:
        left: Expression
        right: Expression
      Addition: '#{left} \+ #{right}'
      Subtraction: '#{left} - #{right}'
      Multiplication: '#{left} \* #{right}'
      Division: '#{left} / #{right}'

    Unary:
      $fields:
        value: Expression
      Increment: '#{value}\+\+'
      Decrement: '#{value}--'

  Comparison:
    $flags: OPTIONAL_WHITESPACE
    $fields:
      left: Expression
      right: Expression
    Equality: '#{left} == #{right}'
    Inequality: '#{left} != #{right}'
    LessThan: '#{left} < #{right}'
    GreaterThan: '#{left} > #{right}'
    LessOrEqual: '#{left} <= #{right}'
    GreaterOrEqual: '#{left} >= #{right}'

Parameter:
  $fields:
    type: Type
    name: Expression::Identifier
  $patterns: '#{type} #{name}(?=,|\))'

CodeElement:

  Comment: '${Comment}'

  MethodCallStatement:
    $flags: OPTIONAL_WHITESPACE
    $fields:
      call: Expression::MethodCall
    $patterns: '#{call};'

  VariableDeclaration:
    $fields:
      type: Type
      name: Expression::Identifier
      value: Expression
    $patterns: '#{type} #{name} = #{value};'

  Block:
    $flags: OPTIONAL_WHITESPACE
    $fields:
      statements: CodeElement[]
    $patterns: '\{ (#{statements}( #{statements})*)? \}'

  ReturnStatement:
    $fields:
      value: Expression
    $patterns: '${Keyword::Return} #{value};'

  ThrowStatement:
    $fields:
      value: Expression
    $patterns: '${Keyword::Throw} #{value};'

  IfElseStatement:
    $fields:
      condition: Expression::Comparison
      ifBody: CodeElement
      elseBody: CodeElement
    $patterns: '${Keyword::If} \(#{condition}\) #{ifBody}( ${Keyword::Else} #{elseBody})?'

  ForStatement:
    $fields:
      type: Type
      name: Expression::Identifier
      initialValue: Expression
      condition: Expression::Comparison
      step: Expression::Operation::Unary::Increment
      body: CodeElement
    $patterns: '${Keyword::For} \(#{type} #{name} = #{initialValue}; #{condition}; #{step}\)\s*#{body}'

  WhileStatement:
    $fields:
      condition: Expression::Comparison
      body: CodeElement
    $patterns: '${Keyword::While} \(#{condition}\) #{body}'

  TryCatchFinallyStatement:
    $fields:
      tryBody: CodeElement
      exception: Parameter
      catchBody: CodeElement
      finallyBody: CodeElement
    $patterns: '${Keyword::Try} #{tryBody}( ${Keyword::Catch} \(#{exception}\) #{catchBody})?( ${Keyword::Finally} #{finallyBody})?'

  MethodDeclaration:
    $fields:
      modifiers: Modifier[]
      returnType: Type
      name: Expression::Identifier
      parameters: Parameter[]
      body: CodeElement::Block
    $patterns: '(#{modifiers} )*#{returnType} #{name}\((#{parameters}(, #{parameters})*)?\) #{body}'

  ClassDeclaration:
    $fields:
      modifiers: Modifier[]
      name: Expression::Identifier
      body: CodeElement::Block
    $patterns: '(#{modifiers} )*${Keyword::Class} #{name} #{body}'
Try it liveOpen Java Code Fragments in StudioTweak the spec, paste your own input, and see the parse tree update in real time.

Or browse other examples →