taskjuggler 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +2086 -0
- data/benchmarks/666tasks.tjp +3183 -0
- data/benchmarks/booking.tjp +14 -10
- data/doc/AppConfig.html +95 -73
- data/doc/Arguments.html +22 -2
- data/doc/CHANGELOG.html +2587 -0
- data/doc/COPYING.html +21 -1
- data/doc/Object.html +161 -122
- data/doc/README.html +21 -1
- data/doc/RuntimeConfig.html +26 -6
- data/doc/String.html +38 -18
- data/doc/StringIO.html +579 -0
- data/doc/TaskJuggler.html +251 -143
- data/doc/TaskJuggler/Account.html +26 -6
- data/doc/TaskJuggler/AccountAttribute.html +28 -8
- data/doc/TaskJuggler/AccountScenario.html +24 -4
- data/doc/TaskJuggler/Allocation.html +30 -10
- data/doc/TaskJuggler/AllocationAttribute.html +28 -8
- data/doc/TaskJuggler/AttributeBase.html +46 -26
- data/doc/TaskJuggler/AttributeDefinition.html +22 -2
- data/doc/TaskJuggler/BatchProcessor.html +40 -20
- data/doc/TaskJuggler/Booking.html +26 -6
- data/doc/TaskJuggler/BookingListAttribute.html +28 -8
- data/doc/TaskJuggler/BooleanAttribute.html +28 -8
- data/doc/TaskJuggler/CSVFile.html +308 -146
- data/doc/TaskJuggler/CellSettingPattern.html +22 -2
- data/doc/TaskJuggler/CellSettingPatternList.html +26 -6
- data/doc/TaskJuggler/Charge.html +26 -6
- data/doc/TaskJuggler/ChargeListAttribute.html +26 -6
- data/doc/TaskJuggler/ChargeSet.html +33 -13
- data/doc/TaskJuggler/ChargeSetListAttribute.html +28 -8
- data/doc/TaskJuggler/ColumnListAttribute.html +26 -6
- data/doc/TaskJuggler/ColumnTable.html +24 -4
- data/doc/TaskJuggler/Daemon.html +26 -6
- data/doc/TaskJuggler/DateAttribute.html +26 -6
- data/doc/TaskJuggler/DefinitionListAttribute.html +22 -2
- data/doc/TaskJuggler/DependencyListAttribute.html +28 -8
- data/doc/TaskJuggler/DurationAttribute.html +28 -8
- data/doc/TaskJuggler/FixnumAttribute.html +24 -4
- data/doc/TaskJuggler/FlagListAttribute.html +28 -8
- data/doc/TaskJuggler/FloatAttribute.html +26 -6
- data/doc/TaskJuggler/FormatListAttribute.html +24 -4
- data/doc/TaskJuggler/GanttChart.html +147 -126
- data/doc/TaskJuggler/GanttContainer.html +34 -14
- data/doc/TaskJuggler/GanttHeader.html +28 -8
- data/doc/TaskJuggler/GanttHeaderScaleItem.html +24 -4
- data/doc/TaskJuggler/GanttLine.html +38 -18
- data/doc/TaskJuggler/GanttLoadStack.html +26 -6
- data/doc/TaskJuggler/GanttMilestone.html +34 -14
- data/doc/TaskJuggler/GanttRouter.html +50 -30
- data/doc/TaskJuggler/GanttTaskBar.html +34 -14
- data/doc/TaskJuggler/HTMLDocument.html +26 -6
- data/doc/TaskJuggler/HTMLGraphics.html +30 -10
- data/doc/TaskJuggler/Interval.html +40 -22
- data/doc/TaskJuggler/IntervalListAttribute.html +28 -8
- data/doc/TaskJuggler/JobInfo.html +24 -4
- data/doc/TaskJuggler/Journal.html +226 -147
- data/doc/TaskJuggler/JournalEntry.html +22 -2
- data/doc/TaskJuggler/JournalEntryList.html +129 -112
- data/doc/TaskJuggler/KeywordArray.html +26 -6
- data/doc/TaskJuggler/KeywordDocumentation.html +46 -26
- data/doc/TaskJuggler/Limits.html +152 -123
- data/doc/TaskJuggler/Limits/Limit.html +149 -70
- data/doc/TaskJuggler/LimitsAttribute.html +36 -51
- data/doc/TaskJuggler/ListAttributeBase.html +24 -4
- data/doc/TaskJuggler/Log.html +50 -32
- data/doc/TaskJuggler/LogFile.html +37 -17
- data/doc/TaskJuggler/LogicalAttribute.html +53 -33
- data/doc/TaskJuggler/LogicalExpression.html +26 -6
- data/doc/TaskJuggler/LogicalExpressionAttribute.html +32 -12
- data/doc/TaskJuggler/LogicalFlag.html +42 -22
- data/doc/TaskJuggler/LogicalFunction.html +204 -140
- data/doc/TaskJuggler/LogicalOperation.html +135 -111
- data/doc/TaskJuggler/Macro.html +22 -2
- data/doc/TaskJuggler/MacroParser.html +32 -12
- data/doc/TaskJuggler/MacroTable.html +32 -12
- data/doc/TaskJuggler/ManagerResponsibilities.html +24 -4
- data/doc/TaskJuggler/ManagerStatusRecord.html +24 -4
- data/doc/TaskJuggler/Message.html +24 -4
- data/doc/TaskJuggler/MessageHandler.html +24 -4
- data/doc/TaskJuggler/Navigator.html +104 -71
- data/doc/TaskJuggler/NavigatorElement.html +32 -12
- data/doc/TaskJuggler/NikuProject.html +22 -2
- data/doc/TaskJuggler/NikuReport.html +310 -228
- data/doc/TaskJuggler/NikuResource.html +22 -2
- data/doc/TaskJuggler/NodeListAttribute.html +615 -0
- data/doc/TaskJuggler/OnShiftCache.html +32 -12
- data/doc/TaskJuggler/ProcessIntercom.html +205 -78
- data/doc/TaskJuggler/ProcessIntercomIface.html +26 -6
- data/doc/TaskJuggler/Project.html +708 -660
- data/doc/TaskJuggler/ProjectBroker.html +506 -304
- data/doc/TaskJuggler/ProjectBrokerIface.html +61 -41
- data/doc/TaskJuggler/ProjectFileParser.html +429 -373
- data/doc/TaskJuggler/ProjectFileScanner.html +1790 -0
- data/doc/TaskJuggler/ProjectRecord.html +80 -60
- data/doc/TaskJuggler/ProjectServer.html +312 -237
- data/doc/TaskJuggler/ProjectServerIface.html +101 -43
- data/doc/TaskJuggler/PropertyAttribute.html +32 -12
- data/doc/TaskJuggler/PropertyList.html +166 -145
- data/doc/TaskJuggler/PropertySet.html +254 -224
- data/doc/TaskJuggler/PropertyTreeNode.html +670 -536
- data/doc/TaskJuggler/Query.html +169 -148
- data/doc/TaskJuggler/RTFHandlers.html +622 -0
- data/doc/TaskJuggler/RTFNavigator.html +28 -8
- data/doc/TaskJuggler/RTFQuery.html +40 -20
- data/doc/TaskJuggler/RTFReport.html +62 -25
- data/doc/TaskJuggler/RTFReportLink.html +765 -0
- data/doc/TaskJuggler/RealFormat.html +26 -6
- data/doc/TaskJuggler/RealFormatAttribute.html +26 -6
- data/doc/TaskJuggler/ReferenceAttribute.html +59 -39
- data/doc/TaskJuggler/Report.html +402 -251
- data/doc/TaskJuggler/ReportBase.html +162 -137
- data/doc/TaskJuggler/ReportContext.html +112 -29
- data/doc/TaskJuggler/ReportServer.html +89 -64
- data/doc/TaskJuggler/ReportServerIface.html +75 -55
- data/doc/TaskJuggler/ReportServerRecord.html +54 -31
- data/doc/TaskJuggler/ReportServlet.html +980 -0
- data/doc/TaskJuggler/ReportTable.html +41 -21
- data/doc/TaskJuggler/ReportTableCell.html +214 -170
- data/doc/TaskJuggler/ReportTableColumn.html +30 -10
- data/doc/TaskJuggler/ReportTableLegend.html +36 -16
- data/doc/TaskJuggler/ReportTableLine.html +32 -12
- data/doc/TaskJuggler/Resource.html +99 -87
- data/doc/TaskJuggler/ResourceListAttribute.html +59 -39
- data/doc/TaskJuggler/ResourceListRE.html +47 -26
- data/doc/TaskJuggler/ResourceScenario.html +403 -437
- data/doc/TaskJuggler/RichText.html +26 -6
- data/doc/TaskJuggler/RichTextAttribute.html +50 -30
- data/doc/TaskJuggler/RichTextDocument.html +37 -17
- data/doc/TaskJuggler/RichTextElement.html +475 -413
- data/doc/TaskJuggler/RichTextException.html +22 -2
- data/doc/TaskJuggler/RichTextFunctionExample.html +28 -8
- data/doc/TaskJuggler/RichTextFunctionHandler.html +24 -4
- data/doc/TaskJuggler/RichTextImage.html +22 -2
- data/doc/TaskJuggler/RichTextIntermediate.html +38 -18
- data/doc/TaskJuggler/RichTextParser.html +56 -34
- data/doc/TaskJuggler/RichTextScanner.html +82 -61
- data/doc/TaskJuggler/RichTextSnip.html +34 -14
- data/doc/TaskJuggler/RichTextSyntaxRules.html +507 -353
- data/doc/TaskJuggler/Scenario.html +22 -2
- data/doc/TaskJuggler/ScenarioData.html +30 -46
- data/doc/TaskJuggler/ScenarioListAttribute.html +38 -18
- data/doc/TaskJuggler/Scoreboard.html +42 -22
- data/doc/TaskJuggler/SheetHandlerBase.html +40 -20
- data/doc/TaskJuggler/SheetReceiver.html +333 -295
- data/doc/TaskJuggler/SheetSender.html +253 -230
- data/doc/TaskJuggler/Shift.html +26 -6
- data/doc/TaskJuggler/ShiftAssignment.html +89 -73
- data/doc/TaskJuggler/ShiftAssignments.html +226 -234
- data/doc/TaskJuggler/ShiftAssignmentsAttribute.html +39 -54
- data/doc/TaskJuggler/ShiftScenario.html +28 -8
- data/doc/TaskJuggler/SortListAttribute.html +34 -14
- data/doc/TaskJuggler/SourceFileInfo.html +24 -4
- data/doc/TaskJuggler/StatusSheetReceiver.html +24 -3
- data/doc/TaskJuggler/StatusSheetReport.html +168 -153
- data/doc/TaskJuggler/StatusSheetSender.html +24 -3
- data/doc/TaskJuggler/StringAttribute.html +38 -18
- data/doc/TaskJuggler/SymbolAttribute.html +32 -12
- data/doc/TaskJuggler/SyntaxReference.html +40 -20
- data/doc/TaskJuggler/TOCEntry.html +26 -6
- data/doc/TaskJuggler/TSResourceRecord.html +22 -2
- data/doc/TaskJuggler/TSTaskRecord.html +22 -2
- data/doc/TaskJuggler/TableColumnDefinition.html +59 -22
- data/doc/TaskJuggler/TableOfContents.html +26 -6
- data/doc/TaskJuggler/TableReport.html +937 -904
- data/doc/TaskJuggler/Task.html +55 -36
- data/doc/TaskJuggler/TaskDependency.html +24 -4
- data/doc/TaskJuggler/TaskListAttribute.html +50 -30
- data/doc/TaskJuggler/TaskListRE.html +27 -7
- data/doc/TaskJuggler/TaskScenario.html +1273 -1153
- data/doc/TaskJuggler/TextFormatter.html +28 -8
- data/doc/TaskJuggler/TextParser.html +585 -338
- data/doc/TaskJuggler/TextParser/Pattern.html +54 -34
- data/doc/TaskJuggler/TextParser/Rule.html +95 -73
- data/doc/TaskJuggler/TextParser/StackElement.html +39 -17
- data/doc/TaskJuggler/TextParser/TextParserResultArray.html +24 -4
- data/doc/TaskJuggler/TextParser/TokenDoc.html +22 -2
- data/doc/TaskJuggler/TextReport.html +28 -8
- data/doc/TaskJuggler/TextScanner.html +400 -1404
- data/doc/TaskJuggler/TextScanner/BufferStreamHandle.html +28 -240
- data/doc/TaskJuggler/TextScanner/FileStreamHandle.html +37 -184
- data/doc/TaskJuggler/TextScanner/MacroStackEntry.html +682 -0
- data/doc/TaskJuggler/TextScanner/StreamHandle.html +342 -67
- data/doc/TaskJuggler/TimeSheet.html +48 -28
- data/doc/TaskJuggler/TimeSheetReceiver.html +24 -3
- data/doc/TaskJuggler/TimeSheetRecord.html +47 -27
- data/doc/TaskJuggler/TimeSheetReport.html +154 -133
- data/doc/TaskJuggler/TimeSheetSender.html +24 -3
- data/doc/TaskJuggler/TimeSheetSummary.html +137 -91
- data/doc/TaskJuggler/TimeSheets.html +26 -6
- data/doc/TaskJuggler/Tj3AppBase.html +85 -58
- data/doc/TaskJuggler/Tj3Client.html +292 -238
- data/doc/TaskJuggler/Tj3Daemon.html +159 -74
- data/doc/TaskJuggler/Tj3SheetAppBase.html +26 -6
- data/doc/TaskJuggler/Tj3SsReceiver.html +26 -6
- data/doc/TaskJuggler/Tj3SsSender.html +53 -26
- data/doc/TaskJuggler/Tj3TsReceiver.html +28 -7
- data/doc/TaskJuggler/Tj3TsSender.html +26 -6
- data/doc/TaskJuggler/Tj3TsSummary.html +26 -6
- data/doc/TaskJuggler/TjException.html +22 -2
- data/doc/TaskJuggler/TjTime.html +216 -160
- data/doc/TaskJuggler/TjpExample.html +34 -14
- data/doc/TaskJuggler/TjpExportRE.html +403 -407
- data/doc/TaskJuggler/TjpSyntaxRules.html +4805 -4408
- data/doc/TaskJuggler/URLParameter.html +649 -0
- data/doc/TaskJuggler/UserManual.html +42 -22
- data/doc/TaskJuggler/WebServer.html +702 -0
- data/doc/TaskJuggler/WorkingHours.html +38 -18
- data/doc/TaskJuggler/WorkingHoursAttribute.html +61 -41
- data/doc/TaskJuggler/XMLBlob.html +24 -4
- data/doc/TaskJuggler/XMLComment.html +24 -4
- data/doc/TaskJuggler/XMLDocument.html +30 -10
- data/doc/TaskJuggler/XMLElement.html +34 -14
- data/doc/TaskJuggler/XMLNamedText.html +22 -2
- data/doc/TaskJuggler/XMLText.html +24 -4
- data/doc/index.html +1841 -1666
- data/doc/lib/AccountScenario_rb.html +1 -1
- data/doc/lib/Account_rb.html +1 -1
- data/doc/lib/Allocation_rb.html +1 -1
- data/doc/lib/AppConfig_rb.html +2 -2
- data/doc/lib/AttributeBase_rb.html +1 -1
- data/doc/lib/AttributeDefinition_rb.html +1 -1
- data/doc/lib/Attributes_rb.html +2 -2
- data/doc/lib/BatchProcessor_rb.html +1 -1
- data/doc/lib/Booking_rb.html +1 -1
- data/doc/lib/ChargeSet_rb.html +1 -1
- data/doc/lib/Charge_rb.html +1 -1
- data/doc/lib/HTMLDocument_rb.html +1 -1
- data/doc/lib/Interval_rb.html +1 -1
- data/doc/lib/Journal_rb.html +2 -2
- data/doc/lib/KeywordArray_rb.html +1 -1
- data/doc/lib/KeywordDocumentation_rb.html +1 -1
- data/doc/lib/Limits_rb.html +2 -2
- data/doc/lib/LogFile_rb.html +2 -2
- data/doc/lib/Log_rb.html +1 -1
- data/doc/lib/LogicalExpression_rb.html +1 -1
- data/doc/lib/LogicalFunction_rb.html +2 -2
- data/doc/lib/LogicalOperation_rb.html +2 -2
- data/doc/lib/MacroParser_rb.html +1 -1
- data/doc/lib/MacroTable_rb.html +1 -1
- data/doc/lib/MessageHandler_rb.html +1 -1
- data/doc/lib/Message_rb.html +1 -1
- data/doc/lib/ProjectFileParser_rb.html +4 -8
- data/doc/lib/ProjectFileScanner_rb.html +67 -0
- data/doc/lib/Project_rb.html +2 -2
- data/doc/lib/PropertyList_rb.html +2 -2
- data/doc/lib/PropertySet_rb.html +2 -2
- data/doc/lib/PropertyTreeNode_rb.html +2 -2
- data/doc/lib/Query_rb.html +2 -2
- data/doc/lib/RTFHandlers_rb.html +73 -0
- data/doc/lib/RTFNavigator_rb.html +1 -1
- data/doc/lib/RTFQuery_rb.html +1 -1
- data/doc/lib/RTFReportLink_rb.html +71 -0
- data/doc/lib/RTFReport_rb.html +2 -2
- data/doc/lib/RealFormat_rb.html +1 -1
- data/doc/lib/ResourceScenario_rb.html +2 -2
- data/doc/lib/Resource_rb.html +2 -2
- data/doc/lib/RichTextDocument_rb.html +1 -1
- data/doc/lib/RichTextElement_rb.html +2 -2
- data/doc/lib/RichTextFunctionExample_rb.html +1 -1
- data/doc/lib/RichTextFunctionHandler_rb.html +1 -1
- data/doc/lib/RichTextParser_rb.html +2 -2
- data/doc/lib/RichTextScanner_rb.html +2 -2
- data/doc/lib/RichTextSnip_rb.html +1 -1
- data/doc/lib/RichTextSyntaxRules_rb.html +2 -2
- data/doc/lib/RichText_rb.html +1 -1
- data/doc/lib/RuntimeConfig_rb.html +1 -1
- data/doc/lib/ScenarioData_rb.html +2 -2
- data/doc/lib/Scenario_rb.html +1 -1
- data/doc/lib/Scoreboard_rb.html +1 -1
- data/doc/lib/SheetHandlerBase_rb.html +1 -1
- data/doc/lib/SheetReceiver_rb.html +2 -2
- data/doc/lib/SheetSender_rb.html +4 -2
- data/doc/lib/ShiftAssignments_rb.html +4 -2
- data/doc/lib/ShiftScenario_rb.html +1 -1
- data/doc/lib/Shift_rb.html +1 -1
- data/doc/lib/SourceFileInfo_rb.html +1 -1
- data/doc/lib/StatusSheetReceiver_rb.html +2 -2
- data/doc/lib/StatusSheetSender_rb.html +2 -2
- data/doc/lib/SyntaxReference_rb.html +1 -1
- data/doc/lib/TOCEntry_rb.html +1 -1
- data/doc/lib/TableColumnDefinition_rb.html +2 -2
- data/doc/lib/TableOfContents_rb.html +1 -1
- data/doc/lib/TaskDependency_rb.html +1 -1
- data/doc/lib/TaskJuggler_rb.html +2 -2
- data/doc/lib/TaskScenario_rb.html +2 -2
- data/doc/lib/Task_rb.html +2 -2
- data/doc/lib/TextFormatter_rb.html +1 -1
- data/doc/lib/TextParser/Pattern_rb.html +1 -1
- data/doc/lib/TextParser/Rule_rb.html +2 -2
- data/doc/lib/TextParser/StackElement_rb.html +2 -2
- data/doc/lib/TextParser/TokenDoc_rb.html +1 -1
- data/doc/lib/TextParser_rb.html +2 -2
- data/doc/lib/TextScanner_rb.html +6 -2
- data/doc/lib/TimeSheetReceiver_rb.html +2 -2
- data/doc/lib/TimeSheetSender_rb.html +2 -2
- data/doc/lib/TimeSheetSummary_rb.html +2 -2
- data/doc/lib/TimeSheets_rb.html +2 -2
- data/doc/lib/Tj3AppBase_rb.html +2 -2
- data/doc/lib/Tj3Config_rb.html +2 -2
- data/doc/lib/Tj3SheetAppBase_rb.html +2 -2
- data/doc/lib/TjException_rb.html +1 -1
- data/doc/lib/TjTime_rb.html +2 -2
- data/doc/lib/TjpExample_rb.html +1 -1
- data/doc/lib/TjpSyntaxRules_rb.html +2 -2
- data/doc/lib/URLParameter_rb.html +67 -0
- data/doc/lib/UTF8String_rb.html +1 -1
- data/doc/lib/UserManual_rb.html +1 -1
- data/doc/lib/WorkingHours_rb.html +1 -1
- data/doc/lib/XMLDocument_rb.html +2 -2
- data/doc/lib/XMLElement_rb.html +1 -1
- data/doc/lib/daemon/Daemon_rb.html +1 -1
- data/doc/lib/daemon/ProcessIntercom_rb.html +2 -2
- data/doc/lib/daemon/ProjectBroker_rb.html +4 -2
- data/doc/lib/daemon/ProjectServer_rb.html +2 -2
- data/doc/lib/daemon/ReportServer_rb.html +2 -2
- data/doc/lib/daemon/WebServer_rb.html +75 -0
- data/doc/lib/deep_copy_rb.html +2 -2
- data/doc/lib/reports/CSVFile_rb.html +2 -2
- data/doc/lib/reports/ColumnTable_rb.html +1 -1
- data/doc/lib/reports/GanttChart_rb.html +2 -2
- data/doc/lib/reports/GanttContainer_rb.html +1 -1
- data/doc/lib/reports/GanttHeaderScaleItem_rb.html +1 -1
- data/doc/lib/reports/GanttHeader_rb.html +1 -1
- data/doc/lib/reports/GanttLine_rb.html +1 -1
- data/doc/lib/reports/GanttLoadStack_rb.html +1 -1
- data/doc/lib/reports/GanttMilestone_rb.html +1 -1
- data/doc/lib/reports/GanttRouter_rb.html +1 -1
- data/doc/lib/reports/GanttTaskBar_rb.html +1 -1
- data/doc/lib/reports/HTMLGraphics_rb.html +1 -1
- data/doc/lib/reports/Navigator_rb.html +2 -2
- data/doc/lib/reports/NikuReport_rb.html +2 -2
- data/doc/lib/reports/ReportBase_rb.html +2 -2
- data/doc/lib/reports/ReportContext_rb.html +2 -2
- data/doc/lib/reports/ReportTableCell_rb.html +2 -2
- data/doc/lib/reports/ReportTableColumn_rb.html +1 -1
- data/doc/lib/reports/ReportTableLegend_rb.html +1 -1
- data/doc/lib/reports/ReportTableLine_rb.html +1 -1
- data/doc/lib/reports/ReportTable_rb.html +2 -2
- data/doc/lib/reports/Report_rb.html +2 -2
- data/doc/lib/reports/ResourceListRE_rb.html +2 -2
- data/doc/lib/reports/StatusSheetReport_rb.html +2 -2
- data/doc/lib/reports/TableReport_rb.html +2 -2
- data/doc/lib/reports/TaskListRE_rb.html +2 -2
- data/doc/lib/reports/TextReport_rb.html +1 -1
- data/doc/lib/reports/TimeSheetReport_rb.html +2 -2
- data/doc/lib/reports/TjpExportRE_rb.html +2 -2
- data/doc/lib/ruby-signal-bug_rb.html +1 -1
- data/doc/lib/taskjuggler3_rb.html +2 -2
- data/doc/lib/tj3client_rb.html +2 -2
- data/doc/lib/tj3d_rb.html +2 -2
- data/doc/lib/tj3man_rb.html +1 -1
- data/doc/lib/tj3ss_receiver_rb.html +1 -1
- data/doc/lib/tj3ss_sender_rb.html +2 -2
- data/doc/lib/tj3ts_receiver_rb.html +2 -2
- data/doc/lib/tj3ts_sender_rb.html +1 -1
- data/doc/lib/tj3ts_summary_rb.html +1 -1
- data/doc/rdoc.css +9 -4
- data/examples/tutorial.tjp +17 -15
- data/gem_spec.rb +3 -0
- data/lib/AppConfig.rb +3 -1
- data/lib/Attributes.rb +10 -8
- data/lib/Journal.rb +55 -20
- data/lib/Limits.rb +72 -46
- data/lib/LogFile.rb +3 -3
- data/lib/LogicalFunction.rb +19 -6
- data/lib/LogicalOperation.rb +5 -1
- data/lib/Project.rb +37 -9
- data/lib/ProjectFileParser.rb +25 -22
- data/lib/ProjectFileScanner.rb +365 -0
- data/lib/PropertyList.rb +2 -1
- data/lib/PropertySet.rb +14 -4
- data/lib/PropertyTreeNode.rb +42 -29
- data/lib/Query.rb +3 -1
- data/lib/RTFHandlers.rb +35 -0
- data/lib/RTFReport.rb +23 -6
- data/lib/RTFReportLink.rb +72 -0
- data/lib/Resource.rb +8 -16
- data/lib/ResourceScenario.rb +1 -22
- data/lib/RichTextElement.rb +42 -0
- data/lib/RichTextParser.rb +6 -4
- data/lib/RichTextScanner.rb +5 -5
- data/lib/RichTextSyntaxRules.rb +48 -10
- data/lib/ScenarioData.rb +5 -3
- data/lib/SheetReceiver.rb +24 -6
- data/lib/SheetSender.rb +17 -13
- data/lib/ShiftAssignments.rb +56 -52
- data/lib/StatusSheetReceiver.rb +1 -0
- data/lib/StatusSheetSender.rb +1 -0
- data/lib/TableColumnDefinition.rb +4 -2
- data/lib/Task.rb +8 -9
- data/lib/TaskJuggler.rb +21 -11
- data/lib/TaskScenario.rb +61 -26
- data/lib/TextParser.rb +268 -106
- data/lib/TextParser/Rule.rb +4 -2
- data/lib/TextParser/StackElement.rb +6 -4
- data/lib/TextScanner.rb +283 -700
- data/lib/TimeSheetReceiver.rb +1 -0
- data/lib/TimeSheetSender.rb +1 -0
- data/lib/TimeSheetSummary.rb +51 -26
- data/lib/TimeSheets.rb +1 -1
- data/lib/Tj3AppBase.rb +8 -1
- data/lib/Tj3Config.rb +1 -1
- data/lib/TjTime.rb +5 -0
- data/lib/TjpSyntaxRules.rb +360 -144
- data/lib/URLParameter.rb +30 -0
- data/lib/XMLDocument.rb +2 -2
- data/lib/daemon/ProcessIntercom.rb +50 -9
- data/lib/daemon/ProjectBroker.rb +63 -10
- data/lib/daemon/ProjectServer.rb +47 -16
- data/lib/daemon/ReportServer.rb +9 -4
- data/lib/daemon/WebServer.rb +204 -0
- data/lib/deep_copy.rb +4 -1
- data/lib/reports/CSVFile.rb +150 -66
- data/lib/reports/GanttChart.rb +2 -1
- data/lib/reports/Navigator.rb +18 -5
- data/lib/reports/NikuReport.rb +32 -2
- data/lib/reports/Report.rb +65 -37
- data/lib/reports/ReportBase.rb +14 -9
- data/lib/reports/ReportContext.rb +19 -4
- data/lib/reports/ReportTable.rb +2 -2
- data/lib/reports/ReportTableCell.rb +54 -30
- data/lib/reports/ResourceListRE.rb +4 -3
- data/lib/reports/StatusSheetReport.rb +8 -13
- data/lib/reports/TableReport.rb +47 -32
- data/lib/reports/TaskListRE.rb +3 -3
- data/lib/reports/TimeSheetReport.rb +14 -5
- data/lib/reports/TjpExportRE.rb +14 -19
- data/lib/taskjuggler3.rb +15 -0
- data/lib/tj3client.rb +9 -7
- data/lib/tj3d.rb +38 -10
- data/lib/tj3ss_sender.rb +7 -0
- data/lib/tj3ts_receiver.rb +1 -0
- data/manual/Day_To_Day_Juggling +1 -1
- data/manual/Rich_Text_Attributes +8 -0
- data/manual/TaskJuggler_2x_Migration +7 -0
- data/manual/The_TaskJuggler_Syntax +20 -6
- data/prj_cfg.rb +3 -2
- data/tasks/changelog.rake +36 -0
- data/tasks/csts.rake +2 -3
- data/tasks/gem.rake +10 -0
- data/tasks/missing.rake +0 -17
- data/test/TestSuite/ReportGenerator/Correct/Journal.html +63 -0
- data/test/TestSuite/ReportGenerator/Correct/Journal.tjp +14 -0
- data/test/TestSuite/{HTML-Reports/LogicalFunctions.tjp → ReportGenerator/Correct/LogicalFunctions1.tjp} +2 -2
- data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.csv +3 -0
- data/test/TestSuite/ReportGenerator/Correct/LogicalFunctions2.tjp +19 -0
- data/test/TestSuite/ReportGenerator/Correct/css/tjmanual.css +66 -0
- data/test/TestSuite/ReportGenerator/Correct/css/tjreport.css +407 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/details.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-green.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-red.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/flag-yellow.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/resource.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/resourcegroup.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/task.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/taskgroup.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-down.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-flat.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/icons/trend-up.png +0 -0
- data/test/TestSuite/ReportGenerator/Correct/opennodes.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/opennodes.tjp +26 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/Journal-1.csv +6 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions1-1.csv +7 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/LogicalFunctions2-1.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/refs/opennodes-1.csv +2 -0
- data/test/TestSuite/ReportGenerator/Correct/scripts/wz_tooltip.js +1301 -0
- data/test/TestSuite/ReportGenerator/Errors/rtp_report_recursion.tjp +20 -0
- data/test/TestSuite/Scheduler/Correct/Container.html +349 -0
- data/test/TestSuite/Scheduler/Correct/Limits.tjp +11 -4
- data/test/TestSuite/Scheduler/Correct/Shift2.html +464 -150
- data/test/TestSuite/Scheduler/Correct/TimeSheet2.html +108 -0
- data/test/TestSuite/Scheduler/Correct/TimeSheet2.tjp +7 -0
- data/test/TestSuite/Scheduler/Correct/css/tjmanual.css +14 -0
- data/test/TestSuite/Scheduler/Correct/css/tjreport.css +233 -21
- data/test/TestSuite/Scheduler/Correct/scripts/wz_tooltip.js +20 -20
- data/test/TestSuite/StatusSheetTemplates/project.tji +35 -0
- data/test/TestSuite/StatusSheetTemplates/project.tjp +56 -0
- data/test/TestSuite/StatusSheets/run +3 -2
- data/test/TestSuite/Syntax/Correct/Include.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/Macro-1.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/Macro-2.tjp +6 -0
- data/test/TestSuite/Syntax/Correct/Macro-3.tjp +14 -0
- data/test/TestSuite/Syntax/Correct/ResourcePrefix.html +32 -0
- data/test/TestSuite/Syntax/Correct/css/tjmanual.css +66 -0
- data/test/TestSuite/Syntax/Correct/css/tjreport.css +407 -0
- data/test/TestSuite/Syntax/Correct/icons/details.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-green.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-red.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/flag-yellow.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/resource.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/resourcegroup.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/task.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/taskgroup.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-down.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-flat.png +0 -0
- data/test/TestSuite/Syntax/Correct/icons/trend-up.png +0 -0
- data/test/TestSuite/Syntax/Correct/include/dir1/file2.tji +3 -0
- data/test/TestSuite/Syntax/Correct/include/dir1/file5.tji +2 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/all.tji +3 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/file1.tji +2 -0
- data/test/TestSuite/Syntax/Correct/include/dir3/file2.tji +1 -0
- data/test/TestSuite/Syntax/Correct/scripts/wz_tooltip.js +1301 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +13 -13
- data/test/TestSuite/Syntax/Errors/empty.tjp +1 -1
- data/test/TestSuite/Syntax/Errors/include_recursion.tjp +1 -0
- data/test/TestSuite/Syntax/Errors/macro_stack_overflow.tjp +2 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring1.tjp → no_token_match1.tjp} +2 -2
- data/test/TestSuite/Syntax/Errors/{eof_in_istring2.tjp → no_token_match2.tjp} +2 -2
- data/test/TestSuite/Syntax/Errors/{eof_in_istring3.tjp → no_token_match3.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring4.tjp → no_token_match4.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/{eof_in_istring5.tjp → no_token_match5.tjp} +1 -1
- data/test/TestSuite/Syntax/Errors/not_scheduled.tjp +13 -0
- data/test/TestSuite/Syntax/Errors/unsupported_token.tjp +1 -1
- data/test/TestSuite/TimeSheets/run +5 -5
- data/test/test_CSVFile.rb +75 -0
- data/test/test_Limits.rb +63 -5
- data/test/test_ProjectFileScanner.rb +163 -0
- data/test/test_ReportGenerator.rb +81 -0
- data/test/test_RichText.rb +21 -3
- data/test/test_Scheduler.rb +1 -1
- data/test/test_ShiftAssignments.rb +4 -4
- data/test/test_Syntax.rb +1 -1
- data/test/test_URLParameter.rb +30 -0
- metadata +126 -32
- data/test/TestSuite/Scheduler/Errors/not_scheduled.tjp +0 -8
- data/test/TestSuite/Syntax/Errors/bad_comment.tjp +0 -7
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/boss_2002-03-01.tji +0 -36
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev1_2002-03-01.tji +0 -48
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev2_2002-03-01.tji +0 -67
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/dev3_2002-03-01.tji +0 -67
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/doc_2002-03-01.tji +0 -48
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/resources.yml +0 -31
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/2002-03-01/test_2002-03-01.tji +0 -36
- data/test/TestSuite/TimeSheets/TimeSheetTemplates/acceptable_intervals +0 -1
- data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/all.tji +0 -1
- data/test/TestSuite/TimeSheets/TimeSheets/2002-03-01/dev2_2002-03-01.tji +0 -54
- data/test/TestSuite/TimeSheets/TimeSheets/all.tji +0 -2
- data/test/TestSuite/TimeSheets/receiver.log +0 -102
- data/test/TestSuite/TimeSheets/sender.log +0 -794
- data/test/TestSuite/TimeSheets/summary.log +0 -884
- data/test/TestSuite/TimeSheets/timesheets.log +0 -45
- data/test/TestSuite/TimeSheets/tj3d.log +0 -292
- data/test/test_TextScanner.rb +0 -95
data/lib/StatusSheetSender.rb
CHANGED
|
@@ -57,7 +57,7 @@ class TaskJuggler
|
|
|
57
57
|
# The column is uniquely identified by an ID.
|
|
58
58
|
class TableColumnDefinition
|
|
59
59
|
|
|
60
|
-
attr_reader :id, :cellText, :tooltip, :cellColor, :fontColor
|
|
60
|
+
attr_reader :id, :cellText, :tooltip, :hAlign, :cellColor, :fontColor
|
|
61
61
|
attr_accessor :title, :start, :end, :scale, :width, :content, :column
|
|
62
62
|
|
|
63
63
|
def initialize(id, title)
|
|
@@ -73,8 +73,10 @@ class TaskJuggler
|
|
|
73
73
|
# the actual cell content.
|
|
74
74
|
@cellText = CellSettingPatternList.new
|
|
75
75
|
# The content attribute is only used for calendar columns. It specifies
|
|
76
|
-
# what content should be displayed in the
|
|
76
|
+
# what content should be displayed in the calendar columns.
|
|
77
77
|
@content = 'load'
|
|
78
|
+
# Horizontal alignment of the cell content.
|
|
79
|
+
@hAlign = CellSettingPatternList.new
|
|
78
80
|
# An alternative content for the tooltip message. It should be a
|
|
79
81
|
# RichText object.
|
|
80
82
|
@tooltip = CellSettingPatternList.new
|
data/lib/Task.rb
CHANGED
|
@@ -32,21 +32,21 @@ class TaskJuggler
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def query_journal(query)
|
|
35
|
-
|
|
35
|
+
journalText(query, true)
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
private
|
|
39
39
|
|
|
40
40
|
# Create a blog-style list of all alert messages that match the Query.
|
|
41
|
-
def
|
|
41
|
+
def journalText(query, longVersion)
|
|
42
42
|
# The components of the message are either UTF-8 text or RichText. For
|
|
43
43
|
# the RichText components, we use the originally provided markup since
|
|
44
44
|
# we compose the result as RichText markup first.
|
|
45
45
|
rText = ''
|
|
46
46
|
list = @project['journal'].entriesByTask(self, query.start, query.end)
|
|
47
47
|
list.reverse.each do |entry|
|
|
48
|
-
# The TimeSheetRecords associated with this entry.
|
|
49
48
|
tsRecord = entry.timeSheetRecord
|
|
49
|
+
|
|
50
50
|
if entry.property.is_a?(Task)
|
|
51
51
|
levelRecord = @project['alertLevels'][entry.alertLevel]
|
|
52
52
|
alertName = "[[File:icons/flag-#{levelRecord[0]}.png|" +
|
|
@@ -79,15 +79,14 @@ class TaskJuggler
|
|
|
79
79
|
end
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
# Don't generate a RichText object for an empty String.
|
|
83
|
+
return if rText.empty?
|
|
84
|
+
|
|
82
85
|
# Now convert the RichText markup String into RichTextIntermediate
|
|
83
86
|
# format.
|
|
84
|
-
handlers = [
|
|
85
|
-
RTFNavigator.new(@project),
|
|
86
|
-
RTFQuery.new(@project),
|
|
87
|
-
RTFReport.new(@project)
|
|
88
|
-
]
|
|
89
87
|
begin
|
|
90
|
-
rti = RichText.new(rText,
|
|
88
|
+
rti = RichText.new(rText, RTFHandlers.create(@project)).
|
|
89
|
+
generateIntermediateFormat
|
|
91
90
|
rescue RichTextException => msg
|
|
92
91
|
$stderr.puts "Error while processing Rich Text\n" +
|
|
93
92
|
"Line #{msg.lineNo}: #{msg.text}\n" +
|
data/lib/TaskJuggler.rb
CHANGED
|
@@ -20,7 +20,7 @@ require 'Log'
|
|
|
20
20
|
# files, schedule them and generate the reports.
|
|
21
21
|
class TaskJuggler
|
|
22
22
|
|
|
23
|
-
attr_reader :messageHandler
|
|
23
|
+
attr_reader :project, :messageHandler
|
|
24
24
|
attr_accessor :maxCpuCores, :warnTsDeltas
|
|
25
25
|
|
|
26
26
|
# Create a new TaskJuggler object. _console_ is a boolean that determines
|
|
@@ -73,9 +73,6 @@ class TaskJuggler
|
|
|
73
73
|
@parser.open(fileName, false)
|
|
74
74
|
@parser.setGlobalMacros
|
|
75
75
|
return nil if (res = @parser.parse(rule)).nil?
|
|
76
|
-
# Make sure that _rule_ described the full content of the file. There
|
|
77
|
-
# should be no more content left.
|
|
78
|
-
@parser.checkForEnd
|
|
79
76
|
@parser.close
|
|
80
77
|
res
|
|
81
78
|
end
|
|
@@ -94,7 +91,8 @@ class TaskJuggler
|
|
|
94
91
|
# Generate all specified reports. The project must have be scheduled before
|
|
95
92
|
# this method can be called. It returns true if no error occured, false
|
|
96
93
|
# otherwise.
|
|
97
|
-
def generateReports(outputDir)
|
|
94
|
+
def generateReports(outputDir = './')
|
|
95
|
+
outputDir += '/' unless outputDir.empty? || outputDir[-1] == '/'
|
|
98
96
|
@project.outputDir = outputDir
|
|
99
97
|
Log.enter('reports', 'Generating reports ...')
|
|
100
98
|
res = @project.generateReports(@maxCpuCores)
|
|
@@ -102,11 +100,15 @@ class TaskJuggler
|
|
|
102
100
|
res
|
|
103
101
|
end
|
|
104
102
|
|
|
105
|
-
# Generate the report with the ID _reportId_.
|
|
106
|
-
|
|
103
|
+
# Generate the report with the ID _reportId_. If _regExpMode_ is true,
|
|
104
|
+
# _reportId_ is interpreted as a Regular Expression and all reports with
|
|
105
|
+
# matching IDs are generated. _dynamicAtributes_ is a String that may
|
|
106
|
+
# contain attributes to supplement the report definition. The String must be
|
|
107
|
+
# in TJP format and may be nil if no additional attributes are provided.
|
|
108
|
+
def generateReport(reportId, regExpMode, dynamicAttributes = nil)
|
|
107
109
|
begin
|
|
108
110
|
Log.enter('generateReport', 'Generating report #{reportId} ...')
|
|
109
|
-
@project.generateReport(reportId, regExpMode)
|
|
111
|
+
@project.generateReport(reportId, regExpMode, dynamicAttributes)
|
|
110
112
|
rescue TjException
|
|
111
113
|
Log.exit('generateReport')
|
|
112
114
|
return false
|
|
@@ -115,7 +117,9 @@ class TaskJuggler
|
|
|
115
117
|
true
|
|
116
118
|
end
|
|
117
119
|
|
|
118
|
-
# Generate the report with the ID _reportId_.
|
|
120
|
+
# Generate the report with the ID _reportId_. If _regExpMode_ is true,
|
|
121
|
+
# _reportId_ is interpreted as a Regular Expression and all reports with
|
|
122
|
+
# matching IDs are listed.
|
|
119
123
|
def listReports(reportId, regExpMode)
|
|
120
124
|
begin
|
|
121
125
|
Log.enter('listReports', 'Generating report list for #{reportId} ...')
|
|
@@ -137,7 +141,7 @@ class TaskJuggler
|
|
|
137
141
|
# Make sure we don't use data from old time sheets or Journal entries.
|
|
138
142
|
@project.timeSheets.clear
|
|
139
143
|
@project['journal'] = Journal.new
|
|
140
|
-
return false unless (ts = parseFile(fileName, '
|
|
144
|
+
return false unless (ts = parseFile(fileName, 'timeSheetFile'))
|
|
141
145
|
return false unless @project.checkTimeSheets
|
|
142
146
|
queryAttrs = { 'project' => @project,
|
|
143
147
|
'property' => ts.resource,
|
|
@@ -169,7 +173,7 @@ class TaskJuggler
|
|
|
169
173
|
def checkStatusSheet(fileName)
|
|
170
174
|
begin
|
|
171
175
|
Log.enter('checkStatusSheet', 'Parsing #{fileName} ...')
|
|
172
|
-
return false unless (ss = parseFile(fileName, '
|
|
176
|
+
return false unless (ss = parseFile(fileName, 'statusSheetFile'))
|
|
173
177
|
queryAttrs = { 'project' => @project,
|
|
174
178
|
'property' => ss[0],
|
|
175
179
|
'scopeProperty' => nil,
|
|
@@ -201,6 +205,12 @@ class TaskJuggler
|
|
|
201
205
|
@project['projectid']
|
|
202
206
|
end
|
|
203
207
|
|
|
208
|
+
# Return the name of the project or nil if no project has been loaded yet.
|
|
209
|
+
def projectName
|
|
210
|
+
return nil if @project.nil?
|
|
211
|
+
@project['name']
|
|
212
|
+
end
|
|
213
|
+
|
|
204
214
|
# Return the number of errors that had been reported during processing.
|
|
205
215
|
def errors
|
|
206
216
|
@project.messageHandler.errors
|
data/lib/TaskScenario.rb
CHANGED
|
@@ -95,10 +95,10 @@ class TaskJuggler
|
|
|
95
95
|
markMilestone
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
-
# The parser only stores the full task IDs for each of the dependencies.
|
|
99
|
-
# function resolves them to task references and checks them. In
|
|
100
|
-
# to the 'depends' and 'precedes' property lists we also keep 4
|
|
101
|
-
# lists.
|
|
98
|
+
# The parser only stores the full task IDs for each of the dependencies.
|
|
99
|
+
# This function resolves them to task references and checks them. In
|
|
100
|
+
# addition to the 'depends' and 'precedes' property lists we also keep 4
|
|
101
|
+
# additional lists.
|
|
102
102
|
# startpreds: All precedessors to the start of this task
|
|
103
103
|
# startsuccs: All successors to the start of this task
|
|
104
104
|
# endpreds: All predecessors to the end of this task
|
|
@@ -304,7 +304,7 @@ class TaskJuggler
|
|
|
304
304
|
if ((startSpeced && endSpeced) ||
|
|
305
305
|
(hasDependencies(false) && a('forward') && endSpeced) ||
|
|
306
306
|
(hasDependencies(true) && !a('forward') && startSpeced)) &&
|
|
307
|
-
durationSpecs > 0 &&
|
|
307
|
+
durationSpecs > 0 && !@property.provided('scheduled', @scenarioIdx)
|
|
308
308
|
error('task_overspecified',
|
|
309
309
|
"Task #{@property.fullId} has a start, an end and a " +
|
|
310
310
|
'duration specification.')
|
|
@@ -842,6 +842,10 @@ class TaskJuggler
|
|
|
842
842
|
propagateDate(a(thisEnd), !atEnd)
|
|
843
843
|
end
|
|
844
844
|
Log << "Milestone #{@property.fullId}: #{a('start')} -> #{a('end')}"
|
|
845
|
+
elsif !a('scheduled') && a('start') && a('end') &&
|
|
846
|
+
!(a('length') == 0 && a('duration') == 0 && a('effort') == 0 &&
|
|
847
|
+
!a('allocate').empty?)
|
|
848
|
+
@property['scheduled', @scenarioIdx] = true
|
|
845
849
|
end
|
|
846
850
|
|
|
847
851
|
# Propagate date to all dependent tasks.
|
|
@@ -942,8 +946,6 @@ class TaskJuggler
|
|
|
942
946
|
end
|
|
943
947
|
end
|
|
944
948
|
|
|
945
|
-
@property['scheduled', @scenarioIdx] = true
|
|
946
|
-
|
|
947
949
|
startSet = endSet = false
|
|
948
950
|
# Propagate the dates to other dependent tasks.
|
|
949
951
|
if a('start').nil? || a('start') > nStart
|
|
@@ -954,6 +956,10 @@ class TaskJuggler
|
|
|
954
956
|
@property['end', @scenarioIdx] = nEnd
|
|
955
957
|
endSet = true
|
|
956
958
|
end
|
|
959
|
+
unless a('start') && a('end')
|
|
960
|
+
raise "Start (#{a('start')}) and end (#{a('end')}) must be set"
|
|
961
|
+
end
|
|
962
|
+
@property['scheduled', @scenarioIdx] = true
|
|
957
963
|
Log << "Container task #{@property.fullId}: #{a('start')} -> #{a('end')}"
|
|
958
964
|
|
|
959
965
|
# If we have modified the start or end date, we need to communicate this
|
|
@@ -1166,10 +1172,10 @@ class TaskJuggler
|
|
|
1166
1172
|
str += "* <nowiki>#{task.name}</nowiki> (#{task.fullId}) "
|
|
1167
1173
|
if onEnd
|
|
1168
1174
|
taskEnd = task['end', query.scenarioIdx].to_s(query.timeFormat)
|
|
1169
|
-
str += "[->
|
|
1175
|
+
str += "[->] #{taskEnd}"
|
|
1170
1176
|
else
|
|
1171
1177
|
taskStart = task['start', query.scenarioIdx].to_s(query.timeFormat)
|
|
1172
|
-
str += "[->
|
|
1178
|
+
str += "[->[ #{taskStart}"
|
|
1173
1179
|
end
|
|
1174
1180
|
str += "\n"
|
|
1175
1181
|
end
|
|
@@ -1178,10 +1184,10 @@ class TaskJuggler
|
|
|
1178
1184
|
str += "* <nowiki>#{task.name}</nowiki> (#{task.fullId}) "
|
|
1179
1185
|
if onEnd
|
|
1180
1186
|
taskEnd = task['end', query.scenarioIdx].to_s(query.timeFormat)
|
|
1181
|
-
str += "]->
|
|
1187
|
+
str += "]->] #{taskEnd}"
|
|
1182
1188
|
else
|
|
1183
1189
|
taskStart = task['start', query.scenarioIdx].to_s(query.timeFormat)
|
|
1184
|
-
str += "]->
|
|
1190
|
+
str += "]->[ #{taskStart}"
|
|
1185
1191
|
end
|
|
1186
1192
|
str += "\n"
|
|
1187
1193
|
end
|
|
@@ -1198,7 +1204,7 @@ class TaskJuggler
|
|
|
1198
1204
|
str += "* <nowiki>#{task.name}</nowiki> (#{task.fullId}) "
|
|
1199
1205
|
if onEnd
|
|
1200
1206
|
taskEnd = task['end', query.scenarioIdx].to_s(query.timeFormat)
|
|
1201
|
-
str += "]->
|
|
1207
|
+
str += "]->] #{taskEnd}"
|
|
1202
1208
|
else
|
|
1203
1209
|
taskStart = task['start', query.scenarioIdx].to_s(query.timeFormat)
|
|
1204
1210
|
str += "[->[ #{taskStart}"
|
|
@@ -1213,7 +1219,7 @@ class TaskJuggler
|
|
|
1213
1219
|
str += "[->] #{taskEnd}"
|
|
1214
1220
|
else
|
|
1215
1221
|
taskStart = task['start', query.scenarioIdx].to_s(query.timeFormat)
|
|
1216
|
-
str += "]->
|
|
1222
|
+
str += "]->[ #{taskStart}"
|
|
1217
1223
|
end
|
|
1218
1224
|
str += "\n"
|
|
1219
1225
|
end
|
|
@@ -1333,6 +1339,7 @@ class TaskJuggler
|
|
|
1333
1339
|
|
|
1334
1340
|
# Check if the Task _task_ depends on this task. _depth_ specifies how
|
|
1335
1341
|
# many dependent task are traversed at max. A value of 0 means no limit.
|
|
1342
|
+
# TODO: Change this to a non-recursive implementation.
|
|
1336
1343
|
def isDependencyOf(task, depth)
|
|
1337
1344
|
return true if task == @property
|
|
1338
1345
|
|
|
@@ -1364,6 +1371,21 @@ class TaskJuggler
|
|
|
1364
1371
|
false
|
|
1365
1372
|
end
|
|
1366
1373
|
|
|
1374
|
+
# If _task_ or any of its sub-tasks depend on this task or any of its
|
|
1375
|
+
# sub-tasks, we call this task a feature of _task_.
|
|
1376
|
+
def isFeatureOf(task)
|
|
1377
|
+
sources = @property.all
|
|
1378
|
+
destinations = task.all
|
|
1379
|
+
|
|
1380
|
+
sources.each do |s|
|
|
1381
|
+
destinations.each do |d|
|
|
1382
|
+
return true if s.isDependencyOf(@scenarioIdx, d, 0)
|
|
1383
|
+
end
|
|
1384
|
+
end
|
|
1385
|
+
|
|
1386
|
+
false
|
|
1387
|
+
end
|
|
1388
|
+
|
|
1367
1389
|
# Returns true of the _resource_ is assigned to this task or any of its
|
|
1368
1390
|
# children.
|
|
1369
1391
|
def hasResourceAllocated?(interval, resource)
|
|
@@ -1421,7 +1443,6 @@ class TaskJuggler
|
|
|
1421
1443
|
# or start date and propagate the value to neighbouring tasks.
|
|
1422
1444
|
if (a('length') > 0 && @doneLength >= a('length')) ||
|
|
1423
1445
|
(a('duration') > 0 && @doneDuration >= a('duration'))
|
|
1424
|
-
@property['scheduled', @scenarioIdx] = true
|
|
1425
1446
|
if a('forward')
|
|
1426
1447
|
propagateDate(slot + slotDuration, true)
|
|
1427
1448
|
else
|
|
@@ -1434,7 +1455,6 @@ class TaskJuggler
|
|
|
1434
1455
|
if @doneEffort >= a('effort')
|
|
1435
1456
|
# The specified effort has been reached. The has been fully scheduled
|
|
1436
1457
|
# now.
|
|
1437
|
-
@property['scheduled', @scenarioIdx] = true
|
|
1438
1458
|
if a('forward')
|
|
1439
1459
|
propagateDate(@tentativeEnd, true)
|
|
1440
1460
|
else
|
|
@@ -1508,11 +1528,9 @@ class TaskJuggler
|
|
|
1508
1528
|
return if !shifts.onShift?(date)
|
|
1509
1529
|
end
|
|
1510
1530
|
|
|
1511
|
-
# If the task has allocation limits we need to make
|
|
1512
|
-
# is already exceeded.
|
|
1513
|
-
|
|
1514
|
-
return if !limit.ok?(date)
|
|
1515
|
-
end
|
|
1531
|
+
# If the task has resource independent allocation limits we need to make
|
|
1532
|
+
# sure that none of them is already exceeded.
|
|
1533
|
+
return unless limitsOk?(date)
|
|
1516
1534
|
|
|
1517
1535
|
sbIdx = @project.dateToIdx(date)
|
|
1518
1536
|
|
|
@@ -1530,8 +1548,11 @@ class TaskJuggler
|
|
|
1530
1548
|
# group must be available.
|
|
1531
1549
|
allAvailable = true
|
|
1532
1550
|
candidate.allLeaves.each do |resource|
|
|
1533
|
-
if !
|
|
1551
|
+
if !limitsOk?(date, resource) ||
|
|
1552
|
+
!resource.available?(@scenarioIdx, sbIdx) ||
|
|
1534
1553
|
takenMandatories.include?(resource)
|
|
1554
|
+
# We've found a mandatory resource that is not available for
|
|
1555
|
+
# the slot.
|
|
1535
1556
|
allAvailable = false
|
|
1536
1557
|
break
|
|
1537
1558
|
else
|
|
@@ -1573,8 +1594,10 @@ class TaskJuggler
|
|
|
1573
1594
|
booked = false
|
|
1574
1595
|
resource.allLeaves.each do |r|
|
|
1575
1596
|
# Prevent overbooking when multiple resources are allocated and
|
|
1576
|
-
# available.
|
|
1577
|
-
|
|
1597
|
+
# available. If the task has allocation limits we need to make sure
|
|
1598
|
+
# that none of them is already exceeded.
|
|
1599
|
+
break if a('effort') > 0 && @doneEffort >= a('effort') ||
|
|
1600
|
+
!limitsOk?(date, resource)
|
|
1578
1601
|
|
|
1579
1602
|
if r.book(@scenarioIdx, sbIdx, @property)
|
|
1580
1603
|
|
|
@@ -1593,7 +1616,7 @@ class TaskJuggler
|
|
|
1593
1616
|
# Limits do not take efficiency into account. Limits are usage limits,
|
|
1594
1617
|
# not effort limits.
|
|
1595
1618
|
@limits.each do |limit|
|
|
1596
|
-
limit.inc(date)
|
|
1619
|
+
limit.inc(date, resource)
|
|
1597
1620
|
end
|
|
1598
1621
|
|
|
1599
1622
|
unless a('assignedresources').include?(r)
|
|
@@ -1606,6 +1629,18 @@ class TaskJuggler
|
|
|
1606
1629
|
booked
|
|
1607
1630
|
end
|
|
1608
1631
|
|
|
1632
|
+
# Check if all of the task limits are not exceded at the given _date_. If
|
|
1633
|
+
# a _resource_ is provided, the limit for that particular resource is
|
|
1634
|
+
# checked. If no resource is provided, only non-resource-specific limits
|
|
1635
|
+
# are checked.
|
|
1636
|
+
def limitsOk?(date, resource = nil)
|
|
1637
|
+
@limits.each do |limit|
|
|
1638
|
+
return false if !limit.ok?(date, true, resource)
|
|
1639
|
+
end
|
|
1640
|
+
true
|
|
1641
|
+
end
|
|
1642
|
+
|
|
1643
|
+
|
|
1609
1644
|
# Register the user provided bookings with the Resource scoreboards. A
|
|
1610
1645
|
# booking describes the assignment of a Resource to a certain Task for a
|
|
1611
1646
|
# specified Interval.
|
|
@@ -1617,7 +1652,7 @@ class TaskJuggler
|
|
|
1617
1652
|
"Booked resources may not be group resources", true,
|
|
1618
1653
|
booking.sourceFileInfo)
|
|
1619
1654
|
end
|
|
1620
|
-
unless a('forward') ||
|
|
1655
|
+
unless a('forward') || scheduled
|
|
1621
1656
|
error('booking_forward_only',
|
|
1622
1657
|
"Only forward scheduled tasks may have booking statements.")
|
|
1623
1658
|
end
|
|
@@ -1639,7 +1674,7 @@ class TaskJuggler
|
|
|
1639
1674
|
@lastSlot = date if @lastSlot.nil? || date > @lastSlot
|
|
1640
1675
|
@tentativeEnd = tEnd if @tentativeEnd.nil? ||
|
|
1641
1676
|
@tentativeEnd < tEnd
|
|
1642
|
-
if !
|
|
1677
|
+
if !scheduled && (a('start').nil? || date < a('start'))
|
|
1643
1678
|
@property['start', @scenarioIdx] = date
|
|
1644
1679
|
end
|
|
1645
1680
|
|
data/lib/TextParser.rb
CHANGED
|
@@ -161,7 +161,7 @@ class TaskJuggler
|
|
|
161
161
|
@@expectedTokens = []
|
|
162
162
|
updateParserTables
|
|
163
163
|
begin
|
|
164
|
-
result =
|
|
164
|
+
result = parseRuleR(@rules[ruleName])
|
|
165
165
|
rescue TjException
|
|
166
166
|
# error('parse_error', $!.message)
|
|
167
167
|
return nil
|
|
@@ -170,21 +170,12 @@ class TaskJuggler
|
|
|
170
170
|
result
|
|
171
171
|
end
|
|
172
172
|
|
|
173
|
-
# Return true if the scanner has processed all files.
|
|
174
|
-
def checkForEnd
|
|
175
|
-
token = @scanner.nextToken
|
|
176
|
-
unless token[0] == '.'
|
|
177
|
-
error('junk_at_expected_eof',
|
|
178
|
-
"Found garbage at expected end of file: #{token[1]}")
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
173
|
# Return the SourceFileInfo of the TextScanner at the beginning of the
|
|
183
174
|
# currently processed TextParser::Rule. Or return nil if we don't have a
|
|
184
175
|
# current position.
|
|
185
176
|
def sourceFileInfo
|
|
186
177
|
return nil if @stack.empty?
|
|
187
|
-
@stack.last.sourceFileInfo
|
|
178
|
+
@stack.last.sourceFileInfo[0]
|
|
188
179
|
end
|
|
189
180
|
|
|
190
181
|
def matchingRules(keyword)
|
|
@@ -196,12 +187,18 @@ class TaskJuggler
|
|
|
196
187
|
matches
|
|
197
188
|
end
|
|
198
189
|
|
|
199
|
-
def error(id, text, property = nil)
|
|
200
|
-
@scanner
|
|
190
|
+
def error(id, text, property = nil, sfi = nil)
|
|
191
|
+
if @scanner
|
|
192
|
+
@scanner.error(id, text, property, sfi)
|
|
193
|
+
else
|
|
194
|
+
message = Message.new(id, 'error', text, property, sfi)
|
|
195
|
+
@messageHandler.send(message)
|
|
196
|
+
raise TjException.new, ''
|
|
197
|
+
end
|
|
201
198
|
end
|
|
202
199
|
|
|
203
|
-
def warning(id, text, property = nil)
|
|
204
|
-
@scanner.warning(id, text, property)
|
|
200
|
+
def warning(id, text, property = nil, sfi = nil)
|
|
201
|
+
@scanner.warning(id, text, property, sfi)
|
|
205
202
|
end
|
|
206
203
|
|
|
207
204
|
private
|
|
@@ -274,7 +271,8 @@ class TaskJuggler
|
|
|
274
271
|
if type == ?$
|
|
275
272
|
if @variables.index(token).nil?
|
|
276
273
|
error('unsupported_token',
|
|
277
|
-
"The token #{token} is not supported here."
|
|
274
|
+
"The token #{token} is not supported here.", nil,
|
|
275
|
+
token[2])
|
|
278
276
|
end
|
|
279
277
|
elsif type == ?!
|
|
280
278
|
if @rules[token].nil?
|
|
@@ -289,8 +287,10 @@ class TaskJuggler
|
|
|
289
287
|
# This function processes the input starting with the syntax description of
|
|
290
288
|
# _rule_. It recursively calls this function whenever the syntax description
|
|
291
289
|
# contains the reference to another rule.
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
# This recursive version has cleaner code and is about 8% faster than
|
|
291
|
+
# parseRuleNR.
|
|
292
|
+
def parseRuleR(rule)
|
|
293
|
+
#Log.enter('parseRuleR', "Parsing with rule #{rule.name}")
|
|
294
294
|
result = rule.repeatable ? TextParserResultArray.new : nil
|
|
295
295
|
# Rules can be marked 'repeatable'. This flag will be set to true after
|
|
296
296
|
# the first iteration has been completed.
|
|
@@ -300,105 +300,34 @@ class TaskJuggler
|
|
|
300
300
|
# which pattern of the rule needs to be processed.
|
|
301
301
|
token = getNextToken
|
|
302
302
|
|
|
303
|
-
|
|
304
|
-
#
|
|
305
|
-
#
|
|
306
|
-
|
|
307
|
-
if token[0] == 'ID'
|
|
308
|
-
if (patIdx = rule.matchingPatternIndex('_' + token[1])).nil?
|
|
309
|
-
patIdx = rule.matchingPatternIndex("$ID")
|
|
310
|
-
end
|
|
311
|
-
elsif token[0] == 'LITERAL'
|
|
312
|
-
patIdx = rule.matchingPatternIndex('_' + token[1])
|
|
313
|
-
elsif token[0] == false
|
|
314
|
-
patIdx = rule.matchingPatternIndex('.')
|
|
315
|
-
else
|
|
316
|
-
patIdx = rule.matchingPatternIndex('$' + token[0])
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
# If no matching pattern is found for the token we have to check if the
|
|
320
|
-
# rule is optional or we are in repeat mode. If this is the case, return
|
|
321
|
-
# the token back to the scanner. Otherwise we have found a token we
|
|
322
|
-
# cannot handle at this point.
|
|
323
|
-
if patIdx.nil?
|
|
324
|
-
# Append the list of expected tokens to the @@expectedToken array.
|
|
325
|
-
# This may be used in a later rule to provide more details when an
|
|
326
|
-
# error occured.
|
|
327
|
-
rule.transitions.each do |transition|
|
|
328
|
-
keys = transition.keys
|
|
329
|
-
keys.collect! { |key| key[1..-1] }
|
|
330
|
-
@@expectedTokens += keys
|
|
331
|
-
@@expectedTokens.sort!
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
unless rule.optional?(@rules) || repeatMode
|
|
335
|
-
error('unexpctd_token',
|
|
336
|
-
(token[0] != false ?
|
|
337
|
-
"Unexpected token '#{token[1]}' of type '#{token[0]}'. " :
|
|
338
|
-
"Unexpected end of file in #{@scanner.fileName}. ") +
|
|
339
|
-
(@@expectedTokens.length > 1 ?
|
|
340
|
-
"Expecting one of #{@@expectedTokens.join(', ')}" :
|
|
341
|
-
"Expecting #{@@expectedTokens[0]}"))
|
|
342
|
-
end
|
|
343
|
-
returnToken(token)
|
|
344
|
-
Log.exit('parseRule', "Finished rule #{rule.name}")
|
|
345
|
-
return result
|
|
346
|
-
end
|
|
347
|
-
|
|
348
|
-
pattern = rule.pattern(patIdx)
|
|
349
|
-
@stack << TextParser::StackElement.new(rule, pattern.function,
|
|
350
|
-
@scanner.sourceFileInfo)
|
|
303
|
+
return result unless (pattern = findPattern(rule, token, repeatMode))
|
|
304
|
+
# The @stack will store the resulting value of each element in the
|
|
305
|
+
# pattern.
|
|
306
|
+
@stack << TextParser::StackElement.new(pattern.function)
|
|
351
307
|
|
|
352
308
|
pattern.each do |element|
|
|
353
309
|
# Separate the type and token text for pattern element.
|
|
354
310
|
elType = element[0]
|
|
355
311
|
elToken = element[1..-1]
|
|
356
312
|
if elType == ?!
|
|
357
|
-
# The element is a reference to another rule. Return the token if
|
|
358
|
-
# still have one and continue with the referenced rule.
|
|
313
|
+
# The element is a reference to another rule. Return the token if
|
|
314
|
+
# we still have one and continue with the referenced rule.
|
|
359
315
|
unless token.nil?
|
|
316
|
+
sfi = token[2]
|
|
360
317
|
returnToken(token)
|
|
361
318
|
token = nil
|
|
319
|
+
else
|
|
320
|
+
sfi = nil
|
|
362
321
|
end
|
|
363
|
-
@stack.last.store(
|
|
364
|
-
|
|
322
|
+
@stack.last.store(parseRuleR(@rules[elToken]), sfi)
|
|
323
|
+
#Log << "Resuming rule #{rule.name}"
|
|
365
324
|
else
|
|
366
325
|
# In case the element is a keyword or variable we have to get a new
|
|
367
326
|
# token if we don't have one anymore.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
327
|
+
token = getNextToken unless token
|
|
328
|
+
|
|
329
|
+
processNormalElements(elType, elToken, token)
|
|
371
330
|
|
|
372
|
-
if elType == ?_
|
|
373
|
-
# If the element requires a keyword the token must match this
|
|
374
|
-
# keyword.
|
|
375
|
-
if elToken != token[1]
|
|
376
|
-
text = "'#{elToken}' expected but found " +
|
|
377
|
-
"'#{token[1]}' (#{token[0]})."
|
|
378
|
-
unless @@expectedTokens.empty?
|
|
379
|
-
text = "#{@@expectedTokens.join(', ')} or " + text
|
|
380
|
-
end
|
|
381
|
-
error('spec_keywork_expctd', text)
|
|
382
|
-
end
|
|
383
|
-
@stack.last.store(elToken, @scanner.sourceFileInfo)
|
|
384
|
-
elsif elType == ?.
|
|
385
|
-
if token != [ '.', '<END>' ]
|
|
386
|
-
error('end_expected', 'End expected but found ' +
|
|
387
|
-
"'#{token[1]}' (#{token[0]}).")
|
|
388
|
-
end
|
|
389
|
-
else
|
|
390
|
-
# The token must match the expected variable type.
|
|
391
|
-
if token[0] != elToken
|
|
392
|
-
text = "'#{elToken}' expected but found " +
|
|
393
|
-
"'#{token[1]}' (#{token[0]})."
|
|
394
|
-
unless @@expectedTokens.empty?
|
|
395
|
-
text = "#{@@expectedTokens.join(', ')} or " + text
|
|
396
|
-
end
|
|
397
|
-
error('spec_token_expctd', text)
|
|
398
|
-
end
|
|
399
|
-
# If the element is a variable store the value of the token.
|
|
400
|
-
@stack.last.store(token[1], @scanner.sourceFileInfo)
|
|
401
|
-
end
|
|
402
331
|
# The token has been consumed. Reset the variable.
|
|
403
332
|
token = nil
|
|
404
333
|
@@expectedTokens = []
|
|
@@ -409,6 +338,7 @@ class TaskJuggler
|
|
|
409
338
|
# function for this pattern to operate on the value array. Then pop the
|
|
410
339
|
# entry for this rule from the stack.
|
|
411
340
|
@val = @stack.last.val
|
|
341
|
+
@sourceFileInfo = @stack.last.sourceFileInfo
|
|
412
342
|
res = nil
|
|
413
343
|
res = @stack.last.function.call unless @stack.last.function.nil?
|
|
414
344
|
@stack.pop
|
|
@@ -426,24 +356,256 @@ class TaskJuggler
|
|
|
426
356
|
repeatMode = true
|
|
427
357
|
end
|
|
428
358
|
|
|
429
|
-
Log.exit('
|
|
359
|
+
#Log.exit('parseRuleR', "Finished rule #{rule.name}")
|
|
360
|
+
return result
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
# This function processes the input starting with the syntax description
|
|
364
|
+
# of _rule_. It's implemented as an unrolled recursion. It recursively
|
|
365
|
+
# iterates over the rule tree as controlled by the input file.
|
|
366
|
+
# This version is not limited by the size of the system stack. So far, I'm
|
|
367
|
+
# not aware of any project that is too large for the system stack. Since
|
|
368
|
+
# the recursive version parseRuleR is about 8% faster and has cleaner
|
|
369
|
+
# code, we use that by default.
|
|
370
|
+
def parseRuleNR(rule)
|
|
371
|
+
elementIdx = 0
|
|
372
|
+
recursionResult = nil
|
|
373
|
+
# These flags are used to managed the control flow to and from the
|
|
374
|
+
# recursion point.
|
|
375
|
+
recur = resume = false
|
|
376
|
+
# The stack that holds the context for the recursion levels. It's either
|
|
377
|
+
# just a rule to start a new recursion or an Array of state variables.
|
|
378
|
+
recursionStack = [ rule ]
|
|
379
|
+
begin
|
|
380
|
+
# Pop the top entry from the recursion stack.
|
|
381
|
+
se = recursionStack.pop
|
|
382
|
+
if se.is_a?(Array)
|
|
383
|
+
# We have essentially finished a recursion level and need to get
|
|
384
|
+
# back to the place where we started the recursion. First, we need
|
|
385
|
+
# to restore the state again.
|
|
386
|
+
rule, pattern, elementIdx, result, repeatMode, sfi = se
|
|
387
|
+
#Log << "Recursion loop started in resume mode for rule #{rule.name}"
|
|
388
|
+
# Now jump to the recursion point without doing anything else.
|
|
389
|
+
resume = true
|
|
390
|
+
else
|
|
391
|
+
# Start a new recursion level. The rule tells us how to interpret
|
|
392
|
+
# the input text.
|
|
393
|
+
rule = se
|
|
394
|
+
#Log.enter('parseRuleNR', "Parsing with rule #{rule.name}")
|
|
395
|
+
resume = false
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
unless resume
|
|
399
|
+
result = rule.repeatable ? TextParserResultArray.new : nil
|
|
400
|
+
# Rules can be marked 'repeatable'. This flag will be set to true
|
|
401
|
+
# after the first iteration has been completed.
|
|
402
|
+
repeatMode = false
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
loop do
|
|
406
|
+
unless resume
|
|
407
|
+
# At the beginning of a rule we need a token from the input to
|
|
408
|
+
# determine which pattern of the rule needs to be processed.
|
|
409
|
+
token = getNextToken
|
|
410
|
+
|
|
411
|
+
break unless (pattern = findPattern(rule, token, repeatMode))
|
|
412
|
+
# The @stack will store the resulting value of each element in the
|
|
413
|
+
# pattern.
|
|
414
|
+
@stack << TextParser::StackElement.new(pattern.function)
|
|
415
|
+
|
|
416
|
+
# Once we've found the right pattern, we need to process each
|
|
417
|
+
# element.
|
|
418
|
+
elementIdx = 0
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
elementCount = pattern.length
|
|
422
|
+
while elementIdx < elementCount
|
|
423
|
+
element = pattern[elementIdx]
|
|
424
|
+
# Separate the type and token text for pattern element.
|
|
425
|
+
elType = element[0]
|
|
426
|
+
elToken = element[1..-1]
|
|
427
|
+
if elType == ?!
|
|
428
|
+
unless resume
|
|
429
|
+
# The element is a reference to another rule. Return the token
|
|
430
|
+
# if we still have one and continue with the referenced rule.
|
|
431
|
+
if token
|
|
432
|
+
sfi = token[2]
|
|
433
|
+
returnToken(token)
|
|
434
|
+
token = nil
|
|
435
|
+
else
|
|
436
|
+
sfi = nil
|
|
437
|
+
end
|
|
438
|
+
# This is where the recursion would happen. Instead, we push
|
|
439
|
+
# the state variables and then the next rule onto the
|
|
440
|
+
# recursion stack.
|
|
441
|
+
recursionStack.push([ rule, pattern, elementIdx, result,
|
|
442
|
+
repeatMode, sfi ])
|
|
443
|
+
recursionStack.push(@rules[elToken])
|
|
444
|
+
# Now terminate all but the outer loops without doing anything
|
|
445
|
+
# else.
|
|
446
|
+
recur = true
|
|
447
|
+
break
|
|
448
|
+
else
|
|
449
|
+
# We're back right after where the recursion started. Store
|
|
450
|
+
# the result and turn resume mode off again.
|
|
451
|
+
@stack.last.store(recursionResult, sfi)
|
|
452
|
+
resume = false
|
|
453
|
+
end
|
|
454
|
+
else
|
|
455
|
+
# In case the element is a keyword or variable we have to get a
|
|
456
|
+
# new token if we don't have one anymore.
|
|
457
|
+
token = getNextToken unless token
|
|
458
|
+
|
|
459
|
+
processNormalElements(elType, elToken, token)
|
|
460
|
+
|
|
461
|
+
# The token has been consumed. Reset the variable.
|
|
462
|
+
token = nil
|
|
463
|
+
@@expectedTokens = []
|
|
464
|
+
end
|
|
465
|
+
elementIdx += 1
|
|
466
|
+
end # of pattern while loop
|
|
467
|
+
|
|
468
|
+
# Skip the rest of the loop in recur mode.
|
|
469
|
+
break if recur
|
|
470
|
+
|
|
471
|
+
elementIdx = 0
|
|
472
|
+
|
|
473
|
+
# Once the complete pattern has been processed we call the
|
|
474
|
+
# processing function for this pattern to operate on the value
|
|
475
|
+
# array. Then pop the entry for this rule from the stack. The
|
|
476
|
+
# called function will use @val and @sourceFileInfo to retrieve
|
|
477
|
+
# data from the parser.
|
|
478
|
+
@val = @stack.last.val
|
|
479
|
+
@sourceFileInfo = @stack.last.sourceFileInfo
|
|
480
|
+
res = @stack.last.function ? @stack.last.function.call : nil
|
|
481
|
+
@stack.pop
|
|
482
|
+
|
|
483
|
+
# If the rule is not repeatable we can store the result and break
|
|
484
|
+
# the outer loop to exit the function.
|
|
485
|
+
unless rule.repeatable
|
|
486
|
+
result = res
|
|
487
|
+
break
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Otherwise we append the result to the result array and turn repeat
|
|
491
|
+
# mode on.
|
|
492
|
+
result << res
|
|
493
|
+
# We have completed the first iteration. Set the repeat mode flag to
|
|
494
|
+
# indicate that further iterations are already re-runs.
|
|
495
|
+
repeatMode = true
|
|
496
|
+
end # of rule processing loop
|
|
497
|
+
|
|
498
|
+
if recur
|
|
499
|
+
recur = false
|
|
500
|
+
else
|
|
501
|
+
#Log.exit('parseRuleNR', "Finished rule #{rule.name}")
|
|
502
|
+
recursionResult = result
|
|
503
|
+
end
|
|
504
|
+
end while !recursionStack.empty?
|
|
505
|
+
|
|
430
506
|
return result
|
|
431
507
|
end
|
|
432
508
|
|
|
433
509
|
def getNextToken
|
|
434
510
|
begin
|
|
435
511
|
token = nextToken
|
|
436
|
-
Log << "Token: [#{token[0]}][#{token[1]}]"
|
|
512
|
+
#Log << "Token: [#{token[0]}][#{token[1]}]"
|
|
437
513
|
rescue TjException
|
|
438
514
|
error('parse_rule', $!.message)
|
|
439
515
|
end
|
|
440
516
|
if @badVariables.include?(token[0])
|
|
441
517
|
error('unsupported_token',
|
|
442
|
-
"The token #{token[1]} is not supported in this context."
|
|
518
|
+
"The token #{token[1]} is not supported in this context.",
|
|
519
|
+
nil, token[2])
|
|
443
520
|
end
|
|
444
521
|
token
|
|
445
522
|
end
|
|
446
523
|
|
|
524
|
+
def findPattern(rule, token, repeatMode)
|
|
525
|
+
# The scanner cannot differentiate between keywords and identifiers. So
|
|
526
|
+
# whenever an identifier is returned we have to see if we have a
|
|
527
|
+
# matching keyword first. If none is found, then look for normal
|
|
528
|
+
# identifiers.
|
|
529
|
+
if token[0] == 'ID'
|
|
530
|
+
if (patIdx = rule.matchingPatternIndex('_' + token[1])).nil?
|
|
531
|
+
patIdx = rule.matchingPatternIndex("$ID")
|
|
532
|
+
end
|
|
533
|
+
elsif token[0] == 'LITERAL'
|
|
534
|
+
patIdx = rule.matchingPatternIndex('_' + token[1])
|
|
535
|
+
elsif token[0] == false
|
|
536
|
+
patIdx = rule.matchingPatternIndex('.')
|
|
537
|
+
else
|
|
538
|
+
patIdx = rule.matchingPatternIndex('$' + token[0])
|
|
539
|
+
end
|
|
540
|
+
|
|
541
|
+
# If no matching pattern is found for the token we have to check if the
|
|
542
|
+
# rule is optional or we are in repeat mode. If this is the case, return
|
|
543
|
+
# the token back to the scanner. Otherwise, we have found a token we
|
|
544
|
+
# cannot handle at this point.
|
|
545
|
+
if patIdx.nil?
|
|
546
|
+
# Append the list of expected tokens to the @@expectedToken array.
|
|
547
|
+
# This may be used in a later rule to provide more details when an
|
|
548
|
+
# error occured.
|
|
549
|
+
rule.transitions.each do |transition|
|
|
550
|
+
keys = transition.keys
|
|
551
|
+
keys.collect! { |key| key[1..-1] }
|
|
552
|
+
@@expectedTokens += keys
|
|
553
|
+
@@expectedTokens.sort!
|
|
554
|
+
end
|
|
555
|
+
|
|
556
|
+
unless rule.optional?(@rules) || repeatMode
|
|
557
|
+
error('unexpctd_token',
|
|
558
|
+
(token[0] != false ?
|
|
559
|
+
"Unexpected token '#{token[1]}' of type " +
|
|
560
|
+
"'#{token[0]}'. " :
|
|
561
|
+
"Unexpected end of file in #{@scanner.fileName}. ") +
|
|
562
|
+
(@@expectedTokens.length > 1 ?
|
|
563
|
+
"Expecting one of #{@@expectedTokens.join(', ')}" :
|
|
564
|
+
"Expecting #{@@expectedTokens[0]}"))
|
|
565
|
+
end
|
|
566
|
+
returnToken(token)
|
|
567
|
+
return nil
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
rule.pattern(patIdx)
|
|
571
|
+
end
|
|
572
|
+
|
|
573
|
+
# Handle the elements that don't trigger a recursion.
|
|
574
|
+
def processNormalElements(elType, elToken, token)
|
|
575
|
+
if elType == ?_
|
|
576
|
+
# If the element requires a keyword the token must match this
|
|
577
|
+
# keyword.
|
|
578
|
+
if elToken != token[1]
|
|
579
|
+
text = "'#{elToken}' expected but found " +
|
|
580
|
+
"'#{token[1]}' (#{token[0]})."
|
|
581
|
+
unless @@expectedTokens.empty?
|
|
582
|
+
text = "#{@@expectedTokens.join(', ')} or " + text
|
|
583
|
+
end
|
|
584
|
+
error('spec_keywork_expctd', text)
|
|
585
|
+
end
|
|
586
|
+
@stack.last.store(elToken, token[2])
|
|
587
|
+
elsif elType == ?.
|
|
588
|
+
if token[0..1] != [ '.', '<END>' ]
|
|
589
|
+
error('end_expected',
|
|
590
|
+
"Found garbage at expected end of file: #{token[1]}\n" +
|
|
591
|
+
"If you see this in the middle of your file, you probably " +
|
|
592
|
+
"have closed your context too early.")
|
|
593
|
+
end
|
|
594
|
+
else
|
|
595
|
+
# The token must match the expected variable type.
|
|
596
|
+
if token[0] != elToken
|
|
597
|
+
text = "'#{elToken}' expected but found " +
|
|
598
|
+
"'#{token[1]}' (#{token[0]})."
|
|
599
|
+
unless @@expectedTokens.empty?
|
|
600
|
+
text = "#{@@expectedTokens.join(', ')} or " + text
|
|
601
|
+
end
|
|
602
|
+
error('spec_token_expctd', text)
|
|
603
|
+
end
|
|
604
|
+
# If the element is a variable store the value of the token.
|
|
605
|
+
@stack.last.store(token[1], token[2])
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
|
|
447
609
|
end
|
|
448
610
|
|
|
449
611
|
end
|