Module TaskJuggler::TjpSyntaxRules
In: lib/taskjuggler/TjpSyntaxRules.rb

This module contains the rule definition for the TJP syntax. Every rule is put in a function who‘s name must start with rule_. The functions are not necessary but make the file more readable and receptable to syntax folding.

Methods

rule_absoluteTaskId   rule_account   rule_accountAttributes   rule_accountBody   rule_accountCredit   rule_accountCredits   rule_accountHeader   rule_accountId   rule_accountReport   rule_accountReportHeader   rule_accountScenarioAttributes   rule_aggregate   rule_alertLevel   rule_alertLevelDefinition   rule_alertLevelDefinitions   rule_allOrNone   rule_allocate   rule_allocateShiftAssignments   rule_allocateShiftsAssignments   rule_allocation   rule_allocationAttributes   rule_allocationBody   rule_allocationHeader   rule_allocationSelectionMode   rule_allocations   rule_argument   rule_argumentList   rule_argumentListBody   rule_author   rule_balance   rule_balanceAccounts   rule_bookingAttributes   rule_bookingBody   rule_calendarDuration   rule_chargeMode   rule_chargeSetItem   rule_chargeset   rule_chartScale   rule_color   rule_columnBody   rule_columnDef   rule_columnId   rule_columnOptions   rule_currencyFormat   rule_date   rule_dateCalcedOrNot   rule_declareFlagList   rule_details   rule_durationUnit   rule_durationUnitOrPercent   rule_export   rule_exportAttributes   rule_exportBody   rule_exportHeader   rule_extendAttributes   rule_extendBody   rule_extendId   rule_extendOptions   rule_extendOptionsBody   rule_extendProperty   rule_extendPropertyId   rule_fail   rule_flag   rule_flagList   rule_flagLogicalExpression   rule_flagOperand   rule_flagOperation   rule_flagOperationChain   rule_flagOperator   rule_flagOperatorAndOperand   rule_flags   rule_formats   rule_functionPatterns   rule_functions   rule_functionsBody   rule_hAlignment   rule_headline   rule_hideaccount   rule_hidejournalentry   rule_hideresource   rule_hidetask   rule_iCalReport   rule_iCalReportAttributes   rule_iCalReportBody   rule_iCalReportHeader   rule_idOrAbsoluteId   rule_includeAttributes   rule_includeAttributesBody   rule_includeFile   rule_includeFileName   rule_includeProperties   rule_interval   rule_intervalDuration   rule_intervalEnd   rule_intervalOptional   rule_intervalOptionalEnd   rule_intervalOrDate   rule_intervals   rule_intervalsOptional   rule_journalEntry   rule_journalEntryAttributes   rule_journalEntryBody   rule_journalEntryHeader   rule_journalReportAttributes   rule_journalReportMode   rule_journalSortCriteria   rule_journalSortCriterium   rule_leafResourceId   rule_leave   rule_leaveAllowance   rule_leaveAllowanceList   rule_leaveAllowances   rule_leaveList   rule_leaveName   rule_leaveType   rule_leaves   rule_limitAttributes   rule_limitAttributesBody   rule_limitValue   rule_limits   rule_limitsAttributes   rule_limitsBody   rule_limitsHeader   rule_listOfDays   rule_listOfTimes   rule_listType   rule_loadunit   rule_logicalExpression   rule_macro   rule_moreAlternatives   rule_moreArguments   rule_moreBangs   rule_moreChargeSetItems   rule_moreColumnDef   rule_moreDepTasks   rule_moreJournalSortCriteria   rule_moreListOfDays   rule_moreOutputFormats   rule_morePredTasks   rule_moreProjectIDs   rule_moreSortCriteria   rule_moreTimeIntervals   rule_navigator   rule_navigatorAttributes   rule_navigatorBody   rule_navigatorHeader   rule_nikuReport   rule_nikuReportAttributes   rule_nikuReportBody   rule_nikuReportHeader   rule_nodeId   rule_nodeIdList   rule_number   rule_numberFormat   rule_operand   rule_operation   rule_operationChain   rule_operator   rule_operatorAndOperand   rule_optionalID   rule_optionalMinus   rule_optionalPercent   rule_optionalVersion   rule_outputFormat   rule_outputFormats   rule_plusOrMinus   rule_project   rule_projectBody   rule_projectBodyAttributes   rule_projectBodyInclude   rule_projectDeclaration   rule_projectHeader   rule_projectIDs   rule_projectProlog   rule_projectProperties   rule_projectPropertiesBody   rule_projection   rule_projectionAttributes   rule_prologInclude   rule_properties   rule_propertiesBody   rule_propertiesFile   rule_propertiesInclude   rule_purge   rule_referenceAttributes   rule_referenceBody   rule_relativeId   rule_reportAttributes   rule_reportBody   rule_reportEnd   rule_reportId   rule_reportIdUnverifd   rule_reportName   rule_reportPeriod   rule_reportProperties   rule_reportPropertiesBody   rule_reportPropertiesFile   rule_reportStart   rule_reportTitle   rule_reportableAttributes   rule_reports   rule_resource   rule_resourceAttributes   rule_resourceBody   rule_resourceBooking   rule_resourceBookingHeader   rule_resourceHeader   rule_resourceId   rule_resourceLeafList   rule_resourceList   rule_resourceReport   rule_resourceReportHeader   rule_resourceScenarioAttributes   rule_resourceShiftAssignments   rule_resourceShiftsAssignments   rule_rollupaccount   rule_rollupresource   rule_rolluptask   rule_scenario   rule_scenarioAttributes   rule_scenarioBody   rule_scenarioHeader   rule_scenarioId   rule_scenarioIdCol   rule_scenarioIdList   rule_scenarioIdx   rule_schedulingDirection   rule_shift   rule_shiftAssignment   rule_shiftAssignments   rule_shiftAttributes   rule_shiftBody   rule_shiftHeader   rule_shiftId   rule_shiftScenarioAttributes   rule_sortAccounts   rule_sortCriteria   rule_sortCriterium   rule_sortJournalEntries   rule_sortNonTree   rule_sortResources   rule_sortTasks   rule_sortTree   rule_ssReportAttributes   rule_ssReportBody   rule_ssReportHeader   rule_ssStatus   rule_ssStatusAttributes   rule_ssStatusBody   rule_ssStatusHeader   rule_statusSheet   rule_statusSheetAttributes   rule_statusSheetBody   rule_statusSheetFile   rule_statusSheetHeader   rule_statusSheetReport   rule_statusSheetTask   rule_statusSheetTaskAttributes   rule_statusSheetTaskBody   rule_statusSheetTaskHeader   rule_subNodeId   rule_summary   rule_supplement   rule_supplementAccount   rule_supplementReport   rule_supplementResource   rule_supplementTask   rule_tagfile   rule_tagfileAttributes   rule_tagfileBody   rule_tagfileHeader   rule_task   rule_taskAttributes   rule_taskBody   rule_taskBooking   rule_taskBookingHeader   rule_taskDep   rule_taskDepAttributes   rule_taskDepBody   rule_taskDepHeader   rule_taskDepId   rule_taskDepList   rule_taskHeader   rule_taskId   rule_taskIdUnverifd   rule_taskList   rule_taskPeriod   rule_taskPred   rule_taskPredHeader   rule_taskPredList   rule_taskReport   rule_taskReportHeader   rule_taskScenarioAttributes   rule_taskShiftAssignments   rule_taskShiftsAssignments   rule_textReport   rule_textReportHeader   rule_timeInterval   rule_timeSheet   rule_timeSheetAttributes   rule_timeSheetBody   rule_timeSheetFile   rule_timeSheetHeader   rule_timeSheetReport   rule_timeformat   rule_timezone   rule_traceReport   rule_traceReportHeader   rule_tsNewTaskHeader   rule_tsReportAttributes   rule_tsReportBody   rule_tsReportHeader   rule_tsStatus   rule_tsStatusAttributes   rule_tsStatusBody   rule_tsStatusHeader   rule_tsTaskAttributes   rule_tsTaskBody   rule_tsTaskHeader   rule_vacationName   rule_valDate   rule_valInterval   rule_valIntervalOrDate   rule_valIntervals   rule_validTimeZone   rule_warn   rule_weekDayInterval   rule_weekDayIntervalEnd   rule_weekday   rule_workingDuration   rule_workingDurationPercent   rule_workinghours   rule_workinghoursProject   rule_workinghoursResource   rule_workinghoursShift   rule_yesNo  

