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/TextParser/Rule.rb
CHANGED
|
@@ -120,8 +120,10 @@ class TaskJuggler::TextParser
|
|
|
120
120
|
# Return the pattern of this rule that matches the given +token+. If no
|
|
121
121
|
# pattern matches, return nil.
|
|
122
122
|
def matchingPatternIndex(token)
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
i = 0
|
|
124
|
+
@transitions.each do |t|
|
|
125
|
+
return i if t.has_key?(token)
|
|
126
|
+
i += 1
|
|
125
127
|
end
|
|
126
128
|
|
|
127
129
|
nil
|
|
@@ -25,20 +25,22 @@ class TaskJuggler::TextParser
|
|
|
25
25
|
# called at the end to store the collected data. _sourceFileInfo_ is a
|
|
26
26
|
# SourceFileInfo reference that describes the TextScanner position when the
|
|
27
27
|
# rule was entered.
|
|
28
|
-
def initialize(
|
|
28
|
+
def initialize(function)
|
|
29
29
|
# This Array stores the collected values.
|
|
30
30
|
@val = []
|
|
31
|
+
# Array to store the source file references for the collected values.
|
|
32
|
+
@sourceFileInfo = []
|
|
33
|
+
# Counter used for StackElement::store()
|
|
31
34
|
@position = 0
|
|
32
|
-
|
|
35
|
+
# The method that will process the collected values.
|
|
33
36
|
@function = function
|
|
34
|
-
@sourceFileInfo = sourceFileInfo
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
# Store a collected value and move the position to the next pattern.
|
|
38
40
|
def store(val, sourceFileInfo = nil)
|
|
39
41
|
@val[@position] = val
|
|
42
|
+
@sourceFileInfo[@position] = sourceFileInfo
|
|
40
43
|
@position += 1
|
|
41
|
-
@sourceFileInfo = sourceFileInfo if sourceFileInfo
|
|
42
44
|
end
|
|
43
45
|
|
|
44
46
|
end
|
data/lib/TextScanner.rb
CHANGED
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
# published by the Free Software Foundation.
|
|
11
11
|
#
|
|
12
12
|
|
|
13
|
+
require 'stringio'
|
|
14
|
+
require 'strscan'
|
|
15
|
+
|
|
13
16
|
require 'UTF8String'
|
|
14
17
|
require 'TjTime'
|
|
15
18
|
require 'TjException'
|
|
@@ -20,10 +23,27 @@ require 'Log'
|
|
|
20
23
|
|
|
21
24
|
class TaskJuggler
|
|
22
25
|
|
|
23
|
-
# The TextScanner class
|
|
24
|
-
#
|
|
26
|
+
# The TextScanner class is an abstract text scanner with support for nested
|
|
27
|
+
# include files and text macros. The tokenizer will operate on rules that
|
|
28
|
+
# must be provided by a derived class. The scanner is modal. Each mode
|
|
29
|
+
# operates only with the subset of token patterns that are assigned to the
|
|
30
|
+
# current mode. The current line is tracked accurately and can be used for
|
|
31
|
+
# error reporting. The scanner can operate on Strings or Files.
|
|
25
32
|
class TextScanner
|
|
26
33
|
|
|
34
|
+
class MacroStackEntry
|
|
35
|
+
|
|
36
|
+
attr_reader :macro, :args, :text, :endPos
|
|
37
|
+
|
|
38
|
+
def initialize(macro, args, text, endPos)
|
|
39
|
+
@macro = macro
|
|
40
|
+
@args = args
|
|
41
|
+
@text = text
|
|
42
|
+
@endPos = endPos
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
27
47
|
# This class is used to handle the low-level input operations. It knows
|
|
28
48
|
# whether it deals with a text buffer or a file and abstracts this to the
|
|
29
49
|
# TextScanner. For each nested file the scanner puts an StreamHandle on the
|
|
@@ -32,21 +52,102 @@ class TaskJuggler
|
|
|
32
52
|
# completely processed.
|
|
33
53
|
class StreamHandle
|
|
34
54
|
|
|
35
|
-
|
|
36
|
-
attr_reader :fileName
|
|
55
|
+
attr_reader :fileName, :macroStack
|
|
37
56
|
|
|
38
57
|
def initialize
|
|
39
|
-
@lineNo = 1
|
|
40
|
-
@columnNo = 1
|
|
41
|
-
@line = ""
|
|
42
|
-
@charBuffer = []
|
|
43
58
|
@fileName = nil
|
|
59
|
+
@stream = nil
|
|
60
|
+
@line = nil
|
|
61
|
+
@pos = 0
|
|
62
|
+
@endPos = 1
|
|
63
|
+
@scanner = nil
|
|
64
|
+
@wrapped = false
|
|
65
|
+
@macroStack = []
|
|
66
|
+
@nextMacroEnd = nil
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def close
|
|
70
|
+
@stream = nil
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def injectMacro(macro, args, text)
|
|
74
|
+
@nextMacroEnd = @pos + text.length
|
|
75
|
+
@line = @line[0, @pos] + text + @line[@pos..-1]
|
|
76
|
+
@scanner = StringScanner.new(@line)
|
|
77
|
+
@scanner.pos = @pos
|
|
78
|
+
|
|
79
|
+
# Simple detection for recursive macro calls.
|
|
80
|
+
return false if @macroStack.length > 20
|
|
81
|
+
|
|
82
|
+
@macroStack << MacroStackEntry.new(macro, args, text, @nextMacroEnd)
|
|
83
|
+
true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def scan(re)
|
|
87
|
+
# We read the file line by line with gets(). If we don't have a line
|
|
88
|
+
# yet or we've reached the end of a line, we get the next one.
|
|
89
|
+
if @scanner.nil? || @scanner.eos?
|
|
90
|
+
if (@line = @stream.gets)
|
|
91
|
+
# Update activity meter about every 1024 lines.
|
|
92
|
+
Log.activity if (@stream.lineno & 0x3FF) == 0
|
|
93
|
+
# Check for DOS or Mac end of line signatures.
|
|
94
|
+
if @line[-1] == ?\r
|
|
95
|
+
# Mac: Convert CR into LF
|
|
96
|
+
@line[-1] = ?\n
|
|
97
|
+
elsif @line[-2] == ?\r
|
|
98
|
+
# DOS: Convert CR+LF into LF
|
|
99
|
+
@line = @line.chomp + "\n"
|
|
100
|
+
end
|
|
101
|
+
else
|
|
102
|
+
# We've reached the end of the current file.
|
|
103
|
+
@scanner = nil
|
|
104
|
+
# Return special EOF symbol.
|
|
105
|
+
return :scannerEOF
|
|
106
|
+
end
|
|
107
|
+
@scanner = StringScanner.new(@line)
|
|
108
|
+
@wrapped = @line[-1] == ?\n
|
|
109
|
+
end
|
|
110
|
+
return nil if (token = @scanner.scan(re)).nil?
|
|
111
|
+
#puts "#{re.to_s[0..20]}: [#{token}]"
|
|
112
|
+
|
|
113
|
+
@pos = @scanner.pos
|
|
114
|
+
while @nextMacroEnd && @nextMacroEnd < @pos
|
|
115
|
+
@macroStack.pop
|
|
116
|
+
@nextMacroEnd = @macroStack.empty? ? nil : @macroStack.last.endPos
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
token
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def peek(n)
|
|
123
|
+
@scanner ? @scanner.peek(n) : nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def eof?
|
|
127
|
+
@stream.eof? && @scanner.eos?
|
|
44
128
|
end
|
|
45
129
|
|
|
46
130
|
def dirname
|
|
47
131
|
@fileName ? File.dirname(@fileName) : ''
|
|
48
132
|
end
|
|
49
133
|
|
|
134
|
+
# Return the number of the currently processed line.
|
|
135
|
+
def lineNo
|
|
136
|
+
# The IO object counts the lines for us by counting the gets() calls.
|
|
137
|
+
currentLine = @stream && @scanner ? @stream.lineno : 1
|
|
138
|
+
# If we've just read the LF, we have to add 1. The LF can only be the
|
|
139
|
+
# last character of the line.
|
|
140
|
+
currentLine += 1 if @wrapped && @line && @scanner && @scanner.eos?
|
|
141
|
+
currentLine
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Return the already processed part of the current line.
|
|
145
|
+
def line
|
|
146
|
+
return '' unless @line
|
|
147
|
+
|
|
148
|
+
@line[0..(@scanner.pos - 1)]
|
|
149
|
+
end
|
|
150
|
+
|
|
50
151
|
end
|
|
51
152
|
|
|
52
153
|
# Specialized version of StreamHandle for operations on files.
|
|
@@ -57,53 +158,14 @@ class TaskJuggler
|
|
|
57
158
|
def initialize(fileName)
|
|
58
159
|
super()
|
|
59
160
|
@fileName = fileName.dup.untaint
|
|
60
|
-
@
|
|
61
|
-
@bytes = 0
|
|
161
|
+
@stream = fileName == '.' ? $stdin : File.new(@fileName, 'r')
|
|
62
162
|
Log << "Parsing file #{@fileName} ..."
|
|
63
163
|
Log.startProgressMeter("Reading file #{fileName}")
|
|
64
164
|
end
|
|
65
165
|
|
|
66
166
|
def close
|
|
67
|
-
@
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
def getc19
|
|
71
|
-
Log.activity if @bytes & 0x3FFF == 0
|
|
72
|
-
|
|
73
|
-
begin
|
|
74
|
-
# This function converts CR+LF or CR into LF on the fly.
|
|
75
|
-
if (c1 = @file.getc) == ?\r
|
|
76
|
-
@bytes += 1
|
|
77
|
-
# CR or CR/LF linebreaks
|
|
78
|
-
if (c2 = @file.getc) == ?\n
|
|
79
|
-
@bytes += 1
|
|
80
|
-
# Ok, CR, LF
|
|
81
|
-
return c2
|
|
82
|
-
else
|
|
83
|
-
# Just CR
|
|
84
|
-
@file.ungetc(c2)
|
|
85
|
-
return ?\n
|
|
86
|
-
end
|
|
87
|
-
else
|
|
88
|
-
# This is for LF linebreaks and all other characters
|
|
89
|
-
@bytes += 1
|
|
90
|
-
return c1
|
|
91
|
-
end
|
|
92
|
-
rescue
|
|
93
|
-
return nil
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def getc18
|
|
98
|
-
c = getc19
|
|
99
|
-
return nil if c.nil?
|
|
100
|
-
'' << c
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
if RUBY_VERSION < '1.9.0'
|
|
104
|
-
alias getc getc18
|
|
105
|
-
else
|
|
106
|
-
alias getc getc19
|
|
167
|
+
@stream.close unless @stream == $stdin
|
|
168
|
+
super
|
|
107
169
|
end
|
|
108
170
|
|
|
109
171
|
end
|
|
@@ -113,43 +175,10 @@ class TaskJuggler
|
|
|
113
175
|
|
|
114
176
|
def initialize(buffer)
|
|
115
177
|
super()
|
|
116
|
-
@
|
|
117
|
-
|
|
118
|
-
@pos = 0
|
|
119
|
-
Log << "Parsing buffer #{@buffer[0, 20]} ..."
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def close
|
|
123
|
-
@buffer = nil
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
def getc18
|
|
127
|
-
return nil if @pos >= @length
|
|
128
|
-
'' << getc19
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def getc19
|
|
132
|
-
return nil if @pos >= @length
|
|
133
|
-
|
|
134
|
-
# This function converts CR+LF or CR into LF on the fly.
|
|
135
|
-
if (c = @buffer[@pos]) == "\r"
|
|
136
|
-
# CR or CR+LF
|
|
137
|
-
@pos += 1 if @buffer[@pos + 1] == "\n"
|
|
138
|
-
c = "\n"
|
|
139
|
-
end
|
|
140
|
-
@pos += 1
|
|
141
|
-
c
|
|
178
|
+
@stream = StringIO.new(buffer)
|
|
179
|
+
Log << "Parsing buffer #{buffer[0, 20]} ..."
|
|
142
180
|
end
|
|
143
181
|
|
|
144
|
-
if RUBY_VERSION < '1.9.0'
|
|
145
|
-
alias getc getc18
|
|
146
|
-
else
|
|
147
|
-
alias getc getc19
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def fileName
|
|
151
|
-
''
|
|
152
|
-
end
|
|
153
182
|
end
|
|
154
183
|
|
|
155
184
|
# Create a new instance of TextScanner. _masterFile_ must be a String that
|
|
@@ -161,33 +190,78 @@ class TaskJuggler
|
|
|
161
190
|
# This table contains all macros that may be expanded when found in the
|
|
162
191
|
# text.
|
|
163
192
|
@macroTable = MacroTable.new(messageHandler)
|
|
193
|
+
# The currently processed IO object.
|
|
194
|
+
@cf = nil
|
|
164
195
|
# This Array stores the currently processed nested files. It's an Array
|
|
165
|
-
# of Arrays. The nested Array consists of
|
|
166
|
-
#
|
|
196
|
+
# of Arrays. The nested Array consists of 2 elements, the IO object and
|
|
197
|
+
# the @tokenBuffer.
|
|
167
198
|
@fileStack = []
|
|
168
|
-
# This
|
|
169
|
-
|
|
170
|
-
#
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
# This flag is set if we have reached the end of a file. Since we will
|
|
200
|
+
# only know when the next new token is requested that the file is really
|
|
201
|
+
# done now, we have to use this flag.
|
|
202
|
+
@finishLastFile = false
|
|
203
|
+
# True if the scanner operates on a buffer.
|
|
173
204
|
@fileNameIsBuffer = false
|
|
205
|
+
# A SourceFileInfo of the start of the currently processed token.
|
|
206
|
+
@startOfToken = nil
|
|
207
|
+
# Line number correction for error messages.
|
|
208
|
+
@lineDelta = 0
|
|
209
|
+
# Lists of regexps that describe the detectable tokens. The Arrays are
|
|
210
|
+
# grouped by mode.
|
|
211
|
+
@patternsByMode = { }
|
|
212
|
+
# The currently active scanner mode.
|
|
213
|
+
@scannerMode = nil
|
|
214
|
+
# Points to the currently active pattern set as defined by the mode.
|
|
215
|
+
@activePatterns = nil
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Add a new pattern to the scanner. _type_ is either nil for tokens that
|
|
219
|
+
# will be ignored, or some identifier that will be returned with each
|
|
220
|
+
# token of this type. _regExp_ is the RegExp that describes the token.
|
|
221
|
+
# _mode_ identifies the scanner mode where the pattern is active. If it's
|
|
222
|
+
# only a single mode, _mode_ specifies the mode directly. For multiple
|
|
223
|
+
# modes, it's an Array of modes. _postProc_ is a method reference. This
|
|
224
|
+
# method is called after the token has been detected. The method gets the
|
|
225
|
+
# type and the matching String and returns them again in an Array.
|
|
226
|
+
def addPattern(type, regExp, mode, postProc = nil)
|
|
227
|
+
if mode.is_a?(Array)
|
|
228
|
+
mode.each do |m|
|
|
229
|
+
# The pattern is active in multiple modes
|
|
230
|
+
@patternsByMode[m] = [] unless @patternsByMode.include?(m)
|
|
231
|
+
@patternsByMode[m] << [ type, regExp, postProc ]
|
|
232
|
+
end
|
|
233
|
+
else
|
|
234
|
+
# The pattern is only active in one specific mode.
|
|
235
|
+
@patternsByMode[mode] = [] unless @patternsByMode.include?(mode)
|
|
236
|
+
@patternsByMode[mode] << [ type, regExp, postProc ]
|
|
237
|
+
end
|
|
174
238
|
end
|
|
175
239
|
|
|
240
|
+
# Switch the parser to another mode. The scanner will then only detect
|
|
241
|
+
# with pattens of that _newMode_.
|
|
242
|
+
def mode=(newMode)
|
|
243
|
+
#puts "**** New mode: #{newMode}"
|
|
244
|
+
@activePatterns = @patternsByMode[newMode]
|
|
245
|
+
raise "Undefined mode #{newMode}" unless @activePatterns
|
|
246
|
+
@scannerMode = newMode
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
|
|
176
250
|
# Start the processing. if _fileNameIsBuffer_ is true, we operate on a
|
|
177
251
|
# String, else on a File.
|
|
178
252
|
def open(fileNameIsBuffer = false)
|
|
179
253
|
@fileNameIsBuffer = fileNameIsBuffer
|
|
180
254
|
if fileNameIsBuffer
|
|
181
|
-
@fileStack = [ [ @cf = BufferStreamHandle.new(@masterFile), nil
|
|
255
|
+
@fileStack = [ [ @cf = BufferStreamHandle.new(@masterFile), nil ] ]
|
|
182
256
|
else
|
|
183
257
|
begin
|
|
184
|
-
@fileStack = [ [ @cf = FileStreamHandle.new(@masterFile), nil
|
|
258
|
+
@fileStack = [ [ @cf = FileStreamHandle.new(@masterFile), nil ] ]
|
|
185
259
|
rescue StandardError
|
|
186
260
|
raise TjException.new, "Cannot open file #{@masterFile}"
|
|
187
261
|
end
|
|
188
262
|
end
|
|
189
263
|
@masterPath = @cf.dirname + '/'
|
|
190
|
-
@tokenBuffer =
|
|
264
|
+
@tokenBuffer = nil
|
|
191
265
|
end
|
|
192
266
|
|
|
193
267
|
# Finish processing and reset all data structures.
|
|
@@ -200,46 +274,46 @@ class TaskJuggler
|
|
|
200
274
|
@cf = @tokenBuffer = nil
|
|
201
275
|
end
|
|
202
276
|
|
|
203
|
-
# Continue processing with a new file specified by
|
|
204
|
-
# file is finished, we will continue in the old file after the
|
|
205
|
-
# where we started with the new file.
|
|
206
|
-
def include(
|
|
207
|
-
if
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
else
|
|
211
|
-
pathOfCallingFile = @fileStack.last[0].dirname
|
|
212
|
-
path = pathOfCallingFile.empty? ? '' : pathOfCallingFile + '/'
|
|
213
|
-
@fileStack.last[1, 2] = [ @tokenBuffer, @pos ]
|
|
214
|
-
end
|
|
277
|
+
# Continue processing with a new file specified by _includeFileName_. When
|
|
278
|
+
# this file is finished, we will continue in the old file after the
|
|
279
|
+
# location where we started with the new file.
|
|
280
|
+
def include(includeFileName, sfi)
|
|
281
|
+
if includeFileName[0] != '/'
|
|
282
|
+
pathOfCallingFile = @fileStack.last[0].dirname
|
|
283
|
+
path = pathOfCallingFile.empty? ? '' : pathOfCallingFile + '/'
|
|
215
284
|
# If the included file is not an absolute name, we interpret the file
|
|
216
285
|
# name relative to the including file.
|
|
217
|
-
|
|
286
|
+
includeFileName = path + includeFileName
|
|
218
287
|
end
|
|
219
288
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
@fileStack.each do |entry|
|
|
227
|
-
if fileName == entry[0].fileName
|
|
228
|
-
error('include_recursion', "Recursive inclusion of #{fileName} " +
|
|
229
|
-
"detected")
|
|
230
|
-
end
|
|
289
|
+
# Try to dectect recursive inclusions. This will not work if files are
|
|
290
|
+
# accessed via filesystem links.
|
|
291
|
+
@fileStack.each do |entry|
|
|
292
|
+
if includeFileName == entry[0].fileName
|
|
293
|
+
error('include_recursion',
|
|
294
|
+
"Recursive inclusion of #{includeFileName} detected", nil, sfi)
|
|
231
295
|
end
|
|
232
296
|
end
|
|
297
|
+
|
|
298
|
+
# Save @tokenBuffer in the record of the parent file.
|
|
299
|
+
@fileStack.last[1] = @tokenBuffer unless @fileStack.empty?
|
|
300
|
+
@tokenBuffer = nil
|
|
301
|
+
@finishLastFile = false
|
|
302
|
+
|
|
303
|
+
# Open the new file and push the handle on the @fileStack.
|
|
233
304
|
begin
|
|
234
|
-
@fileStack << [ (@cf = FileStreamHandle.new(
|
|
305
|
+
@fileStack << [ (@cf = FileStreamHandle.new(includeFileName)), nil, ]
|
|
306
|
+
Log << "Parsing file #{includeFileName}"
|
|
235
307
|
rescue StandardError
|
|
236
|
-
error('bad_include', "Cannot open include file #{
|
|
308
|
+
error('bad_include', "Cannot open include file #{includeFileName}",
|
|
309
|
+
nil, sfi)
|
|
237
310
|
end
|
|
238
311
|
end
|
|
239
312
|
|
|
240
313
|
# Return SourceFileInfo for the current processing prosition.
|
|
241
314
|
def sourceFileInfo
|
|
242
|
-
@
|
|
315
|
+
@cf ? SourceFileInfo.new(fileName, @cf.lineNo - @lineDelta, 0) :
|
|
316
|
+
SourceFileInfo.new(@masterFile, 0, 0)
|
|
243
317
|
end
|
|
244
318
|
|
|
245
319
|
# Return the name of the currently processed file. If we are working on a
|
|
@@ -253,94 +327,97 @@ class TaskJuggler
|
|
|
253
327
|
end
|
|
254
328
|
|
|
255
329
|
def columnNo # :nodoc:
|
|
256
|
-
|
|
330
|
+
0
|
|
257
331
|
end
|
|
258
332
|
|
|
259
333
|
def line # :nodoc:
|
|
260
334
|
@cf ? @cf.line : 0
|
|
261
335
|
end
|
|
262
336
|
|
|
263
|
-
#
|
|
264
|
-
#
|
|
337
|
+
# Return the next token from the input stream. The result is an Array with
|
|
338
|
+
# 3 entries: the token type, the token String and the SourceFileInfo where
|
|
339
|
+
# the token started.
|
|
265
340
|
def nextToken
|
|
266
341
|
# If we have a pushed-back token, return that first.
|
|
267
342
|
unless @tokenBuffer.nil?
|
|
268
343
|
res = @tokenBuffer
|
|
269
344
|
@tokenBuffer = nil
|
|
270
|
-
@pos = @tokenBufferPos
|
|
271
345
|
return res
|
|
272
346
|
end
|
|
273
347
|
|
|
348
|
+
if @finishLastFile
|
|
349
|
+
# The previously processed file has now really been processed to
|
|
350
|
+
# completion. Close it and remove the corresponding entry from the
|
|
351
|
+
# @fileStack.
|
|
352
|
+
@finishLastFile = false
|
|
353
|
+
#Log << "Completed file #{@cf.fileName}"
|
|
354
|
+
@cf.close
|
|
355
|
+
@fileStack.pop
|
|
356
|
+
|
|
357
|
+
if @fileStack.empty?
|
|
358
|
+
# We are done with the top-level file now.
|
|
359
|
+
@cf = @tokenBuffer = nil
|
|
360
|
+
@finishLastFile = true
|
|
361
|
+
return [ '.', '<END>', @startOfToken ]
|
|
362
|
+
else
|
|
363
|
+
# Continue parsing the file that included the current file.
|
|
364
|
+
@cf, tokenBuffer = @fileStack.last
|
|
365
|
+
Log << "Parsing file #{@cf.fileName} ..."
|
|
366
|
+
# If we have a left over token from previously processing this file,
|
|
367
|
+
# return it now.
|
|
368
|
+
return tokenBuffer if tokenBuffer
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
274
372
|
# Start processing characters from the input.
|
|
275
|
-
@startOfToken =
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
373
|
+
@startOfToken = sourceFileInfo
|
|
374
|
+
loop do
|
|
375
|
+
match = nil
|
|
376
|
+
begin
|
|
377
|
+
@activePatterns.each do |type, re, postProc|
|
|
378
|
+
if (match = @cf.scan(re))
|
|
379
|
+
if match == :scannerEOF
|
|
380
|
+
# We've found the end of an input file. Return a special token
|
|
381
|
+
# that describes the end of a file.
|
|
382
|
+
@finishLastFile = true
|
|
383
|
+
return [ '.', '<END>', @startOfToken ]
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
raise "#{re} matches empty string" if match.empty?
|
|
387
|
+
# If we have a post processing method, call it now. It may modify
|
|
388
|
+
# the type or the found token String.
|
|
389
|
+
type, match = postProc.call(type, match) if postProc
|
|
390
|
+
|
|
391
|
+
break if type.nil? # Ignore certain tokens with nil type.
|
|
392
|
+
|
|
393
|
+
return [ type, match, @startOfToken ]
|
|
394
|
+
end
|
|
283
395
|
end
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
token = readNumber(c)
|
|
293
|
-
break
|
|
294
|
-
when "'"
|
|
295
|
-
token = readString(c)
|
|
296
|
-
break
|
|
297
|
-
when '"'
|
|
298
|
-
token = readString(c)
|
|
299
|
-
break
|
|
300
|
-
when '-'
|
|
301
|
-
token = handleDash
|
|
302
|
-
break
|
|
303
|
-
when '!'
|
|
304
|
-
if (c = nextChar) == '='
|
|
305
|
-
token = [ 'LITERAL', '!=' ]
|
|
396
|
+
rescue
|
|
397
|
+
error('scan_encoding_error', $!.to_s)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
if match.nil?
|
|
401
|
+
if @cf.eof?
|
|
402
|
+
error('unexpected_eof',
|
|
403
|
+
"Unexpected end of file found")
|
|
306
404
|
else
|
|
307
|
-
|
|
308
|
-
|
|
405
|
+
error('no_token_match',
|
|
406
|
+
"Unexpected characters found: '#{@cf.peek(10)}...'")
|
|
309
407
|
end
|
|
310
|
-
break
|
|
311
|
-
when 'a'..'z', 'A'..'Z', '_'
|
|
312
|
-
token = readId(c)
|
|
313
|
-
break
|
|
314
|
-
when '<', '>', '='
|
|
315
|
-
token = readOperator(c)
|
|
316
|
-
break
|
|
317
|
-
when '['
|
|
318
|
-
token = readMacro
|
|
319
|
-
break
|
|
320
|
-
when nil
|
|
321
|
-
# We've reached an end of file or buffer
|
|
322
|
-
break
|
|
323
|
-
else
|
|
324
|
-
str = ""
|
|
325
|
-
str << c
|
|
326
|
-
token = [ 'LITERAL', str ]
|
|
327
|
-
break
|
|
328
408
|
end
|
|
329
409
|
end
|
|
330
|
-
@pos = @startOfToken
|
|
331
|
-
return token
|
|
332
410
|
end
|
|
333
411
|
|
|
334
412
|
# Return a token to retrieve it with the next nextToken() call again. Only 1
|
|
335
413
|
# token can be returned before the next nextToken() call.
|
|
336
414
|
def returnToken(token)
|
|
415
|
+
#Log << "-> Returning Token: [#{token[0]}][#{token[1]}]"
|
|
337
416
|
unless @tokenBuffer.nil?
|
|
338
417
|
$stderr.puts @tokenBuffer
|
|
339
418
|
raise "Fatal Error: Cannot return more than 1 token in a row"
|
|
340
419
|
end
|
|
341
420
|
@tokenBuffer = token
|
|
342
|
-
@tokenBufferPos = @pos
|
|
343
|
-
@pos = @lastPos
|
|
344
421
|
end
|
|
345
422
|
|
|
346
423
|
# Add a Macro to the macro translation table.
|
|
@@ -353,548 +430,54 @@ class TaskJuggler
|
|
|
353
430
|
@macroTable.include?(name)
|
|
354
431
|
end
|
|
355
432
|
|
|
356
|
-
|
|
433
|
+
# Expand a macro and inject it into the input stream. _prefix_ is any
|
|
434
|
+
# string that was found right before the macro call. We have to inject it
|
|
435
|
+
# before the expanded macro. _args_ is an Array of Strings. The first is
|
|
436
|
+
# the macro name, the rest are the parameters.
|
|
437
|
+
def expandMacro(prefix, args)
|
|
438
|
+
# Get the expanded macro from the @macroTable.
|
|
357
439
|
macro, text = @macroTable.resolve(args, sourceFileInfo)
|
|
440
|
+
# If the expanded macro is empty, we can ignore it.
|
|
358
441
|
return if text == ''
|
|
359
442
|
|
|
360
|
-
|
|
443
|
+
unless @cf.injectMacro(macro, args, prefix + text)
|
|
361
444
|
error('macro_stack_overflow', "Too many nested macro calls.")
|
|
362
445
|
end
|
|
363
|
-
@macroStack << [ macro, args ]
|
|
364
|
-
# Mark end of macro with a 0 element
|
|
365
|
-
@cf.charBuffer << 0
|
|
366
|
-
text.reverse.each_utf8_char do |c|
|
|
367
|
-
@cf.charBuffer << c
|
|
368
|
-
end
|
|
369
|
-
@cf.line = ''
|
|
370
446
|
end
|
|
371
447
|
|
|
372
448
|
# Call this function to report any errors related to the parsed input.
|
|
373
|
-
def error(id, text, property = nil)
|
|
374
|
-
message('error', id, text, property)
|
|
449
|
+
def error(id, text, property = nil, sfi = nil)
|
|
450
|
+
message('error', id, text, property, sfi)
|
|
375
451
|
end
|
|
376
452
|
|
|
377
|
-
def warning(id, text, property = nil)
|
|
378
|
-
message('warning', id, text, property)
|
|
453
|
+
def warning(id, text, property = nil, sfi = nil)
|
|
454
|
+
message('warning', id, text, property, sfi)
|
|
379
455
|
end
|
|
380
456
|
|
|
381
|
-
def message(type, id, text, property)
|
|
457
|
+
def message(type, id, text, property, sfi)
|
|
382
458
|
unless text.empty?
|
|
383
459
|
message = Message.new(id, type, text + "\n" + line.to_s,
|
|
384
|
-
property, nil, sourceFileInfo)
|
|
460
|
+
property, nil, sfi || sourceFileInfo)
|
|
385
461
|
@messageHandler.send(message)
|
|
386
462
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
args.collect! { |a| '"' + a + '"' }
|
|
390
|
-
message = Message.new('macro_stack', 'info',
|
|
391
|
-
" #{macro.name} #{args.join(' ')}", nil, nil,
|
|
392
|
-
macro.sourceFileInfo)
|
|
463
|
+
if @cf && !@cf.macroStack.empty?
|
|
464
|
+
message = Message.new('macro_stack', 'info', 'Macro call history:')
|
|
393
465
|
@messageHandler.send(message)
|
|
394
|
-
end
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
# An empty strings signals an already reported error
|
|
398
|
-
raise TjException.new, '' if type == 'error'
|
|
399
|
-
end
|
|
400
466
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
# @pos, don't reset it if we have processed all files completely.
|
|
410
|
-
if @pos && @cf
|
|
411
|
-
@lastPos = @pos
|
|
412
|
-
@pos = nil
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
if (c = nextCharI) == '$' && !@ignoreMacros
|
|
416
|
-
# Double $ are reduced to a single $.
|
|
417
|
-
return c if (c = nextCharI) == '$'
|
|
418
|
-
|
|
419
|
-
# Macros start with $( or ${. All other $. are ignored.
|
|
420
|
-
if c != '(' && c != '{'
|
|
421
|
-
returnChar(c)
|
|
422
|
-
return '$'
|
|
423
|
-
end
|
|
424
|
-
|
|
425
|
-
@ignoreMacros = true
|
|
426
|
-
returnChar(c)
|
|
427
|
-
macroParser = MacroParser.new(self, @messageHandler)
|
|
428
|
-
begin
|
|
429
|
-
macroParser.parse('macroCall')
|
|
430
|
-
rescue TjException
|
|
431
|
-
end
|
|
432
|
-
@ignoreMacros = false
|
|
433
|
-
return nextCharI
|
|
434
|
-
else
|
|
435
|
-
return c
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
def nextCharI
|
|
440
|
-
# This can only happen when a previous call already returned nil.
|
|
441
|
-
return nil if @cf.nil?
|
|
442
|
-
|
|
443
|
-
c = nil
|
|
444
|
-
# If there are characters in the return buffer process them first.
|
|
445
|
-
# Otherwise get next character from input stream.
|
|
446
|
-
unless @cf.charBuffer.empty?
|
|
447
|
-
c = @cf.charBuffer.pop
|
|
448
|
-
@cf.lineNo -= 1 if c == "\n" && !@macroStack.empty?
|
|
449
|
-
while !@cf.charBuffer.empty? && @cf.charBuffer[-1] == 0
|
|
450
|
-
@cf.charBuffer.pop
|
|
451
|
-
@macroStack.pop
|
|
452
|
-
end
|
|
453
|
-
else
|
|
454
|
-
# If EOF has been reached, try the parent file until even the master
|
|
455
|
-
# file has been processed completely.
|
|
456
|
-
if (c = @cf.getc).nil?
|
|
457
|
-
# Safe current position so an EOF related error can be properly
|
|
458
|
-
# reported.
|
|
459
|
-
@pos = sourceFileInfo
|
|
460
|
-
|
|
461
|
-
@cf.close
|
|
462
|
-
@fileStack.pop
|
|
463
|
-
if @fileStack.empty?
|
|
464
|
-
# We are done with the top-level file now.
|
|
465
|
-
@cf = @tokenBuffer = nil
|
|
466
|
-
else
|
|
467
|
-
@cf, @tokenBuffer, @lastPos = @fileStack.last
|
|
468
|
-
Log << "Parsing file #{@cf.fileName} ..."
|
|
469
|
-
# We have been called by nextToken() already, so we can't just
|
|
470
|
-
# restore @tokenBuffer and be done. We need to feed the token text
|
|
471
|
-
# back into the charBuffer and return the first character.
|
|
472
|
-
if @tokenBuffer
|
|
473
|
-
@tokenBuffer[1].reverse.each_utf8_char do |ch|
|
|
474
|
-
@cf.charBuffer.push(ch)
|
|
475
|
-
end
|
|
476
|
-
@tokenBuffer = nil
|
|
477
|
-
end
|
|
467
|
+
@cf.macroStack.reverse_each do |entry|
|
|
468
|
+
macro = entry.macro
|
|
469
|
+
args = entry.args[1..-1]
|
|
470
|
+
args.collect! { |a| '"' + a + '"' }
|
|
471
|
+
message = Message.new('macro_stack', 'info',
|
|
472
|
+
" ${#{macro.name} #{args.join(' ')}}",
|
|
473
|
+
nil, nil, macro.sourceFileInfo)
|
|
474
|
+
@messageHandler.send(message)
|
|
478
475
|
end
|
|
479
|
-
return nil
|
|
480
476
|
end
|
|
481
477
|
end
|
|
482
|
-
unless c.nil?
|
|
483
|
-
@cf.lineNo += 1 if c == "\n"
|
|
484
|
-
@cf.line = "" if @cf.line[-1] == ?\n
|
|
485
|
-
@cf.line << c
|
|
486
|
-
end
|
|
487
|
-
c
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
def returnChar(c)
|
|
491
|
-
return if @cf.nil?
|
|
492
478
|
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
@cf.lineNo -= 1 if c == "\n" && @macroStack.empty?
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
def skipComment
|
|
499
|
-
# Read all characters until line or file end is found
|
|
500
|
-
@ignoreMacros = true
|
|
501
|
-
while (c = nextChar) && c != "\n"
|
|
502
|
-
end
|
|
503
|
-
@ignoreMacros = false
|
|
504
|
-
returnChar(c)
|
|
505
|
-
end
|
|
506
|
-
|
|
507
|
-
def skipCPlusPlusComments
|
|
508
|
-
if (c = nextChar) == '*'
|
|
509
|
-
# /* */ style multi-line comment
|
|
510
|
-
@ignoreMacros = true
|
|
511
|
-
begin
|
|
512
|
-
while (c = nextChar) != '*'
|
|
513
|
-
end
|
|
514
|
-
end until (c = nextChar) == '/'
|
|
515
|
-
@ignoreMacros = false
|
|
516
|
-
elsif c == '/'
|
|
517
|
-
# // style single line comment
|
|
518
|
-
skipComment
|
|
519
|
-
else
|
|
520
|
-
error('bad_comment', "'/' or '*' expected after start of comment")
|
|
521
|
-
end
|
|
522
|
-
end
|
|
523
|
-
|
|
524
|
-
def handleDash
|
|
525
|
-
if (c1 = nextChar) == '8'
|
|
526
|
-
if (c2 = nextChar) == '<'
|
|
527
|
-
if (c3 = nextChar) == '-'
|
|
528
|
-
return readIndentedString
|
|
529
|
-
else
|
|
530
|
-
returnChar(c3)
|
|
531
|
-
returnChar(c2)
|
|
532
|
-
returnChar(c1)
|
|
533
|
-
end
|
|
534
|
-
else
|
|
535
|
-
returnChar(c2)
|
|
536
|
-
returnChar(c1)
|
|
537
|
-
end
|
|
538
|
-
else
|
|
539
|
-
returnChar(c1)
|
|
540
|
-
end
|
|
541
|
-
return [ 'LITERAL', ' - ']
|
|
542
|
-
end
|
|
543
|
-
|
|
544
|
-
def readBlanks(c)
|
|
545
|
-
loop do
|
|
546
|
-
if c == ' '
|
|
547
|
-
if (c2 = nextChar) == '-'
|
|
548
|
-
# Special case for the dash between period dates. It must be
|
|
549
|
-
# surrounded by blanks.
|
|
550
|
-
if (c3 = nextChar) == ' '
|
|
551
|
-
return [ 'LITERAL', ' - ']
|
|
552
|
-
end
|
|
553
|
-
returnChar(c3)
|
|
554
|
-
end
|
|
555
|
-
returnChar(c2)
|
|
556
|
-
elsif c != "\n" && c != "\t"
|
|
557
|
-
returnChar(c)
|
|
558
|
-
return nil
|
|
559
|
-
end
|
|
560
|
-
c = nextChar
|
|
561
|
-
end
|
|
562
|
-
end
|
|
563
|
-
|
|
564
|
-
def readNumber(c)
|
|
565
|
-
token = ""
|
|
566
|
-
token << c
|
|
567
|
-
while ('0'..'9') === (c = nextChar)
|
|
568
|
-
token << c
|
|
569
|
-
end
|
|
570
|
-
if c == '-'
|
|
571
|
-
return readDate(token)
|
|
572
|
-
elsif c == '.'
|
|
573
|
-
frac = readDigits
|
|
574
|
-
|
|
575
|
-
return [ 'FLOAT', token.to_f + frac.to_f / (10.0 ** frac.length) ]
|
|
576
|
-
elsif c == ':'
|
|
577
|
-
hours = token.to_i
|
|
578
|
-
mins = readDigits.to_i
|
|
579
|
-
if hours < 0 || hours > 24
|
|
580
|
-
raise TjException.new, "Hour must be between 0 and 23"
|
|
581
|
-
end
|
|
582
|
-
if mins < 0 || mins > 59
|
|
583
|
-
raise TjException.new, "Minutes must be between 0 and 59"
|
|
584
|
-
end
|
|
585
|
-
if hours == 24 && mins != 0
|
|
586
|
-
raise TjException.new, "Time may not be larger than 24:00"
|
|
587
|
-
end
|
|
588
|
-
|
|
589
|
-
# Return time as seconds of day since midnight.
|
|
590
|
-
return [ 'TIME', hours * 60 * 60 + mins * 60 ]
|
|
591
|
-
else
|
|
592
|
-
returnChar(c)
|
|
593
|
-
end
|
|
594
|
-
|
|
595
|
-
[ 'INTEGER', token.to_i ]
|
|
596
|
-
end
|
|
597
|
-
|
|
598
|
-
def readDate(token)
|
|
599
|
-
year = token.to_i
|
|
600
|
-
if year < 1970 || year > 2030
|
|
601
|
-
raise TjException.new, "Year must be between 1970 and 2030"
|
|
602
|
-
end
|
|
603
|
-
|
|
604
|
-
month = readDigits.to_i
|
|
605
|
-
if month < 1 || month > 12
|
|
606
|
-
raise TjException.new, "Month must be between 1 and 12"
|
|
607
|
-
end
|
|
608
|
-
if nextChar != '-'
|
|
609
|
-
raise TjException.new, "Corrupted date"
|
|
610
|
-
end
|
|
611
|
-
|
|
612
|
-
day = readDigits.to_i
|
|
613
|
-
if day < 1 || day > 31
|
|
614
|
-
raise TjException.new, "Day must be between 1 and 31"
|
|
615
|
-
end
|
|
616
|
-
|
|
617
|
-
if (c = nextChar) != '-'
|
|
618
|
-
returnChar(c)
|
|
619
|
-
return [ 'DATE', TjTime.local(year, month, day) ]
|
|
620
|
-
end
|
|
621
|
-
|
|
622
|
-
hour = readDigits.to_i
|
|
623
|
-
if hour < 0 || hour > 23
|
|
624
|
-
raise TjException.new, "Hour must be between 0 and 23"
|
|
625
|
-
end
|
|
626
|
-
|
|
627
|
-
if nextChar != ':'
|
|
628
|
-
raise TjException.new, "Corrupted time. ':' expected."
|
|
629
|
-
end
|
|
630
|
-
|
|
631
|
-
minutes = readDigits.to_i
|
|
632
|
-
if minutes < 0 || minutes > 59
|
|
633
|
-
raise TjException.new, "Minutes must be between 0 and 59"
|
|
634
|
-
end
|
|
635
|
-
|
|
636
|
-
if (c = nextChar) == ':'
|
|
637
|
-
seconds = readDigits.to_i
|
|
638
|
-
if seconds < 0 || seconds > 59
|
|
639
|
-
raise TjException.new, "Seconds must be between 0 and 59"
|
|
640
|
-
end
|
|
641
|
-
else
|
|
642
|
-
seconds = 0
|
|
643
|
-
returnChar(c)
|
|
644
|
-
end
|
|
645
|
-
|
|
646
|
-
if (c = nextChar) != '-'
|
|
647
|
-
returnChar(c)
|
|
648
|
-
return [ 'DATE', TjTime.local(year, month, day, hour, minutes, seconds) ]
|
|
649
|
-
end
|
|
650
|
-
|
|
651
|
-
if (c = nextChar) == '-'
|
|
652
|
-
delta = 1
|
|
653
|
-
elsif c == '+'
|
|
654
|
-
delta = -1
|
|
655
|
-
else
|
|
656
|
-
# An actual time zone name
|
|
657
|
-
tz = readId(c)[1]
|
|
658
|
-
oldTz = ENV['TZ']
|
|
659
|
-
ENV['TZ'] = tz
|
|
660
|
-
timeVal = TjTime.local(year, month, day, hour, minutes, seconds)
|
|
661
|
-
ENV['TZ'] = oldTz
|
|
662
|
-
if timeVal.to_a[9] != tz
|
|
663
|
-
raise TjException.new, "Unknown time zone #{tz}"
|
|
664
|
-
end
|
|
665
|
-
return [ 'DATE', timeVal ]
|
|
666
|
-
end
|
|
667
|
-
|
|
668
|
-
utcDiff = readDigits
|
|
669
|
-
utcHour = utcDiff[0, 2].to_i
|
|
670
|
-
if utcHour < 0 || utcHour > 23
|
|
671
|
-
raise TjException.new, "Hour must be between 0 and 23"
|
|
672
|
-
end
|
|
673
|
-
utcMin = utcDiff[2, 2].to_i
|
|
674
|
-
if utcMin < 0 || utcMin > 59
|
|
675
|
-
raise TjException.new, "Minutes must be between 0 and 59"
|
|
676
|
-
end
|
|
677
|
-
|
|
678
|
-
[ 'DATE', TjTime.gm(year, month, day, hour, minutes, seconds) +
|
|
679
|
-
delta * ((utcHour * 3600) + utcMin * 60) ]
|
|
680
|
-
end
|
|
681
|
-
|
|
682
|
-
def readString(terminator)
|
|
683
|
-
token = ""
|
|
684
|
-
while (c = nextChar) && c != terminator
|
|
685
|
-
if c == "\\"
|
|
686
|
-
# Terminators can be used as regular characters when prefixed by a \.
|
|
687
|
-
if (c = nextChar) && c != terminator
|
|
688
|
-
# \ followed by non-terminator. Just add both.
|
|
689
|
-
token << "\\"
|
|
690
|
-
end
|
|
691
|
-
end
|
|
692
|
-
token << c
|
|
693
|
-
end
|
|
694
|
-
|
|
695
|
-
[ 'STRING', token ]
|
|
696
|
-
end
|
|
697
|
-
|
|
698
|
-
def readIndentedString
|
|
699
|
-
state = 0
|
|
700
|
-
indent = ''
|
|
701
|
-
token = ''
|
|
702
|
-
while true
|
|
703
|
-
case state
|
|
704
|
-
when 0 # Determining indent
|
|
705
|
-
# Skip trailing spaces and tabs.
|
|
706
|
-
while (c = nextChar) == ' ' || c == "\t" do
|
|
707
|
-
# empty on purpose
|
|
708
|
-
end
|
|
709
|
-
if c != "\n"
|
|
710
|
-
error('junk_after_cut',
|
|
711
|
-
'The cut mark -8<- must be immediately followed by a ' +
|
|
712
|
-
'line break.')
|
|
713
|
-
end
|
|
714
|
-
while (c = nextChar) == ' ' || c == "\t"
|
|
715
|
-
indent << c
|
|
716
|
-
end
|
|
717
|
-
@startOfToken = SourceFileInfo.new(fileName, lineNo, columnNo)
|
|
718
|
-
returnChar(c)
|
|
719
|
-
state = 1
|
|
720
|
-
when 1 # reading '-' or first content line character
|
|
721
|
-
if (c = nextChar) == '-'
|
|
722
|
-
state = 3
|
|
723
|
-
elsif c.nil?
|
|
724
|
-
errorEOF(1, token)
|
|
725
|
-
elsif c == "\n"
|
|
726
|
-
token << c
|
|
727
|
-
state = 6
|
|
728
|
-
else
|
|
729
|
-
token << c
|
|
730
|
-
state = 2
|
|
731
|
-
end
|
|
732
|
-
when 2 # reading content line
|
|
733
|
-
# The '->8-' is only valid if no other content preceded it on this
|
|
734
|
-
# line.
|
|
735
|
-
onlyBlanks = true
|
|
736
|
-
while (c = nextChar) != "\n" && !(c == '-' && onlyBlanks)
|
|
737
|
-
onlyBlanks = false if c != ' ' && c != "\t"
|
|
738
|
-
errorEOF(2, token) if c.nil?
|
|
739
|
-
token << c
|
|
740
|
-
end
|
|
741
|
-
if c == '-'
|
|
742
|
-
# we may have found the start of '->8-'
|
|
743
|
-
state = 3
|
|
744
|
-
else
|
|
745
|
-
token << c
|
|
746
|
-
state = 6
|
|
747
|
-
end
|
|
748
|
-
when 3 # reading '>' of '->8-'
|
|
749
|
-
if (c = nextChar) == '>'
|
|
750
|
-
state = 4
|
|
751
|
-
else
|
|
752
|
-
errorEOF(3, token) if c.nil?
|
|
753
|
-
token << '-'
|
|
754
|
-
token << c
|
|
755
|
-
state = 2
|
|
756
|
-
end
|
|
757
|
-
when 4 # reading '8' of '->8-'
|
|
758
|
-
if (c = nextChar) == '8'
|
|
759
|
-
state = 5
|
|
760
|
-
else
|
|
761
|
-
errorEOF(4, token) if c.nil?
|
|
762
|
-
token << c
|
|
763
|
-
state = 2
|
|
764
|
-
end
|
|
765
|
-
when 5 # reading '-' of '->8-'
|
|
766
|
-
if (c = nextChar) == '-'
|
|
767
|
-
return [ 'STRING', token ]
|
|
768
|
-
else
|
|
769
|
-
errorEOF(5, token) if c.nil?
|
|
770
|
-
token << c
|
|
771
|
-
state = 2
|
|
772
|
-
end
|
|
773
|
-
when 6 # reading indentation
|
|
774
|
-
state = 1
|
|
775
|
-
indent.each_utf8_char do |ci|
|
|
776
|
-
if ci != (c = nextChar)
|
|
777
|
-
if c == '-'
|
|
778
|
-
state = 3
|
|
779
|
-
break
|
|
780
|
-
elsif c == "\n"
|
|
781
|
-
returnChar(c)
|
|
782
|
-
break
|
|
783
|
-
else
|
|
784
|
-
warning('bad_indent',
|
|
785
|
-
"Not all lines of string have same indentation. " +
|
|
786
|
-
"The first line of the string determines the " +
|
|
787
|
-
"indentation for all subsequent lines of the same " +
|
|
788
|
-
"string.")
|
|
789
|
-
token << c
|
|
790
|
-
state = 2
|
|
791
|
-
break
|
|
792
|
-
end
|
|
793
|
-
end
|
|
794
|
-
end
|
|
795
|
-
else
|
|
796
|
-
raise "State machine error"
|
|
797
|
-
end
|
|
798
|
-
end
|
|
799
|
-
end
|
|
800
|
-
|
|
801
|
-
def readId(c)
|
|
802
|
-
token = ""
|
|
803
|
-
token << c
|
|
804
|
-
while (c = nextChar) &&
|
|
805
|
-
(('a'..'z') === c || ('A'..'Z') === c || ('0'..'9') === c ||
|
|
806
|
-
c == '_')
|
|
807
|
-
token << c
|
|
808
|
-
end
|
|
809
|
-
if c == ':'
|
|
810
|
-
return [ 'ID_WITH_COLON', token ]
|
|
811
|
-
elsif c == '.'
|
|
812
|
-
token << c
|
|
813
|
-
loop do
|
|
814
|
-
token += readIdentifier
|
|
815
|
-
break if (c = nextChar) != '.'
|
|
816
|
-
token += '.'
|
|
817
|
-
end
|
|
818
|
-
returnChar c
|
|
819
|
-
|
|
820
|
-
return [ 'ABSOLUTE_ID', token ]
|
|
821
|
-
else
|
|
822
|
-
returnChar c
|
|
823
|
-
return [ 'ID', token ]
|
|
824
|
-
end
|
|
825
|
-
end
|
|
826
|
-
|
|
827
|
-
def readMacro
|
|
828
|
-
# We can deal with ']' inside of the macro as long as each ']' is
|
|
829
|
-
# preceeded by a corresponding '['.
|
|
830
|
-
token = ''
|
|
831
|
-
bracketLevel = 1
|
|
832
|
-
while bracketLevel > 0
|
|
833
|
-
case (c = nextCharI)
|
|
834
|
-
when nil
|
|
835
|
-
error('unterminated_macro', "Unterminated macro #{token}")
|
|
836
|
-
when '['
|
|
837
|
-
bracketLevel += 1
|
|
838
|
-
when ']'
|
|
839
|
-
bracketLevel -= 1
|
|
840
|
-
end
|
|
841
|
-
token << c unless bracketLevel == 0
|
|
842
|
-
end
|
|
843
|
-
return [ 'MACRO', token ]
|
|
844
|
-
end
|
|
845
|
-
|
|
846
|
-
# Read operators of logical expressions.
|
|
847
|
-
def readOperator(c)
|
|
848
|
-
case c
|
|
849
|
-
when '='
|
|
850
|
-
return [ 'LITERAL', '=' ]
|
|
851
|
-
when '>'
|
|
852
|
-
return [ 'LITERAL', '>=' ] if (c = nextChar) == '='
|
|
853
|
-
returnChar(c)
|
|
854
|
-
return [ 'LITERAL', '>' ]
|
|
855
|
-
when '<'
|
|
856
|
-
return [ 'LITERAL', '<=' ] if (c = nextChar) == '='
|
|
857
|
-
returnChar(c)
|
|
858
|
-
return [ 'LITERAL', '<' ]
|
|
859
|
-
else
|
|
860
|
-
raise "Unsupported operator #{c}"
|
|
861
|
-
end
|
|
862
|
-
end
|
|
863
|
-
|
|
864
|
-
# Read only decimal digits and return the result als Fixnum.
|
|
865
|
-
def readDigits
|
|
866
|
-
token = ""
|
|
867
|
-
while ('0'..'9') === (c = nextChar)
|
|
868
|
-
token << c
|
|
869
|
-
end
|
|
870
|
-
# Make sure that we have read at least one digit.
|
|
871
|
-
if token == ""
|
|
872
|
-
raise TjException.new, "Digit (0 - 9) expected"
|
|
873
|
-
end
|
|
874
|
-
# Push back the non-digit that terminated the digits.
|
|
875
|
-
returnChar(c)
|
|
876
|
-
token
|
|
877
|
-
end
|
|
878
|
-
|
|
879
|
-
def readIdentifier(noDigit = true)
|
|
880
|
-
token = ""
|
|
881
|
-
while (c = nextChar) &&
|
|
882
|
-
(('a'..'z') === c || ('A'..'Z') === c ||
|
|
883
|
-
(!noDigit && (('0'..'9') === c)) || c == '_')
|
|
884
|
-
token << c
|
|
885
|
-
noDigit = false
|
|
886
|
-
end
|
|
887
|
-
returnChar(c)
|
|
888
|
-
if token == ""
|
|
889
|
-
raise TjException.new, "Identifier expected"
|
|
890
|
-
end
|
|
891
|
-
token
|
|
892
|
-
end
|
|
893
|
-
|
|
894
|
-
def errorEOF(no, token)
|
|
895
|
-
error("eof_in_istring#{no}",
|
|
896
|
-
"Unexpected end of file in string '#{token[0,20]}...'" +
|
|
897
|
-
"starting in line #{@startOfToken.lineNo}.")
|
|
479
|
+
# An empty strings signals an already reported error
|
|
480
|
+
raise TjException.new, '' if type == 'error'
|
|
898
481
|
end
|
|
899
482
|
|
|
900
483
|
end
|