taskjuggler 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|