Public Instance methods

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 21
  def rule_absoluteTaskId
    pattern(%w( !taskIdUnverifd ), lambda {
      id = (@taskprefix.empty? ? '' : @taskprefix + '.') + @val[0]
      if (task = @project.task(id)).nil?
        error('unknown_abs_task', "Unknown task #{id}", @sourceFileInfo[0])
      end
      task
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 31
  def rule_account
    pattern(%w( !accountHeader !accountBody ), lambda {
       @property = @property.parent
    })
    doc('account', "Declares an account. Accounts can be used to calculate costs of tasks or the\nwhole project. Account declaration may be nested, but only leaf accounts may\nbe used to track turnover. When the cost of a task is split over multiple\naccounts they all must have the same top-level group account. Top-level\naccounts can be used for profit/loss calculations. The sub-account structure\nof a top-level account should be organized accordingly.\n\nAccounts have a global name space. All IDs must be unique within the accounts of the project.\n"
       )
    example('Account', '1')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 50
  def rule_accountAttributes
    repeatable
    optional
    pattern(%w( !account))
    pattern(%w( !accountScenarioAttributes ))
    pattern(%w( !scenarioIdCol !accountScenarioAttributes ), lambda {
      @scenarioIdx = 0
    })
    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 61
  def rule_accountBody
    optionsRule('accountAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 65
  def rule_accountCredit
    pattern(%w( !valDate $STRING !number ), lambda {
      AccountCredit.new(@val[0], @val[1], @val[2])
    })
    arg(1, 'description', 'Short description of the transaction')
    arg(2, 'amount', 'Amount to be booked.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 73
  def rule_accountCredits
    listRule('moreAccountCredits', '!accountCredit')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 77
  def rule_accountHeader
    pattern(%w( _account !optionalID $STRING ), lambda {
      if @property.nil? && !@accountprefix.empty?
        @property = @project.accout(@accountprefix)
      end
      if @val[1] && @project.account(@val[1])
        error('account_exists', "Account #{@val[1]} has already been defined.",
              @sourceFileInfo[1], @property)
      end
      @property = Account.new(@project, @val[1], @val[2], @property)
      @property.sourceFileInfo = @sourceFileInfo[0]
      @property.inheritAttributes
      @scenarioIdx = 0
    })
    arg(2, 'name', 'A name or short description of the account')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 94
  def rule_accountId
    pattern(%w( $ID ), lambda {
      id = @val[0]
      id = @accountprefix + '.' + id unless @accountprefix.empty?
      # In case we have a nested supplement, we need to prepend the parent ID.
      id = @property.fullId + '.' + id if @property && @property.is_a?(Account)
      if (account = @project.account(id)).nil?
        error('unknown_account', "Unknown account #{id}", @sourceFileInfo[0])
      end
      account
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 107
  def rule_accountReport
    pattern(%w( !accountReportHeader !reportBody ), lambda {
      @property = @property.parent
    })
    level(:beta)
    doc('accountreport', "The report lists accounts and their respective values in a table. The report\ncan operate in two modes:\n\n# Balance mode: If a [[balance]] has been set, the report will include the\ndefined cost and revenue accounts as well as all their sub accounts. To reduce\nthe list of included accounts, you can use the [[hideaccount]],\n[[rollupaccount]] or [[accountroot]] attributes. The order of the task can\nbe controlled with [[sortaccounts]]. If the first sorting criteria is tree\nsorting, the parent accounts will always be included to form the tree.\nTree sorting is the default. You need to change it if you do not want certain\nparent accounts to be included in the report. Additionally, it will contain a line at the end that lists the balance (revenue - cost).\n\n# Normal mode: All reports are listed in the order and completeness as defined\nby the other report attributes. No balance line will be included.\n"
       )
    example('AccountReport')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 133
  def rule_accountReportHeader
    pattern(%w( _accountreport !optionalID !reportName ), lambda {
      newReport(@val[1], @val[2], :accountreport, @sourceFileInfo[0])

      unless @property.modified?('columns')
        # Set the default columns for this report.
        %w( bsi name monthly ).each do |col|
          @property.get('columns') <<
          TableColumnDefinition.new(col, columnTitle(col))
        end
      end
      # Show all accounts, sorted by tree, seqno-up.
      unless @property.modified?('hideAccount')
        @property.set('hideAccount',
                      LogicalExpression.new(LogicalOperation.new(0)))
      end
      unless @property.modified?('sortAccounts')
        @property.set('sortAccounts',
                      [ [ 'tree', true, -1 ],
                        [ 'seqno', true, -1 ] ])
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 157
  def rule_accountScenarioAttributes
    pattern(%w( _aggregate !aggregate ), lambda {
      @property.set('aggregate', @val[1])
    })
    doc('aggregate', "Specifies whether the account is used to track task or resource specific\namounts. The default is to track tasks.\n"
       )
    example('AccountReport')

    pattern(%w( _credits !accountCredits ), lambda {
      begin
        @property['credits', @scenarioIdx] += @val[1]
      rescue AttributeOverwrite
        # Adding multiple credits for an account is a pretty common idiom.
      end
    })
    doc('credits', "Book the specified amounts to the account at the specified date. The\ndesciptions are just used for documentary purposes.\n"
       )
    example('Account', '1')

    pattern(%w( !flags ))
    doc('flags.account', "Attach a set of flags. The flags can be used in logical expressions to filter\nproperties from the reports.\n"
       )

    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 195
  def rule_aggregate
    pattern(%w( _resources ), lambda {
      :resources
    })
    descr('Aggregate resources')

    pattern(%w( _tasks ), lambda {
      :tasks
    })
    descr('Aggregate tasks')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 207
  def rule_alertLevel
    pattern(%w( $ID ), lambda {
      level = @project['alertLevels'].indexById(@val[0])
      unless level
        levels = @project['alertLevels'].map { |l| l.id }
        error('bad_alert', "Unknown alert level #{@val[0]}. Must be " +
              "one of #{levels.join(', ')}", @sourceFileInfo[0])
      end
      level
    })
    arg(0, 'alert level', "By default supported values are ''''green'''', ''''yellow'''' and ''''red''''.\nThe default value is ''''green''''. You can define your own levels with\n[[alertlevels]].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 226
  def rule_alertLevelDefinition
    pattern(%w( $ID $STRING !color ), lambda {
      [ @val[0], @val[1], @val[2] ]
    })
    arg(0, 'ID', "A unique ID for the alert level")
    arg(1, 'color name', 'A unique name of the alert level color')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 234
  def rule_alertLevelDefinitions
    listRule('moreAlertLevelDefinitions', '!alertLevelDefinition')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 434
  def rule_allOrNone
    pattern(%w( _all ), lambda {
      1
    })
    pattern(%w( _none ), lambda {
      0
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 238
  def rule_allocate
    pattern(%w( _allocate !allocations ), lambda {
      checkContainer('allocate')
      # Don't use << operator here so the 'provided' flag gets set properly.
      begin
        @property['allocate', @scenarioIdx] =
          @property['allocate', @scenarioIdx] + @val[1]
      rescue AttributeOverwrite
        # Adding multiple allocates for a task is a pretty common idiom.
      end
    })
    doc('allocate', "Specify which resources should be allocated to the task. The\nattributes provide numerous ways to control which resource is used and when\nexactly it will be assigned to the task. Shifts and limits can be used to\nrestrict the allocation to certain time intervals or to limit them to a\ncertain maximum per time period. The purge statement can be used to remove\ninherited allocations or flags.\n"
       )
    example('Allocate-1', '1')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 422
  def rule_allocateShiftAssignments
    pattern(%w( _shift ), lambda {
      @shiftAssignments = @allocate.shifts
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 428
  def rule_allocateShiftsAssignments
    pattern(%w( _shifts ), lambda {
      @shiftAssignments = @allocate.shifts
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 262
  def rule_allocation
    pattern(%w( !allocationHeader !allocationBody ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 268
  def rule_allocationAttributes
    optional
    repeatable

    pattern(%w( _alternative !resourceId !moreAlternatives ), lambda {
      ([ @val[1] ] + (@val[2] ? @val[2] : [])).each do |candidate|
        @allocate.addCandidate(candidate)
      end
    })
    doc('alternative', "Specify which resources should be allocated to the task. The optional\nattributes provide numerous ways to control which resource is used and when\nexactly it will be assigned to the task. Shifts and limits can be used to\nrestrict the allocation to certain time intervals or to limit them to a\ncertain maximum per time period.\n"
       )
    example('Alternative', '1')

    pattern(%w( !limits ), lambda {
      limits = @property['limits', @scenarioIdx] = @val[0]
      @allocate.candidates.each do |resource|
         limits.limits.each do |l|
           l.resource = resource if resource.leaf?
         end
      end
    })
    level(:removed)
    doc('limits.allocate', '')

    pattern(%w( _select !allocationSelectionMode ), lambda {
      @allocate.setSelectionMode(@val[1])
    })
    doc('select', "The select functions controls which resource is picked from an allocation and\nit's alternatives. The selection is re-evaluated each time the resource used\nin the previous time slot becomes unavailable.\n\nEven for non-persistent allocations a change in the resource selection only\nhappens if the resource used in the previous (or next for ASAP tasks) time\nslot has become unavailable.\n"
       )

    pattern(%w( _persistent ), lambda {
      @allocate.persistent = true
    })
    doc('persistent', "Specifies that once a resource is picked from the list of alternatives this\nresource is used for the whole task. This is useful when several alternative\nresources have been specified. Normally the selected resource can change after\neach break. A break is an interval of at least one timeslot where no resources\nwere available.\n"
       )

    pattern(%w( _mandatory ), lambda {
      @allocate.mandatory = true
    })
    doc('mandatory', "Makes a resource allocation mandatory. This means, that for each time slot\nonly then resources are allocated when all mandatory resources are available.\nSo either all mandatory resources can be allocated for the time slot, or no\nresource will be allocated.\n"
       )
    pattern(%w( !allocateShiftAssignments !shiftAssignment ), lambda {
      begin
        @allocate.shifts = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    level(:deprecated)
    also('shifts.allocate')
    doc('shift.allocate', "Limits the allocations of resources during the specified interval to the\nspecified shift. Multiple shifts can be defined, but shift intervals may not\noverlap. Allocation shifts are an additional restriction to the\n[[shifts.task|task shifts]] and [[shifts.resource|resource shifts]] or\n[[workinghours.resource|resource working hours]]. Allocations will only be\nmade for time slots that are specified as duty time in all relevant shifts.\nThe restriction to the shift is only active during the specified time\ninterval. Outside of this interval, no restrictions apply.\n"
       )

    pattern(%w( !allocateShiftsAssignments !shiftAssignments ), lambda {
      begin
        @allocate.shifts = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    doc('shifts.allocate', "Limits the allocations of resources during the specified interval to the\nspecified shift. Multiple shifts can be defined, but shift intervals may not\noverlap. Allocation shifts are an additional restriction to the\n[[shifts.task|task shifts]] and [[shifts.resource|resource shifts]] or\n[[workinghours.resource|resource working hours]]. Allocations will only be\nmade for time slots that are specified as duty time in all relevant shifts.\nThe restriction to the shift is only active during the specified time\ninterval. Outside of this interval, no restrictions apply.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 385
  def rule_allocationBody
    optionsRule('allocationAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 389
  def rule_allocationHeader
    pattern(%w( !resourceId ), lambda {
      @allocate = Allocation.new([ @val[0] ])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 399
  def rule_allocationSelectionMode
    singlePattern('_maxloaded')
    descr('Pick the available resource that has been used the most so far.')

    singlePattern('_minloaded')
    descr('Pick the available resource that has been used the least so far.')

    singlePattern('_minallocated')
    descr("Pick the resource that has the smallest allocation factor. The\nallocation factor is calculated from the various allocations of the resource\nacross the tasks. This is the default setting.)\n"
         )

    singlePattern('_order')
    descr('Pick the first available resource from the list.')

    singlePattern('_random')
    descr('Pick a random resource from the list.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 395
  def rule_allocations
    listRule('moreAllocations', '!allocation')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 443
  def rule_argument
    singlePattern('$ABSOLUTE_ID')
    singlePattern('!date')
    singlePattern('$ID')
    singlePattern('$INTEGER')
    singlePattern('$FLOAT')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 451
  def rule_argumentList
    optional
    pattern(%w( _( !argumentListBody _) ), lambda {
      @val[1].nil? ? [] : @val[1]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 458
  def rule_argumentListBody
    optional
    pattern(%w( !argument !moreArguments ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 465
  def rule_author
    pattern(%w( _author !resourceId ), lambda {
      @journalEntry.author = @val[1]
    })
    doc('author', "This attribute can be used to capture the authorship or source of the\ninformation.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 477
  def rule_balance
    pattern(%w( _balance !balanceAccounts ), lambda {
      @val[1]
    })
    doc('balance', "During report generation, TaskJuggler can consider some accounts to be revenue accounts, while other can be considered cost accounts. By using the balance attribute, two top-level accounts can be designated for a profit-loss-analysis. This analysis includes all sub accounts of these two top-level accounts.\n\nTo clear a previously set balance, just use a ''''-''''.\n"
       )
    example('AccountReport')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 491
  def rule_balanceAccounts
    pattern(%w( !accountId !accountId ), lambda {
      if @val[0].parent
        error('cost_acct_no_top',
              "The cost account #{@val[0].fullId} is not a top-level account.",
              @sourceFileInfo[0])
      end
      if @val[1].parent
        error('rev_acct_no_top',
              "The revenue account #{@val[1].fullId} is not a top-level " +
              "account.", @sourceFileInfo[1])
      end
      if @val[0] == @val[1]
        error('cost_rev_same',
              'The cost and revenue accounts may not be the same.',
              @sourceFileInfo[0])
      end
      [ @val[0], @val[1] ]
    })
    arg(0, 'cost account', "The top-level account that is used for all cost related charges.\n"
       )
    arg(2, 'revenue account', "The top-level account that is used for all revenue related charges.\n"
       )

    pattern([ '_-' ], lambda {
      [ nil, nil ]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 526
  def rule_bookingAttributes
    optional
    repeatable

    pattern(%w( _overtime $INTEGER ), lambda {
      if @val[1] < 0 || @val[1] > 2
        error('overtime_range',
              "Overtime value #{@val[1]} out of range (0 - 2).",
              @sourceFileInfo[1], @property)
      end
      @booking.overtime = @val[1]
    })
    doc('overtime.booking', "This attribute enables bookings during off-hours and leaves. It implicitly\nsets the [[sloppy.booking|sloppy]] attribute accordingly.\n"
       )
    arg(1, 'value', "* '''0''': You can only book available working time. (Default)\n\n* '''1''': You can book off-hours as well.\n\n* '''2''': You can book working time, off-hours and vacation time.\n"
       )

    pattern(%w( _sloppy $INTEGER ), lambda {
      if @val[1] < 0 || @val[1] > 2
        error('sloppy_range',
              "Sloppyness value #{@val[1]} out of range (0 - 2).",
              @sourceFileInfo[1], @property)
      end
      @booking.sloppy = @val[1]
    })
    doc('sloppy.booking', "Controls how strict TaskJuggler checks booking intervals for conflicts with\nworking periods and leaves. This attribute only affects the check for\nconflicts. No assignments will be made unless the [[overtime.booking|\novertime]] attribute is set accordingly.\n"
       )
    arg(1, 'sloppyness', "* '''0''': Period may not contain any off-duty hours, vacation or other task\nassignments. (default)\n\n* '''1''': Period may contain off-duty hours, but no vacation time or other\ntask assignments.\n\n* '''2''': Period may contain off-duty hours and vacation time, but no other\ntask assignments.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 584
  def rule_bookingBody
    optionsRule('bookingAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 588
  def rule_calendarDuration
    pattern(%w( !number !durationUnit ), lambda {
      convFactors = [ 60.0, # minutes
                      60.0 * 60, # hours
                      60.0 * 60 * 24, # days
                      60.0 * 60 * 24 * 7, # weeks
                      60.0 * 60 * 24 * 30.4167, # months
                      60.0 * 60 * 24 * 365 # years
                     ]
      ((@val[0] * convFactors[@val[1]]) / @project['scheduleGranularity']).to_i
    })
    arg(0, 'value', 'A floating point or integer number')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 642
  def rule_chargeMode
    singlePattern('_onstart')
    descr('Charge the amount on starting the task.')

    singlePattern('_onend')
    descr('Charge the amount on finishing the task.')

    singlePattern('_perhour')
    descr('Charge the amount for every hour the task lasts.')

    singlePattern('_perday')
    descr('Charge the amount for every day the task lasts.')

    singlePattern('_perweek')
    descr('Charge the amount for every week the task lasts.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 659
  def rule_chargeSetItem
    pattern(%w( !accountId !optionalPercent ), lambda {
      if @property.is_a?(Task)
        aggregate = :tasks
      elsif @property.is_a?(Resource)
        aggregate = :resources
      else
        raise "Unknown property type #{@property.class}"
      end

      if @val[0].get('aggregate') != aggregate
        error('account_bad_aggregate',
              "The account #{@val[0].fullId} cannot aggregate amounts " +
              "related to #{aggregate}.")
      end

      [ @val[0], @val[1] ]
    })
    arg(0, 'account', 'The ID of a previously defined leaf account.')
    arg(1, 'share', 'A percentage between 0 and 100%')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 602
  def rule_chargeset
    pattern(%w( _chargeset !chargeSetItem !moreChargeSetItems ), lambda {
      checkContainer('chargeset')
      items = [ @val[1] ]
      items += @val[2] if @val[2]
      chargeSet = ChargeSet.new
      begin
        items.each do |item|
          chargeSet.addAccount(item[0], item[1])
        end
        chargeSet.complete
      rescue TjException
        error('chargeset', $!.message, @sourceFileInfo[0], @property)
      end
      masterAccounts = []
      @property['chargeset', @scenarioIdx].each do |set|
        masterAccounts << set.master
      end
      if masterAccounts.include?(chargeSet.master)
        error('chargeset_master',
              "All charge sets for this property must have different " +
              "top-level accounts.", @sourceFileInfo[0], @property)
      end
      @property['chargeset', @scenarioIdx] =
        @property['chargeset', @scenarioIdx] + [ chargeSet ]
    })
    doc('chargeset', "A chargeset defines how the turnover associated with the property will be\ncharged to one or more accounts. A property may have any number of charge sets,\nbut each chargeset must deal with a different top-level account. A charge set\nconsists of one or more accounts. Each account must be a leaf account. The\naccount ID may be followed by a percentage value that determines the share for\nthis account. The total percentage of all accounts must be exactly 100%. If\nsome accounts don't have a percentage specification, the remainder to 100% is\ndistributed evenly to them.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 681
  def rule_chartScale
    singlePattern('_hour')
    descr('Set chart resolution to 1 hour.')

    singlePattern('_day')
    descr('Set chart resolution to 1 day.')

    singlePattern('_week')
    descr('Set chart resolution to 1 week.')

    singlePattern('_month')
    descr('Set chart resolution to 1 month.')

    singlePattern('_quarter')
    descr('Set chart resolution to 1 quarter.')

    singlePattern('_year')
    descr('Set chart resolution to 1 year.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 701
  def rule_color
    pattern(%w( $STRING ), lambda {
      col = @val[0]
      unless /#[0-9A-Fa-f]{3}/ =~ col || /#[0-9A-Fa-f]{3}/ =~ col
        error('bad_color',
              "Color values must be specified as '#RGB' or '#RRGGBB' values",
              @sourceFileInfo[0])
      end
      col
    })
    arg(0, 'color', "The RGB color values of the color. The following formats are supported: #RGB\nand #RRGGBB. Where R, G, B are hexadecimal values. See\n[http://en.wikipedia.org/wiki/Web_colors Wikipedia] for more details.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 720
  def rule_columnBody
    optionsRule('columnOptions')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 724
  def rule_columnDef
    pattern(%w( !columnId !columnBody ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 730
  def rule_columnId
    pattern(%w( !reportableAttributes ), lambda {
      @column = TableColumnDefinition.new(@val[0], columnTitle(@val[0]))
    })
    doc('columnid', "This is a comprehensive list of all pre-defined [[columns]]. In addition to\nthe listed IDs all user defined attributes can be used as column IDs.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 742
  def rule_columnOptions
    optional
    repeatable

    pattern(%w( _celltext !logicalExpression $STRING ), lambda {
      @column.cellText.addPattern(
        CellSettingPattern.new(newRichText(@val[2], @sourceFileInfo[2]),
                               @val[1]))
    })
    doc('celltext.column', "Specifies an alternative content that is used for the cells of the column.\nUsually such a text contains a query function. Otherwise all cells of the\ncolumn will have the same fixed value. The logical expression specifies for\nwhich cells the text should be used. If multiple celltext patterns are\nprovided for a column, the first matching one is taken for each cell.\n"
        )
    arg(1, 'text',
        'Alterntive cell text specified as [[Rich_Text_Attributes|Rich Text]]')

    pattern(%w( _cellcolor !logicalExpression !color ), lambda {
      @column.cellColor.addPattern(
        CellSettingPattern.new(@val[2], @val[1]))
    })
    doc('cellcolor.column', "Specifies an alternative background color for the cells of this column. The\nlogical expression specifies for which cells the color should be used. If\nmultiple cellcolor patterns are provided for a column, the first\nmatching one is used for each cell.\n"
       )

    pattern(%w( _end !date ), lambda {
      @column.end = @val[1]
    })
    doc('end.column', "Normally, columns with calculated values take the specified report period into\naccount when calculating their values. With this attribute, the user can\nspecify an end date for the period that should be used when calculating the\nvalues of this column. It does not have an impact on column with time\ninvariant values.\n"
       )

    pattern(%w( _fontcolor !logicalExpression !color ), lambda {
      @column.fontColor.addPattern(
        CellSettingPattern.new(@val[2], @val[1]))
    })
    doc('fontcolor.column', "Specifies an alternative font color for the cells of this column. The\nlogical expression specifies for which cells the color should be used. If\nmultiple fontcolor patterns are provided for a column, the first\nmatching one is used for each cell.\n"
       )

    pattern(%w( _halign !logicalExpression !hAlignment ), lambda {
      @column.hAlign.addPattern(
        CellSettingPattern.new(@val[2], @val[1]))
    })
    doc('halign.column', "Specifies the horizontal alignment of the cell content. The logical expression\nspecifies for which cells the alignment setting should be used. If multiple\nhalign patterns are provided for a column, the first matching one is used for\neach cell.\n"
       )

    pattern(%w( _listitem $STRING ), lambda {
      @column.listItem = @val[1]
    })
    doc('listitem.column', "Specifies a RichText pattern that is used to generate the text for the list\nitems. The pattern should contain at least one ''''<nowiki><</nowiki>-query\nattribute='XXX'->'''' element that will be replaced with the value of\nattribute XXX. For the replacement, the property of the query will be the list\nitem.\n"
       )

    pattern(%w( _listtype !listType ), lambda {
      @column.listType = @val[1]
    })
    also(%w( listitem.column ))
    doc('listtype.column', "Specifies what type of list should be used. This attribute only affects\ncolumns that contain a list of items.\n"
       )

    pattern(%w( _period !interval ), lambda {
      @column.start = @val[1].start
      @column.end = @val[1].end
    })
    doc('period.column', "This property is a shortcut for setting the [[start.column|start]] and\n[[end.column|end]] property at the same time.\n"
       )

    pattern(%w( _scale !chartScale ), lambda {
      @column.scale = @val[1]
    })
    doc('scale.column', "Specifies the scale that should be used for a chart column. This value is ignored for all other columns.\n"
       )

    pattern(%w( _start !date ), lambda {
      @column.start = @val[1]
    })
    doc('start.column', "Normally, columns with calculated values take the specified report period into\naccount when calculating their values. With this attribute, the user can\nspecify a start date for the period that should be used when calculating the\nvalues of this column. It does not have an impact on column with time\ninvariant values.\n"
       )

    pattern(%w( _title $STRING ), lambda {
      @column.title = @val[1]
    })
    doc('title.column', "Specifies an alternative title for a report column.\n"
       )
    arg(1, 'text', 'The new column title.')

    pattern(%w( _tooltip !logicalExpression $STRING ), lambda {
      @column.tooltip.addPattern(
        CellSettingPattern.new(newRichText(@val[2], @sourceFileInfo[2]),
                               @val[1]))
    })
    doc('tooltip.column', "Specifies an alternative content for the tooltip. This will replace the\noriginal content of the tooltip that would be available for columns with text\nthat does not fit the column with.  The logical expression specifies for which\ncells the text should be used. If multiple tooltip patterns are provided for a\ncolumn, the first matching one is taken for each cell.\n"
       )
    arg(2, 'text', "The content of the tooltip. The text is interpreted as [[Rich_Text_Attributes|\nRich Text]].\n"
       )

    pattern(%w( _width !number ), lambda {
      @column.width = @val[1]
    })
    doc('width.column', "Specifies the width of the column in screen pixels. If the content of the\ncolumn does not fit into this width, it will be cut off. In some cases a\nscrollbar is added or a tooltip window with the complete content is shown when\nthe mouse is moved over the column. The latter is only supported in\ninteractive output formats.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 917
  def rule_currencyFormat
    pattern(%w( _currencyformat $STRING $STRING $STRING $STRING $INTEGER ),
        lambda {
      RealFormat.new(@val.slice(1, 5))
    })
    doc('currencyformat',
        'These values specify the default format used for all currency ' +
        'values.')
    example('Currencyformat')
    arg(1, 'negativeprefix', 'Prefix for negative numbers')
    arg(2, 'negativesuffix', 'Suffix for negative numbers')
    arg(3, 'thousandsep', 'Separator used for every 3rd digit')
    arg(4, 'fractionsep', 'Separator used to separate the fraction digits')
    arg(5, 'fractiondigits', 'Number of fraction digits to show')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 933
  def rule_date
    pattern(%w( !dateCalcedOrNot ), lambda {
      resolution = @project.nil? ? Project.maxScheduleGranularity :
                                   @project['scheduleGranularity']
      if @val[0] % resolution != 0
        error('misaligned_date',
              "The date must be aligned to the timing resolution (" +
              "#{resolution / 60} min) of the project.",
              @sourceFileInfo[0])
      end
      @val[0]
    })
    doc('date', "A DATE is date and time specification similar to the ISO 8601 date format.\nInstead of the hard to read ISO notation with a ''''T'''' between the date and\ntime sections, we simply use the more intuitive and easier to read dash:\n''''<nowiki>YYYY-MM-DD[-hh:mm[:ss]][-TIMEZONE]</nowiki>''''. Hour, minutes,\nseconds, and the ''''TIMEZONE'''' are optional. If not specified, the values\nare set to 0.  ''''TIMEZONE'''' must be an offset to GMT or UTC, specified as\n''''+HHMM'''' or ''''-HHMM''''. Dates must always be aligned with the\n[[timingresolution]].\n\nTaskJuggler also supports simple date calculations. You can add or substract a\ngiven interval from a fixed date.\n\n %{2009-11-01 + 8m}\n\nThis will result in an actual date of around 2009-07-01. Keep in mind that due\nto the varying lengths of months TaskJuggler cannot add exactly 8 calendar\nmonths. The date calculation functionality makes most sense when used with\nmacros.\n\n %{${now} - 2w}\n\nThis is result in a date 2 weeks earlier than the current (or specified) date.\nSee [[duration]] for a complete list of supported time intervals. Don't forget\nto put at least one space character after the date to prevent TaskJuggler from\ninterpreting the interval as an hour.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 976
  def rule_dateCalcedOrNot
    singlePattern('$DATE')
    pattern(%w( _% _{ $DATE !plusOrMinus !intervalDuration _} ), lambda {
      @val[2] + ((@val[3] == '+' ? 1 : -1) * @val[4])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 983
  def rule_declareFlagList
    listRule('moreDeclareFlagList', '$ID')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 987
  def rule_details
    pattern(%w( _details $STRING ), lambda {
      return if @val[1].empty?

      rtTokenSetMore =
        [ :LINEBREAK, :SPACE, :WORD, :BOLD, :ITALIC, :CODE, :BOLDITALIC,
          :PRE, :HREF, :HREFEND, :REF, :REFEND, :HLINE, :TITLE2, :TITLE3,
          :TITLE4, :TITLE2END, :TITLE3END, :TITLE4END,
          :BULLET1, :BULLET2, :BULLET3, :BULLET4, :NUMBER1, :NUMBER2, :NUMBER3,
          :NUMBER4 ]
      if @val[1] == "Some more details\n"
        error('ts_default_details',
              "'Some more details' is not a valid value",
              @sourceFileInfo[1])
      end
      @journalEntry.details = newRichText(@val[1], @sourceFileInfo[1],
                                          rtTokenSetMore)
    })
    doc('details', "This is a continuation of the [[summary]] of the journal or status entry. It\ncan be several paragraphs long.\n"
       )
    arg(1, 'text', "The text will be interpreted as [[Rich_Text_Attributes|Rich Text]]. Only a\nsubset of the markup is supported for this attribute. You can use word\nformatting, paragraphs, hyperlinks, lists, section and subsection\nheaders.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1021
  def rule_durationUnit
    pattern(%w( _min ), lambda { 0 })
    descr('minutes')

    pattern(%w( _h ), lambda { 1 })
    descr('hours')

    pattern(%w( _d ), lambda { 2 })
    descr('days')

    pattern(%w( _w ), lambda { 3 })
    descr('weeks')

    pattern(%w( _m ), lambda { 4 })
    descr('months')

    pattern(%w( _y ), lambda { 5 })
    descr('years')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1041
  def rule_durationUnitOrPercent
    pattern(%w( _% ), lambda { -1 })
    descr('percentage of reported period')

    pattern(%w( _min ), lambda { 0 })
    descr('minutes')

    pattern(%w( _h ), lambda { 1 })
    descr('hours')

    pattern(%w( _d ), lambda { 2 })
    descr('days')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1055
  def rule_export
    pattern(%w( !exportHeader !exportBody ), lambda {
      @property = nil
    })
    doc('export', "The export report looks like a regular TaskJuggler file with the provided\ninput data complemented by the results of the scheduling process. The content\nof the report can be controlled with the [[definitions]] attribute. In case\nthe file contains the project header, a ''''.tjp'''' extension is added to the\nfile name. Otherwise, a ''''.tji'''' extension is used.\n\nThe [[resourceattributes]] and [[taskattributes]] attributes provide even more\ncontrol over the content of the file.\n\nThe export report can be used to share certain tasks or milestones with other\nprojects or to save past resource allocations as immutable part for future\nscheduling runs. When an export report is included the project IDs of the\nincluded tasks must be declared first with the project id property.\n"
       )
    example('Export')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1104
  def rule_exportAttributes
    optional
    repeatable

    pattern(%w( _definitions !exportDefinitions ), lambda {
      @property.set('definitions', @val[1])
    })
    doc('definitions', "This attributes controls what definitions will be contained in the report. If\nthe list includes ''project'', the generated file will have a ''''.tjp''''\nextension. Otherwise it will have a ''''.tji'''' extension.\n\nBy default, the report contains everything and the generated files has a ''''.tjp'''' extension.\n"
       )
    allOrNothingListRule('exportDefinitions',
                         { 'flags' => 'Include flag definitions',
                           'project' => 'Include project header',
                           'projecids' => 'Include project IDs',
                           'tasks' => 'Include task definitions',
                           'resources' => 'Include resource definitions' })
    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))
    pattern(%w( !reportEnd ))
    pattern(%w( !reportPeriod ))
    pattern(%w( !reportStart ))

    pattern(%w( _resourceattributes !exportableResourceAttributes ), lambda {
      @property.set('resourceAttributes', @val[1])
    })
    doc('resourceattributes', "Define a list of resource attributes that should be included in the report.\n"
       )
    allOrNothingListRule('exportableResourceAttributes',
                         { 'booking' => 'Include bookings',
                           'leaves' => 'Include leaves',
                           'workinghours' => 'Include working hours' })

    pattern(%w( !rollupresource ))
    pattern(%w( !rolluptask ))

    pattern(%w( _scenarios !scenarioIdList ), lambda {
      # Don't include disabled scenarios in the report
      @val[1].delete_if { |sc| !@project.scenario(sc).get('active') }
      @property.set('scenarios', @val[1])
    })
    doc('scenarios.export', "List of scenarios that should be included in the report. By default, all\nscenarios will be included. This attribute can be used to limit the included\nscenarios to a defined list.\n"
       )

    pattern(%w( _taskattributes !exportableTaskAttributes ), lambda {
      @property.set('taskAttributes', @val[1])
    })
    doc('taskattributes', "Define a list of task attributes that should be included in the report.\n"
       )
    allOrNothingListRule('exportableTaskAttributes',
                         { 'booking' => 'Include bookings',
                           'complete' => 'Include completion values',
                           'depends' => 'Include dependencies',
                           'flags' => 'Include flags',
                           'maxend' => 'Include maximum end dates',
                           'maxstart' => 'Include maximum start dates',
                           'minend' =>  'Include minimum end dates',
                           'minstart' => 'Include minimum start dates',
                           'note' => 'Include notes',
                           'priority' => 'Include priorities',
                           'responsible' => 'Include responsible resource' })

    pattern(%w( _timezone !validTimeZone ), lambda {
      @property.set('timezone', @val[1])
    })
    doc('timezone.export',
        "Set the time zone to be used for all dates in the report.")
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1189
  def rule_exportBody
    optionsRule('exportAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1079
  def rule_exportHeader
    pattern(%w( _export !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :export, @sourceFileInfo[0])
      @property.set('formats', [ :tjp ])

      # By default, we export all scenarios.
      scenarios = Array.new(@project.scenarios.items) { |i| i }
      scenarios.delete_if { |sc| !@project.scenario(sc).get('active') }
      @property.set('scenarios', scenarios)
      # Show all tasks, sorted by seqno-up.
      @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
      # Show all resources, sorted by seqno-up.
      @property.set('hideResource',
                    LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
    })
    arg(2, 'file name', "The name of the report file to generate. It must end with a .tjp or .tji\nextension, or use . to use the standard output channel.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1193
  def rule_extendAttributes
    optional
    repeatable

    pattern(%w( _date !extendId  $STRING !extendOptionsBody ), lambda {
      # Extend the propertySet definition and parser rules
      if extendPropertySetDefinition(DateAttribute, nil)
        @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '!date' ], lambda {
            @property[@val[0], @scenarioIdx] = @val[1]
          }))
      else
        @ruleToExtend.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '!date' ], lambda {
            @property.set(@val[0], @val[1])
          }))
      end
    })
    doc('date.extend', "Extend the property with a new attribute of type date.\n"
       )
    arg(2, 'name', 'The name of the new attribute. It is used as header ' +
                   'in report columns and the like.')

    pattern(%w( _reference !extendId $STRING !extendOptionsBody ), lambda {
      # Extend the propertySet definition and parser rules
      if extendPropertySetDefinition(ReferenceAttribute, nil)
        @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda {
            @property[@val[0], @scenarioIdx] = [ @val[1], @val[2] ]
          }))
      else
        @ruleToExtend.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING', '!referenceBody' ], lambda {
            @property.set(@val[0], [ @val[1], @val[2] ])
          }))
      end
    })
    doc('reference.extend', "Extend the property with a new attribute of type reference. A reference is a\nURL and an optional text that will be shown instead of the URL if needed.\n"
       )
    arg(2, 'name', 'The name of the new attribute. It is used as header ' +
                   'in report columns and the like.')

    pattern(%w( _richtext !extendId $STRING !extendOptionsBody ), lambda {
      # Extend the propertySet definition and parser rules
      if extendPropertySetDefinition(RichTextAttribute, nil)
        @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING' ], lambda {
            @property[@val[0], @scenarioIdx] =
              newRichText(@val[1], @sourceFileInfo[1])
          }))
      else
        @ruleToExtend.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING' ], lambda {
            @property.set(@val[0], newRichText(@val[1], @sourceFileInfo[1]))
          }))
      end
    })
    doc('richtext.extend', "Extend the property with a new attribute of type [[Rich_Text_Attributes|Rich\nText]].\n"
       )
    arg(2, 'name', 'The name of the new attribute. It is used as header ' +
                   'in report columns and the like.')

    pattern(%w( _text !extendId $STRING !extendOptionsBody ), lambda {
      # Extend the propertySet definition and parser rules
      if extendPropertySetDefinition(StringAttribute, nil)
        @ruleToExtendWithScenario.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING' ], lambda {
            @property[@val[0], @scenarioIdx] = @val[1]
          }))
      else
        @ruleToExtend.addPattern(TextParser::Pattern.new(
          [ '_' + @val[1], '$STRING' ], lambda {
            @property.set(@val[0], @val[1])
          }))
      end
    })
    doc('text.extend', "Extend the property with a new attribute of type text. A text is a character\nsequence enclosed in single or double quotes.\n"
       )
    arg(2, 'name', 'The name of the new attribute. It is used as header ' +
                   'in report columns and the like.')

  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1291
  def rule_extendBody
    optionsRule('extendAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1295
  def rule_extendId
    pattern(%w( $ID ), lambda {
      unless (?A..?Z) === @val[0][0]
        error('extend_id_cap',
              "User defined attributes IDs must start with a capital letter",
              @sourceFileInfo[0])
      end
      @val[0]
    })
    arg(0, 'id', 'The ID of the new attribute. It can be used like the ' +
                 'built-in IDs.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1308
  def rule_extendOptions
    optional
    repeatable

    singlePattern('_inherit')
    doc('inherit.extend', "If the this attribute is used, the property extension will be inherited by\nchild properties from their parent property.\n"
       )

    singlePattern('_scenariospecific')
    doc('scenariospecific.extend', "If this attribute is used, the property extension is scenario specific. A\ndifferent value can be set for each scenario.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1329
  def rule_extendOptionsBody
    optionsRule('extendOptions')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1333
  def rule_extendProperty
    pattern(%w( !extendPropertyId ), lambda {
      case @val[0]
      when 'task'
        @ruleToExtend = @rules[:taskAttributes]
        @ruleToExtendWithScenario = @rules[:taskScenarioAttributes]
        @propertySet = @project.tasks
      when 'resource'
        @ruleToExtend = @rules[:resourceAttributes]
        @ruleToExtendWithScenario = @rules[:resourceScenarioAttributes]
        @propertySet = @project.resources
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1348
  def rule_extendPropertyId
    singlePattern('_task')
    singlePattern('_resource')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1353
  def rule_fail
    pattern(%w( _fail !logicalExpression ), lambda {
      begin
        @property.set('fail', @property.get('fail') + [ @val[1] ])
      rescue AttributeOverwrite
      end
    })
    doc('fail', "The fail attribute adds a logical expression to the property. The condition\ndescribed by the logical expression is checked after the scheduling and an\nerror is raised if the condition evaluates to true. This attribute is\nprimarily intended for testing purposes.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1370
  def rule_flag
    pattern(%w( $ID ), lambda {
      unless @project['flags'].include?(@val[0])
        error('undecl_flag', "Undeclared flag '#{@val[0]}'",
              @sourceFileInfo[0])
      end
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1491
  def rule_flagList
    listRule('moreFlagList', '!flag')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1380
  def rule_flagLogicalExpression
    pattern(%w( !flagOperation ), lambda {
      LogicalExpression.new(@val[0], sourceFileInfo)
    })
    doc('logicalflagexpression', "A logical flag expression is a combination of operands and mathematical\noperations.  The final result of a logical expression is always true or false.\nLogical expressions are used the reduce the properties in a report to a\ncertain subset or to select alternatives for the cell content of a table. When\nused with attributes like [[hidejournalentry]] the logical expression\nevaluates to true for a certain property, this property is hidden or rolled-up\nin the report.\n\nOperands must be previously declared flags or another logical expression.\nWhen you combine logical operations to a more complex expression, the\noperators are evaluated from left to right. '''a | b & c''' is identical to\n'''(a | b) & c'''. It's highly recommended that you always use brackets to\ncontrol the evaluation sequence. Currently, TaskJuggler does not support the\nconcept of operator precedence or right-left associativity. This may change in\nthe future.\n"
       )
    also(%w( functions ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1406
  def rule_flagOperand
    pattern(%w( _( !flagOperation _) ), lambda {
      @val[1]
    })
    pattern(%w( _~ !flagOperand ), lambda {
      operation = LogicalOperation.new(@val[1])
      operation.operator = '~'
      operation
    })

    pattern(%w( $ID ), lambda {
      unless @project['flags'].include?(@val[0])
        error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'",
              @sourceFileInfo[0])
      end
      LogicalFlag.new(@val[0])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1425
  def rule_flagOperation
    pattern(%w( !flagOperand !flagOperationChain ), lambda {
      operation = LogicalOperation.new(@val[0])
      if @val[1]
        # Further operators/operands create an operation tree.
        @val[1].each do |ops|
          operation = LogicalOperation.new(operation)
          operation.operator = ops[0]
          operation.operand2 = ops[1]
        end
      end
      operation
    })
    arg(0, 'operand', "An operand is a declared flag. An operand can be a negated operand by\nprefixing a ~ charater or it can be another logical expression enclosed in\nbraces.\n"
        )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1447
  def rule_flagOperationChain
    optional
    repeatable
    pattern(%w( !flagOperatorAndOperand), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1468
  def rule_flagOperator
    singlePattern('_|')
    descr('The \'or\' operator')

    singlePattern('_&')
    descr('The \'and\' operator')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1455
  def rule_flagOperatorAndOperand
    pattern(%w( !flagOperator !flagOperand), lambda{
      [ @val[0], @val[1] ]
    })
    arg(1, 'operand', "An operand is a declared flag. An operand can be a negated operand by\nprefixing a ~ charater or it can be another logical expression enclosed in\nbraces.\n"
        )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1477
  def rule_flags
    pattern(%w( _flags !flagList ), lambda {
      @val[1].each do |flag|
        next if @property['flags', @scenarioIdx].include?(flag)

        # We allow multiple instances of flag definitions.
        begin
          @property['flags', @scenarioIdx] += [ flag ]
        rescue AttributeOverwrite
        end
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1495
  def rule_formats
    pattern(%w( _formats !outputFormats ), lambda {
      @property.set('formats', @val[1])
    })
    doc('formats', "This attribute defines for which output formats the report should be\ngenerated. By default, this list is empty. Unless a formats attribute was\nadded to a report definition, no output will be generated for this report.\n\nAs reports are composable, a report may include other report definitions. A\nformat definition is only needed for the outermost report that includes the\nothers.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1558
  def rule_functionPatterns
    # This rule is not used by the parser. It's only for the documentation.
    pattern(%w( _hasalert _( $INTEGER _, !date _) ))
    doc('hasalert', "Will evaluate to true if the current property has a current alert message within the report time frame and with at least the provided alert level.\n"
       )
    arg(2, 'Level', 'The minimum required alert level to be considered.')

    pattern(%w( _isactive _( $ID _) ))
    doc('isactive', "Will evaluate to true for tasks and resources if they have bookings in\nthe scenario during the report time frame.\n"
       )
    arg(2, 'ID', 'A scenario ID')

    pattern(%w( _ischildof _( $ID _) ))
    doc('ischildof', "Will evaluate to true for tasks and resources if current property is a child\nof the provided parent property.\n"
       )
    arg(2, 'ID', 'The ID of the parent')

    pattern(%w( _isdependencyof _( $ID _, $ID _, $INTEGER _) ))
    doc('isdependencyof', "Will evaluate to true for tasks that depend on the specified task in\nthe specified scenario and are no more than distance tasks away. If\ndistance is 0, all dependencies are considered independent of their\ndistance.\n"
       )
    arg(2, 'Task ID', 'The ID of a defined task')
    arg(4, 'Scenario ID', 'A scenario ID')
    arg(6, 'Distance', 'The maximum task distance to be considered')

    pattern(%w( _isdutyof _( $ID _, $ID _) ))
    doc('isdutyof', "Will evaluate to true for tasks that have the specified resource\nassigned to it in the specified scenario.\n"
       )
    arg(2, 'Resource ID', 'The ID of a defined resource')
    arg(4, 'Scenario ID', 'A scenario ID')

    pattern(%w( _isfeatureof _( $ID _, $ID _) ))
    doc('isfeatureof', "If the provided task or any of its sub-tasks depend on this task or any of its\nsub-tasks, we call this task a feature of the provided task.\n"
       )
    arg(2, 'Task ID', 'The ID of a defined task')
    arg(4, 'Scenario ID', 'A scenario ID')

    pattern(['_isleaf', '_(', '_)' ])
    doc('isleaf', 'The result is true if the property is not a container.')

    pattern(%w( _ismilestone _( $ID _) ))
    doc('ismilestone', "The result is true if the property is a milestone in the provided scenario.\n"
       )
    arg(2, 'Scenario ID', 'A scenario ID')

    pattern(%w( _isongoing _( $ID _) ))
    doc('isongoing', "Will evaluate to true for tasks that overlap with the report period in given\nscenario.\n"
       )
    arg(2, 'ID', 'A scenario ID')

    pattern(['_isresource', '_(', '_)' ])
    doc('isresource', 'The result is true if the property is a resource.')

    pattern(%w( _isresponsibilityof _( $ID _, $ID _) ))
    doc('isresponsibilityof', "Will evaluate to true for tasks that have the specified resource\nassigned as [[responsible]] in the specified scenario.\n"
       )
    arg(2, 'Resource ID', 'The ID of a defined resource')
    arg(4, 'Scenario ID', 'A scenario ID')

    pattern(['_istask', '_(', '_)' ])
    doc('istask', 'The result is true if the property is a task.')

    pattern(%w( _treelevel _( _) ))
    doc('treelevel', "Returns the nesting level of a property in the property tree.\nTop level properties have a level of 1, their children 2 and so on.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1512
  def rule_functions
    # This rule is not used by the parser. It's only for the documentation.
    pattern(%w( !functionsBody ))
    doc('functions', "The following functions are supported in logical expressions. These functions\nare evaluated in logical conditions such as hidetask or rollupresource. For\nthe evaluation, implicit and explicit parameters are used.\n\nAll functions may operate on the current property and the scope property. The\nscope property is the enclosing property in reports with nested properties.\nImagine e. g a task report with nested resources. When the function is called\nfor a task line, the task is the property and we don't have a scope property.\nWhen the function is called for a resource line, the resource is the property\nand the enclosing task is the scope property.\n\nThese number of arguments that are passed in brackets to the function depends\non the specific function. See the reference for details on each function.\n\nAll functions can be suffixed with an underscore character. In that case, the\nfunction is operating on the scope property as if it were the property. The\noriginal property is ignored in that case. In our task report example from\nabove, calling a function with an appended dash would mean that a task\nline would be evaluated for the enclosing resource.\n\nIn the example below you can see how this can be used. To generate a task\nreport that lists all assigned leaf resources for leaf task lines only we use\nthe expression\n\n hideresource ~(isleaf() & isleaf_())\n\nThe tilde in front of the bracketed expression means not that expression. In\nother words: show resources that are leaf resources and show them for leaf\ntasks only. The regular form isleaf() (without the appended underscore)\noperates on the resource. The isleaf_() variant operates on the\nenclosing task.\n"
       )
    example('LogicalFunction', '1')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1553
  def rule_functionsBody
    # This rule is not used by the parser. It's only for the documentation.
    optionsRule('functionPatterns')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1664
  def rule_hAlignment
    pattern(%w( _center ), lambda {
      :center
    })
    doc('halign.center', 'Center the cell content')

    pattern(%w( _left ), lambda {
      :left
    })
    doc('halign.left', 'Left align the cell content')

    pattern(%w( _right ), lambda {
      :right
    })
    doc('halign.right', 'Right align the cell content')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1681
  def rule_headline
    pattern(%w( _headline $STRING ), lambda {
      @property.set('headline', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('headline', "Specifies the headline for a report.\n"
       )
    arg(1, 'text', "The text used for the headline. It is interpreted as\n[[Rich_Text_Attributes|Rich Text]].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1698
  def rule_hideaccount
    pattern(%w( _hideaccount !logicalExpression ), lambda {
      @property.set('hideAccount', @val[1])
    })
    doc('hideaccount', "Do not include accounts that match the specified logical expression. If the\nreport is sorted in ''''tree'''' mode (default) then enclosing accounts are\nlisted even if the expression matches the account.\n"
       )
    also(%w( sortaccounts ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1712
  def rule_hidejournalentry
    pattern(%w( _hidejournalentry !flagLogicalExpression ), lambda {
      @property.set('hideJournalEntry', @val[1])
    })
    doc('hidejournalentry', "Do not include journal entries that match the specified logical expression.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1723
  def rule_hideresource
    pattern(%w( _hideresource !logicalExpression ), lambda {
      @property.set('hideResource', @val[1])
    })
    doc('hideresource', "Do not include resources that match the specified logical expression. If the\nreport is sorted in ''''tree'''' mode (default) then enclosing resources are\nlisted even if the expression matches the resource.\n"
       )
    also(%w( sortresources ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1737
  def rule_hidetask
    pattern(%w( _hidetask !logicalExpression ), lambda {
      @property.set('hideTask', @val[1])
    })
    doc('hidetask', "Do not include tasks that match the specified logical expression. If the\nreport is sorted in ''''tree'''' mode (default) then enclosing tasks are\nlisted even if the expression matches the task.\n"
       )
    also(%w( sorttasks ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1750
  def rule_iCalReport
    pattern(%w( !iCalReportHeader !iCalReportBody ), lambda {
      @property = nil
    })
    doc('icalreport', "Generates an RFC5545 compliant iCalendar file. This file can be used to export\ntask information to calendar applications or other tools that read iCalendar\nfiles.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1766
  def rule_iCalReportAttributes
    optional
    repeatable

    pattern(%w( !hideresource ))
    pattern(%w( !hidejournalentry ))
    pattern(%w( !hidetask ))
    pattern(%w( !reportEnd ))
    pattern(%w( !reportPeriod ))
    pattern(%w( !reportStart ))
    pattern(%w( !rollupresource ))
    pattern(%w( !rolluptask ))

    pattern(%w( _scenario !scenarioId ), lambda {
      # Don't include disabled scenarios in the report
      sc = @val[1]
      unless @project.scenario(sc).get('active')
        warning('ical_sc_disabled',
                "Scenario #{sc} has been disabled")
      else
        @property.set('scenarios', [ @val[1] ])
      end
    })
    doc('scenario.ical', "Id of the scenario that should be included in the report. By default, the\ntop-level scenario will be included. This attribute can be used select another\nscenario.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1762
  def rule_iCalReportBody
    optionsRule('iCalReportAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1798
  def rule_iCalReportHeader
    pattern(%w( _icalreport !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :iCal, @sourceFileInfo[0])
      @property.set('formats', [ :iCal ])

      # By default, we export only the first scenario.
      unless @project.scenario(0).get('active')
        @property.set('scenarios', [ 0 ])
      end
      # Show all tasks, sorted by seqno-up.
      @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
      # Show all resources, sorted by seqno-up.
      @property.set('hideResource',
                    LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
      # Show all journal entries.
      @property.set('hideJournalEntry',
                    LogicalExpression.new(LogicalOperation.new(0)))
    })
    arg(1, 'file name', "The name of the report file to generate without an extension.  Use . to use\nthe standard output channel.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1826
  def rule_idOrAbsoluteId
    singlePattern('$ID')
    singlePattern('$ABSOLUTE_ID')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1831
  def rule_includeAttributes
    optionsRule('includeAttributesBody')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1835
  def rule_includeAttributesBody
    optional
    repeatable

    pattern(%w( _accountprefix !accountId ), lambda {
      @accountprefix = @val[1].fullId
    })
    doc('accountprefix', "This attribute can be used to insert the accounts of the included file as\nsub-account of the account specified by ID. The parent account must already be\ndefined.\n"
    )
    arg(1, 'account ID', 'The absolute ID of an already defined account')

    pattern(%w( _reportprefix !reportId ), lambda {
      @reportprefix = @val[1].fullId
    })
    doc('reportprefix', "This attribute can be used to insert the reports of the included file as\nsub-report of the report specified by ID. The parent report must already\nbe defined.\n"
    )
    arg(1, 'report ID', 'The absolute ID of an already defined report.')

    pattern(%w( _resourceprefix !resourceId ), lambda {
      @resourceprefix = @val[1].fullId
    })
    doc('resourceprefix', "This attribute can be used to insert the resources of the included file as\nsub-resource of the resource specified by ID. The parent resource must already\nbe defined.\n"
    )
    arg(1, 'resource ID', 'The ID of an already defined resource')

    pattern(%w( _taskprefix !taskId ), lambda {
      @taskprefix = @val[1].fullId
    })
    doc('taskprefix', "This attribute can be used to insert the tasks of the included file as\nsub-task of the task specified by ID. The parent task must already be defined.\n"
    )
    arg(1, 'task ID', 'The absolute ID of an already defined task.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1887
  def rule_includeFile
    pattern(%w( !includeFileName ), lambda {
      unless @project
        error('include_before_project',
              "You must declare the project header before you include other " +
              "files.")
      end
      @project.inputFiles << @scanner.include(@val[0], @sourceFileInfo[0]) do
        popFileStack
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1900
  def rule_includeFileName
    pattern(%w( $STRING ), lambda {
      unless @val[0][-4, 4] == '.tji'
        error('bad_include_suffix', "Included files must have a '.tji'" +
                                    "extension: '#{@val[0]}'",
              @sourceFileInfo[0])
      end
      pushFileStack
      @val[0]
    })
    arg(0, 'filename', "Name of the file to include. This must have a ''''.tji'''' extension. The name\nmay have an absolute or relative path. You need to use ''''/'''' characters to\nseparate directories.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1919
  def rule_includeProperties
    pattern(%w( !includeFileName !includeAttributes ), lambda {
      @project.inputFiles << @scanner.include(@val[0], @sourceFileInfo[0]) do
        popFileStack
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1960
  def rule_interval
    pattern(%w( !date !intervalEnd ), lambda {
      mode = @val[1][0]
      endSpec = @val[1][1]
      if mode == 0
        unless @val[0] < endSpec
          error('start_before_end', "The end date (#{endSpec}) must be after " +
                "the start date (#{@val[0]}).", @sourceFileInfo[0])
        end
        TimeInterval.new(@val[0], endSpec)
      else
        TimeInterval.new(@val[0], @val[0] + endSpec)
      end
    })
    doc('interval2', "There are two ways to specify a date interval. The first is the most\nobvious. A date interval consists of a start and end DATE. Watch out for end\ndates without a time specification! Date specifications are 0 extended. An\nend date without a time is expanded to midnight that day. So the day of the\nend date is not included in the interval! The start and end dates must be separated by a hyphen character.\n\nIn the second form specifies the start date and an interval duration. The\nduration must be prefixed by a plus character.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1988
  def rule_intervalDuration
    pattern(%w( !number !durationUnit ), lambda {
      convFactors = [ 60, # minutes
                      60 * 60, # hours
                      60 * 60 * 24, # days
                      60 * 60 * 24 * 7, # weeks
                      60 * 60 * 24 * 30.4167, # months
                      60 * 60 * 24 * 365 # years
                     ]
      if @val[0] == 0.0
        error('zero_duration', "The interval duration may not be 0.",
              @sourceFileInfo[1])
      end
      duration = @val[0] * convFactors[@val[1]]
      resolution = @project.nil? ? 60 * 60 : @project['scheduleGranularity']
      # Make sure the interval aligns with the timing resolution.
      (duration / resolution).to_i * resolution
    })
    arg(0, 'duration', 'The duration of the interval. May not be 0.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2009
  def rule_intervalEnd
    pattern([ '_-', '!date' ], lambda {
      [ 0, @val[1] ]
    })

    pattern(%w( _+ !intervalDuration ), lambda {
      [ 1, @val[1] ]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2034
  def rule_intervalOptional
    optional
    singlePattern('!interval')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2019
  def rule_intervalOptionalEnd
    optional
    pattern([ '_-', '!date' ], lambda {
      [ 0, @val[1] ]
    })

    pattern(%w( _+ !intervalDuration ), lambda {
      [ 1, @val[1] ]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 1927
  def rule_intervalOrDate
    pattern(%w( !date !intervalOptionalEnd ), lambda {
      if @val[1]
        mode = @val[1][0]
        endSpec = @val[1][1]
        if mode == 0
          unless @val[0] < endSpec
            error('start_before_end', "The end date (#{endSpec}) must be " +
                  "after the start date (#{@val[0]}).", @sourceFileInfo[0])
          end
          TimeInterval.new(@val[0], endSpec)
        else
          TimeInterval.new(@val[0], @val[0] + endSpec)
        end
      else
        TimeInterval.new(@val[0], @val[0].sameTimeNextDay)
      end
    })
    doc('interval3', "There are three ways to specify a date interval. The first is the most\nobvious. A date interval consists of a start and end DATE. Watch out for end\ndates without a time specification! Date specifications are 0 extended. An\nend date without a time is expanded to midnight that day. So the day of the\nend date is not included in the interval! The start and end dates must be separated by a hyphen character.\n\nIn the second form, the end date is omitted. A 24 hour interval is assumed.\n\nThe third form specifies the start date and an interval duration. The duration must be prefixed by a plus character.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2030
  def rule_intervals
    listRule('moreIntervals', '!intervalOrDate')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2039
  def rule_intervalsOptional
    optional
    singlePattern('!intervals')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2138
  def rule_journalEntry
    pattern(%w( !journalEntryHeader !journalEntryBody ), lambda {
      @val[0]
    })
    doc('journalentry', "This attribute adds an entry to the journal of the project. A journal can be\nused to record events, decisions or news that happened at a particular moment\nduring the project. Depending on the context, a journal entry may or may not\nbe associated with a specific property or author.\n\nA journal entry can consists of up to three parts. The headline is mandatory\nand should be only 5 to 10 words long. The introduction is optional and should\nbe only one or two sentences long. All other details should be put into the\nthird part.\n\nDepending on the context, journal entries are listed with headlines only, as\nheadlines plus introduction or in full.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2160
  def rule_journalEntryAttributes
    optional
    repeatable

    pattern(%w( _alert !alertLevel ), lambda {
      @journalEntry.alertLevel = @val[1]
    })
    doc('alert', "Specify the alert level for this entry. This attribute is inteded to be used for\nstatus reporting. When used for a journal entry that is associated with a\nproperty, the value can be reported in the alert column. When multiple entries\nhave been specified for the property, the entry with the date closest to the\nreport end date will be used. Container properties will inherit the highest\nalert level of all its sub properties unless it has an own journal entry dated\ncloser to the report end than all of its sub properties.\n"
       )

    pattern(%w( !author ))

    pattern(%w( _flags !flagList ), lambda {
      @val[1].each do |flag|
        next if @journalEntry.flags.include?(flag)

        @journalEntry.flags << flag
      end
    })
    doc('flags.journalentry', "Journal entries can have flags attached to them. These can be used to\ninclude only entries in a report that have a certain flag.\n"
       )

    pattern(%w( !summary ))

    pattern(%w( !details ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2200
  def rule_journalEntryBody
    optionsRule('journalEntryAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2204
  def rule_journalEntryHeader
    pattern(%w( _journalentry !valDate $STRING ), lambda {
      @journalEntry = JournalEntry.new(@project['journal'], @val[1], @val[2],
                                       @property, @sourceFileInfo[0])
    })
    arg(2, 'headline', "The headline of the journal entry. It will be interpreted as\n[[Rich_Text_Attributes|Rich Text]].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2044
  def rule_journalReportAttributes
    pattern(%w( _journalattributes !journalReportAttributesList ), lambda {
      @property.set('journalAttributes', @val[1])
    })
    doc('journalattributes', "A list that determines which of the journal attributes should be included in\nthe journal report.\n"
       )
    allOrNothingListRule('journalReportAttributesList',
                         { 'alert' => 'Include the alert status',
                           'author' => 'Include the author if known',
                           'date' => 'Include the date',
                           'details' => 'Include the details',
                           'flags' => 'Include the flags',
                           'headline' => 'Include the headline',
                           'property' => 'Include the task or resource name',
                           'propertyid' => 'Include the property ID. ' +
                                           'Requires \'property\'.',
                           'summary' => 'Include the summary',
                           'timesheet' => 'Include the timesheet information.' +
                                          ' Requires \'property\'.'})
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2069
  def rule_journalReportMode
    pattern(%w( _journal ), lambda { :journal })
    descr("This is the regular journal. It contains all journal entries that are dated in\nthe query interval. If a property is given, only entries of this property are\nincluded. Without a property context, all the project entries are included\nunless hidden by other attributes like [[hidejournalentry]].\n"
       )
    pattern(%w( _journal_sub ), lambda { :journal_sub })
    descr("This mode only yields entries if used in the context of a task. It contains\nall journal entries that are dated in the query interval for the task and all\nits sub tasks.\n"
       )
    pattern(%w( _status_dep ), lambda { :status_dep })
    descr("In this mode only the last entries before the report end date for each\nproperty and all its sub-properties and their dependencies are included. If\nthere are multiple entries at the exact same date, then all these entries are\nincluded.\n"
       )
    pattern(%w( _status_down ), lambda { :status_down })
    descr("In this mode only the last entries before the report end date for each\nproperty and all its sub-properties are included. If there are multiple entries\nat the exact same date, then all these entries are included.\n"
       )
    pattern(%w( _status_up ), lambda { :status_up })
    descr("In this mode only the last entries before the report end date for each\nproperty are included. If there are multiple entries at the exact same date,\nthen all these entries are included. If any of the parent properties has a\nmore recent entry that is still before the report end date, no entries will be\nincluded.\n"
       )
    pattern(%w( _alerts_dep ), lambda { :alerts_dep })
    descr("In this mode only the last entries before the report end date for the context\nproperty and all its sub-properties and their dependencies is included. If\nthere are multiple entries at the exact same date, then all these entries are\nincluded. In contrast to the ''''status_down'''' mode, only entries with an\nalert level above the default level, and only those with the highest overall\nalert level are included.\n"
       )
    pattern(%w( _alerts_down ), lambda { :alerts_down })
    descr("In this mode only the last entries before the report end date for the context\nproperty and all its sub-properties is included. If there are multiple entries\nat the exact same date, then all these entries are included. In contrast to\nthe ''''status_down'''' mode, only entries with an alert level above the\ndefault level, and only those with the highest overall alert level are\nincluded.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2217
  def rule_journalSortCriteria
    pattern(%w( !journalSortCriterium !moreJournalSortCriteria ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2223
  def rule_journalSortCriterium
    pattern(%w( $ABSOLUTE_ID ), lambda {
      supported = []
      JournalEntryList::SortingAttributes.each do |attr|
        supported << "#{attr}.up"
        supported << "#{attr}.down"
      end
      unless supported.include?(@val[0])
        error('bad_journal_sort_criterium',
              "Unsupported sorting criterium #{@val[0]}. Must be one of " +
              "#{supported.join(', ')}.")
      end
      attr, direction = @val[0].split('.')
      [ attr.intern, direction == 'up' ? 1 : -1 ]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2240
  def rule_leafResourceId
    pattern(%w( !resourceId ), lambda {
      resource = @val[0]
      unless resource.leaf?
        error('leaf_resource_id_expected',
              "#{resource.id} is not a leaf resource.", @sourceFileInfo[0])
      end
      resource
    })
    arg(0, 'resource', 'The ID of a leaf resource')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2252
  def rule_leave
    pattern(%w( !leaveType !vacationName !intervalOrDate ), lambda {
      Leave.new(@val[0].intern, @val[2], @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2270
  def rule_leaveAllowance
    pattern(%w( _annual !valDate !optionalMinus !workingDuration ), lambda {
      LeaveAllowance.new(:annual, @val[1], (@val[2] ? -1 : 1) * @val[3])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2276
  def rule_leaveAllowanceList
    listRule('moreLeaveAllowanceList', '!leaveAllowance')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2280
  def rule_leaveAllowances
    pattern(%w( _leaveallowances !leaveAllowanceList ), lambda {
      appendScListAttribute('leaveallowances', @val[1])
    })
    doc('leaveallowance', "Add or subtract leave allowances. Currently, only allowances for the annual\nleaves are supported. Allowances can be negative to deal with expired\nallowances. The ''''leaveallowancebalance'''' report [[columns|column]] can be\nused to report the current annual leave balance.\n\nLeaves outside of the project period are silently ignored and will not be\nconsidered in the leave balance calculation. Therefor, leave allowances are\nonly allowed within the project period.\n"
      )
    level(:beta)
    example('Leave')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2258
  def rule_leaveList
    listRule('moreLeaveList', '!leave')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2262
  def rule_leaveName
    optional
    pattern(%w( $STRING ), lambda {
      @val[0]
    })
    arg(0, 'name', 'An optional name or reason for the leave')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2325
  def rule_leaveType
    singlePattern('_project')
    descr('Assignment to another project (lowest priority)')

    singlePattern('_annual')
    descr('Personal leave based on annual allowance')

    singlePattern('_special')
    descr('Personal leave based on a special occasion')

    singlePattern('_sick')
    descr('Sick leave')

    singlePattern('_unpaid')
    descr('Unpaid leave')

    singlePattern('_holiday')
    descr('Public or bank holiday (highest priority)')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2300
  def rule_leaves
    pattern(%w( _leaves !leaveList ), lambda {
      LeaveList.new(@val[1])
    })
    doc('leaves', "Describe a list of leave periods. A leave can be due to a public holiday,\npersonal or sick leave. At global scope, the leaves determine which day is\nconsidered a working day. Subsequent resource definitions will inherit the\nleave list.\n\nLeaves can be defined at global level, at resource level and at shift level\nand intervals may overlap. The leave types have different priorities. A higher\npriority leave type can overwrite a lower priority type. This means that\nresource level leaves can overwrite global leaves when they have a higher\npriority. A sub resource can overwrite a leave of a enclosing resource.\n\nLeave periods outside of the project interval are silently ignored. For leave\nperiods that are partially outside of the project period only the part inside\nthe project period will be considered.\n"
       )
    example('Leave')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2345
  def rule_limitAttributes
    optionsRule('limitAttributesBody')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2349
  def rule_limitAttributesBody
    optional
    repeatable

    pattern(%w( _end !valDate ), lambda {
      @limitInterval.end = @val[1]
    })
    doc('end.limit', "The end date of the limit interval. It must be within the project time frame.\n"
    )

    pattern(%w( _period !valInterval ), lambda {
      @limitInterval = ScoreboardInterval.new(@project['start'],
                                              @project['scheduleGranularity'],
                                              @val[1].start, @val[1].end)
    })
    doc('period.limit', "This property is a shortcut for setting the start and end dates of the limit\ninterval. Both dates must be within the project time frame.\n"
       )

    pattern(%w( _resources !resourceLeafList ), lambda {
      @limitResources = @val[1]
    })
    doc('resources.limit', "When [[limits]] are used in a [[task]] context, the limits can be restricted\nto a list of resources that are allocated to the task. In that case each\nlisted resource will not be allocated more than the specified upper limit.\nLower limits have no impact on the scheduler but do generate a warning when\nnot met.  All specified resources must be leaf resources.\n"
       )
    example('Limits-1', '5')

    pattern(%w( _start !valDate ), lambda {
      @limitInterval.start = @val[1]
    })
    doc('start.limit', "The start date of the limit interval. It must be within the project time frame.\n"
    )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2398
  def rule_limitValue
    pattern([ '!workingDuration' ], lambda {
      @limitInterval = ScoreboardInterval.new(@project['start'],
                                              @project['scheduleGranularity'],
                                              @project['start'], @project['end'])
      @limitResources = []
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2408
  def rule_limits
    pattern(%w( !limitsHeader !limitsBody ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2414
  def rule_limitsAttributes
    optional
    repeatable

    pattern(%w( _dailymax !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('dailymax', "Set a maximum limit for each calendar day.\n"
       )
    example('Limits-1', '1')

    pattern(%w( _dailymin !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('dailymin', "Minimum required effort for any calendar day. This value cannot be guaranteed by\nthe scheduler. It is only checked after the schedule is complete. In case the\nminium required amount has not been reached, a warning will be generated.\n"
       )
    example('Limits-1', '4')

    pattern(%w( _maximum !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('maximum', "Set a maximum limit for the specified period. You must ensure that the overall\neffort can be achieved!\n"
       )

    pattern(%w( _minimum !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('minimum', "Set a minim limit for each calendar month. This will only result in a warning\nif not met.\n"
       )

    pattern(%w( _monthlymax !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('monthlymax', "Set a maximum limit for each calendar month.\n"
       )

    pattern(%w( _monthlymin !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('monthlymin', "Minimum required effort for any calendar month. This value cannot be\nguaranteed by the scheduler. It is only checked after the schedule is\ncomplete. In case the minium required amount has not been reached, a warning\nwill be generated.\n"
       )

    pattern(%w( _weeklymax !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('weeklymax', "Set a maximum limit for each calendar week.\n"
       )

    pattern(%w( _weeklymin !limitValue !limitAttributes), lambda {
      setLimit(@val[0], @val[1], @limitInterval)
    })
    doc('weeklymin', "Minimum required effort for any calendar week. This value cannot be guaranteed by\nthe scheduler. It is only checked after the schedule is complete. In case the\nminium required amount has not been reached, a warning will be generated.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2502
  def rule_limitsBody
    optionsRule('limitsAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2506
  def rule_limitsHeader
    pattern(%w( _limits ), lambda {
      @limits = Limits.new
      @limits.setProject(@project)
      @limits
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2514
  def rule_listOfDays
    pattern(%w( !weekDayInterval !moreListOfDays), lambda {
      weekDays = Array.new(7, false)
      ([ @val[0] ] + (@val[1] ? @val[1] : [])).each do |dayList|
        7.times { |i| weekDays[i] = true if dayList[i] }
      end
      weekDays
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2524
  def rule_listOfTimes
    pattern(%w( _off ), lambda {
      [ ]
    })
    pattern(%w( !timeInterval !moreTimeIntervals ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2533
  def rule_listType
    pattern([ '_bullets' ], lambda { :bullets })
    descr('List items as bullet list')

    pattern([ '_comma' ], lambda { :comma })
    descr('List items as comma separated list')

    pattern([ '_numbered' ], lambda { :numbered })
    descr('List items as numbered list')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2544
  def rule_loadunit
    pattern([ '_days' ], lambda { :days })
    descr('Display all load and duration values as days.')

    pattern([ '_hours' ], lambda { :hours })
    descr('Display all load and duration values as hours.')

    pattern([ '_longauto'] , lambda { :longauto })
    descr("Automatically select the unit that produces the shortest and most readable\nvalue. The unit name will not be abbreviated. It will not use quarters since\nit is not common.\n"
         )

    pattern([ '_minutes' ], lambda { :minutes })
    descr('Display all load and duration values as minutes.')

    pattern([ '_months' ], lambda { :months })
    descr('Display all load and duration values as months.')

    pattern([ '_quarters' ], lambda { :quarters })
    descr('Display all load and duration values as quarters.')

    pattern([ '_shortauto' ], lambda { :shortauto })
    descr("Automatically select the unit that produces the shortest and most readable\nvalue. The unit name will be abbreviated. It will not use quarters since it is\nnot common.\n"
         )

    pattern([ '_weeks' ], lambda { :weeks })
    descr('Display all load and duration values as weeks.')

    pattern([ '_years' ], lambda { :years })
    descr('Display all load and duration values as years.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2585
  def rule_logicalExpression
    pattern(%w( !operation ), lambda {
      LogicalExpression.new(@val[0], sourceFileInfo)
    })
    pattern(%w( _@ !allOrNone ), lambda {
      LogicalOperation.new(@val[1])
    })
    doc('logicalexpression', "A logical expression is a combination of operands and mathematical operations.\nThe final result of a logical expression is always true or false. Logical\nexpressions are used the reduce the properties in a report to a certain subset\nor to select alternatives for the cell content of a table. When used with\nattributes like [[hidetask]] or [[hideresource]] the logical expression\nevaluates to true for a certain property, this property is hidden or rolled-up\nin the report.\n\nOperands can be previously declared flags, built-in [[functions]], property\nattributes (specified as scenario.attribute) or another logical expression.\nWhen you combine logical operations to a more complex expression, the\noperators are evaluated from left to right. '''a | b & c''' is identical to\n'''(a | b) & c'''. It's highly recommended that you always use brackets to\ncontrol the evaluation sequence. Currently, TaskJuggler does not support the\nconcept of operator precedence or right-left associativity. This may change in\nthe future.\n\nAn operand can also be just a number. 0 evaluates to false, all other numbers\nto true. The logical expression can also be the special constants ''''@all'''' or ''''@none''''. The first always evaluates to true, the latter to false.\n"
       )
    also(%w( functions ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2618
  def rule_macro
    pattern(%w( _macro $ID $MACRO ), lambda {
      if @scanner.macroDefined?(@val[1])
        warning('marco_redefinition', "Redefining macro #{@val[1]}")
      end
      @scanner.addMacro(TextParser::Macro.new(@val[1], @val[2],
                                              @sourceFileInfo[0]))
    })
    doc('macro', "Defines a text fragment that can later be inserted by using the specified ID.\nTo insert the text fragment anywhere in the text you need to write ${ID}.The\nbody is not optional. It must be enclosed in square brackets. Macros can be\ndeclared like this:\n\n macro FOO [ This text ]\n\nIf later ''''${FOO}'''' is found in the project file, it is expanded to\n''''This text''''.\n\nMacros may have arguments. Arguments are accessed with special macros with\nnumbers as names.  The number specifies the index of the argument.\n\n macro FOO [ This ${1} text ]\n\nwill expand to ''''This stupid text'''' if called as ''''${FOO \"stupid\"}''''.\nMacros may call other macros. All macro arguments must be enclosed by double\nquotes. In case the argument contains a double quote, it must be escaped by a\nslash (''''/'''').\n\nUser defined macro IDs must have at least one uppercase letter as all\nlowercase letter IDs are reserved for built-in macros.\n\nTo terminate the macro definition, the ''''<nowiki>]</nowiki>'''' must be the\nlast character in the line. If there are any other characters trailing it\n(even spaces or comments) the ''''<nowiki>]</nowiki>'''' will not be\nconsidered the end of the macro definition.\n\nIn macro calls the macro names can be prefixed by a question mark. In this\ncase the macro will expand to nothing if the macro is not defined. Otherwise\nthe undefined macro would be flagged with an error message.\n\nThe macro call\n\n ${?foo}\n\nwill expand to nothing if foo is undefined.\n"
       )
    example('Macro-1')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2676
  def rule_moreAlternatives
    commaListRule('!resourceId')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2680
  def rule_moreArguments
    commaListRule('!argument')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2670
  def rule_moreBangs
    optional
    repeatable
    singlePattern('_!')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2684
  def rule_moreChargeSetItems
    commaListRule('!chargeSetItem')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2688
  def rule_moreColumnDef
    commaListRule('!columnDef')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2692
  def rule_moreDepTasks
    commaListRule('!taskDep')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2696
  def rule_moreJournalSortCriteria
    commaListRule('!journalSortCriterium')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2700
  def rule_moreListOfDays
    commaListRule('!weekDayInterval')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2704
  def rule_moreOutputFormats
    commaListRule('!outputFormat')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2712
  def rule_morePredTasks
    commaListRule('!taskPred')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2708
  def rule_moreProjectIDs
    commaListRule('$ID')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2716
  def rule_moreSortCriteria
    commaListRule('!sortNonTree')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2720
  def rule_moreTimeIntervals
    commaListRule('!timeInterval')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2724
  def rule_navigator
    pattern(%w( !navigatorHeader !navigatorBody ), lambda {
      @project['navigators'][@navigator.id] = @navigator
    })
    doc('navigator', "Defines a navigator object with the specified ID. This object can be used in\nreports to include a navigation bar with references to other reports.\n"
          )
    example('navigator')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2737
  def rule_navigatorAttributes
    optional
    repeatable
    pattern(%w( _hidereport !logicalExpression ), lambda {
      @navigator.hideReport = @val[1]
    })
    doc('hidereport', "This attribute can be used to exclude the reports that match the specified\nexpression from the navigation bar.\n"
          )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2751
  def rule_navigatorBody
    optional
    pattern(%w( _{ !navigatorAttributes _} ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2756
  def rule_navigatorHeader
    pattern(%w( _navigator $ID ), lambda {
      if @project['navigators'][@val[1]]
        error('navigator_exists',
              "The navigator #{@val[1]} has already been defined.",
              @sourceFileInfo[0])
      end
      @navigator = Navigator.new(@val[1], @project)
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2817
  def rule_nikuReport
    pattern(%w( !nikuReportHeader !nikuReportBody ), lambda {
      @property = nil
    })
    doc('nikureport', "This report generates an XML file to be imported into the enterprise resource\nmanagement software Clarity(R) from Computer Associates(R). The files contains\nallocation curves for the specified resources. All tasks with identical user\ndefined attributes ''''ClarityPID'''' and ''''ClarityPNAME'''' are bundled\ninto a Clarity project. The resulting XML file can be imported into Clarity\nwith the xog-in tool.\n"
       )
    example('Niku')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2767
  def rule_nikuReportAttributes
    optional
    repeatable

    pattern(%w( !formats ))
    pattern(%w( !headline ))
    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))

    pattern(%w( !numberFormat ), lambda {
      @property.set('numberFormat', @val[0])
    })

    pattern(%w( !reportEnd ))
    pattern(%w( !reportPeriod ))
    pattern(%w( !reportStart ))
    pattern(%w( !reportTitle ))

    pattern(%w( _timeoff $STRING $STRING ), lambda {
      @property.set('timeOffId', @val[1])
      @property.set('timeOffName', @val[2])
    })
    doc('timeoff.nikureport', "Set the Clarity project ID and name that the vacation time will be reported to.\n"
       )
    arg(1, 'ID', 'The Clarity project ID')
    arg(2, 'Name', 'The Clarity project name')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2798
  def rule_nikuReportBody
    pattern(%w( _{ !nikuReportAttributes _} ), lambda {

    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2804
  def rule_nikuReportHeader
    pattern(%w( _nikureport !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :niku, @sourceFileInfo[0])
      @property.set('numberFormat', RealFormat.new(['-', '', '', '.', 2]))
    })
    arg(1, 'file name', "The name of the time sheet report file to generate. It must end with a .tji\nextension, or use . to use the standard output channel.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2834
  def rule_nodeId
    pattern(%w( !idOrAbsoluteId !subNodeId ), lambda {
      case @property.typeSpec
      when :taskreport
        if (p1 = @project.task(@val[0])).nil?
          error('unknown_main_node',
                "Unknown task ID #{@val[0]}", @sourceFileInfo[0])
        end
        if @val[1]
          if (p2 = @project.resource(@val[1])).nil?
            error('unknown_sub_node',
                  "Unknown resource ID #{@val[0]}", @sourceFileInfo[0])
          end
          return [ p2, p1 ]
        end
        return [ p1, nil ]
      when :resourcereport
        if (p1 = @project.task(@val[0])).nil?
          error('unknown_main_node',
                "Unknown task ID #{@val[0]}", @sourceFileInfo[0])
        end
        if @val[1]
          if (p2 = @project.resource(@val[1])).nil?
            error('unknown_sub_node',
                  "Unknown resource ID #{@val[0]}", @sourceFileInfo[0])
          end
          return [ p2, p1 ]
        end
        return [ p1, nil ]
      end

      raise "Node list is not supported for this report type: " +
            "#{@property.typeSpec}"
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2870
  def rule_nodeIdList
    listRule('moreNodeIdList', '!nodeId')
    pattern([ '_-' ], lambda {
      []
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2877
  def rule_number
    singlePattern('$INTEGER')
    singlePattern('$FLOAT')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2882
  def rule_numberFormat
    pattern(%w( _numberformat $STRING $STRING $STRING $STRING $INTEGER ),
        lambda {
      RealFormat.new(@val.slice(1, 5))
    })
    doc('numberformat',
        'These values specify the default format used for all numerical ' +
        'real values.')
    arg(1, 'negativeprefix', 'Prefix for negative numbers')
    arg(2, 'negativesuffix', 'Suffix for negative numbers')
    arg(3, 'thousandsep', 'Separator used for every 3rd digit')
    arg(4, 'fractionsep', 'Separator used to separate the fraction digits')
    arg(5, 'fractiondigits', 'Number of fraction digits to show')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2897
  def rule_operand
    pattern(%w( _( !operation _) ), lambda {
      @val[1]
    })
    pattern(%w( _~ !operand ), lambda {
      operation = LogicalOperation.new(@val[1])
      operation.operator = '~'
      operation
    })

    pattern(%w( $ABSOLUTE_ID ), lambda {
      if @val[0].count('.') > 1
        error('operand_attribute',
              'Attributes must be specified as <scenarioID>.<attribute>',
              @sourceFileInfo[0])
      end
      scenario, attribute = @val[0].split('.')
      if (scenarioIdx = @project.scenarioIdx(scenario)).nil?
        error('operand_unkn_scen', "Unknown scenario ID #{scenario}",
              @sourceFileInfo[0])
      end
      # TODO: Do at least some basic sanity checks of the attribute is valid.
      LogicalAttribute.new(attribute, @project.scenario(scenarioIdx))
    })
    pattern(%w( !date ), lambda {
      LogicalOperation.new(@val[0])
    })
    pattern(%w( $ID !argumentList ), lambda {
      if @val[1].nil?
        unless @project['flags'].include?(@val[0])
          error('operand_unkn_flag', "Undeclared flag '#{@val[0]}'",
                @sourceFileInfo[0])
        end
        LogicalFlag.new(@val[0])
      else
        func = LogicalFunction.new(@val[0])
        res = func.setArgumentsAndCheck(@val[1])
        unless res.nil?
          error(*res)
        end
        func
      end
    })
    pattern(%w( $INTEGER ), lambda {
      LogicalOperation.new(@val[0])
    })
    pattern(%w( $FLOAT ), lambda {
      LogicalOperation.new(@val[0])
    })
    pattern(%w( $STRING ), lambda {
      LogicalOperation.new(@val[0])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2951
  def rule_operation
    pattern(%w( !operand !operationChain ), lambda {
      operation = LogicalOperation.new(@val[0])
      if @val[1]
        # Further operators/operands create an operation tree.
        @val[1].each do |ops|
          operation = LogicalOperation.new(operation)
          operation.operator = ops[0]
          operation.operand2 = ops[1]
        end
      end
      operation
    })
    arg(0, 'operand', "An operand can consist of a date, a text string, a [[functions|function]], a\nproperty attribute or a numerical value. It can also be the name of a declared\nflag.  Use the ''''scenario_id.attribute'''' notation to use an attribute of\nthe currently evaluated property. The scenario ID always has to be specified,\nalso for non-scenario specific attributes. This is necessary to distinguish\nthem from flags. See [[columnid]] for a list of available attributes. The use\nof list attributes is not recommended. User defined attributes are available\nas well.\n\nAn operand can be a negated operand by prefixing a ~ charater or it can be\nanother logical expression enclosed in braces.\n"
        )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2981
  def rule_operationChain
    optional
    repeatable
    pattern(%w( !operatorAndOperand), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3000
  def rule_operator
    singlePattern('_|')
    descr('The \'or\' operator')

    singlePattern('_&')
    descr('The \'and\' operator')

    singlePattern('_>')
    descr('The \'greater than\' operator')

    singlePattern('_<')
    descr('The \'smaller than\' operator')

    singlePattern('_=')
    descr('The \'equal\' operator')

    singlePattern('_>=')
    descr('The \'greater-or-equal\' operator')

    singlePattern('_<=')
    descr('The \'smaller-or-equal\' operator')

    singlePattern('_!=')
    descr('The \'not-equal\' operator')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 2989
  def rule_operatorAndOperand
    pattern(%w( !operator !operand), lambda{
      [ @val[0], @val[1] ]
    })
    arg(1, 'operand', "An operand can consist of a date, a text string or a numerical value. It can also be the name of a declared flag. Finally, an operand can be a negated operand by prefixing a ~ charater or it can be another operation enclosed in braces.\n"
        )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3026
  def rule_optionalID
    optional
    pattern(%w( $ID ), lambda {
      @val[0]
    })
    arg(0, 'id', "An optional ID. If you ever want to reference this property, you must specify\nyour own unique ID. If no ID is specified one will be automatically generated.\nThese IDs may become visible in reports, but may change at any time. You may\nnever rely on automatically generated IDs.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3041
  def rule_optionalMinus
    optional
    pattern(%w( _- ), lambda {
      true
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3048
  def rule_optionalPercent
    optional
    pattern(%w( !number _% ), lambda {
      @val[0] / 100.0
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3055
  def rule_optionalVersion
    optional
    pattern(%w( $STRING ), lambda {
      @val[0]
    })
    arg(0, 'version', "An optional version ID. This can be something simple as \"4.2\" or an ID tag of\na revision control system. If not specified, it defaults to \"1.0\".\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3068
  def rule_outputFormat
    pattern(%w( _csv ), lambda {
      :csv
    })
    descr("The report lists the resources and their respective values as\ncolon-separated-value (CSV) format. Due to the very simple nature of the CSV\nformat, only a small subset of features will be supported for CSV output.\nIncluding tasks or listing multiple scenarios will result in very difficult to\nread reports.\n"
         )

    pattern(%w( _html ), lambda {
      :html
    })
    descr('Generate a web page (HTML file)')

    pattern(%w( _niku ), lambda {
      :niku
    })
    descr('Generate a XOG XML file to be used with Clarity.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3093
  def rule_outputFormats
    pattern(%w( !outputFormat !moreOutputFormats ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3099
  def rule_plusOrMinus
    singlePattern('_+')
    singlePattern('_-')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3104
  def rule_project
    pattern(%w( !projectProlog !projectDeclaration !properties . ), lambda {
      @val[1]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3110
  def rule_projectBody
    optionsRule('projectBodyAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3114
  def rule_projectBodyAttributes
    repeatable
    optional

    pattern(%w( _alertlevels !alertLevelDefinitions ), lambda {
      if @val[1].length < 2
        error('too_few_alert_levels',
              'You must specify at least 2 different alert levels.',
              @sourceFileInfo[1])
      end
      levels = @project['alertLevels']
      levels.clear
      @val[1].each do |level|
        if levels.indexById(level[0])
          error('alert_level_redef',
                "Alert level '#{level[0]}' has been defined multiple times.",
                @sourceFileInfo[1])
        end

        if levels.indexByName(level[1])
          error('alert_name_redef',
                "Alert level name '#{level[1]}' has been defined multiple " +
                "times.", @sourceFileInfo[1])
        end

        @project['alertLevels'].add(AlertLevelDefinition.new(*level))
      end
    })
    level(:beta)
    doc('alertlevels', "By default TaskJuggler supports the pre-defined alert levels: green, yellow\nand red. This attribute can be used to replace them with your own set of alert\nlevels. You can define any number of levels, but you need to define at least\ntwo and they must be specified in ascending order from the least severity to\nhighest severity. Additionally, you need to provide a 15x15 pixel image file\nwith the name ''''flag-X.png'''' for each level where ''''X'''' matches the ID\nof the alert level. These files need to be in the ''''icons'''' directory to\nbe found by the browser when showing HTML reports.\n"
       )
    example('AlertLevels')

    pattern(%w( !currencyFormat ), lambda {
      @project['currencyFormat'] = @val[0]
    })

    pattern(%w( _currency $STRING ), lambda {
      @project['currency'] = @val[1]
    })
    doc('currency', 'The default currency unit.')
    example('Account')
    arg(1, 'symbol', 'Currency symbol')

    pattern(%w( _dailyworkinghours !number ), lambda {
      @project['dailyworkinghours'] = @val[1]
    })
    doc('dailyworkinghours', "Set the average number of working hours per day. This is used as\nthe base to convert working hours into working days. This affects\nfor example the length task attribute. The default value is 8 hours\nand should work for most Western countries. The value you specify should match\nthe settings you specified as your default [[workinghours.project|working\nhours]].\n"
       )
    example('Project')
    arg(1, 'hours', 'Average number of working hours per working day')

    pattern(%w( _extend !extendProperty !extendBody ), lambda {
      updateParserTables
    })
    doc('extend', "Often it is desirable to collect more information in the project file than is\nnecessary for task scheduling and resource allocation. To add such information\nto tasks, resources or accounts the user can extend these properties with\nuser-defined attributes. The new attributes can be of various types such as\ntext, date or reference to capture various types of data. Optionally the user\ncan specify if the attribute value should be inherited from the enclosing\nproperty.\n"
       )
    example('CustomAttributes')

    pattern(%w( !projectBodyInclude ))

    pattern(%w( !journalEntry ))

    pattern(%w( _now !date ), lambda {
      @project['now'] = @val[1]
      @scanner.addMacro(TextParser::Macro.new('now', @val[1].to_s,
                                              @sourceFileInfo[0]))
      @scanner.addMacro(TextParser::Macro.new(
        'today', @val[1].to_s(@project['timeFormat']), @sourceFileInfo[0]))
    })
    doc('now', "Specify the date that TaskJuggler uses for calculation as current\ndate. If no value is specified, the current value of the system\nclock is used.\n"
       )
    arg(1, 'date', 'Alternative date to be used as current date for all ' +
        'computations')

    pattern(%w( !numberFormat ), lambda {
      @project['numberFormat'] = @val[0]
    })

    pattern(%w( !scenario ))
    pattern(%w( _shorttimeformat $STRING ), lambda {
      @project['shortTimeFormat'] = @val[1]
    })
    doc('shorttimeformat',
        'Specifies time format for time short specifications. This is normal' +
        'just the hour and minutes.')
    arg(1, 'format', 'strftime like format string')

    pattern(%w( !timeformat ), lambda {
      @project['timeFormat'] = @val[0]
    })

    pattern(%w( !timezone ), lambda {
      @val[0]
    })

    pattern(%w( _timingresolution $INTEGER _min ), lambda {
      goodValues = [ 5, 10, 15, 20, 30, 60 ]
      unless goodValues.include?(@val[1])
        error('bad_timing_res',
              "Timing resolution must be one of #{goodValues.join(', ')} min.",
              @sourceFileInfo[1])
      end
      if @val[1] > (Project.maxScheduleGranularity / 60)
        error('too_large_timing_res',
              'The maximum allowed timing resolution for the timezone is ' +
              "#{Project.maxScheduleGranularity / 60} minutes.",
              @sourceFileInfo[1])
      end
      @project['scheduleGranularity'] = @val[1] * 60
    })
    doc('timingresolution', "Sets the minimum timing resolution. The smaller the value, the longer the\nscheduling process lasts and the more memory the application needs. The\ndefault and maximum value is 1 hour. The smallest value is 5 min.\nThis value is a pretty fundamental setting of TaskJuggler. It has a severe\nimpact on memory usage and scheduling performance. You should set this value\nto the minimum required resolution. Make sure that all values that you specify\nare aligned with the resolution.\n\nChanging the timing resolution will reset the [[workinghours.project|working\nhours]] to the default times. It's recommended that this is the very first\noption in the project header section.\n\nDo not use this option after you've set the time zone!\n"
        )

    pattern(%w( _trackingscenario !scenarioId ), lambda {
      @project['trackingScenarioIdx'] = @val[1]
      # The tracking scenario and all child scenarios will always be scheduled
      # in projection mode.
      @project.scenario(@val[1]).all.each do |scenario|
        scenario.set('projection', true)
      end
    })
    doc('trackingscenario', "Specifies which scenario is used to capture what actually has happened with\nthe project. All sub-scenarios of this scenario inherit the bookings of the\ntracking scenario and may not have any bookings of their own. The tracking\nscenario must also be specified to use time and status sheet reports.\n\nThe tracking scenario must be defined after all scenario have been defined.\n\nThe tracking scenario and all scenarios derived from it will be scheduled in\nprojection mode. This means that the scheduler will only add bookings after\nthe current date or the date specified by [[now]]. It is assumed that all\nallocations prior to this date have been provided as [[booking.task|\ntask bookings]] or [[booking.resource|resource bookings]].\n"
       )
    example('TimeSheet1', '2')

    pattern(%w( _weekstartsmonday ), lambda {
      @project['weekStartsMonday'] = true
    })
    doc('weekstartsmonday',
        'Specify that you want to base all week calculation on weeks ' +
        'starting on Monday. This is common in many European countries.')

    pattern(%w( _weekstartssunday ), lambda {
      @project['weekStartsMonday'] = false
    })
    doc('weekstartssunday',
        'Specify that you want to base all week calculation on weeks ' +
        'starting on Sunday. This is common in the United States of America.')

    pattern(%w( !workinghoursProject ))
    pattern(%w( _yearlyworkingdays !number ), lambda {
      @project['yearlyworkingdays'] = @val[1]
    })
    doc('yearlyworkingdays', "Specifies the number of average working days per year. This should correlate\nto the specified workinghours and vacation. It affects the conversion of\nworking hours, working days, working weeks, working months and working years\ninto each other.\n\nWhen public holidays and leaves are disregarded, this value should be equal\nto the number of working days per week times 52.1428 (the average number of\nweeks per year). E. g. for a culture with 5 working days it is 260.714 (the\ndefault), for 6 working days it is 312.8568 and for 7 working days it is\n365.\n"
       )
    arg(1, 'days', 'Number of average working days for a year')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3424
  def rule_projectBodyInclude
    pattern(%w( _include !includeFile !projectBodyAttributes . ))
    lastSyntaxToken(1)
    doc('include.project', "Includes the specified file name as if its contents would be written\ninstead of the include property. When the included files contains other\ninclude statements or report definitions, the filenames are relative to file\nwhere they are defined in.\n\nThis version of the include directive may only be used inside the [[project]]\nheader section. The included files must only contain content that may be\npresent in a project header section.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3336
  def rule_projectDeclaration
    pattern(%w( !projectHeader !projectBody ), lambda {
      # If the user has specified a tracking scenario, we mark all children of
      # that scenario to disallow own bookings. These scenarios will inherit
      # their bookings from the tracking scenario.
      if (idx = @project['trackingScenarioIdx'])
        @project.scenario(idx).allLeaves(true).each do |scenario|
          scenario.set('ownbookings', false)
        end
      end
      @val[0]
    })
    doc('project', "The project property is mandatory and should be the first property\nin a project file. It is used to capture basic attributes such as\nthe project id, name and the expected time frame.\n\nBe aware that the dates for the project period default to UTC times. See [[interval2]] for details.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3359
  def rule_projectHeader
    pattern(%w( _project !optionalID $STRING !optionalVersion !interval ), lambda {
      @project = Project.new(@val[1], @val[2], @val[3])
      @project['start'] = @val[4].start
      @project['end'] = @val[4].end
      @projectId = @val[1]
      setGlobalMacros
      @property = nil
      @reportCounter = 0
      @project
    })
    arg(2, 'name', 'The name of the project')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3373
  def rule_projectIDs
    pattern(%w( $ID !moreProjectIDs ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3400
  def rule_projectProlog
    optional
    repeatable
    pattern(%w( !prologInclude ))
    pattern(%w( !macro ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3407
  def rule_projectProperties
    # This rule is not defining actual syntax. It's only used for the
    # documentation.
    pattern(%w( !projectPropertiesBody ))
    doc('properties', "The project properties. Every project must consists of at least one task. The other properties are optional. To save the scheduled data at least one output generating property should be used.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3418
  def rule_projectPropertiesBody
    # This rule is not defining actual syntax. It's only used for the
    # documentation.
    optionsRule('properties')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3379
  def rule_projection
    optionsRule('projectionAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3383
  def rule_projectionAttributes
    optional
    repeatable
    pattern(%w( _sloppy ))
    level(:deprecated)
    also('trackingscenario')
    doc('sloppy.projection', '')

    pattern(%w( _strict ), lambda {
      warning('projection_strict',
              'The strict mode is now always used.')
    })
    level(:deprecated)
    also('trackingscenario')
    doc('strict.projection', '')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3441
  def rule_prologInclude
    pattern(%w( _include !includeFile !projectProlog . ))
    lastSyntaxToken(1)
    doc('include.macro', "Includes the specified file name as if its contents would be written\ninstead of the include property. The only exception is the include\nstatement itself. When the included files contains other include\nstatements or report definitions, the filenames are relative to file\nwhere they are defined in.\n\nThe included file may only contain macro definitions. This version of the\ninclude directive can only be used before the [[project]] header.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3458
  def rule_properties
    pattern(%w( !propertiesBody ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3462
  def rule_propertiesBody
    repeatable
    optional

    pattern(%w( !account ))

    pattern(%w( _copyright $STRING ), lambda {
      @project['copyright'] = @val[1]
    })
    doc('copyright', "Set a copyright notice for the project file and its content. This copyright notice will be added to all reports that can support it.\n"
       )
    example('Caption', '2')

    pattern(%w( !balance ), lambda {
      @project['costaccount'] = @val[0][0]
      @project['revenueaccount'] = @val[0][1]
    })

    pattern(%w( _flags !declareFlagList ), lambda {
      unless @project['flags'].include?(@val[1])
        @project['flags'] += @val[1]
      end
    })
    doc('flags', "Declare one or more flag for later use. Flags can be used to mark tasks, resources or other properties to filter them in reports.\n"
       )

    pattern(%w( !propertiesInclude ))

    pattern(%w( !leaves ), lambda {
      @val[0].each do |v|
        @project['leaves'] << v
      end
    })

    pattern(%w( !limits ), lambda {
      @project['limits'] = @val[0]
    })
    doc('limits', "Set per-interval allocation limits for the following resource definitions.\nThe limits can be overwritten in each resource definition and the global\nlimits can be changed later.\n"
       )

    pattern(%w( !macro ))

    pattern(%w( !navigator ))

    pattern(%w( _projectid $ID ), lambda {
      @project['projectids'] << @val[1]
      @project['projectids'].uniq!
      @project['projectid'] = @projectId = @val[1]
    })
    doc('projectid', "This declares a new project id and activates it. All subsequent\ntask definitions will inherit this ID. The tasks of a project can have\ndifferent IDs.  This is particularly helpful if the project is merged from\nseveral sub projects that each have their own ID.\n"
       )

    pattern(%w( _projectids !projectIDs ), lambda {
      @project['projectids'] += @val[1]
      @project['projectids'].uniq!
    })
    doc('projectids', "Declares a list of project IDs. When an include file that was generated from another project brings different project IDs, these need to be declared first.\n"
        )

    pattern(%w( _rate !number ), lambda {
      @project['rate'] = @val[1].to_f
    })
    doc('rate', "Set the default rate for all subsequently defined resources. The rate describes the daily cost of a resource.\n"
        )

    pattern(%w( !reportProperties ))
    pattern(%w( !resource ))
    pattern(%w( !shift ))
    pattern(%w( !statusSheet ))

    pattern(%w( _supplement !supplement ))
    doc('supplement', "The supplement keyword provides a mechanism to add more attributes to already\ndefined accounts, tasks or resources. The additional attributes must obey the\nsame rules as in regular task or resource definitions and must be enclosed by\ncurly braces.\n\nThis construct is primarily meant for situations where the information about a\ntask or resource is split over several files. E. g. the vacation dates for the\nresources may be in a separate file that was generated by some other tool.\n"
       )
    example('Supplement')

    pattern(%w( !task ))
    pattern(%w( !timeSheet ))
    pattern(%w( _vacation !vacationName !intervals ), lambda {
      @val[2].each do |interval|
        @project['leaves'] << Leave.new(:holiday, interval)
      end
    })
    doc('vacation', "Specify a global vacation period for all subsequently defined resources. A\nvacation can also be used to block out the time before a resource joined or\nafter it left. For employees changing their work schedule from full-time to\npart-time, or vice versa, please refer to the 'Shift' property.\n"
       )
    arg(1, 'name', 'Name or purpose of the vacation')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3588
  def rule_propertiesFile
    pattern(%w( !propertiesBody . ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3592
  def rule_propertiesInclude
    pattern(%w( _include !includeProperties !properties . ), lambda {
    })
    lastSyntaxToken(1)
    doc('include.properties', "Includes the specified file name as if its contents would be written\ninstead of the include property. The only exception is the include\nstatement itself. When the included files contains other include\nstatements or report definitions, the filenames are relative to file\nwhere they are defined in. include commands can be used in the project\nheader, at global scope or between property declarations of tasks,\nresources, and accounts.\n\nFor technical reasons you have to supply the optional pair of curly\nbrackets if the include is followed immediately by a macro call that\nis defined within the included file.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3613
  def rule_purge
    pattern(%w( _purge $ID ), lambda {
      if (attributeDefinition = @property.attributeDefinition(@val[1])).nil?
        error('purge_unknown_id',
              "#{@val[1]} is not a known attribute for this property",
              @sourceFileInfo[1])
      end
      if attributeDefinition.scenarioSpecific
        attr = @property[@val[1], 0]
      else
        attr = @property.get(@val[1])
      end
      if @property.attributeDefinition(@val[1]).scenarioSpecific
        @property.getAttribute(@val[1], @scenarioIdx).reset
      else
        @property.getAttribute(@val[1]).reset
      end
    })
    doc('purge', "Many attributes inherit their values from the enclosing property or the global\nscope. In certain circumstances, this is not desirable, e. g. for list\nattributes. A list attribute is any attribute that takes a comma separated\nlist of values as argument. [[allocate]] and [[flags.task]] are\ngood examples of commonly used list attributes. By defining values for\nsuch a list attribute in a nested property, the new values will be appended to\nthe list that was inherited from the enclosing property. The purge\nattribute resets any attribute to its default value. A subsequent definition\nfor the attribute within the property will then add their values to an empty\nlist. The value of the enclosing property is not affected by purge.\n"
       )
    arg(1, 'attribute', 'Any name of a list attribute')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3648
  def rule_referenceAttributes
    optional
    repeatable
    pattern(%w( _label $STRING ), lambda {
      @val[1]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3656
  def rule_referenceBody
    optionsRule('referenceAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3660
  def rule_relativeId
    pattern(%w( _! !moreBangs !idOrAbsoluteId ), lambda {
      str = '!'
      if @val[1]
        @val[1].each { |bang| str += bang }
      end
      str += @val[2]
      str
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4131
  def rule_reportAttributes
    optional
    repeatable

    pattern(%w( _accountroot !accountId), lambda {
      if @val[1].leaf?
        error('accountroot_leaf',
              "#{@val[1].fullId} is not a container account",
              @sourceFileInfo[1])
      end
      @property.set('accountroot', @val[1])
    })
    doc('accountroot', "Only accounts below the specified root-level accounts are exported. The exported\naccounts will have the ID of the root-level account stripped from their ID, so that\nthe sub-accounts of the root-level account become top-level accounts in the report\nfile.\n"
       )
    example('AccountReport')

    pattern(%w( !balance ), lambda {
      @property.set('costaccount', @val[0][0])
      @property.set('revenueaccount', @val[0][1])
    })

    pattern(%w( _caption $STRING ), lambda {
      @property.set('caption', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('caption', "The caption will be embedded in the footer of the table or data segment. The\ntext will be interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    arg(1, 'text', 'The caption text.')
    example('Caption', '1')

    pattern(%w( _center $STRING ), lambda {
      @property.set('center', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('center', "This attribute defines the center section of the [[textreport]]. The text will\nbe interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    arg(1, 'text', 'The text')
    example('textreport')

    pattern(%w( _columns !columnDef !moreColumnDef ), lambda {
      columns = [ @val[1] ]
      columns += @val[2] if @val[2]
      @property.set('columns', columns)
    })
    doc('columns', "Specifies which columns shall be included in a report. Some columns show\nvalues that are constant over the course of the project. Other columns show\ncalculated values that depend on the time period that was chosen for the\nreport.\n"
       )

    pattern(%w( !currencyFormat ), lambda {
      @property.set('currencyFormat', @val[0])
    })

    pattern(%w( !reportEnd ))

    pattern(%w( _epilog $STRING ), lambda {
      @property.set('epilog', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('epilog', "Define a text section that is printed right after the actual report data. The\ntext will be interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    also(%w( footer header prolog ))

    pattern(%w( !flags ))
    doc('flags.report', "Attach a set of flags. The flags can be used in logical expressions to filter\nproperties from the reports.\n"
       )

    pattern(%w( _footer $STRING ), lambda {
      @property.set('footer', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('footer', "Define a text section that is put at the bottom of the report. The\ntext will be interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    example('textreport')
    also(%w( epilog header prolog ))

    pattern(%w( !formats ))

    pattern(%w( _header $STRING ), lambda {
      @property.set('header', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('header', "Define a text section that is put at the top of the report. The\ntext will be interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    example('textreport')
    also(%w( epilog footer prolog ))

    pattern(%w( !headline ))
    pattern(%w( !hidejournalentry ))
    pattern(%w( !hideaccount ))
    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))

    pattern(%w( _height $INTEGER ), lambda {
      if @val[1] < 200
        error('min_report_height',
              "The report must have a minimum height of 200 pixels.")
      end
      @property.set('height', @val[1])
    })
    doc('height', "Set the height of the report in pixels. This attribute is only used for\nreports that cannot determine the height based on the content. Such report can\nbe freely resized to fit in. The vast majority of reports can determine their\nheight based on the provided content. These reports will simply ignore this\nsetting.\n"
       )
    also('width')

    pattern(%w( !journalReportAttributes ))
    pattern(%w( _journalmode !journalReportMode ), lambda {
      @property.set('journalMode', @val[1])
    })
    doc('journalmode', "This attribute controls what journal entries are aggregated into the report.\n"
       )

    pattern(%w( _left $STRING ), lambda {
      @property.set('left', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('left', "This attribute defines the left margin section of the [[textreport]]. The text\nwill be interpreted as [[Rich_Text_Attributes|Rich Text]]. The margin will not\nspan the [[header]] or [[footer]] sections.\n"
       )
    example('textreport')

    pattern(%w( _loadunit !loadunit ), lambda {
      @property.set('loadUnit', @val[1])
    })
    doc('loadunit', "Determines what unit should be used to display all load values in this report.\n"
       )

    pattern(%w( !numberFormat ), lambda {
      @property.set('numberFormat', @val[0])
    })

    pattern(%w( _opennodes !nodeIdList ), lambda {
      @property.set('openNodes', @val[1])
    })
    doc('opennodes', 'For internal use only!')

    pattern(%w( !reportPeriod ))

    pattern(%w( _prolog $STRING ), lambda {
      @property.set('prolog', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('prolog', "Define a text section that is printed right before the actual report data. The\ntext will be interpreted as [[Rich_Text_Attributes|Rich Text]].\n"
       )
    also(%w( epilog footer header ))

    pattern(%w( !purge ))
    pattern(%w( !reports ))

    pattern(%w( _right $STRING ), lambda {
      @property.set('right', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('right', "This attribute defines the right margin section of the [[textreport]]. The text\nwill be interpreted as [[Rich_Text_Attributes|Rich Text]]. The margin will not\nspan the [[header]] or [[footer]] sections.\n"
       )
    example('textreport')

    pattern(%w( !rollupaccount ))
    pattern(%w( !rollupresource ))
    pattern(%w( !rolluptask ))

    pattern(%w( _scenarios !scenarioIdList ), lambda {
      # Don't include disabled scenarios in the report
      @val[1].delete_if { |sc| !@project.scenario(sc).get('active') }
      @property.set('scenarios', @val[1])
    })
    doc('scenarios', "List of scenarios that should be included in the report. By default, only the\ntop-level scenario will be included. You can use this attribute to include\ndata from the defined set of scenarios. Not all reports support reporting data\nfrom multiple scenarios. They will only include data from the first one in the\nlist.\n"
       )

    pattern(%w( _selfcontained !yesNo ), lambda {
      @property.set('selfcontained', @val[1])
    })
    doc('selfcontained', "Try to generate selfcontained output files when the format supports this. E.\ng. for HTML reports, the style sheet will be included and no icons will be\nused.\n"
       )

    pattern(%w( !sortAccounts ))
    pattern(%w( !sortJournalEntries ))
    pattern(%w( !sortResources ))
    pattern(%w( !sortTasks ))

    pattern(%w( !reportStart ))

    pattern(%w( _resourceroot !resourceId), lambda {
      if @val[1].leaf?
        error('resourceroot_leaf',
              "#{@val[1].fullId} is not a group resource",
              @sourceFileInfo[1])
      end
      @property.set('resourceroot', @val[1])
    })
    doc('resourceroot', "Only resources below the specified root-level resources are exported. The\nexported resources will have the ID of the root-level resource stripped from\ntheir ID, so that the sub-resourcess of the root-level resource become\ntop-level resources in the report file.\n"
       )
    example('ResourceRoot')

    pattern(%w( _taskroot !taskId), lambda {
      if @val[1].leaf?
        error('taskroot_leaf',
              "#{@val[1].fullId} is not a container task",
              @sourceFileInfo[1])
      end
      @property.set('taskroot', @val[1])
    })
    doc('taskroot', "Only tasks below the specified root-level tasks are exported. The exported\ntasks will have the ID of the root-level task stripped from their ID, so that\nthe sub-tasks of the root-level task become top-level tasks in the report\nfile.\n"
       )
    example('TaskRoot')

    pattern(%w( !timeformat ), lambda {
      @property.set('timeFormat', @val[0])
    })

    pattern(%w( _timezone !validTimeZone ), lambda {
      @property.set('timezone', @val[1])
    })
    doc('timezone.report', "Sets the time zone used for all dates in the report. This setting is ignored\nif the report is embedded into another report. Embedded in this context means\nthe report is part of another generated report. It does not mean that the\nreport definition is a sub report of another report definition.\n"
       )

    pattern(%w( !reportTitle ))

    pattern(%w( _width $INTEGER ), lambda {
      if @val[1] < 400
        error('min_report_width',
              "The report must have a minimum width of 400 pixels.")
      end
      @property.set('width', @val[1])
    })
    doc('width', "Set the width of the report in pixels. This attribute is only used for\nreports that cannot determine the width based on the content. Such report can\nbe freely resized to fit in. The vast majority of reports can determine their\nwidth based on the provided content. These reports will simply ignore this\nsetting.\n"
       )
    also('height')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4567
  def rule_reportBody
    optionsRule('reportAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4449
  def rule_reportEnd
    pattern(%w( _end !date ), lambda {
      if @val[1] < @property.get('start')
        error('report_end',
              "End date must be before start date #{@property.get('start')}",
              @sourceFileInfo[1])
      end
      @property.set('end', @val[1])
    })
    doc('end.report', "Specifies the end date of the report. In task reports only tasks that start\nbefore this end date are listed.\n"
       )
    example('Export', '2')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4466
  def rule_reportId
    pattern(%w( !reportIdUnverifd ), lambda {
      id = @val[0]
      if @property && @property.is_a?(Report)
        id = @property.fullId + '.' + id
      else
        id = @reportprefix + '.' + id unless @reportprefix.empty?
      end
      # In case we have a nested supplement, we need to prepend the parent ID.
      if (report = @project.report(id)).nil?
        error('report_id_expected', "#{id} is not a defined report.",
              @sourceFileInfo[0])
      end
      report
    })
    arg(0, 'report', 'The ID of a defined report')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4484
  def rule_reportIdUnverifd
    singlePattern('$ABSOLUTE_ID')
    singlePattern('$ID')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4489
  def rule_reportName
    pattern(%w( $STRING ), lambda {
      @val[0]
    })
    arg(0, 'name', "The name of the report. This will be the base name for generated output files.\nThe suffix will depend on the specified [[formats]]. It will also be used in\nnavigation bars.\n\nBy default, report definitions do not generate any files. With more complex\nprojects, most report definitions will be used to describe elements of\ncomposed reports. If you want to generate a file from this report, you must\nspecify the list of [[formats]] that you want to generate. The report name\nwill then be used as a base name to create the file. The suffix will be\nappended based on the generated format.\n\nReports have a local name space. All IDs and file names must be unique within\nthe reports that belong to the same enclosing report. To reference a report\nfor inclusion into another report, you need to specify the full report ID.\nThis is composed of the report ID, prefixed by a dot-separated list of all\nparent report IDs.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4515
  def rule_reportPeriod
    pattern(%w( _period !interval ), lambda {
      @property.set('start', @val[1].start)
      @property.set('end', @val[1].end)
    })
    doc('period.report', "This property is a shortcut for setting the start and end property at the\nsame time.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4528
  def rule_reportProperties
    pattern(%w( !export ))
    pattern(%w( !iCalReport ))
    pattern(%w( !nikuReport ))
    pattern(%w( !reports ))
    pattern(%w( !tagfile ))
    pattern(%w( !statusSheetReport ))
    pattern(%w( !timeSheetReport ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4538
  def rule_reportPropertiesBody
    optional
    repeatable

    pattern(%w( !macro ))
    pattern(%w( !reportProperties ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4546
  def rule_reportPropertiesFile
    pattern(%w( !reportPropertiesBody . ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4550
  def rule_reportStart
    pattern(%w( _start !date ), lambda {
      if @val[1] > @property.get('end')
        error('report_start',
              "Start date must be before end date #{@property.get('end')}",
              @sourceFileInfo[1])
      end
      @property.set('start', @val[1])
    })
    doc('start.report', "Specifies the start date of the report. In task reports only tasks that end\nafter this end date are listed.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4571
  def rule_reportTitle
    pattern(%w( _title $STRING ), lambda {
      @property.set('title', @val[1])
    })
    doc('title', "The title of the report will be used in external references to the report. It\nwill not show up in the reports directly. It's used e. g. by [[navigator]].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3680
  def rule_reportableAttributes
    singlePattern('_activetasks')
    descr("The number of sub-tasks (including the current task) that are active in the\nreported time period. Active means that they are ongoing at the current time\nor [[now]] date.\n"
         )

    singlePattern('_annualleave')
    descr("The number of annual leave units within the reported time period. The unit\ncan be adjusted with [[loadunit]].\n"
         )

    singlePattern('_annualleavebalance')
    descr("The balance of the annual leave at the end of the reporting interval. The unit\ncan be adjusted with [[loadunit]].\n"
         )

    singlePattern('_alert')
    descr("The alert level of the property that was reported with the date closest to the\nend date of the report. Container properties that don't have their own alert\nlevel reported with a date equal or newer than the alert levels of all their\nsub properties will get the highest alert level of their direct sub\nproperties.\n"
         )

    singlePattern('_alertmessages')
    level(:deprecated)
    also('journal')
    descr('Deprecated. Please use ''''journal'''' instead')

    singlePattern('_alertsummaries')
    level(:deprecated)
    also('journal')
    descr('Deprecated. Please use ''''journal'''' instead')

    singlePattern('_alerttrend')
    descr("Shows how the alert level at the end of the report period compares to the\nalert level at the begining of the report period. Possible values are up, down\nor flat.\n"
         )

    singlePattern('_balance')
    descr('The account balance at the beginning of the reported period.')

    singlePattern('_bsi')
    descr('The hierarchical or work breakdown structure index (i. e. 1.2.3)')

    singlePattern('_chart')
    descr("A Gantt chart. This column type requires all lines to have the same fixed\nheight. This does not work well with rich text columns in some browsers. Some\nshow a scrollbar for the compressed table cells, others don't. It is\nrecommended, that you don't use rich text columns in conjuction with the chart\ncolumn.\n"
         )

    singlePattern('_closedtasks')
    descr("The number of sub-tasks (including the current task) that have been closed\nduring the reported time period.  Closed means that they have and end date\nbefore the current time or [[now]] date.\n"
         )

    singlePattern('_complete')
    descr("The completion degree of a task. Unless a completion degree is manually\nprovided, this is a computed value relative the [[now]] date of the project. A\ntask that has ended before the now date is always 100% complete. A task that\nstarts at or after the now date is always 0%. For [[effort]] based task the\ncomputation degree is the percentage of done effort of the overall effort. For\nother leaf task, the completion degree is the percentage of the already passed\nduration of the overall task duration. For container task, it's always the\naverage of the direct sub tasks. If the sub tasks consist of a mixture of\neffort and non-effort tasks, the completion value is only of limited value.\n"
         )

    pattern([ '_completed' ], lambda {
      'complete'
    })
    level(:deprecated)
    also('complete')
    descr('Deprecated alias for complete')

    singlePattern('_criticalness')
    descr('A measure for how much effort the resource is allocated for, or' +
          'how strained the allocated resources of a task are')

    singlePattern('_cost')
    descr("The cost of the task or resource. The use of this column requires that a cost\naccount has been set for the report using the [[balance]] attribute.\n"
         )

    singlePattern('_daily')
    descr('A group of columns with one column for each day')

    singlePattern('_directreports')
    descr("The resources that have this resource assigned as manager.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    singlePattern('_duration')
    descr('The duration of a task')

    singlePattern('_duties')
    descr('List of tasks that the resource is allocated to')

    singlePattern('_efficiency')
    descr('Measure for how efficient a resource can perform tasks')

    singlePattern('_effort')
    descr('The allocated effort during the reporting period')

    singlePattern('_effortdone')
    descr('The already completed effort as of now')

    singlePattern('_effortleft')
    descr('The remaining allocated effort as of now')

    singlePattern('_email')
    descr('The email address of a resource')

    singlePattern('_end')
    descr('The end date of a task')

    singlePattern('_flags')
    descr('List of attached flags')

    singlePattern('_followers')
    descr("A list of tasks that depend on the current task. The list contains the names,\nthe IDs, the date and the type of dependency. For the type the following\nsymbols are used for <nowiki><dep></nowiki>.\n\n* '''<nowiki>]->[</nowiki>''': End-to-Start dependency\n* '''<nowiki>[->[</nowiki>''': Start-to-Start dependency\n* '''<nowiki>]->]</nowiki>''': End-to-End dependency\n* '''<nowiki>[->]</nowiki>''': Start-to-End dependency\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\nThe dependency symbol can be generated via the ''''dependency'''' attribute\ninthe query, the target date via the ''''date'''' attribute.\n"
         )

    singlePattern('_freetime')
    descr("The amount of unallocated work time of a resource during the reporting period.\n"
         )

    singlePattern('_freework')
    descr("The amount of unallocated work capacity of a resource during the reporting\nperiod. This is the product of unallocated work time times the efficiency of\nthe resource.\n"
         )

    singlePattern('_fte')
    descr("The Full-Time-Equivalent of a resource or group. This is the ratio of the\nresource working time and the global working time. Working time is defined by\nworking hours and leaves. The FTE value can vary over time and is\ncalculated for the report interval or the user specified interval.\n"
         )

    singlePattern('_gauge')
    descr("When [[complete]] values have been provided to capture the actual progress on\ntasks, the gauge column will list whether the task is ahead of, behind or on\nschedule.\n"
         )

    singlePattern('_headcount')
    descr("For resources this is the headcount number of the resource or resource group.\nFor a single resource this is the [[efficiency]] rounded to the next integer.\nFor a group it is the sum of the sub resources headcount.\n\nFor tasks it's the number of different resources allocated to the task during\nthe report interval. Resources are weighted with their rounded efficiencies.\n"
         )

    pattern([ '_hierarchindex' ], lambda {
      'bsi'
    })
    level(:deprecated)
    also('bsi')
    descr('Deprecated alias for bsi')

    singlePattern('_hourly')
    descr('A group of columns with one column for each hour')

    singlePattern('_id')
    descr('The id of the item')

    singlePattern('_index')
    descr('The index of the item based on the nesting hierachy')

    singlePattern('_inputs')
    descr("A list of milestones that are a prerequiste for the current task. For\ncontainer tasks it will also include the inputs of the child tasks. Inputs may\nnot have any predecessors.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    singlePattern('_journal')
    descr("The journal entries for the task or resource for the reported interval. The\ngenerated text can be customized with the [[journalmode]],\n[[journalattributes]], [[hidejournalentry]] and [[sortjournalentries]]. If\nused in queries without a property context, the journal for the complete\nproject is generated.\n"
         )

    singlePattern('_journal_sub')
    level(:deprecated)
    also('journal')
    descr('Deprecated. Please use ''''journal'''' instead')

    singlePattern('_journalmessages')
    level(:deprecated)
    also('journal')
    descr('Deprecated. Please use ''''journal'''' instead')

    singlePattern('_journalsummaries')
    level(:deprecated)
    also('journal')
    descr('Deprecated. Please use ''''journal'''' instead')

    singlePattern('_line')
    descr('The line number in the report')

    singlePattern('_managers')
    descr("A list of managers that the resource reports to.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
        )

    singlePattern('_maxend')
    descr('The latest allowed end of a task')

    singlePattern('_maxstart')
    descr('The lastest allowed start of a task')

    singlePattern('_minend')
    descr('The earliest allowed end of a task')

    singlePattern('_minstart')
    descr('The earliest allowed start of a task')

    singlePattern('_monthly')
    descr('A group of columns with one column for each month')

    singlePattern('_no')
    descr('The object line number in the report (Cannot be used for sorting!)')

    singlePattern('_name')
    descr('The name or description of the item')

    singlePattern('_note')
    descr('The note attached to a task')

    singlePattern('_opentasks')
    descr("The number of sub-tasks (including the current task) that have not yet been\nclosed during the reported time period. Closed means that they have and end\ndate before the current time or [[now]] date.\n"
         )

    singlePattern('_pathcriticalness')
    descr('The criticalness of the task with respect to all the paths that ' +
          'it is a part of.')

    singlePattern('_precursors')
    descr("A list of tasks the current task depends on. The list contains the names, the\nIDs, the date and the type of dependency. For the type the following symbols\nare used\n\n* '''<nowiki>]->[</nowiki>''': End-to-Start dependency\n* '''<nowiki>[->[</nowiki>''': Start-to-Start dependency\n* '''<nowiki>]->]</nowiki>''': End-to-End dependency\n* '''<nowiki>[->]</nowiki>''': Start-to-End dependency\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\nThe dependency symbol can be generated via the ''''dependency'''' attribute\ninthe query, the target date via the ''''date'''' attribute.\n"
         )

    singlePattern('_priority')
    descr('The priority of a task')

    singlePattern('_quarterly')
    descr('A group of columns with one column for each quarter')

    singlePattern('_rate')
    descr('The daily cost of a resource.')

    singlePattern('_reports')
    descr("All resources that have this resource assigned as a direct or indirect manager.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    singlePattern('_resources')
    descr("A list of resources that are assigned to the task in the report time frame.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    singlePattern('_responsible')
    descr("The responsible people for this task.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    singlePattern('_revenue')
    descr("The revenue of the task or resource. The use of this column requires that a\nrevenue account has been set for the report using the [[balance]] attribute.\n"
         )

    singlePattern('_scenario')
    descr('The name of the scenario')

    singlePattern('_seqno')
    descr('The index of the item based on the declaration order')

    singlePattern('_sickleave')
    descr("The number of sick leave units within the reported time period. The unit can\nbe adjusted with [[loadunit]].\n"
         )

    singlePattern('_specialleave')
    descr("The number of special leave units within the reported time period. The unit\ncan be adjusted with [[loadunit]].\n"
         )

    singlePattern('_start')
    descr('The start date of the task')

    singlePattern('_status')
    descr("The status of a task. It is determined based on the current date or the date\nspecified by [[now]].\n"
         )

    singlePattern('_targets')
    descr("A list of milestones that depend on the current task. For container tasks it\nwill also include the targets of the child tasks. Targets may not have any\nfollower tasks.\n\nThe list can be customized by the [[listitem.column|listitem]] attribute.\n"
         )

    pattern([ '_wbs' ], lambda {
      'bsi'
    })
    level(:deprecated)
    also('bsi')
    descr('Deprecated alias for bsi.')

    singlePattern('_unpaidleave')
    descr("The number of unpaid leave units within the reported time period. The unit\ncan be adjusted with [[loadunit]].\n"
         )

    singlePattern('_weekly')
    descr('A group of columns with one column for each week')

    singlePattern('_yearly')
    descr('A group of columns with one column for each year')

  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 3672
  def rule_reports
    pattern(%w( !accountReport ))
    pattern(%w( !resourceReport ))
    pattern(%w( !taskReport ))
    pattern(%w( !textReport ))
    pattern(%w( !traceReport ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4583
  def rule_resource
    pattern(%w( !resourceHeader !resourceBody ), lambda {
       @property = @property.parent
    })
    doc('resource', "Tasks that have an effort specification need to have at least one resource\nassigned to do the work. Use this property to define resources or groups of\nresources.\n\nResources have a global name space. All IDs must be unique within the resources\nof the project.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4599
  def rule_resourceAttributes
    repeatable
    optional
    pattern(%w( _email $STRING ), lambda {
      @property.set('email', @val[1])
    })
    doc('email',
        'The email address of the resource.')

    pattern(%w( !journalEntry ))
    pattern(%w( !purge ))
    pattern(%w( !resource ))
    pattern(%w( !resourceScenarioAttributes ))
    pattern(%w( !scenarioIdCol !resourceScenarioAttributes ), lambda {
      @scenarioIdx = 0
    })

    pattern(%w( _supplement !resourceId !resourceBody ), lambda {
      @property = @idStack.pop
    })
    doc('supplement.resource', "The supplement keyword provides a mechanism to add more attributes to already\ndefined resources. The additional attributes must obey the same rules as in\nregular resource definitions and must be enclosed by curly braces.\n\nThis construct is primarily meant for situations where the information about a\nresource is split over several files. E. g. the vacation dates for the\nresources may be in a separate file that was generated by some other tool.\n"
       )
    example('Supplement', 'resource')

    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4635
  def rule_resourceBody
    optionsRule('resourceAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4639
  def rule_resourceBooking
    pattern(%w( !resourceBookingHeader !bookingBody ), lambda {
      unless @project.scenario(@scenarioIdx).get('ownbookings')
        error('no_own_resource_booking',
              "The scenario #{@project.scenario(@scenarioIdx).fullId} " +
              'inherits its bookings from the tracking ' +
              'scenario. You cannot specificy additional bookings for it.')
      end
      @val[0].task.addBooking(@scenarioIdx, @val[0])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4651
  def rule_resourceBookingHeader
    pattern(%w( !taskId !valIntervals ), lambda {
      checkBooking(@val[0], @property)
      @booking = Booking.new(@property, @val[0], @val[1])
      @booking.sourceFileInfo = @sourceFileInfo[0]
      @booking
    })
    arg(0, 'id', 'Absolute ID of a defined task')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4673
  def rule_resourceHeader
    pattern(%w( _resource !optionalID $STRING ), lambda {
      if @property.nil? && !@resourceprefix.empty?
        @property = @project.resource(@resourceprefix)
      end
      if @val[1] && @project.resource(@val[1])
        error('resource_exists',
              "Resource #{@val[1]} has already been defined.",
              @sourceFileInfo[1], @property)
      end
      @property = Resource.new(@project, @val[1], @val[2], @property)
      @property.sourceFileInfo = @sourceFileInfo[0]
      @property.inheritAttributes
      @scenarioIdx = 0
    })
#    arg(1, 'id', <<'EOT'
#The ID of the resource. Resources have a global name space. The ID must be
#unique within the whole project.
#EOT
#       )
    arg(2, 'name', 'The name of the resource')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4661
  def rule_resourceId
    pattern(%w( $ID ), lambda {
      id = (@resourceprefix.empty? ? '' : @resourceprefix + '.') + @val[0]
      if (resource = @project.resource(id)).nil?
        error('resource_id_expected', "#{id} is not a defined resource.",
              @sourceFileInfo[0])
      end
      resource
    })
    arg(0, 'resource', 'The ID of a defined resource')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4696
  def rule_resourceLeafList
    listRule('moreResourceLeafList', '!leafResourceId')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4700
  def rule_resourceList
    listRule('moreResources', '!resourceId')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4704
  def rule_resourceReport
    pattern(%w( !resourceReportHeader !reportBody ), lambda {
      @property = @property.parent
    })
    doc('resourcereport', "The report lists resources and their respective values in a table. The task\nthat are the resources are allocated to can be listed as well. To reduce the\nlist of included resources, you can use the [[hideresource]],\n[[rollupresource]] or [[resourceroot]] attributes. The order of the task can\nbe controlled with [[sortresources]]. If the first sorting criteria is tree\nsorting, the parent resources will always be included to form the tree.\nTree sorting is the default. You need to change it if you do not want certain\nparent resources to be included in the report.\n\nBy default, all the tasks that the resources are allocated to are hidden, but\nthey can be listed as well. Use the [[hidetask]] attribute to select which\ntasks should be included.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4726
  def rule_resourceReportHeader
    pattern(%w( _resourcereport !optionalID !reportName ), lambda {
      newReport(@val[1], @val[2], :resourcereport, @sourceFileInfo[0])

      unless @property.modified?('columns')
        # Set the default columns for this report.
        %w( no name ).each do |col|
          @property.get('columns') <<
          TableColumnDefinition.new(col, columnTitle(col))
        end
      end
      # Show all resources, sorted by tree and id-up.
      unless @property.modified?('hideResource')
        @property.set('hideResource',
                      LogicalExpression.new(LogicalOperation.new(0)))
      end
      unless @property.modified?('sortResources')
        @property.set('sortResources', [ [ 'tree', true, -1 ],
                      [ 'id', true, -1 ] ])
      end
      # Hide all resources, but set sorting to tree, start-up, seqno-up.
      unless @property.modified?('hideTask')
        @property.set('hideTask',
                      LogicalExpression.new(LogicalOperation.new(1)))
      end
      unless @property.modified?('sortTasks')
        @property.set('sortTasks',
                      [ [ 'tree', true, -1 ],
                        [ 'start', true, 0 ],
                        [ 'seqno', true, -1 ] ])
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4760
  def rule_resourceScenarioAttributes
    pattern(%w( !chargeset ))

    pattern(%w( _efficiency !number ), lambda {
      @property['efficiency', @scenarioIdx] = @val[1]
    })
    doc('efficiency', "The efficiency of a resource can be used for two purposes. First you can use\nit as a crude way to model a team. A team of 5 people should have an\nefficiency of 5.0. Keep in mind that you cannot track the members of the team\nindividually if you use this feature. They always act as a group.\n\nThe other use is to model performance variations between your resources. Again, this is a fairly crude mechanism and should be used with care. A resource that isn't every good at some task might be pretty good at another. This can't be taken into account as the resource efficiency can only set globally for all tasks.\n\nAll resources that do not contribute effort to the task, should have an\nefficiency of 0.0. A typical example would be a conference room. It's necessary for a meeting, but it does not contribute any work.\n"
       )
    example('Efficiency')
    pattern(%w( !flags ))
    doc('flags.resource', "Attach a set of flags. The flags can be used in logical expressions to filter\nproperties from the reports.\n"
       )

    pattern(%w( _booking !resourceBooking ))
    doc('booking.resource', "The booking attribute can be used to report actually completed work.  A task\nwith bookings must be [[scheduling|scheduled]] in ''''asap'''' mode.  If the\nscenario is not the [[trackingscenario|tracking scenario]] or derived from it,\nthe scheduler will not allocate resources prior to the current date or the\ndate specified with [[now]] when a task has at least one booking.\n\nBookings are only valid in the scenario they have been defined in. They will\nin general not be passed to any other scenario. If you have defined a\n[[trackingscenario|tracking scenario]], the bookings of this scenario will be\npassed to all the derived scenarios of the tracking scenario.\n\nThe sloppy attribute can be used when you want to skip non-working time or\nother allocations automatically. If it's not given, all bookings must only\ncover working time for the resource.\n\nThe booking attributes is designed to capture the exact amount of completed\nwork. This attribute is not really intended to specify completed effort by\nhand. Usually, booking statements are generated by [[export]] reports. The\n[[sloppy.booking|sloppy]] and [[overtime.booking|overtime]] attributes are\nonly kludge for users who want to write them manually.\nBookings can be used to report already completed work by specifying the exact\ntime intervals a certain resource has worked on this task.\n\nBookings can be defined in the task or resource context. If you move tasks\naround very often, put your bookings in the task context.\n"
       )
    also(%w( scheduling booking.task ))
    example('Booking')

    pattern(%w( !fail ))

    pattern(%w( !leaveAllowances ))

    pattern(%w( !leaves ), lambda {
      begin
        @property['leaves', @scenarioIdx] += @val[0]
      rescue AttributeOverwrite
      end
    })

    pattern(%w( !limits ), lambda {
      @property['limits', @scenarioIdx] = @val[0]
    })
    doc('limits.resource', "Set per-interval usage limits for the resource.\n"
       )
    example('Limits-1', '6')

    pattern(%w( _managers !resourceList ), lambda {
      @property['managers', @scenarioIdx] =
        @property['managers', @scenarioIdx] + @val[1]
    })
    doc('managers', "Defines one or more resources to be the manager who is responsible for this\nresource. Managers must be leaf resources. This attribute does not impact the\nscheduling. It can only be used for documentation purposes.\n\nYou must only specify direct managers here. Do not list higher level managers\nhere. If necessary, use the [[purge]] attribute to clear\ninherited managers. For most use cases, there should be only one manager. But\nTaskJuggler is not limited to just one manager. Dotted reporting lines can be\ncaptured as well as long as the managers are not reporting to each other.\n"
       )
    also(%w( statussheet ))
    example('Manager')


    pattern(%w( _rate !number ), lambda {
      @property['rate', @scenarioIdx] = @val[1]
    })
    doc('rate.resource', "The rate specifies the daily cost of the resource.\n"
       )

    pattern(%w( !resourceShiftAssignments !shiftAssignments ), lambda {
      checkContainer('shifts')
      # Set same value again to set the 'provided' state for the attribute.
      begin
        @property['shifts', @scenarioIdx] = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    level(:deprecated)
    also('shift.resource')
    doc('shift.resource', "This keyword has been deprecated. Please use [[shifts.resource|shifts\n(resource)]] instead.\n"
       )

    pattern(%w( !resourceShiftsAssignments !shiftAssignments ), lambda {
      checkContainer('shifts')
      # Set same value again to set the 'provided' state for the attribute.
      begin
        @property['shifts', @scenarioIdx] = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    doc('shifts.resource', "Limits the working time of a resource to a defined shift during the specified\ninterval. Multiple shifts can be defined, but shift intervals may not overlap.\nIn case a shift is defined for a certain interval, the shift working hours\nreplace the standard resource working hours for this interval.\n"
        )

    pattern(%w( _vacation !vacationName !intervals ), lambda {
      @val[2].each do |interval|
        begin
          # We map the old 'vacation' attribute to public holidays.
          @property['leaves', @scenarioIdx] += [ Leave.new(:holiday, interval) ]
        rescue AttributeOverwrite
        end
      end
    })
    doc('vacation.resource', "Specify a vacation period for the resource. It can also be used to block out\nthe time before a resource joined or after it left. For employees changing\ntheir work schedule from full-time to part-time, or vice versa, please refer\nto the 'Shift' property.\n"
       )

    pattern(%w( !warn ))

    pattern(%w( !workinghoursResource ))
    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4936
  def rule_resourceShiftAssignments
    pattern(%w( _shift ), lambda {
      @shiftAssignments = @property['shifts', @scenarioIdx]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4942
  def rule_resourceShiftsAssignments
    pattern(%w( _shifts ), lambda {
      @shiftAssignments = @property['shifts', @scenarioIdx]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4948
  def rule_rollupaccount
    pattern(%w( _rollupaccount !logicalExpression ), lambda {
      @property.set('rollupAccount', @val[1])
    })
    doc('rollupaccount', "Do not show sub-accounts of accounts that match the specified logical\nexpression.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4960
  def rule_rollupresource
    pattern(%w( _rollupresource !logicalExpression ), lambda {
      @property.set('rollupResource', @val[1])
    })
    doc('rollupresource', "Do not show sub-resources of resources that match the specified logical\nexpression.\n"
       )
    example('RollupResource')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4973
  def rule_rolluptask
    pattern(%w( _rolluptask !logicalExpression ), lambda {
      @property.set('rollupTask', @val[1])
    })
    doc('rolluptask', "Do not show sub-tasks of tasks that match the specified logical expression.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 4985
  def rule_scenario
    pattern(%w( !scenarioHeader !scenarioBody ), lambda {
      @property = @property.parent
    })
    doc('scenario', "Defines a new project scenario. By default, the project has only one scenario\ncalled ''''plan''''. To do plan vs. actual comparisons or to do a\nwhat-if-analysis, you can define a set of scenarios. There can only be one\ntop-level scenario. Additional scenarios are either derived from this\ntop-level scenario or other scenarios.\n\nEach nested scenario is a variation of the enclosing scenario. All scenarios\nshare the same set of properties (task, resources, etc.) but the attributes\nthat are listed as scenario specific may differ between the various\nscenarios. A nested scenario uses all attributes from the enclosing scenario\nunless the user has specified a different value for this attribute.\n\nBy default, the scheduler assigns resources to task beginning with the project\nstart date. If the scenario is switched to projection mode, no assignments\nwill be made prior to the current date or the date specified by [[now]]. In\nthis case, TaskJuggler assumes, that all assignements prior to the\ncurrent date have been provided by [[booking.task]] statements.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5012
  def rule_scenarioAttributes
    optional
    repeatable

    pattern(%w( _active !yesNo), lambda {
      @property.set('active', @val[1])
    })
    doc('active', "Enable the scenario to be scheduled or not. By default, all scenarios will be\nscheduled. If a scenario is marked as inactive, it not be scheduled and will\nbe ignored in the reports.\n"
       )
    pattern(%w( _disabled ), lambda {
      @property.set('active', false)
    })
    level(:deprecated)
    also('active')
    doc('disabled', "This attribute is deprecated. Please use [active] instead.\n\nDisable the scenario for scheduling. The default for the top-level\nscenario is to be enabled.\n"
       )
    example('Scenario')
    pattern(%w( _enabled ), lambda {
      @property.set('active', true)
    })
    level(:deprecated)
    also('active')
    doc('enabled', "This attribute is deprecated. Please use [active] instead.\n\nEnable the scenario for scheduling. This is the default for the top-level\nscenario.\n"
       )

    pattern(%w( _projection !projection ))
    level(:deprecated)
    also('booking.task')
    doc('projection', "This keyword has been deprecated! Don't use it anymore!\n\nProjection mode is now automatically enabled as soon as a scenario has\nbookings.\n"
       )

    pattern(%w( !scenario ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5069
  def rule_scenarioBody
    optionsRule('scenarioAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5073
  def rule_scenarioHeader

    pattern(%w( _scenario $ID $STRING ), lambda {
      # If this is the top-level scenario, we must delete the default scenario
      # first.
      @project.scenarios.each do |scenario|
        if scenario.get('projection')
          error('scenario_after_tracking',
                'Scenarios must be defined before a tracking scenario is set.')
        end
      end
      @project.scenarios.clearProperties if @property.nil?
      if @project.scenario(@val[1])
        error('scenario_exists',
              "Scenario #{@val[1]} has already been defined.",
              @sourceFileInfo[1])
      end
      @property = Scenario.new(@project, @val[1], @val[2], @property)
      @property.inheritAttributes
    })
    arg(1, 'id', 'The ID of the scenario')
    arg(2, 'name', 'The name of the scenario')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5097
  def rule_scenarioId
    pattern(%w( $ID ), lambda {
      if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
        error('unknown_scenario_id', "Unknown scenario: #{@val[0]}",
              @sourceFileInfo[0])
      end
      @scenarioIdx
    })
    arg(0, 'scenario', 'ID of a defined scenario')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5108
  def rule_scenarioIdCol
    pattern(%w( $ID_WITH_COLON ), lambda {
      if (@scenarioIdx = @project.scenarioIdx(@val[0])).nil?
        error('unknown_scenario_id', "Unknown scenario: #{@val[0]}",
              @sourceFileInfo[0])
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5117
  def rule_scenarioIdList
    listRule('moreScnarioIdList', '!scenarioIdx')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5121
  def rule_scenarioIdx
    pattern(%w( $ID ), lambda {
      if (scenarioIdx = @project.scenarioIdx(@val[0])).nil?
        error('unknown_scenario_idx', "Unknown scenario #{@val[0]}",
              @sourceFileInfo[0])
      end
      scenarioIdx
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5131
  def rule_schedulingDirection
    singlePattern('_alap')
    singlePattern('_asap')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5136
  def rule_shift
    pattern(%w( !shiftHeader !shiftBody ), lambda {
      @property = @property.parent
    })
    doc('shift', "A shift combines several workhours related settings in a reusable entity.\nBesides the weekly working hours it can also hold information such as\nleaves and a time zone.\n\nShifts have a global name space. All IDs must be unique within the shifts of\nthe project.\n"
       )
    also(%w( shifts.task shifts.resource ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5153
  def rule_shiftAssignment
    pattern(%w( !shiftId !intervalOptional ), lambda {
      # Make sure we have a ShiftAssignment for the property.
      unless @shiftAssignments
        @shiftAssignments = ShiftAssignments.new
        @shiftAssignments.project = @project
      end

      if @val[1].nil?
        interval = TimeInterval.new(@project['start'], @project['end'])
      else
        interval = @val[1]
      end
      if !@shiftAssignments.addAssignment(
         ShiftAssignment.new(@val[0].scenario(@scenarioIdx), interval))
        error('shift_assignment_overlap',
              'Shifts may not overlap each other.',
              @sourceFileInfo[0], @property)
      end
      @shiftAssignments.assignments.last
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5176
  def rule_shiftAssignments
    listRule('moreShiftAssignments', '!shiftAssignment')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5180
  def rule_shiftAttributes
    optional
    repeatable

    pattern(%w( !shift ))
    pattern(%w( !shiftScenarioAttributes ))
    pattern(%w( !scenarioIdCol !shiftScenarioAttributes ), lambda {
      @scenarioIdx = 0
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5191
  def rule_shiftBody
    optionsRule('shiftAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5195
  def rule_shiftHeader
    pattern(%w( _shift !optionalID $STRING ), lambda {
      if @val[1] && @project.shift(@val[1])
        error('shift_exists', "Shift #{@val[1]} has already been defined.",
              @sourceFileInfo[1])
      end
      @property = Shift.new(@project, @val[1], @val[2], @property)
      @property.sourceFileInfo = @sourceFileInfo[0]
      @property.inheritAttributes
      @scenarioIdx = 0
    })
    arg(2, 'name', 'The name of the shift')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5209
  def rule_shiftId
    pattern(%w( $ID ), lambda {
      if (shift = @project.shift(@val[0])).nil?
        error('shift_id_expected', "#{@val[0]} is not a defined shift.",
              @sourceFileInfo[0])
      end
      shift
    })
    arg(0, 'shift', 'The ID of a defined shift')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5220
  def rule_shiftScenarioAttributes
    pattern(%w( !leaves ), lambda {
      begin
        @property['leaves', @scenarioIdx] += @val[0]
      rescue AttributeOverwrite
      end
    })

    pattern(%w( _replace ), lambda {
      @property['replace', @scenarioIdx] = true
    })
    doc('replace', "This replace mode is only effective for shifts that are assigned to resources\ndirectly. When replace mode is activated the leave definitions of the shift\nwill replace all the leave definitions of the resource for the given period.\n\nThe mode is not effective for shifts that are assigned to tasks or allocations.\n"
       )

    pattern(%w( _timezone !validTimeZone ), lambda {
      @property['timezone', @scenarioIdx] = @val[1]
    })
    doc('timezone.shift', "Sets the time zone of the shift. The working hours of the shift are assumed to\nbe within the specified time zone. The time zone does not effect the vaction\ninterval. The latter is assumed to be within the project time zone.\n\nTaskJuggler stores all dates internally as UTC. Since all events must align\nwith the [[timingresolution|timing resolution]] for time zones you may have to\nchange the timing resolution appropriately. The time zone difference compared\nto UTC must be a multiple of the used timing resolution.\n"
        )
    arg(1, 'zone', "Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3\nletter acronyms. See\n[http://en.wikipedia.org/wiki/List_of_zoneinfo_time_zones Wikipedia] for\npossible values.\n"
       )

    pattern(%w( _vacation !vacationName !intervalsOptional ), lambda {
      @val[2].each do |interval|
        begin
          # We map the old 'vacation' attribute to public holidays.
          @property['leaves', @scenarioIdx] += [ Leave.new(:holiday, interval) ]
        rescue AttributeOverwrite
        end
      end
    })
    doc('vacation.shift', "Specify a vacation period associated with this shift.\n"
       )

    pattern(%w( !workinghoursShift ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5370
  def rule_sortAccounts
    pattern(%w( _sortaccounts !sortCriteria ), lambda {
      @property.set('sortAccounts', @val[1])
    })
    doc('sortaccounts', "Determines how the accounts are sorted in the report. Multiple criteria can be\nspecified as a comma separated list. If one criteria is not sufficient to sort\na group of accounts, the next criteria will be used to sort the accounts in\nthis group.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5283
  def rule_sortCriteria
    pattern([ "!sortCriterium", "!moreSortCriteria" ], lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5289
  def rule_sortCriterium
    pattern(%w( !sortTree ), lambda {
      @val[0]
    })
    pattern(%w( !sortNonTree ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5344
  def rule_sortJournalEntries
    pattern(%w( _sortjournalentries !journalSortCriteria ), lambda {
      @property.set('sortJournalEntries', @val[1])
    })
    doc('sortjournalentries', "Determines how the entries in a journal are sorted. Multiple criteria can be\nspecified as a comma separated list. If one criteria is not sufficient to sort\na group of journal entries, the next criteria will be used to sort the entries\nin this group.\n\nThe following values are supported:\n* ''''date.down'''': Sort descending order by the date of the journal entry\n* ''''date.up'''': Sort ascending order by the date of the journal entry\n* ''''alert.down'''': Sort in descending order by the alert level of the\njournal entry\n* ''''alert.up'''': Sort in ascending order by the alert level of the\njournal entry\n ''''property.down'''': Sort in descending order by the task or resource\nthe journal entry is associated with\n* ''''property.up'''': Sort in ascending order by the task or resource the\njournal entry is associated with\n"
        )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5298
  def rule_sortNonTree
    pattern(%w( $ABSOLUTE_ID ), lambda {
      args = @val[0].split('.')
      case args.length
      when 2
        # <attribute>.<up|down>
        scenario = -1
        direction = args[1] == 'up'
        attribute = args[0]
      when 3
        # <scenario>.<attribute>.<up|down>
        if (scenario = @project.scenarioIdx(args[0])).nil?
          error('sort_unknown_scen',
                "Unknown scenario #{args[0]} in sorting criterium",
                @sourceFileInfo[0])
        end
        attribute = args[1]
        if args[2] != 'up' && args[2] != 'down'
          error('sort_direction', "Sorting direction must be 'up' or 'down'",
                @sourceFileInfo[0])
        end
        direction = args[2] == 'up'
      else
        error('sorting_crit_exptd1',
              "Sorting criterium expected (e.g. tree, start.up or " +
              "plan.end.down).", @sourceFileInfo[0])
      end
      if attribute == 'bsi'
        error('sorting_bsi',
              "Sorting by bsi is not supported. Please use 'tree' " +
              '(without appended .up or .down) instead.',
              @sourceFileInfo[0])
      end
      [ attribute, direction, scenario ]
    })
    arg(0, 'criteria', "The sorting criteria must consist of a property attribute ID. See [[columnid]]\nfor a complete list of available attributes. The ID must be suffixed by '.up'\nor '.down' to determine the sorting direction. Optionally the ID may be\nprefixed with a scenario ID and a dot to determine the scenario that should be\nused for sorting. So, possible values are 'plan.start.up' or 'priority.down'.\n"
         )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5384
  def rule_sortResources
    pattern(%w( _sortresources !sortCriteria ), lambda {
      @property.set('sortResources', @val[1])
    })
    doc('sortresources', "Determines how the resources are sorted in the report. Multiple criteria can be\nspecified as a comma separated list. If one criteria is not sufficient to sort\na group of resources, the next criteria will be used to sort the resources in\nthis group.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5398
  def rule_sortTasks
    pattern(%w( _sorttasks !sortCriteria ), lambda {
      @property.set('sortTasks', @val[1])
    })
    doc('sorttasks', "Determines how the tasks are sorted in the report. Multiple criteria can be\nspecified as comma separated list. If one criteria is not sufficient to sort a\ngroup of tasks, the next criteria will be used to sort the tasks within\nthis group.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5412
  def rule_sortTree
    pattern(%w( $ID ), lambda {
      if @val[0] != 'tree'
        error('sorting_crit_exptd2',
              "Sorting criterium expected (e.g. tree, start.up or " +
              "plan.end.down).", @sourceFileInfo[0])
      end
      [ 'tree', true, -1 ]
    })
    arg(0, 'tree',
        'Use \'tree\' as first criteria to keep the breakdown structure.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5450
  def rule_ssReportAttributes
    optional
    repeatable

    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))
    pattern(%w( !reportEnd ))
    pattern(%w( !reportPeriod ))
    pattern(%w( !reportStart ))
    pattern(%w( !sortResources ))
    pattern(%w( !sortTasks ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5463
  def rule_ssReportBody
    optionsRule('ssReportAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5424
  def rule_ssReportHeader
    pattern(%w( _statussheetreport !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :statusSheet, @sourceFileInfo[0])
      @property.set('formats', [ :tjp ])

      unless @project.scenario(0).get('active')
        @property.set('scenarios', [ 0 ])
      end
      # Show all tasks, sorted by id-up.
      @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortTasks', [ [ 'id', true, -1 ] ])
      # Show all resources, sorted by seqno-up.
      @property.set('hideResource',
                    LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
      @property.set('loadUnit', :hours)
      @property.set('definitions', [])
    })
    arg(2, 'file name', "The name of the status sheet report file to generate. It must end with a .tji\nextension, or use . to use the standard output channel.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5507
  def rule_ssStatus
    pattern(%w( !ssStatusHeader !ssStatusBody ))
    doc('status.statussheet', "The status attribute can be used to describe the current status of the task or\nresource. The content of the status messages is added to the project journal.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5467
  def rule_ssStatusAttributes
    optional
    repeatable

    pattern(%w( !author ))
    pattern(%w( !details ))

    pattern(%w( _flags !flagList ), lambda {
      @val[1].each do |flag|
        next if @journalEntry.flags.include?(flag)

        @journalEntry.flags << flag
      end
    })
    doc('flags.statussheet', "Status sheet entries can have flags attached to them. These can be used to\ninclude only entries in a report that have a certain flag.\n"
       )

    pattern(%w( !summary ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5491
  def rule_ssStatusBody
    optional
    pattern(%w( _{ !ssStatusAttributes _} ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5496
  def rule_ssStatusHeader
    pattern(%w( _status !alertLevel $STRING ), lambda {
      @journalEntry = JournalEntry.new(@project['journal'], @sheetEnd,
                                       @val[2], @property,
                                       @sourceFileInfo[0])
      @journalEntry.alertLevel = @val[1]
      @journalEntry.author = @sheetAuthor
      @journalEntry.moderators << @sheetModerator
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5517
  def rule_statusSheet
    pattern(%w( !statusSheetHeader !statusSheetBody ), lambda {
      [ @sheetAuthor, @sheetStart, @sheetEnd ]
    })
    doc('statussheet', "A status sheet can be used to capture the status of various tasks outside of\nthe regular task tree definition. It is intended for use by managers that\ndon't directly work with the full project plan, but need to report the current\nstatus of each task or task-tree that they are responsible for.\n"
       )
    example('StatusSheet')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5532
  def rule_statusSheetAttributes
    optional
    repeatable

    pattern(%w( !statusSheetTask ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5539
  def rule_statusSheetBody
    optionsRule('statusSheetAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5543
  def rule_statusSheetFile
    pattern(%w( !statusSheet . ), lambda {
      @val[0]
    })
    lastSyntaxToken(1)
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5551
  def rule_statusSheetHeader
    pattern(%w( _statussheet !resourceId !valIntervalOrDate ), lambda {
      unless @project['trackingScenarioIdx']
        error('ss_no_tracking_scenario',
              'No trackingscenario defined.')
      end
      @sheetAuthor = @val[1]
      @sheetModerator = @val[1]
      @sheetStart = @val[2].start
      @sheetEnd = @val[2].end
      # Make sure that we don't have any status sheet entries from the same
      # author for the same report period. There may have been a previous
      # submission of the same report and this is an update to it. All old
      # entries must be removed before we process the sheet.
      @project['journal'].delete_if do |e|
        # Journal entries from status sheets have the sheet end date as entry
        # date.
        e.moderators.include?(@sheetModerator) && e.date == @sheetEnd
      end
    })
    arg(1, 'reporter', "The ID of a defined resource. This identifies the status reporter. Unless the\nstatus entries provide a different author, the sheet author will be used as\nstatus entry author.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5580
  def rule_statusSheetReport
    pattern(%w( !ssReportHeader !ssReportBody ), lambda {
      @property = nil
    })
    doc('statussheetreport', "A status sheet report is a template for a status sheet. It collects all the\nstatus information of the top-level task that a resource is responsible for.\nThis report is typically used by managers or team leads to review the time\nsheet status information and destill it down to a summary that can be\nforwarded to the next person in the reporting chain. The report will be for\nthe specified [trackingscenario].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5596
  def rule_statusSheetTask
    pattern(%w( !statusSheetTaskHeader !statusSheetTaskBody), lambda {
      @property = @propertyStack.pop
    })
    doc('task.statussheet', "Opens the task with the specified ID to add a status report. Child task can be\nopened inside this context by specifying their relative ID to this parent.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5608
  def rule_statusSheetTaskAttributes
    optional
    repeatable
    pattern(%w( !ssStatus ))
    pattern(%w( !statusSheetTask ), lambda {
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5616
  def rule_statusSheetTaskBody
    optionsRule('statusSheetTaskAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5620
  def rule_statusSheetTaskHeader
    pattern(%w( _task !taskId ), lambda {
      if @property
        @propertyStack.push(@property)
      else
        @propertyStack = []
      end
      @property = @val[1]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5631
  def rule_subNodeId
    optional
    pattern(%w( _: !idOrAbsoluteId ), lambda {
      @val[1]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5638
  def rule_summary
    pattern(%w( _summary $STRING ), lambda {
      return if @val[1].empty?

      if @val[1].length > 480
        error('ts_summary_too_long',
              "The summary text must be 480 characters long or shorter. " +
              "This text has #{@val[1].length} characters.",
              @sourceFileInfo[1])
      end
      if @val[1] == "A summary text\n"
          error('ts_default_summary',
                "'A summary text' is not a valid summary",
                @sourceFileInfo[1])
      end
      rtTokenSetIntro =
        [ :LINEBREAK, :SPACE, :WORD, :BOLD, :ITALIC, :CODE, :BOLDITALIC,
          :HREF, :HREFEND ]
      @journalEntry.summary = newRichText(@val[1], @sourceFileInfo[1],
                                          rtTokenSetIntro)
    })
    doc('summary', "This is the introductory part of the journal or status entry. It should\nonly summarize the full entry but should contain more details than the\nheadline. The text including formatting characters must be 240 characters long\nor less.\n"
       )
    arg(1, 'text', "The text will be interpreted as [[Rich_Text_Attributes|Rich Text]]. Only a\nsmall subset of the markup is supported for this attribute. You can use word\nformatting, hyperlinks and paragraphs.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5676
  def rule_supplement
    pattern(%w( !supplementAccount !accountBody ), lambda {
      @property = @idStack.pop
    })
    pattern(%w( !supplementReport !reportBody ), lambda {
      @property = @idStack.pop
    })
    pattern(%w( !supplementResource !resourceBody ), lambda {
      @property = @idStack.pop
    })
    pattern(%w( !supplementTask !taskBody ), lambda {
      @property = @idStack.pop
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5691
  def rule_supplementAccount
    pattern(%w( _account !accountId ), lambda {
      @idStack.push(@property)
      @property = @val[1]
    })
    arg(1, 'account ID', 'The ID of an already defined account.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5699
  def rule_supplementReport
    pattern(%w( _report !reportId ), lambda {
      @idStack.push(@property)
      @property = @val[1]
    })
    arg(1, 'report ID', 'The absolute ID of an already defined report.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5707
  def rule_supplementResource
    pattern(%w( _resource !resourceId ), lambda {
      @idStack.push(@property)
      @property = @val[1]
    })
    arg(1, 'resource ID', 'The ID of an already defined resource.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5715
  def rule_supplementTask
    pattern(%w( _task !taskId ), lambda {
      @idStack.push(@property)
      @property = @val[1]
    })
    arg(1, 'task ID', 'The absolute ID of an already defined task.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5723
  def rule_tagfile
    pattern(%w( !tagfileHeader !tagfileBody ), lambda {
      @property = nil
    })
    doc('tagfile', "The tagfile report generates a file that maps properties to source file\nlocations. This can be used by editors to quickly jump to a certain task or\nresource definition. Currently only the ctags format is supported that is used\nby editors like [http://www.vim.org|vim].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5758
  def rule_tagfileAttributes
    optional
    repeatable

    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))
    pattern(%w( !rollupresource ))
    pattern(%w( !rolluptask ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5768
  def rule_tagfileBody
    optionsRule('tagfileAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5737
  def rule_tagfileHeader
    pattern(%w( _tagfile !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :tagfile, @sourceFileInfo[0])
      @property.set('formats', [ :ctags ])

      # Include all tasks.
      @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
      # Include all resources.
      @property.set('hideResource',
                    LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
    })
    arg(2, 'file name', "The name of the tagfile to generate. You can leave it empty and it will\ndefault to the commonly used name ''''tags''''.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5773
  def rule_task
    pattern(%w( !taskHeader !taskBody ), lambda {
      @property = @property.parent
    })
    doc('task', "Tasks are the central elements of a project plan. Use a task to specify the\nvarious steps and phases of the project. Depending on the attributes of that\ntask, a task can be a container task, a milestone or a regular leaf task. The\nlatter may have resources assigned. By specifying dependencies the user can\nforce a certain sequence of tasks.\n\nTasks have a local name space. All IDs must be unique within the tasks\nthat belong to the same enclosing task.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5791
  def rule_taskAttributes
    repeatable
    optional

    pattern(%w( _adopt !taskList ), lambda {
      @val[1].each do |task|
        @property.adopt(task)
      end
    })
    level(:experimental)
    doc('adopt.task', "Add a previously defined task to the sub-tasks of this task. This can be used\nto create virtual sub projects that contain of task trees that were defined as\nsub tasks of other tasks. Adopted tasks don't inherit anything from their step\nparents. However, the adopting task is scheduled to fit all adopted childs as\nwell.\n\nA top-level tasks must never include the same task more than once.\n"
       )

    pattern(%w( !journalEntry ))

    pattern(%w( _note $STRING ), lambda {
      @property.set('note', newRichText(@val[1], @sourceFileInfo[1]))
    })
    doc('note.task', "Attach a note to the task. This is usually a more detailed specification of\nwhat the task is about.\n"
       )

    pattern(%w( !purge ))

    pattern(%w( _supplement !supplementTask !taskBody ), lambda {
      @property = @idStack.pop
    })
    doc('supplement.task', "The supplement keyword provides a mechanism to add more attributes to already\ndefined tasks. The additional attributes must obey the same rules as in\nregular task definitions and must be enclosed by curly braces.\n\nThis construct is primarily meant for situations where the information about a\ntask is split over several files. E. g. the vacation dates for the\nresources may be in a separate file that was generated by some other tool.\n"
       )
    example('Supplement', 'task')

    pattern(%w( !task ))
    pattern(%w( !taskScenarioAttributes ))
    pattern(%w( !scenarioIdCol !taskScenarioAttributes ), lambda {
      @scenarioIdx = 0
    })
    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5851
  def rule_taskBody
    optionsRule('taskAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5855
  def rule_taskBooking
    pattern(%w( !taskBookingHeader !bookingBody ), lambda {
      unless @project.scenario(@scenarioIdx).get('ownbookings')
        error('no_own_task_booking',
              "The scenario #{@project.scenario(@scenarioIdx).fullId} " +
              'inherits its bookings from the tracking ' +
              'scenario. You cannot specificy additional bookings for it.')
      end
      @val[0].task.addBooking(@scenarioIdx, @val[0])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5867
  def rule_taskBookingHeader
    pattern(%w( !resourceId !valIntervals ), lambda {
      checkBooking(@property, @val[0])
      @booking = Booking.new(@val[0], @property, @val[1])
      @booking.sourceFileInfo = @sourceFileInfo[0]
      @booking
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5876
  def rule_taskDep
    pattern(%w( !taskDepHeader !taskDepBody ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5882
  def rule_taskDepAttributes
    optional
    repeatable

    pattern(%w( _gapduration !intervalDuration ), lambda {
      @taskDependency.gapDuration = @val[1]
    })
    doc('gapduration', "Specifies the minimum required gap between the end of a preceding task and the\nstart of this task, or the start of a following task and the end of this task.\nThis is calendar time, not working time. 7d means one week.\n"
       )

    pattern(%w( _gaplength !workingDuration ), lambda {
      @taskDependency.gapLength = @val[1]
    })
    doc('gaplength', "Specifies the minimum required gap between the end of a preceding task and the\nstart of this task, or the start of a following task and the end of this task.\nThis is working time, not calendar time. 7d means 7 working days, not one\nweek. Whether a day is considered a working day or not depends on the defined\nworking hours and global leaves.\n"
       )

    pattern(%w( _onend ), lambda {
      @taskDependency.onEnd = true
    })
    doc('onend', "The target of the dependency is the end of the task.\n"
       )

    pattern(%w( _onstart ), lambda {
      @taskDependency.onEnd = false
    })
    doc('onstart', "The target of the dependency is the start of the task.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5929
  def rule_taskDepBody
    optionsRule('taskDepAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5933
  def rule_taskDepHeader
    pattern(%w( !taskDepId ), lambda {
      @taskDependency = TaskDependency.new(@val[0], true)
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5939
  def rule_taskDepId
    singlePattern('$ABSOLUTE_ID')
    arg(0, 'ABSOLUTE ID', "A reference using the full qualified ID of a task. The IDs of all enclosing\nparent tasks must be prepended to the task ID and separated with a dot, e.g.\n''''proj.plan.doc''''.\n"
         )

    singlePattern('$ID')
    arg(0, 'ID', 'Just the ID of the task without and parent IDs.')

    pattern(%w( !relativeId ), lambda {
      task = @property
      id = @val[0]
      while task && id[0] == ?!
        id = id.slice(1, id.length)
        task = task.parent
      end
      error('too_many_bangs',
            "Too many '!' for relative task in this context.",
            @sourceFileInfo[0], @property) if id[0] == ?!
      if task
        task.fullId + '.' + id
      else
        id
      end
    })
    arg(0, 'RELATIVE ID', "A relative task ID always starts with one or more exclamation marks and is\nfollowed by a task ID. Each exclamation mark lifts the scope where the ID is\nlooked for to the enclosing task. The ID may contain some of the parent IDs\nseparated by dots, e. g. ''''!!plan.doc''''.\n"
         )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5978
  def rule_taskDepList
    pattern(%w( !taskDep !moreDepTasks ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 5984
  def rule_taskHeader
    pattern(%w( _task !optionalID $STRING ), lambda {
      if @property.nil? && !@taskprefix.empty?
        @property = @project.task(@taskprefix)
      end
      if @val[1]
        id = (@property ? @property.fullId + '.' : '') + @val[1]
        if @project.task(id)
          error('task_exists', "Task #{id} has already been defined.",
                @sourceFileInfo[0])
        end
      end
      @property = Task.new(@project, @val[1], @val[2], @property)
      @property['projectid', 0] = @projectId
      @property.sourceFileInfo = @sourceFileInfo[0]
      @property.inheritAttributes
      @scenarioIdx = 0
    })
    arg(2, 'name', 'The name of the task')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6005
  def rule_taskId
    pattern(%w( !taskIdUnverifd ), lambda {
      id = @val[0]
      if @property && @property.is_a?(Task)
        # In case we have a nested supplement, we need to prepend the parent ID.
        id = @property.fullId + '.' + id
      else
        id = @taskprefix + '.' + id unless @taskprefix.empty?
      end
      if (task = @project.task(id)).nil?
        error('unknown_task', "Unknown task #{id}", @sourceFileInfo[0])
      end
      task
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6021
  def rule_taskIdUnverifd
    singlePattern('$ABSOLUTE_ID')
    singlePattern('$ID')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6026
  def rule_taskList
    listRule('moreTasks', '!absoluteTaskId')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6030
  def rule_taskPeriod
    pattern(%w( _period !valInterval), lambda {
      @property['start', @scenarioIdx] = @val[1].start
      @property['end', @scenarioIdx] = @val[1].end
    })
    doc('period.task', "This property is a shortcut for setting the start and end property at the same\ntime. In contrast to using these, it does not change the scheduling direction.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6043
  def rule_taskPred
    pattern(%w( !taskPredHeader !taskDepBody ), lambda {
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6049
  def rule_taskPredHeader
    pattern(%w( !taskDepId ), lambda {
      @taskDependency = TaskDependency.new(@val[0], false)
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6055
  def rule_taskPredList
    pattern(%w( !taskPred !morePredTasks ), lambda {
      [ @val[0] ] + (@val[1].nil? ? [] : @val[1])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6061
  def rule_taskReport
    pattern(%w( !taskReportHeader !reportBody ), lambda {
      @property = @property.parent
    })
    doc('taskreport', "The report lists tasks and their respective values in a table. To reduce the\nlist of included tasks, you can use the [[hidetask]], [[rolluptask]] or\n[[taskroot]] attributes. The order of the task can be controlled with\n[[sorttasks]]. If the first sorting criteria is tree sorting, the parent tasks\nwill always be included to form the tree. Tree sorting is the default. You\nneed to change it if you do not want certain parent tasks to be included in\nthe report.\n\nBy default, all the resources that are allocated to each task are hidden, but\nthey can be listed as well. Use the [[hideresource]] attribute to select which\nresources should be included.\n"
       )
    example('HtmlTaskReport')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6083
  def rule_taskReportHeader
    pattern(%w( _taskreport !optionalID !reportName ), lambda {
      newReport(@val[1], @val[2], :taskreport, @sourceFileInfo[0])

      unless @property.modified?('columns')
        # Set the default columns for this report.
        %w( bsi name start end effort chart ).each do |col|
          @property.get('columns') <<
          TableColumnDefinition.new(col, columnTitle(col))
        end
      end
      # Show all tasks, sorted by tree, start-up, seqno-up.
      unless @property.modified?('hideTask')
        @property.set('hideTask',
                      LogicalExpression.new(LogicalOperation.new(0)))
      end
      unless @property.modified?('sortTasks')
        @property.set('sortTasks',
                      [ [ 'tree', true, -1 ],
                        [ 'start', true, 0 ],
                        [ 'seqno', true, -1 ] ])
      end
      # Show no resources, but set sorting to id-up.
      unless @property.modified?('hideResource')
        @property.set('hideResource',
                      LogicalExpression.new(LogicalOperation.new(1)))
      end
      unless @property.modified?('sortResources')
        @property.set('sortResources', [ [ 'id', true, -1 ] ])
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6116
  def rule_taskScenarioAttributes

    pattern(%w( _account $ID ))
    level(:removed)
    also('chargeset')
    doc('account.task', '')

    pattern(%w( !allocate ))

    pattern(%w( _booking !taskBooking ))
    doc('booking.task', "The booking attribute can be used to report actually completed work.  A task\nwith bookings must be [[scheduling|scheduled]] in ''''asap'''' mode.  If the\nscenario is not the [[trackingscenario|tracking scenario]] or derived from it,\nthe scheduler will not allocate resources prior to the current date or the\ndate specified with [[now]] when a task has at least one booking.\n\nBookings are only valid in the scenario they have been defined in. They will\nin general not be passed to any other scenario. If you have defined a\n[[trackingscenario|tracking scenario]], the bookings of this scenario will be\npassed to all the derived scenarios of the tracking scenario.\n\nThe sloppy attribute can be used when you want to skip non-working time or\nother allocations automatically. If it's not given, all bookings must only\ncover working time for the resource.\n\nThe booking attributes is designed to capture the exact amount of completed\nwork. This attribute is not really intended to specify completed effort by\nhand. Usually, booking statements are generated by [[export]] reports. The\n[[sloppy.booking|sloppy]] and [[overtime.booking|overtime]] attributes are\nonly kludge for users who want to write them manually.\nBookings can be used to report already completed work by specifying the exact\ntime intervals a certain resource has worked on this task.\n\nBookings can be defined in the task or resource context. If you move tasks\naround very often, put your bookings in the task context.\n"
       )
    also(%w( booking.resource ))
    example('Booking')

    pattern(%w( _charge !number !chargeMode ), lambda {
      checkContainer('charge')

      if @property['chargeset', @scenarioIdx].empty?
        error('task_without_chargeset',
              'The task does not have a chargeset defined.',
              @sourceFileInfo[0], @property)
      end
      case @val[2]
      when 'onstart'
        mode = :onStart
        amount = @val[1]
      when 'onend'
        mode = :onEnd
        amount = @val[1]
      when 'perhour'
        mode = :perDiem
        amount = @val[1] * 24
      when 'perday'
        mode = :perDiem
        amount = @val[1]
      when 'perweek'
        mode = :perDiem
        amount = @val[1] / 7.0
      end
      # Multiple 'charge' attributes are allowed.
      begin
        @property['charge', @scenarioIdx] +=
          [ Charge.new(amount, mode, @property, @scenarioIdx) ]
      rescue AttributeOverwrite
      end
    })
    doc('charge', "Specify a one-time or per-period charge to a certain account. The charge can\noccur at the start of the task, at the end of it, or continuously over the\nduration of the task. The accounts to be charged are determined by the\n[[chargeset]] setting of the task.\n"
       )
    arg(1, 'amount', 'The amount to charge')

    pattern(%w( !chargeset ))

    pattern(%w( _complete !number), lambda {
      if @val[1] < 0.0 || @val[1] > 100.0
        error('task_complete', "Complete value must be between 0 and 100",
              @sourceFileInfo[1], @property)
      end
      @property['complete', @scenarioIdx] = @val[1]
    })
    doc('complete', "Specifies what percentage of the task is already completed. This can be useful\nfor simple progress tracking like in a TODO list. The provided completion\ndegree is used for the ''''complete'''' and ''''gauge'''' columns in reports.\nReports with calendar elements may show the completed part of the task in a\ndifferent color.\n\nThe completion percentage has no impact on the scheduler. It's meant for\ndocumentation purposes only.\n"
        )
    example('Complete', '1')

    arg(1, 'percent', 'The percent value. It must be between 0 and 100.')

    pattern(%w( _depends !taskDepList ), lambda {
      checkContainer('depends')
      begin
        @property['depends', @scenarioIdx] =
          @property['depends', @scenarioIdx] + @val[1]
        @property['forward', @scenarioIdx] = true
      rescue AttributeOverwrite
      end
    })
    doc('depends', "Specifies that the task cannot start before the specified tasks have been\nfinished.\n\nBy using the 'depends' attribute, the scheduling policy is automatically set\nto asap. If both depends and precedes are used, the last policy counts.\n"
        )
    example('Depends1')
    pattern(%w( _duration !calendarDuration ), lambda {
      setDurationAttribute('duration', @val[1])
    })
    doc('duration', "Specifies the time the task should last. This is calendar time, not working\ntime. 7d means one week. If resources are specified they are allocated when\navailable. Availability of resources has no impact on the duration of the\ntask. It will always be the specified duration.\n\nTasks may not have subtasks if this attribute is used. Setting this attribute\nwill reset the [[effort]] and [[length]] attributes.\n"
       )
    example('Durations')
    also(%w( effort length ))

    pattern(%w( _effort !workingDuration ), lambda {
      if @val[1] <= 0
        error('effort_zero', "Effort value must at least as large as the " +
                             "timing resolution " +
                             "(#{@project['scheduleGranularity'] / 60}min).",
              @sourceFileInfo[1], @property)
      end
      setDurationAttribute('effort', @val[1])
    })
    doc('effort', "Specifies the effort needed to complete the task. An effort of ''''6d'''' (6\nresource-days) can be done with 2 full-time resources in 3 working days. The\ntask will not finish before the allocated resources have contributed the\nspecified effort. Hence the duration of the task will depend on the\navailability of the allocated resources. The specified effort value must be at\nleast as large as the [[timingresolution]].\n\nWARNING: In almost all real world projects effort is not the product of time\nand resources. This is only true if the task can be partitioned without adding\nany overhead. For more information about this read ''The Mythical Man-Month'' by\nFrederick P. Brooks, Jr.\n\nTasks may not have subtasks if this attribute is used. Setting this attribute\nwill reset the [[duration]] and [[length]] attributes. A task with an effort\nvalue cannot be a [[milestone]].\n"
       )
    example('Durations')
    also(%w( duration length ))

    pattern(%w( _end !valDate ), lambda {
      @property['end', @scenarioIdx] = @val[1]
      begin
        @property['forward', @scenarioIdx] = false
      rescue AttributeOverwrite
      end
    })
    doc('end', "The end attribute provides a guideline to the scheduler when the task should\nend. It will never end later, but it may end earlier when allocated\nresources are not available that long. When an end date is provided for a\ncontainer task, it will be passed down to ALAP task that don't have a well\ndefined end criteria.\n\nSetting an end date will implicitely set the scheduling policy for this task\nto ALAP.\n"
       )
    example('Export', '1')
    pattern(%w( _endcredit !number ), lambda {
      @property['charge', @scenarioIdx] =
        @property['charge', @scenarioIdx] +
        [ Charge.new(@val[1], :onEnd, @property, @scenarioIdx) ]
    })
    level(:deprecated)
    doc('endcredit', "Specifies an amount that is credited to the accounts specified by the\n[[chargeset]] attributes at the moment the tasks ends.\n"
       )
    also('charge')
    example('Account', '1')
    pattern(%w( !flags ))
    doc('flags.task', "Attach a set of flags. The flags can be used in logical expressions to filter\nproperties from the reports.\n"
       )

    pattern(%w( !fail ))

    pattern(%w( _length !workingDuration ), lambda {
      setDurationAttribute('length', @val[1])
    })
    doc('length', "Specifies the global working time to be used for this task. The value is\nspecified in working time, not calendar time. 7d means 7 working days, or 7\ntimes 8 hours (assuming default settings), not one week.\n\nA task with a length specification may have resource allocations. Resources\nare allocated when they are available.  There is no guarantee that the task\nwill get any resources allocated.  The availability of resources has no impact\non the duration of the task. A time slot where none of the specified resources\nis available is still considered working time, if there is no global vacation\nand global working hours are defined accordingly.\n\nFor the length calculation, only the global working hours and the global\nleaves matter. If a resource has additinal working hours defined, it's\nquite possible that a task with a length of 5d will have an allocated effort\nlarger than 40 hours. Resource working hours only have an impact on whether an\nallocation is made or not for a particular time slot. They don't effect the\nresulting duration of the task.\n\nTasks may not have subtasks if this attribute is used. Setting this attribute\nwill reset the [[duration]], [[effort]] and [[milestone]] attributes.\n"
       )
    also(%w( duration effort ))

    pattern(%w( !limits ), lambda {
      checkContainer('limits')
      @property['limits', @scenarioIdx] = @val[0]
    })
    doc('limits.task', "Set per-interval allocation limits for the task. This setting affects all allocations for this task.\n"
       )
    example('Limits-1', '2')

    pattern(%w( _maxend !valDate ), lambda {
      @property['maxend', @scenarioIdx] = @val[1]
    })
    doc('maxend', "Specifies the maximum wanted end time of the task. The value is not used\nduring scheduling, but is checked after all tasks have been scheduled. If the\nend of the task is later than the specified value, then an error is reported.\n"
       )

    pattern(%w( _maxstart !valDate ), lambda {
      @property['maxstart', @scenarioIdx] = @val[1]
    })
    doc('maxstart', "Specifies the maximum wanted start time of the task. The value is not used\nduring scheduling, but is checked after all tasks have been scheduled. If the\nstart of the task is later than the specified value, then an error is\nreported.\n"
       )

    pattern(%w( _milestone ), lambda {
      setDurationAttribute('milestone')
    })
    doc('milestone', "Turns the task into a special task that has no duration. You may not specify a\nduration, length, effort or subtasks for a milestone task.\n\nA task that only has a start or an end specification and no duration\nspecification, inherited start or end dates, no dependencies or sub tasks,\nwill be recognized as milestone automatically.\n"
       )

    pattern(%w( _minend !valDate ), lambda {
      @property['minend', @scenarioIdx] = @val[1]
    })
    doc('minend', "Specifies the minimum wanted end time of the task. The value is not used\nduring scheduling, but is checked after all tasks have been scheduled. If the\nend of the task is earlier than the specified value, then an error is\nreported.\n"
       )

    pattern(%w( _minstart !valDate ), lambda {
      @property['minstart', @scenarioIdx] = @val[1]
    })
    doc('minstart', "Specifies the minimum wanted start time of the task. The value is not used\nduring scheduling, but is checked after all tasks have been scheduled. If the\nstart of the task is earlier than the specified value, then an error is\nreported.\n"
       )

    pattern(%w( _startcredit !number ), lambda {
      @property['charge', @scenarioIdx] +=
        [ Charge.new(@val[1], :onStart, @property, @scenarioIdx) ]
    })
    level(:deprecated)
    doc('startcredit', "Specifies an amount that is credited to the account specified by the\n[[chargeset]] attributes at the moment the tasks starts.\n"
       )
    also('charge')
    pattern(%w( !taskPeriod ))

    pattern(%w( _precedes !taskPredList ), lambda {
      checkContainer('precedes')
      begin
        @property['precedes', @scenarioIdx] += @val[1]
        @property['forward', @scenarioIdx] = false
      rescue AttributeOverwrite
      end
    })
    doc('precedes', "Specifies that the tasks with the specified IDs cannot start before the task\nhas been finished. If multiple IDs are specified, they must be separated by\ncommas. IDs must be either global or relative. A relative ID starts with a\nnumber of '!'. Each '!' moves the scope to the parent task. Global IDs do not\ncontain '!', but have IDs separated by dots.\n\nBy using the 'precedes' attribute, the scheduling policy is automatically set\nto alap. If both depends and precedes are used within a task, the last policy\ncounts.\n"
       )

    pattern(%w( _priority $INTEGER ), lambda {
      if @val[1] < 0 || @val[1] > 1000
        error('task_priority', "Priority must have a value between 0 and 1000",
              @sourceFileInfo[1], @property)
      end
      @property['priority', @scenarioIdx] = @val[1]
    })
    doc('priority', "Specifies the priority of the task. A task with higher priority is more\nlikely to get the requested resources. The default priority value of all tasks\nis 500. Don't confuse the priority of a tasks with the importance or urgency\nof a task. It only increases the chances that the tasks gets the requested\nresources. It does not mean that the task happens earlier, though that is\nusually the effect you will see. It also does not have any effect on tasks\nthat don't have any resources assigned (e.g. milestones).\n\nFor milestones it will raise or lower the chances that task leading up the\nmilestone will get their resources over task with equal priority that compete\nfor the same resources.\n\nThis attribute is inherited by subtasks if specified prior to the definition\nof the subtask.\n"
       )
    arg(1, 'value', 'Priority value (1 - 1000)')
    example('Priority')

    pattern(%w( _projectid $ID ), lambda {
      unless @project['projectids'].include?(@val[1])
        error('unknown_projectid', "Unknown project ID #{@val[1]}",
              @sourceFileInfo[1])
      end
      begin
        @property['projectid', @scenarioIdx] = @val[1]
      rescue AttributeOverwrite
        # This attribute always overwrites the implicitely provided ID.
      end
    })
    doc('projectid.task', "In larger projects it may be desireable to work with different project IDs for\nparts of the project. This attribute assignes a new project ID to this task an\nall subsequently defined sub tasks. The project ID needs to be declared first using [[projectid]] or [[projectids]].\n"
       )

    pattern(%w( _responsible !resourceList ), lambda {
      @property['responsible', @scenarioIdx] += @val[1]
      @property['responsible', @scenarioIdx].uniq!
    })
    doc('responsible', "The ID of the resource that is responsible for this task. This value is for\ndocumentation purposes only. It's not used by the scheduler.\n"
       )

    pattern(%w( _scheduled ), lambda {
      if (@property['milestone', @scenarioIdx] &&
          @property['start', @scenarioIdx].nil? &&
          @property['end', @scenarioIdx].nil?) ||
         (!@property['milestone', @scenarioIdx] &&
          (@property['start', @scenarioIdx].nil? ||
           @property['end', @scenarioIdx].nil?))
        error('not_scheduled',
              "Task #{@property.fullId} is marked as scheduled but does not " +
              'have a fixed start and end date.',
              @sourceFileInfo[0], @property)
      end
      @property['scheduled', @scenarioIdx] = true
    })
    doc('scheduled', "This is mostly for internal use. It specifies that the task can be ignored for\nscheduling in the scenario.\n"
       )

    pattern(%w( _scheduling !schedulingDirection ), lambda {
      if @val[1] == 'alap'
        begin
          @property['forward', @scenarioIdx] = false
        rescue AttributeOverwrite
        end
      elsif @val[1] == 'asap'
        begin
          @property['forward', @scenarioIdx] = true
        rescue AttributeOverwrite
        end
      end
    })
    doc('scheduling', "Specifies the scheduling policy for the task. A task can be scheduled from\nstart to end (As Soon As Possible, asap) or from end to start (As Late As\nPossible, alap).\n\nA task can be scheduled from start to end (ASAP mode) when it has a hard\n(start) or soft (depends) criteria for the start time. A task can be scheduled\nfrom end to start (ALAP mode) when it has a hard (end) or soft (precedes)\ncriteria for the end time.\n\nSome task attributes set the scheduling policy implicitly. This attribute can\nbe used to explicitly set the scheduling policy of the task to a certain\ndirection. To avoid it being overwritten again by an implicit attribute this\nattribute should always be the last attribute of the task.\n\nA random mixture of ASAP and ALAP tasks can have unexpected side effects on\nthe scheduling of the project. It increases significantly the scheduling\ncomplexity and results in much longer scheduling times. Especially in projects\nwith many hundreds of tasks the scheduling time of a project with a mixture of\nASAP and ALAP times can be 2 to 10 times longer. When the projects contains\nchains of ALAP and ASAP tasks the tasks further down the dependency chain will\nbe served much later than other non-chained task even when they have a much\nhigher priority. This can result in situations where high priority tasks do\nnot get their resources even though the parallel competing tasks have a much\nlower priority.\n\nAs a general rule, try to avoid ALAP tasks whenever possible. Have a close\neye on tasks that have been switched implicitly to ALAP mode because the\nend attribute comes after the start attribute.\n"
       )

    pattern(%w( !taskShiftAssignments !shiftAssignments ), lambda {
      checkContainer('shift')
      # Set same value again to set the 'provided' state for the attribute.
      begin
        @property['shifts', @scenarioIdx] = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    level(:deprecated)
    doc('shift.task', "This keyword has been deprecated. Please use [[shifts.task|shifts\n(task)]] instead.\n"
       )
    also('shifts.task')

    pattern(%w( !taskShiftsAssignments !shiftAssignments ), lambda {
      checkContainer('shifts')
      begin
        @property['shifts', @scenarioIdx] = @shiftAssignments
      rescue AttributeOverwrite
        # Multiple shift assignments are a common idiom, so don't warn about
        # them.
      end
      @shiftAssignments = nil
    })
    doc('shifts.task', "Limits the working time for this task during the during the specified interval\nto the working hours of the given shift. Multiple shifts can be defined, but\nshift intervals may not overlap. This is an additional working time\nrestriction ontop of the working hours of the allocated resources. It does not\nreplace the resource working hour restrictions. For a resource to be assigned\nto a time slot, both the respective task shift as well as the resource working\nhours must declare the time slot as duty slot.\n"
        )

    pattern(%w( _start !valDate), lambda {
      @property['start', @scenarioIdx] = @val[1]
      begin
        @property['forward', @scenarioIdx] = true
      rescue AttributeOverwrite
      end
    })
    doc('start', "The start attribute provides a guideline to the scheduler when the task should\nstart. It will never start earlier, but it may start later when allocated\nresources are not available immediately. When a start date is provided for a\ncontainer task, it will be passed down to ASAP task that don't have a well\ndefined start criteria.\n\nSetting a start date will implicitely set the scheduling policy for this task\nto ASAP.\n"
       )
    also(%w( end period.task maxstart minstart scheduling ))

    pattern(%w( !warn ))

    # Other attributes will be added automatically.
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6666
  def rule_taskShiftAssignments
    pattern(%w( _shift ), lambda {
      @shiftAssignments = @property['shifts', @scenarioIdx]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6672
  def rule_taskShiftsAssignments
    pattern(%w( _shifts ), lambda {
      @shiftAssignments = @property['shifts', @scenarioIdx]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6678
  def rule_textReport
    pattern(%w( !textReportHeader !reportBody ), lambda {
      @property = @property.parent
    })
    doc('textreport', "This report consists of 5 RichText sections, a header, a center section with a\nleft and right margin and a footer. The sections may contain the output of\nother defined reports.\n"
       )
    example('textreport')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6692
  def rule_textReportHeader
    pattern(%w( _textreport !optionalID !reportName ), lambda {
      newReport(@val[1], @val[2], :textreport, @sourceFileInfo[0])
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6842
  def rule_timeInterval
    pattern([ '$TIME', '_-', '$TIME' ], lambda {
      if @val[0] >= @val[2]
        error('time_interval',
              "End time of interval must be larger than start time",
              @sourceFileInfo[0])
      end
      [ @val[0], @val[2] ]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6853
  def rule_timeSheet
    pattern(%w( !timeSheetHeader !timeSheetBody ), lambda {
      @timeSheet
    })
    doc('timesheet', "A time sheet record can be used to capture the current status of the tasks\nassigned to a specific resource and the achieved progress for a given period\nof time. The status is assumed to be for the end of this time period. There\nmust be a separate time sheet record for each resource per period. Different\nresources can use different reporting periods and reports for the same\nresource may have different reporting periods as long as they don't overlap.\nFor the time after the last time sheet, TaskJuggler will project the result\nbased on the plan data. For periods without a time sheet record prior to the\nlast record for this resource, TaskJuggler assumes that no work has been done.\nThe work is booked for the scenario specified by [[trackingscenario]].\n\nThe intended use for time sheets is to have all resources report a time sheet\nevery day, week or month. All time sheets can be added to the project plan.\nThe status information is always used to determin the current status of the\nproject. The [[work]], [[remaining]] and [[end.timesheet|end]] attributes are\nignored if there are also [[booking.task|bookings]] for the resource in the\ntime sheet period. The non-ignored attributes of the time sheets will be\nconverted into [[booking.task|booking]] statements internally. These bookings\ncan then be [[export|exported]] into a file which can then be added to the\nproject again. This way, you can use time sheets to incrementally record\nprogress of your project. There is a possibility that time sheets conflict\nwith other data in the plan. In case TaskJuggler cannot automatically resolve\nthem, these conflicts have to be manually resolved by either changing the plan\nor the time sheet.\n\nThe status messages are interpreted as [[journalentry|journal entries]]. The\nalert level will be evaluated and the current state of the project can be put\ninto a dashboard using the ''''alert'''' and ''''alertmessage'''' [[columnid|\ncolumns]].\n\nCurrently, the provided effort values and dates are not yet used to\nautomatically update the plan data. This feature will be added in future\nversions.\n"
       )
    example('TimeSheet1', '1')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6897
  def rule_timeSheetAttributes
    optional
    repeatable

    pattern(%w( !tsNewTaskHeader !tsTaskBody ), lambda {
      @property = nil
      @timeSheetRecord = nil
    })
    doc('newtask', "The keyword can be used add a new task to the project. If the task ID requires\nfurther parent task that don't exist yet, these tasks will be created as well.\nIf the task exists already, an error is generated. The new task can be used\nimmediately to report progress and status against it.\n"
       )
    example('TimeSheet1', '3')

    pattern(%w( _shift !shiftId ), lambda {
      #TODO
    })
    doc('shift.timesheet', "Specifies an alternative [[shift]] for the time sheet period. This shift will\noverride any existing working hour definitions for the resource. It will not\noverride already declared [[leaves]] though.\n\nThe primary use of this feature is to let the resources report different total\nwork time for the report period.\n"
       )

    pattern(%w( !tsStatus ))

    pattern(%w( !tsTaskHeader !tsTaskBody ), lambda {
      @property = nil
      @timeSheetRecord = nil
    })
    doc('task.timesheet', "Specifies an existing task that progress and status should be reported\nagainst.\n"
       )
    example('TimeSheet1', '4')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6951
  def rule_timeSheetBody
    pattern(%w( _{ !timeSheetAttributes _} ), lambda {

    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6944
  def rule_timeSheetFile
    pattern(%w( !timeSheet . ), lambda {
      @val[0]
    })
    lastSyntaxToken(1)
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6957
  def rule_timeSheetHeader
    pattern(%w( _timesheet !resourceId !valIntervalOrDate ), lambda {
      @sheetAuthor = @val[1]
      @property = nil
      unless @sheetAuthor.leaf?
        error('ts_group_author',
              'A resource group cannot file a time sheet',
              @sourceFileInfo[1])
      end
      unless (scenarioIdx = @project['trackingScenarioIdx'])
        error('ts_no_tracking_scenario',
              'No trackingscenario defined.')
      end
      # Currently time sheets are hardcoded for scenario 0.
      @timeSheet = TimeSheet.new(@sheetAuthor, @val[2], scenarioIdx)
      @timeSheet.sourceFileInfo = @sourceFileInfo[0]
      @project.timeSheets << @timeSheet
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6977
  def rule_timeSheetReport
    pattern(%w( !tsReportHeader !tsReportBody ), lambda {
      @property = nil
    })
    doc('timesheetreport', "For projects that flow mostly according to plan, TaskJuggler already knows\nmuch of the information that should be contained in the time sheets. With this\nproperty, you can generate a report that contains drafts of the time sheets\nfor one or more resources. The time sheet drafts will be for the\nspecified report period and the specified [trackingscenario].\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6698
  def rule_timeformat
    pattern(%w( _timeformat $STRING ), lambda {
      @val[1]
    })
    doc('timeformat', "Determines how time specifications in reports look like.\n"
       )
    arg(1, 'format', "Ordinary characters placed in the format string are copied without\nconversion. Conversion specifiers are introduced by a `%' character, and are\nreplaced in s as follows:\n\n* ''''%a''''  The abbreviated weekday name according to the current locale.\n\n* ''''%A''''  The full weekday name according to the current locale.\n\n* ''''%b''''  The abbreviated month name according to the current locale.\n\n* ''''%B''''  The full month name according to the current locale.\n\n* ''''%c''''  The preferred date and time representation for the current locale.\n\n* ''''%C''''  The century number (year/100) as a 2-digit integer. (SU)\n\n* ''''%d''''  The day of the month as a decimal number (range 01 to 31).\n\n* ''''%e''''  Like ''''%d'''', the day of the month as a decimal number, but a\nleading zero is replaced by a space. (SU)\n\n* ''''%E''''  Modifier: use alternative format, see below. (SU)\n\n* ''''%F''''  Equivalent to ''''%Y-%m-%d'''' (the ISO 8601 date format). (C99)\n\n* ''''%G''''  The ISO 8601 year with century as a decimal number. The 4-digit\nyear corresponding to the ISO week number (see %V). This has the same format\nand value as ''''%y'''', except that if the ISO week number belongs to the\nprevious or next year, that year is used instead. (TZ)\n\n* ''''%g''''  Like %G, but without century, i.e., with a 2-digit year (00-99).\n(TZ)\n\n* ''''%h''''  Equivalent to ''''%b''''. (SU)\n\n* ''''%H''''  The hour as a decimal number using a 24-hour clock (range 00 to\n23).\n\n* ''''%I''''  The hour as a decimal number using a 12-hour clock (range 01 to\n12).\n\n* ''''%j''''  The day of the year as a decimal number (range 001 to 366).\n\n* ''''%k''''  The hour (24-hour clock) as a decimal number (range 0 to 23);\nsingle digits are preceded by a blank. (See also ''''%H''''.) (TZ)\n\n* ''''%l''''  The hour (12-hour clock) as a decimal number (range 1 to 12);\nsingle digits are preceded by a blank. (See also ''''%I''''.) (TZ)\n\n* ''''%m''''  The month as a decimal number (range 01 to 12).\n\n* ''''%M''''  The minute as a decimal number (range 00 to 59).\n\n* ''''%n''''  A newline character. (SU)\n\n* ''''%O''''  Modifier: use alternative format, see below. (SU)\n\n* ''''%p''''  Either 'AM' or 'PM' according to the given time value, or the\ncorresponding strings for the current locale. Noon is treated as `pm' and\nmidnight as 'am'.\n\n* ''''%P''''  Like %p but in lowercase: 'am' or 'pm' or ''''%a''''\ncorresponding string for the current locale. (GNU)\n\n* ''''%r''''  The time in a.m. or p.m. notation. In the POSIX locale this is\nequivalent to ''''%I:%M:%S %p''''. (SU)\n\n* ''''%R''''  The time in 24-hour notation (%H:%M). (SU) For a version\nincluding the seconds, see ''''%T'''' below.\n\n* ''''%s''''  The number of seconds since the Epoch, i.e., since 1970-01-01\n00:00:00 UTC.  (TZ)\n\n* ''''%S''''  The second as a decimal number (range 00 to 61).\n\n* ''''%t''''  A tab character. (SU)\n\n* ''''%T''''  The time in 24-hour notation (%H:%M:%S). (SU)\n\n* ''''%u''''  The day of the week as a decimal, range 1 to 7, Monday being 1.\nSee also ''''%w''''. (SU)\n\n* ''''%U''''  The week number of the current year as a decimal number, range\n00 to 53, starting with the first Sunday as the first day of week 01. See also\n''''%V'''' and ''''%W''''.\n\n* ''''%V''''  The ISO 8601:1988 week number of the current year as a decimal\nnumber, range 01 to 53, where week 1 is the first week that has at least 4\ndays in the current year, and with Monday as the first day of the week. See\nalso ''''%U'''' and ''''%W''''. %(SU)\n\n* ''''%w''''  The day of the week as a decimal, range 0 to 6, Sunday being 0. See also ''''%u''''.\n\n* ''''%W''''  The week number of the current %year as a decimal number, range\n00 to 53, starting with the first Monday as the first day of week 01.\n\n* ''''%x''''  The preferred date representation for the current locale without\nthe time.\n\n* ''''%X''''  The preferred time representation for the current locale without\nthe date.\n\n* ''''%y''''  The year as a decimal number without a century (range 00 to 99).\n\n* ''''%Y''''   The year as a decimal number including the century.\n\n* ''''%z''''   The time zone as hour offset from GMT. Required to emit\nRFC822-conformant dates (using ''''%a, %d %%b %Y %H:%M:%S %%z''''). (GNU)\n\n* ''''%Z''''  The time zone or name or abbreviation.\n\n* ''''%+''''  The date and time in date(1) format. (TZ)\n\n* ''''%%''''  A literal ''''%'''' character.\n\nSome conversion specifiers can be modified by preceding them by the E or O\nmodifier to indicate that an alternative format should be used. If the\nalternative format or specification does not exist for the current locale, the\nbehavior will be as if the unmodified conversion specification were used.\n\n(SU) The Single Unix Specification mentions %Ec, %EC, %Ex, %%EX, %Ry, %EY,\n%Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou, %OU, %OV, %Ow, %OW, %Oy, where the\neffect of the O modifier is to use alternative numeric symbols (say, Roman\nnumerals), and that of the E modifier is to use a locale-dependent alternative\nrepresentation.\n\nThis documentation of the timeformat attribute has been taken from the man page\nof the GNU strftime function.\n"
       )

  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 6992
  def rule_timezone
    pattern(%w( _timezone !validTimeZone ), lambda{
      TjTime.setTimeZone(@val[1])
      @project['timezone'] = @val[1]
    })
    doc('timezone', "Sets the default time zone of the project. All dates and times that have no\ntime zones specified will be assumed to be in this time zone. If no time zone\nis specified for the project, UTC is assumed.\n\nThe project start and end time are not affected by this setting. They are\nalways considered to be UTC unless specified differently.\n\nIn case the specified time zone is not hour-aligned with UTC, the\n[[timingresolution]] will automatically be decreased accordingly. Do not\nchange the timingresolution after you've set the time zone!\n\nChanging the time zone will reset the [[workinghours.project|working hours]]\nto the default times. It's recommended that you declare your working hours\nafter the time zone.\n"
        )
    arg(1, 'zone', "Time zone to use. E. g. 'Europe/Berlin' or 'America/Denver'. Don't use the 3\nletter acronyms. See\n[http://en.wikipedia.org/wiki/List_of_zoneinfo_time_zones Wikipedia] for\npossible values.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7025
  def rule_traceReport
    pattern(%w( !traceReportHeader !reportBody ), lambda {
      @property = @property.parent
    })
    doc('tracereport', "The trace report works noticeably different than all other TaskJuggler\nreports. It uses a CSV file to track the values of the selected attributes.\nEach time ''''tj3'''' is run with the ''''--add-trace'''' option, a new set of\nvalues is appended to the CSV file. The first column of the CSV file holds the\ndate when the snapshot was taken. This is either the current date or the\n''''now'''' date if provided. There is no need to specify CSV as output format\nfor the report. You can either use these tracked values directly by specifying other report formats or by importing the CSV file into another program.\n\nThe first column always contains the current date when that\ntable row was added. All subsequent columns can be defined by the user with\nthe [[columns]] attribute. This column set is then repeated for all properties\nthat are not hidden by [[hideaccount]], [[hideresource]] and [[hidetask]]. By\ndefault, all properties are excluded. You must provide at least one of the\n''''hide...'''' attributes to select the properties you want to have included\nin the report. Please be aware that total number of columns is the product of\nattributes defined with [[columns]] times the number of included properties.\nSelect you values carefully or you will end up with very large reports.\n\nThe column headers can be customized by using the [[title.column|title]]\nattribute.  When you include multiple properties, these headers are not unique\nunless you include mini-queries to modify them based on the property they\ncolum is represeting.  You can use the queries\n''''<nowiki><-id-></nowiki>'''', ''''<nowiki><-name-></nowiki>'''',\n''''<nowiki><-scenario-></nowiki>'''' and\n''''<nowiki><-attribute-></nowiki>''''. ''''<nowiki><-id-></nowiki>'''' is\nreplaced with the ID of the property, ''''<nowiki><-name-></nowiki>'''' with\nthe name and so on.\n\nYou can change the set of tracked values over time. Old values will be\npreserved and the corresponding columns will be the last ones in the CSV file.\n\nWhen other formats are requested, the CSV file is read in and a report that\nshows the tracked values over time will be generated. The CSV file may contain\nall kinds of values that are being tracked. Report formats that don't support\na mix of different values will just show the values of the second column.\n\nThe HTML version generates SVG graphs that are embedded in the HTML page.\nThese graphs are only visble if the web browser supports HTML5. This is true\nfor the latest generation of browsers, but older browsers may not support this\nformat.\n"
       )
    example('TraceReport')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7076
  def rule_traceReportHeader
    pattern(%w( _tracereport !optionalID !reportName ), lambda {
      newReport(@val[1], @val[2], :tracereport, @sourceFileInfo[0])

      # The top-level always inherits the global timeFormat setting. This is
      # not desireable in this case, so we ignore this.
      if (@property.level == 0 && !@property.provided('timeFormat')) ||
         (@property.level > 0 && !@property.modified?('timeFormat'))
        # CSV readers such of Libre-/OpenOffice can't deal with time zones. We
        # probably also don't need seconds.
        @property.set('timeFormat', '%Y-%m-%d-%H:%M')
      end
      unless @property.modified?('columns')
        # Set the default columns for this report.
        %w( end ).each do |col|
          @property.get('columns') <<
          TableColumnDefinition.new(col, columnTitle(col))
        end
      end
      # Hide all accounts.
      unless @property.modified?('hideAccount')
        @property.set('hideAccount',
                      LogicalExpression.new(LogicalOperation.new(1)))
      end
      unless @property.modified?('sortAccounts')
        @property.set('sortAccounts',
                      [ [ 'tree', true, -1 ],
                        [ 'seqno', true, -1 ] ])
      end
      # Show all tasks, sorted by tree, start-up, seqno-up.
      unless @property.modified?('hideTask')
        @property.set('hideTask',
                      LogicalExpression.new(LogicalOperation.new(0)))
      end
      unless @property.modified?('sortTasks')
        @property.set('sortTasks',
                      [ [ 'tree', true, -1 ],
                        [ 'start', true, 0 ],
                        [ 'seqno', true, -1 ] ])
      end
      # Show no resources, but set sorting to id-up.
      unless @property.modified?('hideResource')
        @property.set('hideResource',
                      LogicalExpression.new(LogicalOperation.new(1)))
      end
      unless @property.modified?('sortResources')
        @property.set('sortResources', [ [ 'id', true, -1 ] ])
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7127
  def rule_tsNewTaskHeader
    pattern(%w( _newtask !taskIdUnverifd $STRING ), lambda {
      @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @val[1])
      @timeSheetRecord.name = @val[2]
      @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
    })
    arg(1, 'task', 'ID of the new task')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7161
  def rule_tsReportAttributes
    optional
    repeatable

    pattern(%w( !hideresource ))
    pattern(%w( !hidetask ))
    pattern(%w( !reportEnd ))
    pattern(%w( !reportPeriod ))
    pattern(%w( !reportStart ))
    pattern(%w( !sortResources ))
    pattern(%w( !sortTasks ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7174
  def rule_tsReportBody
    optionsRule('tsReportAttributes')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7135
  def rule_tsReportHeader
    pattern(%w( _timesheetreport !optionalID $STRING ), lambda {
      newReport(@val[1], @val[2], :timeSheet, @sourceFileInfo[0])
      @property.set('formats', [ :tjp ])

      unless @project.scenario(0).get('active')
        @property.set('scenarios', [ 0 ])
      end
      # Show all tasks, sorted by seqno-up.
      @property.set('hideTask', LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortTasks', [ [ 'seqno', true, -1 ] ])
      # Show all resources, sorted by seqno-up.
      @property.set('hideResource',
                    LogicalExpression.new(LogicalOperation.new(0)))
      @property.set('sortResources', [ [ 'seqno', true, -1 ] ])
      @property.set('loadUnit', :hours)
      @property.set('definitions', [])
    })
    arg(2, 'file name', "The name of the time sheet report file to generate. It must end with a .tji\nextension, or use . to use the standard output channel.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7230
  def rule_tsStatus
    pattern(%w( !tsStatusHeader !tsStatusBody ))
    doc('status.timesheet', "The status attribute can be used to describe the current status of the task or\nresource. The content of the status messages is added to the project journal.\nThe status section is optional for tasks that have been worked on less than\none day during the report interval.\n"
       )
    arg(2, 'headline', "A short headline for the status. Must be 60 characters or shorter.\n"
       )
    example('TimeSheet1', '4')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7178
  def rule_tsStatusAttributes
    optional
    repeatable

    pattern(%w( !details ))

    pattern(%w( _flags !flagList ), lambda {
      @val[1].each do |flag|
        next if @journalEntry.flags.include?(flag)

        @journalEntry.flags << flag
      end
    })
    doc('flags.timesheet', "Time sheet entries can have flags attached to them. These can be used to\ninclude only entries in a report that have a certain flag.\n"
       )

    pattern(%w( !summary ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7201
  def rule_tsStatusBody
    optional
    pattern(%w( _{ !tsStatusAttributes _} ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7206
  def rule_tsStatusHeader
    pattern(%w( _status !alertLevel $STRING ), lambda {
      if @val[2].length > 120
        error('ts_headline_too_long',
              "The headline must be 120 or less characters long. This one " +
              "has #{@val[2].length} characters.", @sourceFileInfo[2])
      end
      if @val[2] == 'Your headline here!'
        error('ts_no_headline',
              "'Your headline here!' is not a valid headline",
              @sourceFileInfo[2])
      end
      @journalEntry = JournalEntry.new(@project['journal'],
                                       @timeSheet.interval.end,
                                       @val[2],
                                       @property || @timeSheet.resource,
                                       @sourceFileInfo[0])
      @journalEntry.alertLevel = @val[1]
      @journalEntry.timeSheetRecord = @timeSheetRecord
      @journalEntry.author = @sheetAuthor
      @timeSheetRecord.status = @journalEntry if @timeSheetRecord
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7248
  def rule_tsTaskAttributes
    optional
    repeatable

    pattern(%w( _end !valDate ), lambda {
      if @val[1] < @timeSheet.interval.start
        error('ts_end_too_early',
              "The expected task end date must be after the start date of " +
              "this time sheet report.", @sourceFileInfo[1])
      end
      @timeSheetRecord.expectedEnd = @val[1]
    })
    doc('end.timesheet', "The expected end date for the task. This can only be used for duration based\ntask. For effort based task [[remaining]] has to be used.\n"
       )
    example('TimeSheet1', '5')

    pattern(%w( _priority $INTEGER ), lambda {
      priority = @val[1]
      if priority < 1 || priority > 1000
        error('ts_bad_priority',
              "Priority value #{priority} must be between 1 and 1000.",
              @sourceFileInfo[1])
      end
      @timeSheetRecord.priority = priority
    })
    doc('priority.timesheet', "The priority is a value between 1 and 1000. It is used to determine the\nsequence of task when converting [[work]] to [[booking.task|bookings]]. Tasks\nthat need to finish earlier in the period should have a high priority, tasks\nthat end later in the period should have a low priority. For tasks that don't\nget finished in the reported period the priority should be set to 1.\n"
       )

    pattern(%w( _remaining !workingDuration ), lambda {
      @timeSheetRecord.remaining = @val[1]
    })
    doc('remaining', "The remaining effort for the task. This value is ignored if there are\n[[booking.task|bookings]] for the resource that overlap with the time sheet\nperiod.  If there are no bookings, the value is compared with the [[effort]]\nspecification of the task. If there a mismatch between the accumulated effort\nspecified with bookings, [[work]] and [[remaining]] on one side and the\nspecified [[effort]] on the other, a warning is generated.\n\nThis attribute can only be used with tasks that are effort based. Duration\nbased tasks need to have an [[end.timesheet|end]] attribute.\n"
       )
    example('TimeSheet1', '6')

    pattern(%w( !tsStatus ))

    pattern(%w( _work !workingDurationPercent ), lambda {
      @timeSheetRecord.work = @val[1]
    })
    doc('work', "The amount of time that the resource has spend with the task during the\nreported period. This value is ignored when there are\n[[booking.task|bookings]] for the resource overlapping with the time sheet\nperiod. If there are no bookings, TaskJuggler will try to convert the work\nspecification into bookings internally before the actual scheduling is\nstarted.\n\nEvery task listed in the time sheet needs to have a work attribute. The total\naccumulated work time that is reported must match exactly the total working\nhours for the resource for that period.\n\nIf a resource has no vacation during the week that is reported and it has a\nregular 40 hour work week, exactly 40 hours total or 5 working days have to be\nreported.\n"
       )
    example('TimeSheet1', '4')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7331
  def rule_tsTaskBody
    pattern(%w( _{ !tsTaskAttributes _} ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7335
  def rule_tsTaskHeader
    pattern(%w( _task !taskId ), lambda {
      @property = @val[1]
      unless @property.leaf?
        error('ts_task_not_leaf',
              'You cannot specify a task that has sub tasks here.',
              @sourceFileInfo[1], @property)
      end

      @timeSheetRecord = TimeSheetRecord.new(@timeSheet, @property)
      @timeSheetRecord.sourceFileInfo = @sourceFileInfo[0]
    })
    arg(1, 'task', 'ID of an already existing task')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7350
  def rule_vacationName
    optional
    pattern(%w( $STRING )) # We just throw the name away
    arg(0, 'name', 'An optional name or reason for the leave')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7356
  def rule_valDate
    pattern(%w( !date ), lambda {
      if @val[0] < @project['start'] || @val[0] > @project['end']
        error('date_in_range',
              "Date #{@val[0]} must be within the project time frame " +
              "#{@project['start']}  - #{@project['end']}",
              @sourceFileInfo[0])
      end
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7417
  def rule_valInterval
    pattern(%w( !date !intervalEnd ), lambda {
      mode = @val[1][0]
      endSpec = @val[1][1]
      if mode == 0
        unless @val[0] < endSpec
          error('start_before_end', "The end date (#{endSpec}) must be after " +
                "the start date (#{@val[0]}).", @sourceFileInfo[1])
        end
        iv = TimeInterval.new(@val[0], endSpec)
      else
        iv = TimeInterval.new(@val[0], @val[0] + endSpec)
      end
      checkInterval(iv)
      iv
    })
    doc('interval1', "There are two ways to specify a date interval. The start and end date must lie within the specified project period.\n\nThe first is the most obvious. A date interval consists of a start and end\nDATE. Watch out for end dates without a time specification! Date\nspecifications are 0 extended. An end date without a time is expanded to\nmidnight that day. So the day of the end date is not included in the interval!\nThe start and end dates must be separated by a hyphen character.\n\nIn the second form specifies the start date and an interval duration. The\nduration must be prefixed by a plus character.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7378
  def rule_valIntervalOrDate
    pattern(%w( !date !intervalOptionalEnd ), lambda {
      if @val[1]
        mode = @val[1][0]
        endSpec = @val[1][1]
        if mode == 0
          unless @val[0] < endSpec
            error('start_before_end', "The end date (#{endSpec}) must be " +
                  "after the start date (#{@val[0]}).",
                  @sourceFileInfo[1])
          end
          iv = TimeInterval.new(@val[0], endSpec)
        else
          iv = TimeInterval.new(@val[0], @val[0] + endSpec)
        end
      else
        iv = TimeInterval.new(@val[0], @val[0].sameTimeNextDay)
      end
      checkInterval(iv)
      iv
    })
    doc('interval4', "There are three ways to specify a date interval. The first is the most\nobvious. A date interval consists of a start and end DATE. Watch out for end\ndates without a time specification! Date specifications are 0 extended. An\nend date without a time is expanded to midnight that day. So the day of the\nend date is not included in the interval! The start and end dates must be separated by a hyphen character.\n\nIn the second form, the end date is omitted. A 24 hour interval is assumed.\n\nThe third form specifies the start date and an interval duration. The duration must be prefixed by a plus character.\n\nThe start and end date of the interval must be within the specified project\ntime frame.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7449
  def rule_valIntervals
    listRule('moreValIntervals', '!valIntervalOrDate')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7368
  def rule_validTimeZone
    pattern(%w( $STRING ), lambda {
      unless TjTime.checkTimeZone(@val[0])
        error('bad_time_zone', "#{@val[0]} is not a known time zone",
              @sourceFileInfo[0])
      end
      @val[0]
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7453
  def rule_warn
    pattern(%w( _warn !logicalExpression ), lambda {
      begin
        @property.set('warn', @property.get('warn') + [ @val[1] ])
      rescue AttributeOverwrite
      end
    })
    doc('warn', "The warn attribute adds a logical expression to the property. The condition\ndescribed by the logical expression is checked after the scheduling and an\nwarning is generated if the condition evaluates to true. This attribute is\nprimarily intended for testing purposes.\n"
       )
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7481
  def rule_weekDayInterval
    pattern(%w( !weekday !weekDayIntervalEnd ), lambda {
      weekdays = Array.new(7, false)
      if @val[1].nil?
        weekdays[@val[0]] = true
      else
        d = @val[0]
        loop do
          weekdays[d] = true
          break if d == @val[1]
          d = (d + 1) % 7
        end
      end

      weekdays
    })
    arg(0, 'weekday', 'Weekday (sun - sat)')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7500
  def rule_weekDayIntervalEnd
    optional
    pattern([ '_-', '!weekday' ], lambda {
      @val[1]
    })
    arg(1, 'end weekday',
        'Weekday (sun - sat). It is included in the interval.')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7471
  def rule_weekday
    pattern(%w( _sun ), lambda { 0 })
    pattern(%w( _mon ), lambda { 1 })
    pattern(%w( _tue ), lambda { 2 })
    pattern(%w( _wed ), lambda { 3 })
    pattern(%w( _thu ), lambda { 4 })
    pattern(%w( _fri ), lambda { 5 })
    pattern(%w( _sat ), lambda { 6 })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7509
  def rule_workingDuration
    pattern(%w( !number !durationUnit ), lambda {
      convFactors = [ 60, # minutes
                      60 * 60, # hours
                      60 * 60 * @project['dailyworkinghours'], # days
                      60 * 60 * @project['dailyworkinghours'] *
                      (@project.weeklyWorkingDays), # weeks
                      60 * 60 * @project['dailyworkinghours'] *
                      (@project['yearlyworkingdays'] / 12), # months
                      60 * 60 * @project['dailyworkinghours'] *
                      @project['yearlyworkingdays'] # years
                    ]
      # The result will always be in number of time slots.
      (@val[0] * convFactors[@val[1]] /
       @project['scheduleGranularity']).round.to_i
    })
    arg(0, 'value', 'A floating point or integer number')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7528
  def rule_workingDurationPercent
    pattern(%w( !number !durationUnitOrPercent ), lambda {
      if @val[1] >= 0
        # Absolute value in minutes, hours or days.
        convFactors = [ 60, # minutes
          60 * 60, # hours
          60 * 60 * @project['dailyworkinghours'] # days
        ]
        # The result will always be in number of time slots.
        (@val[0] * convFactors[@val[1]] /
         @project['scheduleGranularity']).round.to_i
      else
        # Percentage values are always returned as Float in the rage of 0.0 to
        # 1.0.
        if @val[0] < 0.0 || @val[0] > 100.0
          error('illegal_percentage',
                "Percentage values must be between 0 and 100%.",
                @sourceFileInfo[1])
        end
        @val[0] / 100.0
      end
    })
    arg(0, 'value', 'A floating point or integer number')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7553
  def rule_workinghours
    pattern(%w( _workinghours !listOfDays !listOfTimes), lambda {
      if @property.nil?
        # We are changing global working hours.
        wh = @project['workinghours']
      else
        unless (wh = @property['workinghours', @scenarioIdx])
          # The property does not have it's own WorkingHours yet.
          wh = WorkingHours.new(@project['workinghours'])
        end
      end
      wh.timezone = @project['timezone']
      begin
        7.times { |i| wh.setWorkingHours(i, @val[2]) if @val[1][i] }
      rescue
        error('bad_workinghours', $!.message)
      end

      if @property
        # Make sure we actually assign something so the attribute is marked as
        # set by the user.
        begin
          @property['workinghours', @scenarioIdx] = wh
        rescue AttributeOverwrite
          # Working hours can be set multiple times.
        end
      end
    })
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7583
  def rule_workinghoursProject
    pattern(%w( !workinghours ))
    doc('workinghours.project', "Set the default working hours for all subsequent resource definitions. The\nstandard working hours are 9:00am - 12:00am, 1:00pm - 18:00pm, Monday to\nFriday. The working hours specification limits the availability of resources\nto certain time slots of week days.\n\nThese default working hours can be replaced with other working hours for\nindividual resources.\n"
       )
    also(%w( dailyworkinghours workinghours.resource workinghours.shift ))
    example('Project')
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7600
  def rule_workinghoursResource
    pattern(%w( !workinghours ))
    doc('workinghours.resource', "Set the working hours for a specific resource. The working hours specification\nlimits the availability of resources to certain time slots of week days.\n"
       )
    also(%w( workinghours.project workinghours.shift ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7611
  def rule_workinghoursShift
    pattern(%w( !workinghours ))
    doc('workinghours.shift', "Set the working hours for the shift. The working hours specification limits\nthe availability of resources or the activity on a task to certain time\nslots of week days.\n\nThe shift working hours will replace the default or resource working hours for\nthe specified time frame when assigning the shift to a resource.\n\nIn case the shift is used for a task, resources are only assigned during the\nworking hours of this shift and during the working hours of the allocated\nresource. Allocations only happen when both the task shift and the resource\nwork hours allow work to happen.\n"
       )
    also(%w( workinghours.project workinghours.resource ))
  end

[Source]

# File lib/taskjuggler/TjpSyntaxRules.rb, line 7631
  def rule_yesNo
    pattern(%w( _yes ), lambda {
      true
    })
    pattern(%w( _no ), lambda {
      false
    })
  end

[Validate]