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/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
|